diff options
Diffstat (limited to 'jni/ruby/test/ruby')
127 files changed, 66551 insertions, 0 deletions
diff --git a/jni/ruby/test/ruby/allpairs.rb b/jni/ruby/test/ruby/allpairs.rb new file mode 100644 index 0000000..27b6f59 --- /dev/null +++ b/jni/ruby/test/ruby/allpairs.rb @@ -0,0 +1,102 @@ +module AllPairs + module_function + + def make_prime(v) + return 2 if v < 2 + ary = [true] * (v*2) + 2.upto(Math.sqrt(ary.length).ceil) {|i| + return i if ary[i] && v <= i + (i*2).step(ary.length, i) {|j| + ary[j] = false + } + } + v.upto(ary.length-1) {|i| + return i if ary[i] + } + raise "[bug] prime not found greater than #{v}" + end + + def make_basic_block(prime) + prime.times {|i| + prime.times {|j| + row = [i] + 0.upto(prime-1) {|m| + row << (i*m + j) % prime + } + yield row + } + } + end + + def combine_block(tbl1, tbl2) + result = [] + tbl2.each {|row| + result << row * tbl1.first.length + } + tbl1.each_with_index {|row, k| + next if k == 0 + result << row.map {|i| [i] * tbl2.first.length }.flatten + } + result + end + + def make_large_block(v, prime) + if prime <= v+1 + make_basic_block(v) {|row| + yield row + } + else + tbl = [] + make_basic_block(v) {|row| + tbl << row + } + tbls = [tbl] + while tbl.first.length ** 2 < prime + tbl = combine_block(tbl, tbl) + tbls << tbl + end + tbl1 = tbls.find {|t| prime <= t.first.length * tbl.first.length } + tbl = combine_block(tbl, tbl1) + tbl.each {|row| + yield row + } + end + end + + def each_index(*vs) + n = vs.length + max_v = vs.max + h = {} + make_large_block(max_v, n) {|row| + row = vs.zip(row).map {|v, i| i % v } + next if h[row] + h[row] = true + yield row + } + end + + # generate all pairs test. + def each(*args) + args.map! {|a| a.to_a } + each_index(*args.map {|a| a.length}) {|is| + yield is.zip(args).map {|i, a| a[i] } + } + end + + # generate all combination in cartesian product. (not all-pairs test) + def exhaustive_each(*args) + args = args.map {|a| a.to_a } + i = 0 + while true + n = i + as = [] + args.reverse_each {|a| + n, m = n.divmod(a.length) + as.unshift a[m] + } + break if 0 < n + yield as + i += 1 + end + end +end diff --git a/jni/ruby/test/ruby/beginmainend.rb b/jni/ruby/test/ruby/beginmainend.rb new file mode 100644 index 0000000..6cdfb15 --- /dev/null +++ b/jni/ruby/test/ruby/beginmainend.rb @@ -0,0 +1,80 @@ +errout = ARGV.shift + +BEGIN { + puts "b1" + local_begin1 = "local_begin1" + $global_begin1 = "global_begin1" + ConstBegin1 = "ConstBegin1" +} + +BEGIN { + puts "b2" + + BEGIN { + puts "b2-1" + } +} + +# for scope check +#raise if defined?(local_begin1) +raise unless defined?($global_begin1) +raise unless defined?(::ConstBegin1) +local_for_end2 = "e2" +$global_for_end1 = "e1" + +puts "main" + +END { + puts local_for_end2 # e2 +} + +eval <<EOE + BEGIN { + puts "b3" + + BEGIN { + puts "b3-1" + } + } + + BEGIN { + puts "b4" + } + + END { + puts "e3" + } + + END { + puts "e4" + + END { + puts "e4-1" + + END { + puts "e4-1-1" + } + } + + END { + puts "e4-2" + } + } +EOE + +END { + exit + puts "should not be dumped" + + END { + puts "not reached" + } +} + +END { + puts $global_for_end1 # e1 + + END { + puts "e1-1" + } +} diff --git a/jni/ruby/test/ruby/enc/test_big5.rb b/jni/ruby/test/ruby/enc/test_big5.rb new file mode 100644 index 0000000..e8fe027 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_big5.rb @@ -0,0 +1,28 @@ +require "test/unit" + +class TestBig5 < Test::Unit::TestCase + def s(s) + s.force_encoding("big5") + end + + def test_mbc_enc_len + assert_equal(1, s("\xa1\xa1").size) + end + + def test_mbc_to_code + assert_equal(0xa1a1, s("\xa1\xa1").ord) + end + + def test_code_to_mbc + assert_equal(s("\xa1\xa1"), 0xa1a1.chr("big5")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\xa1\xa1)\\1"), "i") + assert_match(r, s("\xa1\xa1\xa1\xa1")) + end + + def test_left_adjust_char_head + assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop) + end +end diff --git a/jni/ruby/test/ruby/enc/test_cp949.rb b/jni/ruby/test/ruby/enc/test_cp949.rb new file mode 100644 index 0000000..e675c7b --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_cp949.rb @@ -0,0 +1,28 @@ +require "test/unit" + +class TestCP949 < Test::Unit::TestCase + def s(s) + s.force_encoding("cp949") + end + + def test_mbc_enc_len + assert_equal(1, s("\xa1\xa1").size) + end + + def test_mbc_to_code + assert_equal(0xa1a1, s("\xa1\xa1").ord) + end + + def test_code_to_mbc + assert_equal(s("\xa1\xa1"), 0xa1a1.chr("cp949")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\xa1\xa1)\\1"), "i") + assert_match(r, s("\xa1\xa1\xa1\xa1")) + end + + def test_left_adjust_char_head + assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop) + end +end diff --git a/jni/ruby/test/ruby/enc/test_emoji.rb b/jni/ruby/test/ruby/enc/test_emoji.rb new file mode 100644 index 0000000..1f80c5a --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_emoji.rb @@ -0,0 +1,442 @@ +require 'test/unit' + +module Emoji + + class TestRenameSJIS < Test::Unit::TestCase + def test_shift_jis + assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-DoCoMo") } + assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-KDDI") } + assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-SoftBank") } + end + end + + class TestUTF8_BLACK_SUN_WITH_RAYS < Test::Unit::TestCase + include Emoji + + def setup + @codes = { + "UTF8-DoCoMo" => utf8_docomo("\u{E63E}"), + "UTF8-KDDI" => utf8_kddi("\u{E488}"), + "UTF8-SoftBank" => utf8_softbank("\u{E04A}"), + "UTF-8" => "\u{2600}", + } + end + + def test_convert + @codes.each do |from_enc, from_str| + @codes.each do |to_enc, to_str| + next if from_enc == to_enc + assert_equal to_str, from_str.encode(to_enc), "convert from #{from_enc} to #{to_enc}" + end + end + end + end + + class TestDoCoMo < Test::Unit::TestCase + include Emoji + + def setup + setup_instance_variable(self) + end + + def test_encoding_name + %w(UTF8-DoCoMo + SJIS-DoCoMo).each do |n| + assert_include Encoding.name_list, n, "encoding not found: #{n}" + end + end + + def test_comparison + assert_not_equal Encoding::UTF_8, Encoding::UTF8_DoCoMo + assert_not_equal Encoding::Windows_31J, Encoding::SJIS_DoCoMo + end + + def test_from_utf8 + assert_nothing_raised { assert_equal utf8_docomo(@aiueo_utf8), to_utf8_docomo(@aiueo_utf8) } + assert_nothing_raised { assert_equal sjis_docomo(@aiueo_sjis), to_sjis_docomo(@aiueo_utf8) } + end + + def test_from_sjis + assert_nothing_raised { assert_equal utf8_docomo(@aiueo_utf8), to_utf8_docomo(@aiueo_sjis) } + assert_nothing_raised { assert_equal sjis_docomo(@aiueo_sjis), to_sjis_docomo(@aiueo_sjis) } + end + + def test_to_utf8 + assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_docomo) } + assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_docomo) } + end + + def test_to_sjis + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_docomo) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_docomo) } + end + + def test_to_eucjp + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_docomo) } + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_docomo) } + end + + def test_docomo + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_docomo) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_docomo) } + end + + def test_to_kddi + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@utf8_docomo) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_docomo) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_docomo) } + + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_docomo) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_docomo) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_docomo) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@utf8_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@utf8_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@utf8_docomo_only) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@sjis_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@sjis_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@sjis_docomo_only) } + end + + def test_to_softbank + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_docomo) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_docomo) } + + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_docomo) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_docomo) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_softbank(@utf8_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_softbank(@utf8_docomo_only) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_softbank(@sjis_docomo_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_softbank(@sjis_docomo_only) } + end + end + + class TestKDDI < Test::Unit::TestCase + include Emoji + + def setup + setup_instance_variable(self) + end + + def test_encoding_name + %w(UTF8-KDDI + SJIS-KDDI + ISO-2022-JP-KDDI + stateless-ISO-2022-JP-KDDI).each do |n| + assert_include Encoding.name_list, n, "encoding not found: #{n}" + end + end + + def test_comparison + assert_not_equal Encoding::UTF_8, Encoding::UTF8_KDDI + assert_not_equal Encoding::Windows_31J, Encoding::SJIS_KDDI + assert_not_equal Encoding::ISO_2022_JP, Encoding::ISO_2022_JP_KDDI + assert_not_equal Encoding::Stateless_ISO_2022_JP, Encoding::Stateless_ISO_2022_JP_KDDI + end + + def test_from_utf8 + assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_utf8) } + assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_utf8) } + assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_utf8) } + end + + def test_from_sjis + assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_sjis) } + assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_sjis) } + assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_sjis) } + end + + def test_from_iso2022jp + assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_iso2022jp) } + assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_iso2022jp) } + assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_iso2022jp) } + end + + def test_to_utf8 + assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_kddi) } + assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_undoc_kddi) } + assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_kddi) } + assert_nothing_raised { assert_equal @utf8, to_utf8(@iso2022jp_kddi) } + end + + def test_to_sjis + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_undoc_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@iso2022jp_kddi) } + end + + def test_to_eucjp + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_undoc_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_kddi) } + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@iso2022jp_kddi) } + end + + def test_kddi + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_kddi) } + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@iso2022jp_kddi) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_kddi) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_undoc_kddi) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@iso2022jp_kddi) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_kddi) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_undoc_kddi) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@iso2022jp_kddi) } + end + + def test_to_docomo + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_kddi) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_kddi) } + + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_undoc_kddi) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_undoc_kddi) } + + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_kddi) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_kddi) } + + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@iso2022jp_kddi) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@iso2022jp_kddi) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_undoc_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_undoc_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@iso2022jp_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@iso2022jp_kddi_only) } + end + + def test_to_softbank + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_kddi) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_kddi) } + + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_undoc_kddi) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_undoc_kddi) } + + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_kddi) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_kddi) } + + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@iso2022jp_kddi) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@iso2022jp_kddi) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_undoc_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_undoc_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_kddi_only) } + + assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@iso2022jp_kddi_only) } + assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@iso2022jp_kddi_only) } + end + end + + class TestSoftBank < Test::Unit::TestCase + include Emoji + + def setup + setup_instance_variable(self) + end + + def test_encoding_name + %w(UTF8-SoftBank + SJIS-SoftBank).each do |n| + assert_include Encoding.name_list, n, "encoding not found: #{n}" + end + end + + def test_comparison + assert_not_equal Encoding::UTF_8, Encoding::UTF8_SoftBank + assert_not_equal Encoding::Windows_31J, Encoding::SJIS_SoftBank + end + + def test_from_utf8 + assert_nothing_raised { assert_equal utf8_softbank(@aiueo_utf8), to_utf8_softbank(@aiueo_utf8) } + assert_nothing_raised { assert_equal sjis_softbank(@aiueo_sjis), to_sjis_softbank(@aiueo_utf8) } + end + + def test_from_sjis + assert_nothing_raised { assert_equal utf8_softbank(@aiueo_utf8), to_utf8_softbank(@aiueo_sjis) } + assert_nothing_raised { assert_equal sjis_softbank(@aiueo_sjis), to_sjis_softbank(@aiueo_sjis) } + end + + def test_to_utf8 + assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_softbank) } + assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_softbank) } + end + + def test_to_sjis + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_softbank) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_softbank) } + end + + def test_to_eucjp + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_softbank) } + assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_softbank) } + end + + def test_softbank + assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_softbank) } + assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_softbank) } + end + + def test_to_docomo + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_softbank) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_softbank) } + + assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_softbank) } + assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_softbank) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_docomo(@utf8_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_docomo(@utf8_softbank_only) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_docomo(@sjis_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_docomo(@sjis_softbank_only) } + end + + def test_to_kddi + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@utf8_softbank) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_softbank) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_softbank) } + + assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_softbank) } + assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_softbank) } + assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_softbank) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@utf8_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@utf8_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@utf8_softbank_only) } + + assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@sjis_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@sjis_softbank_only) } + assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@sjis_softbank_only) } + end + end + + private + + def setup_instance_variable(obj) + obj.instance_eval do + @aiueo_utf8 = "\u{3042}\u{3044}\u{3046}\u{3048}\u{304A}" + @aiueo_sjis = to_sjis(@aiueo_utf8) + @aiueo_iso2022jp = to_iso2022jp(@aiueo_utf8) + + @utf8 = "\u{2600}" + + @utf8_docomo = utf8_docomo("\u{E63E}") + @sjis_docomo = sjis_docomo("\xF8\x9F") + @utf8_docomo_only = utf8_docomo("\u{E6B1}") + @sjis_docomo_only = sjis_docomo("\xF9\x55") + + @utf8_kddi = utf8_kddi("\u{E488}") + @utf8_undoc_kddi = utf8_kddi("\u{EF60}") + @sjis_kddi = sjis_kddi("\xF6\x60") + @iso2022jp_kddi = iso2022jp_kddi("\x1B$B\x75\x41\x1B(B") + @stateless_iso2022jp_kddi = stateless_iso2022jp_kddi("\x92\xF5\xC1") + @utf8_kddi_only = utf8_kddi("\u{E5B3}") + @utf8_undoc_kddi_only = utf8_kddi("\u{F0D0}") + @sjis_kddi_only = sjis_kddi("\xF7\xD0") + @iso2022jp_kddi_only = iso2022jp_kddi("\x1B$B\x78\x52\x1B(B") + @stateless_iso2022jp_kddi_only = stateless_iso2022jp_kddi("\x92\xF8\xD2") + + @utf8_softbank = utf8_softbank("\u{E04A}") + @sjis_softbank = sjis_softbank("\xF9\x8B") + @utf8_softbank_only = utf8_softbank("\u{E524}") + @sjis_softbank_only = sjis_softbank("\xFB\xC4") + end + end + + def utf8(str) + str.force_encoding("UTF-8") + end + + def to_utf8(str) + str.encode("UTF-8") + end + + def to_sjis(str) + str.encode("Windows-31J") + end + + def to_eucjp(str) + str.encode("eucJP-ms") + end + + def to_iso2022jp(str) + str.encode("ISO-2022-JP") + end + + def utf8_docomo(str) + str.force_encoding("UTF8-DoCoMo") + end + + def to_utf8_docomo(str) + str.encode("UTF8-DoCoMo") + end + + def utf8_kddi(str) + str.force_encoding("UTF8-KDDI") + end + + def to_utf8_kddi(str) + str.encode("UTF8-KDDI") + end + + def utf8_softbank(str) + str.force_encoding("UTF8-SoftBank") + end + + def to_utf8_softbank(str) + str.encode("UTF8-SoftBank") + end + + def sjis_docomo(str) + str.force_encoding("SJIS-DoCoMo") + end + + def to_sjis_docomo(str) + str.encode("SJIS-DoCoMo") + end + + def sjis_kddi(str) + str.force_encoding("SJIS-KDDI") + end + + def to_sjis_kddi(str) + str.encode("SJIS-KDDI") + end + + def sjis_softbank(str) + str.force_encoding("SJIS-SoftBank") + end + + def to_sjis_softbank(str) + str.encode("SJIS-SoftBank") + end + + def iso2022jp_kddi(str) + str.force_encoding("ISO-2022-JP-KDDI") + end + + def to_iso2022jp_kddi(str) + str.encode("ISO-2022-JP-KDDI") + end + + def stateless_iso2022jp_kddi(str) + str.force_encoding("stateless-ISO-2022-JP-KDDI") + end + + def to_stateless_iso2022jp_kddi(str) + str.encode("stateless-ISO-2022-JP-KDDI") + end + +end diff --git a/jni/ruby/test/ruby/enc/test_euc_jp.rb b/jni/ruby/test/ruby/enc/test_euc_jp.rb new file mode 100644 index 0000000..510ee46 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_euc_jp.rb @@ -0,0 +1,24 @@ +# vim: set fileencoding=euc-jp + +require "test/unit" + +class TestEUC_JP < Test::Unit::TestCase + def test_mbc_case_fold + assert_match(/()(a)\1\2/i, "aA") + assert_match(/()(a)\1\2/i, "aA") + end + + def test_property + assert_match(/{0}\p{Hiragana}{4}/, "Ҥ餬") + assert_no_match(/{0}\p{Hiragana}{4}/, "") + assert_no_match(/{0}\p{Hiragana}{4}/, "") + assert_no_match(/{0}\p{Katakana}{4}/, "Ҥ餬") + assert_match(/{0}\p{Katakana}{4}/, "") + assert_no_match(/{0}\p{Katakana}{4}/, "") + assert_raise(RegexpError) { Regexp.new('{0}\p{foobarbaz}') } + end + + def test_charboundary + assert_nil(/\xA2\xA2/ =~ "\xA1\xA2\xA2\xA3") + end +end diff --git a/jni/ruby/test/ruby/enc/test_euc_kr.rb b/jni/ruby/test/ruby/enc/test_euc_kr.rb new file mode 100644 index 0000000..5413fa6 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_euc_kr.rb @@ -0,0 +1,36 @@ +require "test/unit" + +class TestEucKr < Test::Unit::TestCase + def s(s) + s.force_encoding("euc-kr") + end + + def test_mbc_enc_len + assert_equal(1, s("\xa1\xa1").size) + end + + def test_mbc_to_code + assert_equal(0xa1a1, s("\xa1\xa1").ord) + end + + def test_code_to_mbc + assert_equal(s("\xa1\xa1"), 0xa1a1.chr("euc-kr")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\xa1\xa1)\\1"), "i") + assert_match(r, s("\xa1\xa1\xa1\xa1")) + end + + def test_left_adjust_char_head + assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop) + end + + def test_euro_sign + assert_equal("\u{20ac}", s("\xa2\xe6").encode("utf-8")) + end + + def test_registered_mark + assert_equal("\u{00ae}", s("\xa2\xe7").encode("utf-8")) + end +end diff --git a/jni/ruby/test/ruby/enc/test_euc_tw.rb b/jni/ruby/test/ruby/enc/test_euc_tw.rb new file mode 100644 index 0000000..f36d86b --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_euc_tw.rb @@ -0,0 +1,28 @@ +require "test/unit" + +class TestEucTw < Test::Unit::TestCase + def s(s) + s.force_encoding("euc-tw") + end + + def test_mbc_enc_len + assert_equal(1, s("\xa1\xa1").size) + end + + def test_mbc_to_code + assert_equal(0xa1a1, s("\xa1\xa1").ord) + end + + def test_code_to_mbc + assert_equal(s("\xa1\xa1"), 0xa1a1.chr("euc-tw")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\xa1\xa1)\\1"), "i") + assert_match(r, s("\xa1\xa1\xa1\xa1")) + end + + def test_left_adjust_char_head + assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop) + end +end diff --git a/jni/ruby/test/ruby/enc/test_gb18030.rb b/jni/ruby/test/ruby/enc/test_gb18030.rb new file mode 100644 index 0000000..f379504 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_gb18030.rb @@ -0,0 +1,126 @@ +require "test/unit" + +class TestGB18030 < Test::Unit::TestCase + def s(s) + s.force_encoding("gb18030") + end + + def test_mbc_enc_len + assert_equal(1, s("\x81\x40").size) + assert_equal(1, s("\x81\x30\x81\x30").size) + end + + def test_mbc_to_code + assert_equal(0x8140, s("\x81\x40").ord) + end + + def test_code_to_mbc + assert_equal(s("\x81\x40"), 0x8140.chr("gb18030")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\x81\x40)\\1"), "i") + assert_match(r, s("\x81\x40\x81\x40")) + end + + def scheck(c, i) + assert_equal(s(c.reverse.take(c.size - i).join), s(c.reverse.join).chop) + end + + def fcheck(c) + c = s(c.reverse.join) + assert_raise(ArgumentError, c) { c.chop } + end + + def test_left_adjust_char_head + # C1: 00-2f, 3a-3f, 7f, ff + # C2: 40-7e, 80 + # C4: 30-39 + # CM: 81-fe + c1 = "\x2f" + c2 = "\x40" + c4 = "\x30" + cm = "\x81" + + # S_START-c1 + # S_START-c2-S_one_C2-0 + # S_START-c2-S_one_C2-c1 + # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-c1 + # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-cm-S_even_CM_one_CX-c1 + # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-cm-S_even_CM_one_CX-cm-S_odd_CM_one_CX(rec) + # S_START-c4-S_one_C4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-c4-S_one_C4_odd_CMC4(rec) + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-cm-S_even_CM_odd_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-cm-S_even_CM_odd_CMC4-cm-S_odd_CM_odd_CMC4(rec) + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-cm-S_even_CM_even_CMC4-c1 + # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-cm-S_even_CM_even_CMC4-cm-S_odd_CM_even_CMC4(rec) + # S_START-c4-S_one_C4-cm-S_one_CMC4-cm-S_even_CM_one_CX(rec) + # S_START-cm-S_one_CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-c4-S_odd_C4CM(rec) + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-cm-S_odd_CM_even_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-cm-S_odd_CM_even_C4CM-cm-S_even_CM_even_C4CM(rec) + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-cm-S_odd_CM_odd_C4CM-c1 + # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-cm-S_odd_CM_odd_C4CM-cm-S_even_CM_odd_C4CM(rec) + # S_START-cm-S_one_CM-cm-S_odd_CM_one_CX(rec) + + scheck([c1], 1) + scheck([c2], 1) + scheck([c2, c1], 1) + scheck([c2, cm, c1], 2) + scheck([c2, cm, cm, c1], 1) + scheck([c2, cm, cm, cm], 2) + scheck([c4], 1) + scheck([c4, c1], 1) + scheck([c4, cm], 2) + scheck([c4, cm, c1], 2) + scheck([c4, cm, c4, c1], 2) + scheck([c4, cm, c4, cm], 4) + scheck([c4, cm, c4, cm, c1], 4) + scheck([c4, cm, c4, cm, c4], 4) + scheck([c4, cm, c4, cm, c4, c1], 4) + scheck([c4, cm, c4, cm, c4, cm], 2) + scheck([c4, cm, c4, cm, c4, cm, c1], 2) + scheck([c4, cm, c4, cm, c4, cm, c4], 2) + scheck([c4, cm, c4, cm, c4, cm, cm, c1], 4) + scheck([c4, cm, c4, cm, c4, cm, cm, cm], 2) + scheck([c4, cm, c4, cm, c4, cm, cm, cm, c1], 2) + scheck([c4, cm, c4, cm, c4, cm, cm, cm, cm], 4) + scheck([c4, cm, c4, cm, cm, c1], 2) + scheck([c4, cm, c4, cm, cm, cm], 4) + scheck([c4, cm, c4, cm, cm, cm, c1], 4) + scheck([c4, cm, c4, cm, cm, cm, cm], 2) + scheck([c4, cm, cm], 1) + scheck([cm], 1) + scheck([cm, c1], 1) + scheck([cm, c4, c1], 1) + scheck([cm, c4, cm], 3) + scheck([cm, c4, cm, c1], 3) + scheck([cm, c4, cm, c4], 3) + scheck([cm, c4, cm, c4, c1], 3) + scheck([cm, c4, cm, c4, cm], 1) + scheck([cm, c4, cm, c4, cm, c1], 1) + scheck([cm, c4, cm, c4, cm, c4], 1) + scheck([cm, c4, cm, c4, cm, cm, c1], 3) + scheck([cm, c4, cm, c4, cm, cm, cm], 1) + scheck([cm, c4, cm, c4, cm, cm, cm, c1], 1) + scheck([cm, c4, cm, c4, cm, cm, cm, cm], 3) + scheck([cm, c4, cm, cm, c1], 1) + scheck([cm, c4, cm, cm, cm], 3) + scheck([cm, c4, cm, cm, cm, c1], 3) + scheck([cm, c4, cm, cm, cm, cm], 1) + scheck([cm, cm], 2) + end +end diff --git a/jni/ruby/test/ruby/enc/test_gbk.rb b/jni/ruby/test/ruby/enc/test_gbk.rb new file mode 100644 index 0000000..d6dc5d6 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_gbk.rb @@ -0,0 +1,28 @@ +require "test/unit" + +class TestGBK < Test::Unit::TestCase + def s(s) + s.force_encoding("gbk") + end + + def test_mbc_enc_len + assert_equal(1, s("\x81\x40").size) + end + + def test_mbc_to_code + assert_equal(0x8140, s("\x81\x40").ord) + end + + def test_code_to_mbc + assert_equal(s("\x81\x40"), 0x8140.chr("gbk")) + end + + def test_mbc_case_fold + r = Regexp.new(s("(\x81\x40)\\1"), "i") + assert_match(r, s("\x81\x40\x81\x40")) + end + + def test_left_adjust_char_head + assert_equal(s("\x81\x40"), s("\x81\x40\x81\x40").chop) + end +end diff --git a/jni/ruby/test/ruby/enc/test_iso_8859.rb b/jni/ruby/test/ruby/enc/test_iso_8859.rb new file mode 100644 index 0000000..64cc7cd --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_iso_8859.rb @@ -0,0 +1,163 @@ +require 'test/unit' + +class TestISO8859 < Test::Unit::TestCase + ASSERTS = %q( + assert_match(/^(\xdf)\1$/i, "\xdf\xdf") + assert_match(/^(\xdf)\1$/i, "ssss") + # assert_match(/^(\xdf)\1$/i, "\xdfss") # this must be bug... + assert_match(/^[\xdfz]+$/i, "sszzsszz") + assert_match(/^SS$/i, "\xdf") + assert_match(/^Ss$/i, "\xdf") + ((0xc0..0xde).to_a - [0xd7]).each do |c| + c1 = c.chr("ENCODING") + c2 = (c + 0x20).chr("ENCODING") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + assert_match(/^\xff$/i, "\xff") + ) + + def test_iso_8859_1 + eval("# encoding: iso8859-1\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-1")) + end + + def test_iso_8859_2 + eval("# encoding: iso8859-2\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-2")) + end + + def test_iso_8859_3 + eval(%q(# encoding: iso8859-3 + assert_match(/^(\xdf)\1$/i, "\xdf\xdf") + assert_match(/^(\xdf)\1$/i, "ssss") + assert_match(/^[\xdfz]+$/i, "sszzsszz") + assert_match(/^SS$/i, "\xdf") + assert_match(/^Ss$/i, "\xdf") + [0xa1, 0xa6, *(0xa9..0xac), 0xaf].each do |c| + c1 = c.chr("iso8859-3") + c2 = (c + 0x10).chr("iso8859-3") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + ([*(0xc0..0xde)] - [0xc3, 0xd0, 0xd7]).each do |c| + c1 = c.chr("iso8859-3") + c2 = (c + 0x20).chr("iso8859-3") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + )) + end + + def test_iso_8859_4 + eval("# encoding: iso8859-4\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-4")) + end + + def test_iso_8859_5 + eval(%q(# encoding: iso8859-5 + (0xb0..0xcf).each do |c| + c1 = c.chr("iso8859-5") + c2 = (c + 0x20).chr("iso8859-5") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + ((0xa1..0xaf).to_a - [0xad]).each do |c| + c1 = c.chr("iso8859-5") + c2 = (c + 0x50).chr("iso8859-5") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + )) + end + + def test_iso_8859_6 + eval(%q(# encoding: iso8859-6 + [0xa4, 0xac, 0xbb, 0xbf, *(0xc1..0xda), *(0xe0..0xf2)].each do |c| + c1 = c.chr("iso8859-6") + assert_match(/^(#{ c1 })\1$/i, c1 * 2) + end + )) + end + + def test_iso_8859_7 + eval(%q(# encoding: iso8859-7 + ((0xa0..0xfe).to_a - [0xae, 0xd2]).each do |c| + c1 = c.chr("iso8859-7") + assert_match(/^(#{ c1 })\1$/i, c1 * 2) + end + ((0xc1..0xd9).to_a - [0xd2]).each do |c| + c1 = c.chr("iso8859-7") + c2 = (c + 0x20).chr("iso8859-7") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + )) + end + + def test_iso_8859_8 + eval(%q(# encoding: iso8859-8 + [0xa0, *(0xa2..0xbe), *(0xdf..0xfa), 0xfc, 0xfd].each do |c| + c1 = c.chr("iso8859-8") + assert_match(/^(#{ c1 })\1$/i, c1 * 2) + end + )) + end + + def test_iso_8859_9 + eval(%q(# encoding: iso8859-9 + assert_match(/^(\xdf)\1$/i, "\xdf\xdf") + assert_match(/^(\xdf)\1$/i, "ssss") + assert_match(/^[\xdfz]+$/i, "sszzsszz") + assert_match(/^SS$/i, "\xdf") + assert_match(/^Ss$/i, "\xdf") + ([*(0xc0..0xdc)] - [0xd7]).each do |c| + c1 = c.chr("iso8859-9") + c2 = (c + 0x20).chr("iso8859-9") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + )) + end + + def test_iso_8859_10 + eval("# encoding: iso8859-10\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-10")) + end + + def test_iso_8859_11 + eval(%q(# encoding: iso8859-11 + [*(0xa0..0xda), *(0xdf..0xfb)].each do |c| + c1 = c.chr("iso8859-11") + assert_match(/^(#{ c1 })\1$/i, c1 * 2) + end + )) + end + + def test_iso_8859_13 + eval("# encoding: iso8859-13\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-13")) + end + + def test_iso_8859_14 + eval("# encoding: iso8859-14\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-14")) + end + + def test_iso_8859_15 + eval("# encoding: iso8859-15\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-15")) + end + + def test_iso_8859_16 + eval("# encoding: iso8859-16\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-16")) + end +end + diff --git a/jni/ruby/test/ruby/enc/test_koi8.rb b/jni/ruby/test/ruby/enc/test_koi8.rb new file mode 100644 index 0000000..ce2d892 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_koi8.rb @@ -0,0 +1,22 @@ +require "test/unit" + +class TestKOI8 < Test::Unit::TestCase + ASSERTS = %q( + (0xc0..0xdf).each do |c| + c1 = c.chr("ENCODING") + c2 = (c + 0x20).chr("ENCODING") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + ) + + def test_koi8_r + eval("# encoding: koi8-r\n" + ASSERTS.gsub("ENCODING", "koi8-r")) + end + + def test_koi8_u + eval("# encoding: koi8-u\n" + ASSERTS.gsub("ENCODING", "koi8-u")) + end +end diff --git a/jni/ruby/test/ruby/enc/test_shift_jis.rb b/jni/ruby/test/ruby/enc/test_shift_jis.rb new file mode 100644 index 0000000..1bd47fa --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_shift_jis.rb @@ -0,0 +1,27 @@ +# vim: set fileencoding=shift_jis + +require "test/unit" + +class TestShiftJIS < Test::Unit::TestCase + def test_mbc_case_fold + assert_match(/()(a)\1\2/i, "aA") + assert_match(/()(a)\1\2/i, "a`A") + end + + def test_property + assert_match(/{0}\p{Hiragana}{4}/, "Ђ炪") + assert_no_match(/{0}\p{Hiragana}{4}/, "J^Ji") + assert_no_match(/{0}\p{Hiragana}{4}/, "") + assert_no_match(/{0}\p{Katakana}{4}/, "Ђ炪") + assert_match(/{0}\p{Katakana}{4}/, "J^Ji") + assert_no_match(/{0}\p{Katakana}{4}/, "") + assert_raise(RegexpError) { Regexp.new('{0}\p{foobarbaz}') } + end + + def test_code_to_mbclen + s = "" + s << 0x82a9 + assert_equal("", s) + assert_raise(RangeError) { s << 0x82 } + end +end diff --git a/jni/ruby/test/ruby/enc/test_utf16.rb b/jni/ruby/test/ruby/enc/test_utf16.rb new file mode 100644 index 0000000..63929c6 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_utf16.rb @@ -0,0 +1,384 @@ +require 'test/unit' + +class TestUTF16 < Test::Unit::TestCase + def encdump(obj) + case obj + when String + d = obj.dump + if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d + d + else + "#{d}.force_encoding(#{obj.encoding.name.dump})" + end + when Regexp + "Regexp.new(#{encdump(obj.source)}, #{obj.options})" + else + raise Argument, "unexpected: #{obj.inspect}" + end + end + + def enccall(recv, meth, *args) + desc = '' + if String === recv + desc << encdump(recv) + else + desc << recv.inspect + end + desc << '.' << meth.to_s + if !args.empty? + desc << '(' + args.each_with_index {|a, i| + desc << ',' if 0 < i + if String === a + desc << encdump(a) + else + desc << a.inspect + end + } + desc << ')' + end + result = nil + assert_nothing_raised(desc) { + result = recv.send(meth, *args) + } + result + end + + def assert_str_equal(expected, actual, message=nil) + full_message = build_message(message, <<EOT) +#{encdump expected} expected but not equal to +#{encdump actual}. +EOT + assert_equal(expected, actual, full_message) + end + + # tests start + + def test_utf16be_valid_encoding + [ + "\x00\x00", + "\xd7\xff", + "\xd8\x00\xdc\x00", + "\xdb\xff\xdf\xff", + "\xe0\x00", + "\xff\xff", + ].each {|s| + s.force_encoding("utf-16be") + assert_equal(true, s.valid_encoding?, "#{encdump s}.valid_encoding?") + } + [ + "\x00", + "\xd7", + "\xd8\x00", + "\xd8\x00\xd8\x00", + "\xdc\x00", + "\xdc\x00\xd8\x00", + "\xdc\x00\xdc\x00", + "\xe0", + "\xff", + ].each {|s| + s.force_encoding("utf-16be") + assert_equal(false, s.valid_encoding?, "#{encdump s}.valid_encoding?") + } + end + + def test_utf16le_valid_encoding + [ + "\x00\x00", + "\xff\xd7", + "\x00\xd8\x00\xdc", + "\xff\xdb\xff\xdf", + "\x00\xe0", + "\xff\xff", + ].each {|s| + s.force_encoding("utf-16le") + assert_equal(true, s.valid_encoding?, "#{encdump s}.valid_encoding?") + } + [ + "\x00", + "\xd7", + "\x00\xd8", + "\x00\xd8\x00\xd8", + "\x00\xdc", + "\x00\xdc\x00\xd8", + "\x00\xdc\x00\xdc", + "\xe0", + "\xff", + ].each {|s| + s.force_encoding("utf-16le") + assert_equal(false, s.valid_encoding?, "#{encdump s}.valid_encoding?") + } + end + + def test_strftime + s = "aa".force_encoding("utf-16be") + assert_raise(ArgumentError, "Time.now.strftime(#{encdump s})") { Time.now.strftime(s) } + end + + def test_intern + s = "aaaa".force_encoding("utf-16be") + assert_equal(s.encoding, s.intern.to_s.encoding, "#{encdump s}.intern.to_s.encoding") + end + + def test_sym_eq + s = "aa".force_encoding("utf-16le") + assert_not_equal(:aa, s.intern, "#{encdump s}.intern != :aa") + end + + def test_compatible + s1 = "aa".force_encoding("utf-16be") + s2 = "z".force_encoding("us-ascii") + assert_nil(Encoding.compatible?(s1, s2), "Encoding.compatible?(#{encdump s1}, #{encdump s2})") + end + + def test_casecmp + s1 = "aa".force_encoding("utf-16be") + s2 = "AA" + assert_not_equal(0, s1.casecmp(s2), "#{encdump s1}.casecmp(#{encdump s2})") + end + + def test_end_with + s1 = "ab".force_encoding("utf-16be") + s2 = "b".force_encoding("utf-16be") + assert_equal(false, s1.end_with?(s2), "#{encdump s1}.end_with?(#{encdump s2})") + end + + def test_hex + assert_raise(Encoding::CompatibilityError) { + "ff".encode("utf-16le").hex + } + assert_raise(Encoding::CompatibilityError) { + "ff".encode("utf-16be").hex + } + end + + def test_oct + assert_raise(Encoding::CompatibilityError) { + "77".encode("utf-16le").oct + } + assert_raise(Encoding::CompatibilityError) { + "77".encode("utf-16be").oct + } + end + + def test_count + s1 = "aa".force_encoding("utf-16be") + s2 = "aa" + assert_raise(Encoding::CompatibilityError, "#{encdump s1}.count(#{encdump s2})") { + s1.count(s2) + } + end + + def test_plus + s1 = "a".force_encoding("us-ascii") + s2 = "aa".force_encoding("utf-16be") + assert_raise(Encoding::CompatibilityError, "#{encdump s1} + #{encdump s2}") { + s1 + s2 + } + end + + def test_encoding_find + assert_raise(ArgumentError) { + Encoding.find("utf-8".force_encoding("utf-16be")) + } + end + + def test_interpolation + s = "aa".force_encoding("utf-16be") + assert_raise(Encoding::CompatibilityError, "\"a\#{#{encdump s}}\"") { + "a#{s}" + } + end + + def test_slice! + enccall("aa".force_encoding("UTF-16BE"), :slice!, -1) + end + + def test_plus_empty1 + s1 = "" + s2 = "aa".force_encoding("utf-16be") + assert_nothing_raised("#{encdump s1} << #{encdump s2}") { + s1 + s2 + } + end + + def test_plus_empty2 + s1 = "aa" + s2 = "".force_encoding("utf-16be") + assert_nothing_raised("#{encdump s1} << #{encdump s2}") { + s1 + s2 + } + end + + def test_plus_nonempty + s1 = "aa" + s2 = "bb".force_encoding("utf-16be") + assert_raise(Encoding::CompatibilityError, "#{encdump s1} << #{encdump s2}") { + s1 + s2 + } + end + + def test_concat_empty1 + s1 = "" + s2 = "aa".force_encoding("utf-16be") + assert_nothing_raised("#{encdump s1} << #{encdump s2}") { + s1 << s2 + } + end + + def test_concat_empty2 + s1 = "aa" + s2 = "".force_encoding("utf-16be") + assert_nothing_raised("#{encdump s1} << #{encdump s2}") { + s1 << s2 + } + end + + def test_concat_nonempty + s1 = "aa" + s2 = "bb".force_encoding("utf-16be") + assert_raise(Encoding::CompatibilityError, "#{encdump s1} << #{encdump s2}") { + s1 << s2 + } + end + + def test_chomp + s = "\1\n".force_encoding("utf-16be") + assert_equal(s, s.chomp, "#{encdump s}.chomp") + s = "\0\n".force_encoding("utf-16be") + assert_equal("", s.chomp, "#{encdump s}.chomp") + s = "\0\r\0\n".force_encoding("utf-16be") + assert_equal("", s.chomp, "#{encdump s}.chomp") + end + + def test_succ + s = "\xff\xff".force_encoding("utf-16be") + assert_predicate(s.succ, :valid_encoding?, "#{encdump s}.succ.valid_encoding?") + + s = "\xdb\xff\xdf\xff".force_encoding("utf-16be") + assert_predicate(s.succ, :valid_encoding?, "#{encdump s}.succ.valid_encoding?") + end + + def test_regexp_union + enccall(Regexp, :union, "aa".force_encoding("utf-16be"), "bb".force_encoding("utf-16be")) + end + + def test_empty_regexp + s = "".force_encoding("utf-16be") + assert_equal(Encoding.find("utf-16be"), Regexp.new(s).encoding, + "Regexp.new(#{encdump s}).encoding") + end + + def test_regexp_match + assert_raise(Encoding::CompatibilityError) { Regexp.new("aa".force_encoding("utf-16be")) =~ "aa" } + end + + def test_gsub + s = "abcd".force_encoding("utf-16be") + assert_nothing_raised { + s.gsub(Regexp.new(".".encode("utf-16be")), "xy") + } + s = "ab\0\ncd".force_encoding("utf-16be") + assert_raise(Encoding::CompatibilityError) { + s.gsub(Regexp.new(".".encode("utf-16be")), "xy") + } + end + + def test_split_awk + s = " ab cd ".encode("utf-16be") + r = s.split(" ".encode("utf-16be")) + assert_equal(2, r.length) + assert_str_equal("ab".encode("utf-16be"), r[0]) + assert_str_equal("cd".encode("utf-16be"), r[1]) + end + + def test_count2 + e = "abc".count("^b") + assert_equal(e, "abc".encode("utf-16be").count("^b".encode("utf-16be"))) + assert_equal(e, "abc".encode("utf-16le").count("^b".encode("utf-16le"))) + end + + def test_header + assert_raise(ArgumentError) { eval("# encoding:utf-16le\nfoo") } + assert_raise(ArgumentError) { eval("# encoding:utf-16be\nfoo") } + end + + + def test_is_mbc_newline + sl = "f\0o\0o\0\n\0b\0a\0r\0\n\0b\0a\0z\0\n\0".force_encoding("utf-16le") + sb = "\0f\0o\0o\0\n\0b\0a\0r\0\n\0b\0a\0z\0\n".force_encoding("utf-16be") + al = sl.lines.to_a + ab = sb.lines.to_a + assert_equal("f\0o\0o\0\n\0".force_encoding("utf-16le"), al.shift) + assert_equal("b\0a\0r\0\n\0".force_encoding("utf-16le"), al.shift) + assert_equal("b\0a\0z\0\n\0".force_encoding("utf-16le"), al.shift) + assert_equal("\0f\0o\0o\0\n".force_encoding("utf-16be"), ab.shift) + assert_equal("\0b\0a\0r\0\n".force_encoding("utf-16be"), ab.shift) + assert_equal("\0b\0a\0z\0\n".force_encoding("utf-16be"), ab.shift) + + sl = "f\0o\0o\0\n\0".force_encoding("utf-16le") + sb = "\0f\0o\0o\0\n".force_encoding("utf-16be") + sl2 = "f\0o\0o\0".force_encoding("utf-16le") + sb2 = "\0f\0o\0o".force_encoding("utf-16be") + assert_equal(sl2, sl.chomp) + assert_equal(sl2, sl.chomp.chomp) + assert_equal(sb2, sb.chomp) + assert_equal(sb2, sb.chomp.chomp) + + sl = "f\0o\0o\0\n".force_encoding("utf-16le") + sb = "\0f\0o\0o\n".force_encoding("utf-16be") + assert_equal(sl, sl.chomp) + assert_equal(sb, sb.chomp) + end + + def test_code_to_mbc + assert_equal("a\0".force_encoding("utf-16le"), "a".ord.chr("utf-16le")) + assert_equal("\0a".force_encoding("utf-16be"), "a".ord.chr("utf-16be")) + end + + def utf8_to_utf16(s, e) + s.chars.map {|c| c.ord.chr(e) }.join + end + + def test_mbc_case_fold + rl = Regexp.new(utf8_to_utf16("^(\u3042)(a)\\1\\2$", "utf-16le"), "i") + rb = Regexp.new(utf8_to_utf16("^(\u3042)(a)\\1\\2$", "utf-16be"), "i") + assert_equal(Encoding.find("utf-16le"), rl.encoding) + assert_equal(Encoding.find("utf-16be"), rb.encoding) + assert_match(rl, utf8_to_utf16("\u3042a\u3042a", "utf-16le")) + assert_match(rb, utf8_to_utf16("\u3042a\u3042a", "utf-16be")) + end + + def test_surrogate_pair + sl = "\x42\xd8\xb7\xdf".force_encoding("utf-16le") + sb = "\xd8\x42\xdf\xb7".force_encoding("utf-16be") + + assert_equal(1, sl.size) + assert_equal(1, sb.size) + assert_equal(0x20bb7, sl.ord) + assert_equal(0x20bb7, sb.ord) + assert_equal(sl, 0x20bb7.chr("utf-16le")) + assert_equal(sb, 0x20bb7.chr("utf-16be")) + assert_equal("", sl.chop) + assert_equal("", sb.chop) + end + + def test_regexp_escape + s = "\0*".force_encoding("UTF-16BE") + r = Regexp.new(Regexp.escape(s)) + assert_match(r, s, "#{encdump(r)} =~ #{encdump(s)}") + end + + def test_casecmp2 + assert_equal(0, "\0A".force_encoding("UTF-16BE").casecmp("\0a".force_encoding("UTF-16BE"))) + assert_not_equal(0, "\0A".force_encoding("UTF-16LE").casecmp("\0a".force_encoding("UTF-16LE"))) + assert_not_equal(0, "A\0".force_encoding("UTF-16BE").casecmp("a\0".force_encoding("UTF-16BE"))) + assert_equal(0, "A\0".force_encoding("UTF-16LE").casecmp("a\0".force_encoding("UTF-16LE"))) + + ary = ["01".force_encoding("UTF-16LE"), + "10".force_encoding("UTF-16LE")] + e = ary.sort {|x,y| x <=> y } + a = ary.sort {|x,y| x.casecmp(y) } + assert_equal(e, a) + end +end diff --git a/jni/ruby/test/ruby/enc/test_utf32.rb b/jni/ruby/test/ruby/enc/test_utf32.rb new file mode 100644 index 0000000..29a2240 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_utf32.rb @@ -0,0 +1,93 @@ +require 'test/unit' + +class TestUTF32 < Test::Unit::TestCase + def encdump(str) + d = str.dump + if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d + d + else + "#{d}.force_encoding(#{str.encoding.name.dump})" + end + end + + def assert_str_equal(expected, actual, message=nil) + full_message = build_message(message, <<EOT) +#{encdump expected} expected but not equal to +#{encdump actual}. +EOT + assert_equal(expected, actual, full_message) + end + + def test_substr + assert_str_equal( + "abcdefgh".force_encoding("utf-32le"), + "abcdefgh".force_encoding("utf-32le")[0,3]) + assert_str_equal( + "abcdefgh".force_encoding("utf-32be"), + "abcdefgh".force_encoding("utf-32be")[0,3]) + end + + def test_mbc_len + al = "abcdefghijkl".force_encoding("utf-32le").each_char.to_a + ab = "abcdefghijkl".force_encoding("utf-32be").each_char.to_a + assert_equal("abcd".force_encoding("utf-32le"), al.shift) + assert_equal("efgh".force_encoding("utf-32le"), al.shift) + assert_equal("ijkl".force_encoding("utf-32le"), al.shift) + assert_equal("abcd".force_encoding("utf-32be"), ab.shift) + assert_equal("efgh".force_encoding("utf-32be"), ab.shift) + assert_equal("ijkl".force_encoding("utf-32be"), ab.shift) + end + + def ascii_to_utf16le(s) + s.unpack("C*").map {|x| [x,0,0,0] }.flatten.pack("C*").force_encoding("utf-32le") + end + + def ascii_to_utf16be(s) + s.unpack("C*").map {|x| [0,0,0,x] }.flatten.pack("C*").force_encoding("utf-32be") + end + + def test_mbc_newline + al = ascii_to_utf16le("foo\nbar\nbaz\n").lines.to_a + ab = ascii_to_utf16be("foo\nbar\nbaz\n").lines.to_a + + assert_equal(ascii_to_utf16le("foo\n"), al.shift) + assert_equal(ascii_to_utf16le("bar\n"), al.shift) + assert_equal(ascii_to_utf16le("baz\n"), al.shift) + assert_equal(ascii_to_utf16be("foo\n"), ab.shift) + assert_equal(ascii_to_utf16be("bar\n"), ab.shift) + assert_equal(ascii_to_utf16be("baz\n"), ab.shift) + + sl = "a\0".force_encoding("utf-32le") + sb = "a\0".force_encoding("utf-32be") + assert_equal(sl, sl.chomp) + assert_equal(sb, sb.chomp) + end + + def test_mbc_to_code + sl = "a\0\0\0".force_encoding("utf-32le") + sb = "\0\0\0a".force_encoding("utf-32be") + assert_equal("a".ord, sl.ord) + assert_equal("a".ord, sb.ord) + end + + def utf8_to_utf32(s, e) + s.chars.map {|c| c.ord.chr(e) }.join + end + + def test_mbc_case_fold + rl = Regexp.new(utf8_to_utf32("^(\u3042)(a)\\1\\2$", "utf-32le"), "i") + rb = Regexp.new(utf8_to_utf32("^(\u3042)(a)\\1\\2$", "utf-32be"), "i") + assert_equal(Encoding.find("utf-32le"), rl.encoding) + assert_equal(Encoding.find("utf-32be"), rb.encoding) + assert_match(rl, utf8_to_utf32("\u3042a\u3042a", "utf-32le")) + assert_match(rb, utf8_to_utf32("\u3042a\u3042a", "utf-32be")) + end + + def test_code_to_mbc + sl = "a\0\0\0".force_encoding("utf-32le") + sb = "\0\0\0a".force_encoding("utf-32be") + assert_equal(sl, "a".ord.chr("utf-32le")) + assert_equal(sb, "a".ord.chr("utf-32be")) + end +end + diff --git a/jni/ruby/test/ruby/enc/test_windows_1251.rb b/jni/ruby/test/ruby/enc/test_windows_1251.rb new file mode 100644 index 0000000..6fbf315 --- /dev/null +++ b/jni/ruby/test/ruby/enc/test_windows_1251.rb @@ -0,0 +1,16 @@ +# encoding:windows-1251 + +require "test/unit" + +class TestWindows1251 < Test::Unit::TestCase + def test_windows_1251 + (0xc0..0xdf).each do |c| + c1 = c.chr("windows-1251") + c2 = (c + 0x20).chr("windows-1251") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + end +end diff --git a/jni/ruby/test/ruby/endblockwarn_rb b/jni/ruby/test/ruby/endblockwarn_rb new file mode 100644 index 0000000..7b7f97f --- /dev/null +++ b/jni/ruby/test/ruby/endblockwarn_rb @@ -0,0 +1,12 @@ +def end1 + END {} +end + +end1 + +eval <<EOE + def end2 + END {} + end +EOE + diff --git a/jni/ruby/test/ruby/lbtest.rb b/jni/ruby/test/ruby/lbtest.rb new file mode 100644 index 0000000..ae047fb --- /dev/null +++ b/jni/ruby/test/ruby/lbtest.rb @@ -0,0 +1,49 @@ +require 'thread' + +class LocalBarrier + def initialize(n) + @wait = Queue.new + @done = Queue.new + @keeper = begin_keeper(n) + end + + def sync + @done.push(true) + @wait.pop + end + + def join + @keeper.join + end + + private + def begin_keeper(n) + Thread.start do + n.times do + @done.pop + end + n.times do + @wait.push(true) + end + end + end +end + +n = 10 + +lb = LocalBarrier.new(n) + +(n - 1).times do |i| + Thread.start do + sleep((rand(n) + 1) / 100.0) + print "#{i}: done\n" + lb.sync + print "#{i}: cont\n" + end +end + +lb.sync +print "#{n-1}: cont\n" +# lb.join # [ruby-dev:30653] + +print "exit.\n" diff --git a/jni/ruby/test/ruby/marshaltestlib.rb b/jni/ruby/test/ruby/marshaltestlib.rb new file mode 100644 index 0000000..665d365 --- /dev/null +++ b/jni/ruby/test/ruby/marshaltestlib.rb @@ -0,0 +1,436 @@ +# coding: utf-8 +module MarshalTestLib + # include this module to a Test::Unit::TestCase and define encode(o) and + # decode(s) methods. e.g. + # + # def encode(o) + # SOAPMarshal.dump(o) + # end + # + # def decode(s) + # SOAPMarshal.load(s) + # end + + NegativeZero = (-1.0 / (1.0 / 0.0)) + + module Mod1; end + module Mod2; end + + def marshaltest(o1) + str = encode(o1) + print str.dump, "\n" if $DEBUG + o2 = decode(str) + o2 + end + + def marshal_equal(o1, msg = nil) + msg = msg ? msg + "(#{ caller[0] })" : caller[0] + o2 = marshaltest(o1) + assert_equal(o1.class, o2.class, msg) + iv1 = o1.instance_variables.sort + iv2 = o2.instance_variables.sort + assert_equal(iv1, iv2) + val1 = iv1.map {|var| o1.instance_eval {eval var.to_s}} + val2 = iv1.map {|var| o2.instance_eval {eval var.to_s}} + assert_equal(val1, val2, msg) + if block_given? + assert_equal(yield(o1), yield(o2), msg) + else + assert_equal(o1, o2, msg) + end + end + + def marshal_equal_with_ancestry(o1, msg = nil) + marshal_equal(o1, msg) do |o| + ancestry = o.singleton_class.ancestors + ancestry[ancestry.index(o.singleton_class)] = :singleton_class + ancestry + end + end + + class MyObject; def initialize(v) @v = v end; attr_reader :v; end + def test_object + o1 = Object.new + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + def test_object_subclass + marshal_equal(MyObject.new(2)) {|o| o.v} + end + + def test_object_extend + o1 = Object.new + o1.extend(Mod1) + marshal_equal_with_ancestry(o1) + o1.extend(Mod2) + marshal_equal_with_ancestry(o1) + end + + def test_object_subclass_extend + o1 = MyObject.new(2) + o1.extend(Mod1) + marshal_equal_with_ancestry(o1) + o1.extend(Mod2) + marshal_equal_with_ancestry(o1) + end + + def test_object_prepend + bug8041 = '[ruby-core:53202] [Bug #8041]' + + o1 = MyObject.new(42) + o1.singleton_class.class_eval {prepend Mod1} + assert_nothing_raised(ArgumentError, bug8041) { + marshal_equal_with_ancestry(o1, bug8041) + } + end + + class MyArray < Array + def initialize(v, *args) + super(args) + @v = v + end + end + def test_array + marshal_equal(5) + marshal_equal([1,2,3]) + end + + def test_array_subclass + marshal_equal(MyArray.new(0, 1, 2, 3)) + end + + def test_array_ivar + o1 = Array.new + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + class MyException < Exception; def initialize(v, *args) super(*args); @v = v; end; attr_reader :v; end + def test_exception + marshal_equal(Exception.new('foo')) {|o| o.message} + marshal_equal(assert_raise(NoMethodError) {no_such_method()}) {|o| o.message} + end + + def test_exception_subclass + marshal_equal(MyException.new(20, "bar")) {|o| [o.message, o.v]} + end + + def test_false + marshal_equal(false) + end + + class MyHash < Hash; def initialize(v, *args) super(*args); @v = v; end end + def test_hash + marshal_equal({1=>2, 3=>4}) + end + + def test_hash_default + h = Hash.new(:default) + h[5] = 6 + marshal_equal(h) + end + + def test_hash_subclass + h = MyHash.new(7, 8) + h[4] = 5 + marshal_equal(h) + end + + def test_hash_default_proc + h = Hash.new {} + assert_raise(TypeError) { marshaltest(h) } + end + + def test_hash_ivar + o1 = Hash.new + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + def test_hash_extend + o1 = Hash.new + o1.extend(Mod1) + marshal_equal_with_ancestry(o1) + o1.extend(Mod2) + marshal_equal_with_ancestry(o1) + end + + def test_hash_subclass_extend + o1 = MyHash.new(2) + o1.extend(Mod1) + marshal_equal_with_ancestry(o1) + o1.extend(Mod2) + marshal_equal_with_ancestry(o1) + end + + def test_bignum + marshal_equal(-0x4000_0000_0000_0001) + marshal_equal(-0x4000_0001) + marshal_equal(0x4000_0000) + marshal_equal(0x4000_0000_0000_0000) + end + + def test_fixnum + marshal_equal(-0x4000_0000) + marshal_equal(-0x3fff_ffff) + marshal_equal(-1) + marshal_equal(0) + marshal_equal(1) + marshal_equal(0x3fff_ffff) + end + + def test_float + marshal_equal(-1.0) + marshal_equal(0.0) + marshal_equal(1.0) + end + + def test_float_inf_nan + marshal_equal(1.0/0.0) + marshal_equal(-1.0/0.0) + marshal_equal(0.0/0.0) {|o| o.nan?} + marshal_equal(NegativeZero) {|o| 1.0/o} + end + + class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end + def test_range + marshal_equal(1..2) + marshal_equal(1...3) + end + + def test_range_subclass + marshal_equal(MyRange.new(4,5,8, false)) + end + + class MyRegexp < Regexp; def initialize(v, *args) super(*args); @v = v; end end + def test_regexp + marshal_equal(/a/) + marshal_equal(/A/i) + marshal_equal(/A/mx) + marshal_equal(/a\u3042/) + marshal_equal(/aあ/) + assert_equal(Regexp.new("あ".force_encoding("ASCII-8BIT")), + Marshal.load("\004\b/\b\343\201\202\000")) + assert_equal(/au3042/, Marshal.load("\004\b/\fa\\u3042\000")) + #assert_equal(/au3042/u, Marshal.load("\004\b/\fa\\u3042@")) # spec + end + + def test_regexp_subclass + marshal_equal(MyRegexp.new(10, "a")) + end + + class MyString < String; def initialize(v, *args) super(*args); @v = v; end end + def test_string + marshal_equal("abc") + end + + def test_string_ivar + o1 = "" + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + def test_string_subclass + marshal_equal(MyString.new(10, "a")) + end + + def test_string_subclass_cycle + str = MyString.new(10, "b") + str.instance_eval { @v = str } + marshal_equal(str) { |o| + assert_same(o, o.instance_eval { @v }) + o.instance_eval { @v } + } + end + + def test_string_subclass_extend + o = "abc" + o.extend(Mod1) + str = MyString.new(o, "c") + marshal_equal(str) { |v| + assert_kind_of(Mod1, v.instance_eval { @v }) + } + end + + MyStruct = Struct.new("MyStruct", :a, :b) + class MySubStruct < MyStruct; def initialize(v, *args) super(*args); @v = v; end end + def test_struct + marshal_equal(MyStruct.new(1,2)) + end + + def test_struct_subclass + marshal_equal(MySubStruct.new(10,1,2)) + end + + def test_struct_ivar + o1 = MyStruct.new + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + def test_struct_subclass_extend + o1 = MyStruct.new + o1.extend(Mod1) + marshal_equal_with_ancestry(o1) + o1.extend(Mod2) + marshal_equal_with_ancestry(o1) + end + + def test_symbol + marshal_equal(:a) + marshal_equal(:a?) + marshal_equal(:a!) + marshal_equal(:a=) + marshal_equal(:|) + marshal_equal(:^) + marshal_equal(:&) + marshal_equal(:<=>) + marshal_equal(:==) + marshal_equal(:===) + marshal_equal(:=~) + marshal_equal(:>) + marshal_equal(:>=) + marshal_equal(:<) + marshal_equal(:<=) + marshal_equal(:<<) + marshal_equal(:>>) + marshal_equal(:+) + marshal_equal(:-) + marshal_equal(:*) + marshal_equal(:/) + marshal_equal(:%) + marshal_equal(:**) + marshal_equal(:~) + marshal_equal(:+@) + marshal_equal(:-@) + marshal_equal(:[]) + marshal_equal(:[]=) + marshal_equal(:`) #` + marshal_equal("a b".intern) + end + + class MyTime < Time; def initialize(v, *args) super(*args); @v = v; end end + def test_time + # once there was a bug caused by usec overflow. try a little harder. + 10.times do + t = Time.now + marshal_equal(t, t.usec.to_s) + end + end + + def test_time_subclass + marshal_equal(MyTime.new(10)) + end + + def test_time_ivar + o1 = Time.now + o1.instance_eval { @iv = 1 } + marshal_equal(o1) {|o| o.instance_eval { @iv }} + end + + def test_time_in_array + t = Time.now + assert_equal([t,t], Marshal.load(Marshal.dump([t, t])), "[ruby-dev:34159]") + end + + def test_true + marshal_equal(true) + end + + def test_nil + marshal_equal(nil) + end + + def test_share + o = [:share] + o1 = [o, o] + o2 = marshaltest(o1) + assert_same(o2.first, o2.last) + end + + class CyclicRange < Range + def <=>(other); true; end + end + def test_range_cyclic + return unless CyclicRange.respond_to?(:allocate) # test for 1.8 + o1 = CyclicRange.allocate + o1.instance_eval { initialize(o1, o1) } + o2 = marshaltest(o1) + assert_same(o2, o2.begin) + assert_same(o2, o2.end) + end + + def test_singleton + o = Object.new + def o.m() end + assert_raise(TypeError) { marshaltest(o) } + + bug8043 = '[ruby-core:53206] [Bug #8043]' + class << o; prepend Mod1; end + assert_raise(TypeError, bug8043) {marshaltest(o)} + + o = Object.new + c = class << o + @v = 1 + class C; self; end + end + assert_raise(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(c) } + assert_raise(TypeError) { marshaltest(ARGF) } + assert_raise(TypeError) { marshaltest(ENV) } + end + + def test_extend + o = Object.new + o.extend Mod1 + marshal_equal(o) { |obj| obj.kind_of? Mod1 } + o = Object.new + o.extend Mod1 + o.extend Mod2 + marshal_equal_with_ancestry(o) + o = Object.new + o.extend Module.new + assert_raise(TypeError) { marshaltest(o) } + end + + def test_extend_string + o = "" + o.extend Mod1 + marshal_equal(o) { |obj| obj.kind_of? Mod1 } + o = "" + o.extend Mod1 + o.extend Mod2 + marshal_equal_with_ancestry(o) + o = "" + o.extend Module.new + assert_raise(TypeError) { marshaltest(o) } + end + + def test_anonymous + c = Class.new + assert_raise(TypeError) { marshaltest(c) } + o = c.new + assert_raise(TypeError) { marshaltest(o) } + m = Module.new + assert_raise(TypeError) { marshaltest(m) } + end + + def test_string_empty + marshal_equal("") + end + + def test_string_crlf + marshal_equal("\r\n") + end + + def test_string_escape + marshal_equal("\0<;;>\1;;") + end + + MyStruct2 = Struct.new(:a, :b) + def test_struct_toplevel + o = MyStruct2.new(1,2) + marshal_equal(o) + end +end diff --git a/jni/ruby/test/ruby/sentence.rb b/jni/ruby/test/ruby/sentence.rb new file mode 100644 index 0000000..50f42d6 --- /dev/null +++ b/jni/ruby/test/ruby/sentence.rb @@ -0,0 +1,668 @@ +# == sentence library +# +# = Features +# +# * syntax based sentences generation +# * sentence operations such as substitution. +# +# = Example +# +# Some arithmetic expressions using "+", "-", "*" and "/" are generated as follows. +# +# require 'sentence' +# Sentence.each({ +# :exp => [["num"], +# [:exp, "+", :exp], +# [:exp, "-", :exp], +# [:exp, "*", :exp], +# [:exp, "/", :exp]] +# }, :exp, 2) {|sent| p sent } +# #=> +# #<Sentence: "num"> +# #<Sentence: ("num") "+" ("num")> +# #<Sentence: ("num") "+" (("num") "+" ("num"))> +# #<Sentence: ("num") "+" (("num") "-" ("num"))> +# #<Sentence: ("num") "+" (("num") "*" ("num"))> +# #<Sentence: ("num") "+" (("num") "/" ("num"))> +# #<Sentence: (("num") "+" ("num")) "+" ("num")> +# ... +# +# Sentence.each takes 3 arguments. +# The first argument is the syntax for the expressions. +# The second argument, :exp, is a generating nonterminal. +# The third argument, 2, limits derivation to restrict results finitely. +# +# Some arithmetic expressions including parenthesis can be generated as follows. +# +# syntax = { +# :factor => [["n"], +# ["(", :exp, ")"]], +# :term => [[:factor], +# [:term, "*", :factor], +# [:term, "/", :factor]], +# :exp => [[:term], +# [:exp, "+", :term], +# [:exp, "-", :term]] +# } +# Sentence.each(syntax, :exp, 2) {|sent| p sent } +# #=> +# #<Sentence: (("n"))> +# #<Sentence: (("(" ((("n"))) ")"))> +# #<Sentence: (("(" ((("(" ((("n"))) ")"))) ")"))> +# #<Sentence: (("(" (((("n")) "*" ("n"))) ")"))> +# #<Sentence: (("(" (((("n")) "/" ("n"))) ")"))> +# #<Sentence: (("(" (((("n"))) "+" (("n"))) ")"))> +# #<Sentence: (("(" (((("n"))) "-" (("n"))) ")"))> +# #<Sentence: ((("n")) "*" ("n"))> +# #<Sentence: ((("n")) "*" ("(" ((("n"))) ")"))> +# ... +# +# Sentence#to_s can be used to concatenate strings +# in a sentence: +# +# Sentence.each(syntax, :exp, 2) {|sent| p sent.to_s } +# #=> +# "n" +# "(n)" +# "((n))" +# "(n*n)" +# "(n/n)" +# "(n+n)" +# "(n-n)" +# "n*n" +# "n*(n)" +# ... +# + +# Sentence() instantiates a sentence object. +# +# Sentence("foo", "bar") +# #=> #<Sentence: "foo" "bar"> +# +# Sentence("foo", ["bar", "baz"]) +# #=> #<Sentence: "foo" ("bar" "baz")> +# +def Sentence(*ary) + Sentence.new(ary) +end + +# Sentence class represents a tree with string leaves. +# +class Sentence + # _ary_ represents a tree. + # It should be a possibly nested array which contains strings. + # + # Note that _ary_ is not copied. + # Don't modify _ary_ after the sentence object is instantiated. + # + # Sentence.new(["a", "pen"]) + # #<Sentence: "a" "pen"> + # + # Sentence.new(["I", "have", ["a", "pen"]]) + # #<Sentence: "I" "have" ("a" "pen")> + # + def initialize(ary) + @sent = ary + end + + # returns a string which is concatenation of all strings. + # No separator is used. + # + # Sentence("2", "+", "3").to_s + # "2+3" + # + # Sentence("2", "+", ["3", "*", "5"]).to_s + # "2+3*5" + # + def to_s + @sent.join('') + end + + # returns a string which is concatenation of all strings separated by _sep_. + # If _sep_ is not given, single space is used. + # + # Sentence("I", "have", ["a", "pen"]).join + # "I have a pen" + # + # Sentence("I", "have", ["a", "pen"]).join("/") + # "I/have/a/pen" + # + # Sentence("a", [], "b").join("/") + # "a/b" + # + def join(sep=' ') + @sent.flatten.join(sep) + end + + # returns a tree as a nested array. + # + # Note that the result is not copied. + # Don't modify the result. + # + # Sentence(["foo", "bar"], "baz").to_a + # #=> [["foo", "bar"], "baz"] + # + def to_a + @sent + end + + # returns <i>i</i>th element as a sentence or string. + # + # s = Sentence(["foo", "bar"], "baz") + # s #=> #<Sentence: ("foo" "bar") "baz"> + # s[0] #=> #<Sentence: "foo" "bar"> + # s[1] #=> "baz" + # + def [](i) + e = @sent[i] + e.respond_to?(:to_ary) ? Sentence.new(e) : e + end + + # returns the number of top level elements. + # + # Sentence.new(%w[foo bar]).length + # #=> 2 + # + # Sentence(%w[2 * 7], "+", %w[3 * 5]).length + # #=> 3 + # + def length + @sent.length + end + + # iterates over children. + # + # Sentence(%w[2 * 7], "+", %w[3 * 5]).each {|v| p v } + # #=> + # #<Sentence: "2" "*" "7"> + # "+" + # #<Sentence: "3" "*" "5"> + # + def each # :yield: element + @sent.each_index {|i| + yield self[i] + } + end + include Enumerable + + def inspect + "#<#{self.class}: #{inner_inspect(@sent, '')}>" + end + + # :stopdoc: + def inner_inspect(ary, r) + first = true + ary.each {|obj| + r << ' ' if !first + first = false + if obj.respond_to? :to_ary + r << '(' + inner_inspect(obj, r) + r << ')' + else + r << obj.inspect + end + } + r + end + # :startdoc: + + # returns new sentence object which + # _target_ is substituted by the block. + # + # Sentence#subst invokes <tt>_target_ === _string_</tt> for each + # string in the sentence. + # The strings which === returns true are substituted by the block. + # The block is invoked with the substituting string. + # + # Sentence.new(%w[2 + 3]).subst("+") { "*" } + # #<Sentence: "2" "*" "3"> + # + # Sentence.new(%w[2 + 3]).subst(/\A\d+\z/) {|s| ((s.to_i)*2).to_s } + # #=> #<Sentence: "4" "+" "6"> + # + def subst(target, &b) # :yield: string + Sentence.new(subst_rec(@sent, target, &b)) + end + + # :stopdoc: + def subst_rec(obj, target, &b) + if obj.respond_to? :to_ary + a = [] + obj.each {|e| a << subst_rec(e, target, &b) } + a + elsif target === obj + yield obj + else + obj + end + end + # :startdoc: + + # find a subsentence and return it. + # The block is invoked for each subsentence in preorder manner. + # The first subsentence which the block returns true is returned. + # + # Sentence(%w[2 * 7], "+", %w[3 * 5]).find_subtree {|s| s[1] == "*" } + # #=> #<Sentence: "2" "*" "7"> + # + def find_subtree(&b) # :yield: sentence + find_subtree_rec(@sent, &b) + end + + # :stopdoc: + def find_subtree_rec(obj, &b) + if obj.respond_to? :to_ary + s = Sentence.new(obj) + if b.call s + return s + else + obj.each {|e| + r = find_subtree_rec(e, &b) + return r if r + } + end + end + nil + end + # :startdoc: + + # returns a new sentence object which expands according to the condition + # given by the block. + # + # The block is invoked for each subsentence. + # The subsentences which the block returns true are + # expanded into parent. + # + # s = Sentence(%w[2 * 7], "+", %w[3 * 5]) + # #=> #<Sentence: ("2" "*" "7") "+" ("3" "*" "5")> + # + # s.expand { true } + # #=> #<Sentence: "2" "*" "7" "+" "3" "*" "5"> + # + # s.expand {|s| s[0] == "3" } + # #=> #<Sentence: (("2" "*" "7") "+" "3" "*" "5")> + # + def expand(&b) # :yield: sentence + Sentence.new(expand_rec(@sent, &b)) + end + + # :stopdoc: + def expand_rec(obj, r=[], &b) + if obj.respond_to? :to_ary + obj.each {|o| + s = Sentence.new(o) + if b.call s + expand_rec(o, r, &b) + else + a = [] + expand_rec(o, a, &b) + r << a + end + } + else + r << obj + end + r + end + # :startdoc: + + # Sentence.each generates sentences + # by deriving the start symbol _sym_ using _syntax_. + # The derivation is restricted by an positive integer _limit_ to + # avoid infinite generation. + # + # Sentence.each yields the block with a generated sentence. + # + # Sentence.each({ + # :exp => [["n"], + # [:exp, "+", :exp], + # [:exp, "*", :exp]] + # }, :exp, 1) {|sent| p sent } + # #=> + # #<Sentence: "n"> + # #<Sentence: ("n") "+" ("n")> + # #<Sentence: ("n") "*" ("n")> + # + # Sentence.each({ + # :exp => [["n"], + # [:exp, "+", :exp], + # [:exp, "*", :exp]] + # }, :exp, 2) {|sent| p sent } + # #=> + # #<Sentence: "n"> + # #<Sentence: ("n") "+" ("n")> + # #<Sentence: ("n") "+" (("n") "+" ("n"))> + # #<Sentence: ("n") "+" (("n") "*" ("n"))> + # #<Sentence: (("n") "+" ("n")) "+" ("n")> + # #<Sentence: (("n") "*" ("n")) "+" ("n")> + # #<Sentence: ("n") "*" ("n")> + # #<Sentence: ("n") "*" (("n") "+" ("n"))> + # #<Sentence: ("n") "*" (("n") "*" ("n"))> + # #<Sentence: (("n") "+" ("n")) "*" ("n")> + # #<Sentence: (("n") "*" ("n")) "*" ("n")> + # + def Sentence.each(syntax, sym, limit) + Gen.new(syntax).each_tree(sym, limit) {|tree| + yield Sentence.new(tree) + } + end + + # Sentence.expand_syntax returns an expanded syntax: + # * No rule derives to empty sequence + # * Underivable rule simplified + # * No channel rule + # * Symbols which has zero or one choices are not appered in rhs. + # + # Note that the rules which can derive empty and non-empty + # sequences are modified to derive only non-empty sequences. + # + # Sentence.expand_syntax({ + # :underivable1 => [], + # :underivable2 => [[:underivable1]], + # :underivable3 => [[:underivable3]], + # :empty_only1 => [[]], + # :empty_only2 => [[:just_empty1, :just_empty1]], + # :empty_or_not => [[], ["foo"]], + # :empty_or_not_2 => [[:empty_or_not, :empty_or_not]], + # :empty_or_not_3 => [[:empty_or_not, :empty_or_not, :empty_or_not]], + # :empty_or_not_4 => [[:empty_or_not_2, :empty_or_not_2]], + # :channel1 => [[:channeled_data]], + # :channeled_data => [["a", "b"], ["c", "d"]], + # :single_choice => [["single", "choice"]], + # :single_choice_2 => [[:single_choice, :single_choice]], + # }) + # #=> + # { + # :underivable1=>[], # underivable rules are simplified to []. + # :underivable2=>[], + # :underivable3=>[], + # :empty_only1=>[], # derivation to empty sequence are removed. + # :empty_only2=>[], + # :empty_or_not=>[["foo"]], # empty sequences are removed too. + # :empty_or_not_2=>[["foo"], ["foo", "foo"]], + # :empty_or_not_3=>[["foo"], ["foo", "foo"], ["foo", "foo", "foo"]], + # :empty_or_not_4=> [["foo"], ["foo", "foo"], [:empty_or_not_2, :empty_or_not_2]], + # :channel1=>[["a", "b"], ["c", "d"]], # channel rules are removed. + # :channeled_data=>[["a", "b"], ["c", "d"]], + # :single_choice=>[["single", "choice"]], # single choice rules are expanded. + # :single_choice_2=>[["single", "choice", "single", "choice"]], + # } + # + # Sentence.expand_syntax({ + # :factor => [["n"], + # ["(", :exp, ")"]], + # :term => [[:factor], + # [:term, "*", :factor], + # [:term, "/", :factor]], + # :exp => [[:term], + # [:exp, "+", :term], + # [:exp, "-", :term]] + # }) + # #=> + # {:exp=> [["n"], + # ["(", :exp, ")"], + # [:exp, "+", :term], + # [:exp, "-", :term], + # [:term, "*", :factor], + # [:term, "/", :factor]], + # :factor=> [["n"], + # ["(", :exp, ")"]], + # :term=> [["n"], + # ["(", :exp, ")"], + # [:term, "*", :factor], + # [:term, "/", :factor]] + # } + # + def Sentence.expand_syntax(syntax) + Sentence::Gen.expand_syntax(syntax) + end + + # :stopdoc: + class Gen + def Gen.each_tree(syntax, sym, limit, &b) + Gen.new(syntax).each_tree(sym, limit, &b) + end + + def Gen.each_string(syntax, sym, limit, &b) + Gen.new(syntax).each_string(sym, limit, &b) + end + + def initialize(syntax) + @syntax = syntax + end + + def self.expand_syntax(syntax) + syntax = simplify_underivable_rules(syntax) + syntax = simplify_emptyonly_rules(syntax) + syntax = make_rules_no_empseq(syntax) + syntax = expand_channel_rules(syntax) + + syntax = expand_noalt_rules(syntax) + syntax = reorder_rules(syntax) + end + + def self.simplify_underivable_rules(syntax) + deribable_syms = {} + changed = true + while changed + changed = false + syntax.each {|sym, rules| + next if deribable_syms[sym] + rules.each {|rhs| + if rhs.all? {|e| String === e || deribable_syms[e] } + deribable_syms[sym] = true + changed = true + break + end + } + } + end + result = {} + syntax.each {|sym, rules| + if deribable_syms[sym] + rules2 = [] + rules.each {|rhs| + rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] } + } + result[sym] = rules2.uniq + else + result[sym] = [] + end + } + result + end + + def self.simplify_emptyonly_rules(syntax) + justempty_syms = {} + changed = true + while changed + changed = false + syntax.each {|sym, rules| + next if justempty_syms[sym] + if !rules.empty? && rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } } + justempty_syms[sym] = true + changed = true + end + } + end + result = {} + syntax.each {|sym, rules| + result[sym] = rules.map {|rhs| rhs.reject {|e| justempty_syms[e] } }.uniq + } + result + end + + def self.expand_emptyable_syms(rhs, emptyable_syms) + if rhs.empty? + yield [] + else + first = rhs[0] + rest = rhs[1..-1] + if emptyable_syms[first] + expand_emptyable_syms(rest, emptyable_syms) {|rhs2| + yield [first] + rhs2 + yield rhs2 + } + else + expand_emptyable_syms(rest, emptyable_syms) {|rhs2| + yield [first] + rhs2 + } + end + end + end + + def self.make_rules_no_empseq(syntax) + emptyable_syms = {} + changed = true + while changed + changed = false + syntax.each {|sym, rules| + next if emptyable_syms[sym] + rules.each {|rhs| + if rhs.all? {|e| emptyable_syms[e] } + emptyable_syms[sym] = true + changed = true + break + end + } + } + end + result = {} + syntax.each {|sym, rules| + rules2 = [] + rules.each {|rhs| + expand_emptyable_syms(rhs, emptyable_syms) {|rhs2| + next if rhs2.empty? + rules2 << rhs2 + } + } + result[sym] = rules2.uniq + } + result + end + + def self.expand_channel_rules(syntax) + channel_rules = {} + syntax.each {|sym, rules| + channel_rules[sym] = {sym=>true} + rules.each {|rhs| + if rhs.length == 1 && Symbol === rhs[0] + channel_rules[sym][rhs[0]] = true + end + } + } + changed = true + while changed + changed = false + channel_rules.each {|sym, set| + n1 = set.size + set.keys.each {|s| + set.update(channel_rules[s]) + } + n2 = set.size + changed = true if n1 < n2 + } + end + result = {} + syntax.each {|sym, rules| + rules2 = [] + channel_rules[sym].each_key {|s| + syntax[s].each {|rhs| + unless rhs.length == 1 && Symbol === rhs[0] + rules2 << rhs + end + } + } + result[sym] = rules2.uniq + } + result + end + + def self.expand_noalt_rules(syntax) + noalt_syms = {} + syntax.each {|sym, rules| + if rules.length == 1 + noalt_syms[sym] = true + end + } + result = {} + syntax.each {|sym, rules| + rules2 = [] + rules.each {|rhs| + rhs2 = [] + rhs.each {|e| + if noalt_syms[e] + rhs2.concat syntax[e][0] + else + rhs2 << e + end + } + rules2 << rhs2 + } + result[sym] = rules2.uniq + } + result + end + + def self.reorder_rules(syntax) + result = {} + syntax.each {|sym, rules| + result[sym] = rules.sort_by {|rhs| + [rhs.find_all {|e| Symbol === e }.length, rhs.length] + } + } + result + end + + def each_tree(sym, limit) + generate_from_sym(sym, limit) {|_, tree| + yield tree + } + nil + end + + def each_string(sym, limit) + generate_from_sym(sym, limit) {|_, tree| + yield [tree].join('') + } + nil + end + + def generate_from_sym(sym, limit, &b) + return if limit < 0 + if String === sym + yield limit, sym + else + rules = @syntax[sym] + raise "undefined rule: #{sym}" if !rules + rules.each {|rhs| + if rhs.length == 1 || rules.length == 1 + limit1 = limit + else + limit1 = limit-1 + end + generate_from_rhs(rhs, limit1, &b) + } + end + nil + end + + def generate_from_rhs(rhs, limit) + return if limit < 0 + if rhs.empty? + yield limit, [] + else + generate_from_sym(rhs[0], limit) {|limit1, child| + generate_from_rhs(rhs[1..-1], limit1) {|limit2, arr| + yield limit2, [child, *arr] + } + } + end + nil + end + end + # :startdoc: + +end + diff --git a/jni/ruby/test/ruby/test_alias.rb b/jni/ruby/test/ruby/test_alias.rb new file mode 100644 index 0000000..8901fc2 --- /dev/null +++ b/jni/ruby/test/ruby/test_alias.rb @@ -0,0 +1,196 @@ +require 'test/unit' + +class TestAlias < Test::Unit::TestCase + class Alias0 + def foo + "foo" + end + end + + class Alias1 < Alias0 + alias bar foo + + def foo + "foo+#{super}" + end + end + + class Alias2 < Alias1 + alias baz foo + undef foo + end + + class Alias3 < Alias2 + def foo + super + end + + def bar + super + end + + def quux + super + end + end + + def test_alias + x = Alias2.new + assert_equal "foo", x.bar + assert_equal "foo+foo", x.baz + assert_equal "foo+foo", x.baz # test_check for cache + + x = Alias3.new + assert_raise(NoMethodError) { x.foo } + assert_equal "foo", x.bar + assert_raise(NoMethodError) { x.quux } + end + + class C + def m + $SAFE + end + end + + def test_nonexistmethod + assert_raise(NameError){ + Class.new{ + alias_method :foobarxyzzy, :barbaz + } + } + end + + def test_send_alias + x = "abc" + class << x + alias_method :try, :__send__ + end + assert_equal("ABC", x.try(:upcase), '[ruby-dev:38824]') + end + + def test_special_const_alias + assert_raise(TypeError) do + 1.instance_eval do + alias to_string to_s + end + end + end + + def test_alias_with_zsuper_method + c = Class.new + c.class_eval do + def foo + :ok + end + def bar + :ng + end + private :foo + end + d = Class.new(c) + d.class_eval do + public :foo + alias bar foo + end + assert_equal(:ok, d.new.bar) + end + + module SuperInAliasedModuleMethod + module M + def foo + super << :M + end + + alias bar foo + end + + class Base + def foo + [:Base] + end + end + + class Derived < Base + include M + end + end + + # [ruby-dev:46028] + def test_super_in_aliased_module_method # fails in 1.8 + assert_equal([:Base, :M], SuperInAliasedModuleMethod::Derived.new.bar) + end + + def test_alias_wb_miss + assert_normal_exit %q{ + require 'stringio' + GC.verify_internal_consistency + GC.start + class StringIO + alias_method :read_nonblock, :sysread + end + GC.verify_internal_consistency + } + end + + def test_cyclic_zsuper + bug9475 = '[ruby-core:60431] [Bug #9475]' + + a = Module.new do + def foo + "A" + end + end + + b = Class.new do + include a + attr_reader :b + + def foo + @b ||= 0 + raise SystemStackError if (@b += 1) > 1 + # "foo from B" + super + "B" + end + end + + c = Class.new(b) do + alias orig_foo foo + + def foo + # "foo from C" + orig_foo + "C" + end + end + + b.class_eval do + alias orig_foo foo + attr_reader :b2 + + def foo + @b2 ||= 0 + raise SystemStackError if (@b2 += 1) > 1 + # "foo from B (again)" + orig_foo + "B2" + end + end + + assert_nothing_raised(SystemStackError, bug9475) do + assert_equal("ABC", c.new.foo, bug9475) + end + end + + def test_alias_in_module + bug9663 = '[ruby-core:61635] [Bug #9663]' + + assert_separately(['-', bug9663], <<-'end;') + bug = ARGV[0] + + m = Module.new do + alias orig_to_s to_s + end + + o = Object.new.extend(m) + assert_equal(o.to_s, o.orig_to_s, bug) + end; + end +end diff --git a/jni/ruby/test/ruby/test_argf.rb b/jni/ruby/test/ruby/test_argf.rb new file mode 100644 index 0000000..6975b83 --- /dev/null +++ b/jni/ruby/test/ruby/test_argf.rb @@ -0,0 +1,859 @@ +require 'test/unit' +require 'timeout' +require 'tmpdir' +require 'tempfile' +require 'fileutils' + +class TestArgf < Test::Unit::TestCase + def setup + @tmpdir = Dir.mktmpdir + @tmp_count = 0 + @t1 = make_tempfile0("argf-foo") + @t1.binmode + @t1.puts "1" + @t1.puts "2" + @t1.close + @t2 = make_tempfile0("argf-bar") + @t2.binmode + @t2.puts "3" + @t2.puts "4" + @t2.close + @t3 = make_tempfile0("argf-baz") + @t3.binmode + @t3.puts "5" + @t3.puts "6" + @t3.close + end + + def teardown + FileUtils.rmtree(@tmpdir) + end + + def make_tempfile0(basename) + @tmp_count += 1 + open("#{@tmpdir}/#{basename}-#{@tmp_count}", "w") + end + + def make_tempfile + t = make_tempfile0("argf-qux") + t.puts "foo" + t.puts "bar" + t.puts "baz" + t.close + t + end + + def ruby(*args, external_encoding: Encoding::UTF_8) + args = ['-e', '$>.write($<.read)'] if args.empty? + ruby = EnvUtil.rubybin + f = IO.popen([ruby] + args, 'r+', external_encoding: external_encoding) + yield(f) + ensure + f.close unless !f || f.closed? + end + + def no_safe_rename + /cygwin|mswin|mingw|bccwin/ =~ RUBY_PLATFORM + end + + def assert_src_expected(line, src, args = nil) + args ||= [@t1.path, @t2.path, @t3.path] + expected = src.split(/^/) + ruby('-e', src, *args) do |f| + expected.each_with_index do |e, i| + /#=> *(.*)/ =~ e or next + a = f.gets + assert_not_nil(a, "[ruby-dev:34445]: remained") + assert_equal($1, a.chomp, "[ruby-dev:34445]: line #{line+i}") + end + end + end + + def test_argf + assert_src_expected(__LINE__+1, <<-'SRC') + a = ARGF + b = a.dup + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["1", 1, "1", 1] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["2", 2, "2", 2] + a.rewind + b.rewind + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["1", 1, "1", 3] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["2", 2, "2", 4] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["3", 3, "3", 5] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["4", 4, "4", 6] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["5", 5, "5", 7] + a.rewind + b.rewind + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["5", 5, "5", 8] + p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["6", 6, "6", 9] + SRC + end + + def test_lineno + assert_src_expected(__LINE__+1, <<-'SRC') + a = ARGF + a.gets; p $. #=> 1 + a.gets; p $. #=> 2 + a.gets; p $. #=> 3 + a.rewind; p $. #=> 3 + a.gets; p $. #=> 3 + a.gets; p $. #=> 4 + a.rewind; p $. #=> 4 + a.gets; p $. #=> 3 + a.lineno = 1000; p $. #=> 1000 + a.gets; p $. #=> 1001 + a.gets; p $. #=> 1002 + $. = 2000 + a.gets; p $. #=> 2001 + a.gets; p $. #=> 2001 + SRC + end + + def test_lineno2 + assert_src_expected(__LINE__+1, <<-'SRC') + a = ARGF.dup + a.gets; p $. #=> 1 + a.gets; p $. #=> 2 + a.gets; p $. #=> 1 + a.rewind; p $. #=> 1 + a.gets; p $. #=> 1 + a.gets; p $. #=> 2 + a.gets; p $. #=> 1 + a.lineno = 1000; p $. #=> 1 + a.gets; p $. #=> 2 + a.gets; p $. #=> 2 + $. = 2000 + a.gets; p $. #=> 2000 + a.gets; p $. #=> 2000 + SRC + end + + def test_lineno3 + assert_in_out_err(["-", @t1.path, @t2.path], <<-INPUT, %w"1 1 1 2 2 2 3 3 1 4 4 2", [], "[ruby-core:25205]") + ARGF.each do |line| + puts [$., ARGF.lineno, ARGF.file.lineno] + end + INPUT + end + + def test_inplace + assert_in_out_err(["-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], []) + ARGF.inplace_mode = '.bak' + while line = ARGF.gets + puts line.chomp + '.new' + end + INPUT + assert_equal("1.new\n2.new\n", File.read(@t1.path)) + assert_equal("3.new\n4.new\n", File.read(@t2.path)) + assert_equal("5.new\n6.new\n", File.read(@t3.path)) + assert_equal("1\n2\n", File.read(@t1.path + ".bak")) + assert_equal("3\n4\n", File.read(@t2.path + ".bak")) + assert_equal("5\n6\n", File.read(@t3.path + ".bak")) + end + + def test_inplace2 + assert_in_out_err(["-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], []) + ARGF.inplace_mode = '.bak' + puts ARGF.gets.chomp + '.new' + puts ARGF.gets.chomp + '.new' + p ARGF.inplace_mode + ARGF.inplace_mode = nil + puts ARGF.gets.chomp + '.new' + puts ARGF.gets.chomp + '.new' + p ARGF.inplace_mode + ARGF.inplace_mode = '.bak' + puts ARGF.gets.chomp + '.new' + p ARGF.inplace_mode + ARGF.inplace_mode = nil + puts ARGF.gets.chomp + '.new' + INPUT + assert_equal("1.new\n2.new\n\".bak\"\n3.new\n4.new\nnil\n", File.read(@t1.path)) + assert_equal("3\n4\n", File.read(@t2.path)) + assert_equal("5.new\n\".bak\"\n6.new\n", File.read(@t3.path)) + assert_equal("1\n2\n", File.read(@t1.path + ".bak")) + assert_equal(false, File.file?(@t2.path + ".bak")) + assert_equal("5\n6\n", File.read(@t3.path + ".bak")) + end + + def test_inplace3 + assert_in_out_err(["-i.bak", "-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], []) + puts ARGF.gets.chomp + '.new' + puts ARGF.gets.chomp + '.new' + p $-i + $-i = nil + puts ARGF.gets.chomp + '.new' + puts ARGF.gets.chomp + '.new' + p $-i + $-i = '.bak' + puts ARGF.gets.chomp + '.new' + p $-i + $-i = nil + puts ARGF.gets.chomp + '.new' + INPUT + assert_equal("1.new\n2.new\n\".bak\"\n3.new\n4.new\nnil\n", File.read(@t1.path)) + assert_equal("3\n4\n", File.read(@t2.path)) + assert_equal("5.new\n\".bak\"\n6.new\n", File.read(@t3.path)) + assert_equal("1\n2\n", File.read(@t1.path + ".bak")) + assert_equal(false, File.file?(@t2.path + ".bak")) + assert_equal("5\n6\n", File.read(@t3.path + ".bak")) + end + + def test_inplace_rename_impossible + t = make_tempfile + + assert_in_out_err(["-", t.path], <<-INPUT) do |r, e| + ARGF.inplace_mode = '/\\\\:' + while line = ARGF.gets + puts line.chomp + '.new' + end + INPUT + assert_match(/Can't rename .* to .*: .*. skipping file/, e.first) #' + assert_equal([], r) + assert_equal("foo\nbar\nbaz\n", File.read(t.path)) + end + + base = "argf-\u{30c6 30b9 30c8}" + name = "#{@tmpdir}/#{base}" + File.write(name, "foo") + argf = ARGF.class.new(name) + argf.inplace_mode = '/\\:' + assert_warning(/#{base}/) {argf.gets} + end + + def test_inplace_no_backup + t = make_tempfile + + assert_in_out_err(["-", t.path], <<-INPUT) do |r, e| + ARGF.inplace_mode = '' + while line = ARGF.gets + puts line.chomp + '.new' + end + INPUT + if no_safe_rename + assert_match(/Can't do inplace edit without backup/, e.join) #' + else + assert_equal([], e) + assert_equal([], r) + assert_equal("foo.new\nbar.new\nbaz.new\n", File.read(t.path)) + end + end + end + + def test_inplace_dup + t = make_tempfile + + assert_in_out_err(["-", t.path], <<-INPUT, [], []) + ARGF.inplace_mode = '.bak' + f = ARGF.dup + while line = f.gets + puts line.chomp + '.new' + end + INPUT + assert_equal("foo.new\nbar.new\nbaz.new\n", File.read(t.path)) + end + + def test_inplace_stdin + assert_in_out_err(["-", "-"], <<-INPUT, [], /Can't do inplace edit for stdio; skipping/) + ARGF.inplace_mode = '.bak' + f = ARGF.dup + while line = f.gets + puts line.chomp + '.new' + end + INPUT + end + + def test_inplace_stdin2 + assert_in_out_err(["-"], <<-INPUT, [], /Can't do inplace edit for stdio/) + ARGF.inplace_mode = '.bak' + while line = ARGF.gets + puts line.chomp + '.new' + end + INPUT + end + + def test_encoding + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + p ARGF.external_encoding.is_a?(Encoding) + p ARGF.internal_encoding.is_a?(Encoding) + ARGF.gets + p ARGF.external_encoding.is_a?(Encoding) + p ARGF.internal_encoding + SRC + assert_equal("true\ntrue\ntrue\nnil\n", f.read) + end + end + + def test_tell + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + ARGF.binmode + loop do + p ARGF.tell + p ARGF.gets + end + rescue ArgumentError + puts "end" + end + SRC + a = f.read.split("\n") + [0, 2, 4, 2, 4, 2, 4].map {|i| i.to_s }. + zip((1..6).map {|i| '"' + i.to_s + '\n"' } + ["nil"]).flatten. + each do |x| + assert_equal(x, a.shift) + end + assert_equal('end', a.shift) + end + end + + def test_seek + assert_src_expected(__LINE__+1, <<-'SRC') + ARGF.seek(4) + p ARGF.gets #=> "3\n" + ARGF.seek(0, IO::SEEK_END) + p ARGF.gets #=> "5\n" + ARGF.seek(4) + p ARGF.gets #=> nil + begin + ARGF.seek(0) + rescue + puts "end" #=> end + end + SRC + end + + def test_set_pos + assert_src_expected(__LINE__+1, <<-'SRC') + ARGF.pos = 4 + p ARGF.gets #=> "3\n" + ARGF.pos = 4 + p ARGF.gets #=> "5\n" + ARGF.pos = 4 + p ARGF.gets #=> nil + begin + ARGF.pos = 4 + rescue + puts "end" #=> end + end + SRC + end + + def test_rewind + assert_src_expected(__LINE__+1, <<-'SRC') + ARGF.pos = 4 + ARGF.rewind + p ARGF.gets #=> "1\n" + ARGF.pos = 4 + p ARGF.gets #=> "3\n" + ARGF.pos = 4 + p ARGF.gets #=> "5\n" + ARGF.pos = 4 + p ARGF.gets #=> nil + begin + ARGF.rewind + rescue + puts "end" #=> end + end + SRC + end + + def test_fileno + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + p ARGF.fileno + ARGF.gets + ARGF.gets + p ARGF.fileno + ARGF.gets + ARGF.gets + p ARGF.fileno + ARGF.gets + ARGF.gets + p ARGF.fileno + ARGF.gets + begin + ARGF.fileno + rescue + puts "end" + end + SRC + a = f.read.split("\n") + fd1, fd2, fd3, fd4, tag = a + assert_match(/^\d+$/, fd1) + assert_match(/^\d+$/, fd2) + assert_match(/^\d+$/, fd3) + assert_match(/^\d+$/, fd4) + assert_equal('end', tag) + end + end + + def test_to_io + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + 8.times do + p ARGF.to_io + ARGF.gets + end + SRC + a = f.read.split("\n") + f11, f12, f13, f21, f22, f31, f32, f4 = a + assert_equal(f11, f12) + assert_equal(f11, f13) + assert_equal(f21, f22) + assert_equal(f31, f32) + assert_match(/\(closed\)/, f4) + f4.sub!(/ \(closed\)/, "") + assert_equal(f31, f4) + end + end + + def test_eof + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + 8.times do + p ARGF.eof? + ARGF.gets + end + rescue IOError + puts "end" + end + SRC + a = f.read.split("\n") + (%w(false) + (%w(false true) * 3) + %w(end)).each do |x| + assert_equal(x, a.shift) + end + end + + t1 = open("#{@tmpdir}/argf-hoge", "w") + t1.binmode + t1.puts "foo" + t1.close + t2 = open("#{@tmpdir}/argf-moge", "w") + t2.binmode + t2.puts "bar" + t2.close + ruby('-e', 'STDERR.reopen(STDOUT); ARGF.gets; ARGF.skip; p ARGF.eof?', t1.path, t2.path) do |f| + assert_equal(%w(false), f.read.split(/\n/)) + end + end + + def test_read + ruby('-e', "p ARGF.read(8)", @t1.path, @t2.path, @t3.path) do |f| + assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read) + end + end + + def test_read2 + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "" + ARGF.read(8, s) + p s + SRC + assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read) + end + end + + def test_read2_with_not_empty_buffer + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "0123456789" + ARGF.read(8, s) + p s + SRC + assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read) + end + end + + def test_read3 + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + nil while ARGF.gets + p ARGF.read + p ARGF.read(0, "") + SRC + assert_equal("nil\n\"\"\n", f.read) + end + end + + def test_readpartial + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "" + begin + loop do + s << ARGF.readpartial(1) + t = ""; ARGF.readpartial(1, t); s << t + # not empty buffer + u = "abcdef"; ARGF.readpartial(1, u); s << u + end + rescue EOFError + puts s + end + SRC + assert_equal("1\n2\n3\n4\n5\n6\n", f.read) + end + end + + def test_readpartial2 + ruby('-e', <<-SRC) do |f| + s = "" + begin + loop do + s << ARGF.readpartial(1) + t = ""; ARGF.readpartial(1, t); s << t + end + rescue EOFError + $stdout.binmode + puts s + end + SRC + f.binmode + f.puts("foo") + f.puts("bar") + f.puts("baz") + f.close_write + assert_equal("foo\nbar\nbaz\n", f.read) + end + end + + def test_getc + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "" + while c = ARGF.getc + s << c + end + puts s + SRC + assert_equal("1\n2\n3\n4\n5\n6\n", f.read) + end + end + + def test_getbyte + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = [] + while c = ARGF.getbyte + s << c + end + p s + SRC + assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read) + end + end + + def test_readchar + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "" + begin + while c = ARGF.readchar + s << c + end + rescue EOFError + puts s + end + SRC + assert_equal("1\n2\n3\n4\n5\n6\n", f.read) + end + end + + def test_readbyte + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + s = [] + while c = ARGF.readbyte + s << c + end + rescue EOFError + p s + end + SRC + assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read) + end + end + + def test_each_line + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = [] + ARGF.each_line {|l| s << l } + p s + SRC + assert_equal("[\"1\\n\", \"2\\n\", \"3\\n\", \"4\\n\", \"5\\n\", \"6\\n\"]\n", f.read) + end + end + + def test_each_line_paragraph + assert_in_out_err(['-e', 'ARGF.each_line("") {|para| p para}'], "a\n\nb\n", + ["\"a\\n\\n\"", "\"b\\n\""], []) + end + + def test_each_byte + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = [] + ARGF.each_byte {|c| s << c } + p s + SRC + assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read) + end + end + + def test_each_char + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + s = "" + ARGF.each_char {|c| s << c } + puts s + SRC + assert_equal("1\n2\n3\n4\n5\n6\n", f.read) + end + end + + def test_filename + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + puts ARGF.filename.dump + end while ARGF.gets + puts ARGF.filename.dump + SRC + a = f.read.split("\n") + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + end + end + + def test_filename2 + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + puts $FILENAME.dump + end while ARGF.gets + puts $FILENAME.dump + SRC + a = f.read.split("\n") + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + end + end + + def test_file + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + begin + puts ARGF.file.path.dump + end while ARGF.gets + puts ARGF.file.path.dump + SRC + a = f.read.split("\n") + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t1.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t2.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + assert_equal(@t3.path.dump, a.shift) + end + end + + def test_binmode + bug5268 = '[ruby-core:39234]' + open(@t3.path, "wb") {|f| f.write "5\r\n6\r\n"} + ruby('-e', "ARGF.binmode; STDOUT.binmode; puts ARGF.read", @t1.path, @t2.path, @t3.path) do |f| + f.binmode + assert_equal("1\n2\n3\n4\n5\r\n6\r\n", f.read, bug5268) + end + end + + def test_textmode + bug5268 = '[ruby-core:39234]' + open(@t3.path, "wb") {|f| f.write "5\r\n6\r\n"} + ruby('-e', "STDOUT.binmode; puts ARGF.read", @t1.path, @t2.path, @t3.path) do |f| + f.binmode + assert_equal("1\n2\n3\n4\n5\n6\n", f.read, bug5268) + end + end unless IO::BINARY.zero? + + def test_skip + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.skip + puts ARGF.gets + ARGF.skip + puts ARGF.read + SRC + assert_equal("1\n3\n4\n5\n6\n", f.read) + end + end + + def test_skip_in_each_line + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.each_line {|l| print l; ARGF.skip} + SRC + assert_equal("1\n3\n5\n", f.read, '[ruby-list:49185]') + end + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.each_line {|l| ARGF.skip; puts [l, ARGF.gets].map {|s| s ? s.chomp : s.inspect}.join("+")} + SRC + assert_equal("1+3\n4+5\n6+nil\n", f.read, '[ruby-list:49185]') + end + end + + def test_skip_in_each_byte + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.each_byte {|l| print l; ARGF.skip} + SRC + assert_equal("135".unpack("C*").join(""), f.read, '[ruby-list:49185]') + end + end + + def test_skip_in_each_char + [[@t1, "\u{3042}"], [@t2, "\u{3044}"], [@t3, "\u{3046}"]].each do |f, s| + File.write(f.path, s, mode: "w:utf-8") + end + ruby('-Eutf-8', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.each_char {|l| print l; ARGF.skip} + SRC + assert_equal("\u{3042 3044 3046}", f.read, '[ruby-list:49185]') + end + end + + def test_skip_in_each_codepoint + [[@t1, "\u{3042}"], [@t2, "\u{3044}"], [@t3, "\u{3046}"]].each do |f, s| + File.write(f.path, s, mode: "w:utf-8") + end + ruby('-Eutf-8', '-Eutf-8', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.each_codepoint {|l| printf "%x:", l; ARGF.skip} + SRC + assert_equal("3042:3044:3046:", f.read, '[ruby-list:49185]') + end + end + + def test_close + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + ARGF.close + puts ARGF.read + SRC + assert_equal("3\n4\n5\n6\n", f.read) + end + end + + def test_close_replace + ruby('-e', <<-SRC) do |f| + ARGF.close + ARGV.replace ['#{@t1.path}', '#{@t2.path}', '#{@t3.path}'] + puts ARGF.read + SRC + assert_equal("1\n2\n3\n4\n5\n6\n", f.read) + end + end + + def test_closed + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + 3.times do + p ARGF.closed? + ARGF.gets + ARGF.gets + end + p ARGF.closed? + ARGF.gets + p ARGF.closed? + SRC + assert_equal("false\nfalse\nfalse\nfalse\ntrue\n", f.read) + end + end + + def test_argv + ruby('-e', "p ARGF.argv; p $*", @t1.path, @t2.path, @t3.path) do |f| + assert_equal([@t1.path, @t2.path, @t3.path].inspect, f.gets.chomp) + assert_equal([@t1.path, @t2.path, @t3.path].inspect, f.gets.chomp) + end + end + + def test_readlines_limit_0 + bug4024 = '[ruby-dev:42538]' + t = make_tempfile + argf = ARGF.class.new(t.path) + begin + assert_raise(ArgumentError, bug4024) do + argf.readlines(0) + end + ensure + argf.close + end + end + + def test_each_line_limit_0 + bug4024 = '[ruby-dev:42538]' + t = make_tempfile + argf = ARGF.class.new(t.path) + begin + assert_raise(ArgumentError, bug4024) do + argf.each_line(0).next + end + ensure + argf.close + end + end + + def test_unreadable + bug4274 = '[ruby-core:34446]' + paths = (1..2).map do + t = Tempfile.new("bug4274-") + path = t.path + t.close! + path + end + argf = ARGF.class.new(*paths) + paths.each do |path| + assert_raise_with_message(Errno::ENOENT, /- #{Regexp.quote(path)}\z/) {argf.gets} + end + assert_nil(argf.gets, bug4274) + end + + def test_readlines_twice + bug5952 = '[ruby-dev:45160]' + assert_ruby_status(["-e", "2.times {STDIN.tty?; readlines}"], "", bug5952) + end + + def test_lines + ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + $stderr = $stdout + s = [] + ARGF.lines {|l| s << l } + p s + SRC + assert_match(/deprecated/, f.gets) + assert_equal("[\"1\\n\", \"2\\n\", \"3\\n\", \"4\\n\", \"5\\n\", \"6\\n\"]\n", f.read) + end + end + + def test_bytes + ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + $stderr = $stdout + print Marshal.dump(ARGF.bytes.to_a) + SRC + assert_match(/deprecated/, f.gets) + assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read)) + end + end + + def test_chars + ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + $stderr = $stdout + print [Marshal.dump(ARGF.chars.to_a)].pack('m') + SRC + assert_match(/deprecated/, f.gets) + assert_equal(["1", "\n", "2", "\n", "3", "\n", "4", "\n", "5", "\n", "6", "\n"], Marshal.load(f.read.unpack('m').first)) + end + end + + def test_codepoints + ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + $stderr = $stdout + print Marshal.dump(ARGF.codepoints.to_a) + SRC + assert_match(/deprecated/, f.gets) + assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read)) + end + end +end diff --git a/jni/ruby/test/ruby/test_arity.rb b/jni/ruby/test/ruby/test_arity.rb new file mode 100644 index 0000000..e026841 --- /dev/null +++ b/jni/ruby/test/ruby/test_arity.rb @@ -0,0 +1,69 @@ +require 'test/unit' + +class TestArity < Test::Unit::TestCase + def err_mess(method_proc = nil, argc = 0) + args = (1..argc).to_a + assert_raise_with_message(ArgumentError, /wrong number of arguments \((.*)\)/) do + case method_proc + when nil + yield + when Symbol + method(method_proc).call(*args) + else + method_proc.call(*args) + end + end + $1 + end + + def a + end + + def b(a, b, c, d=1, e=2, f, g, h, i, &block) + end + + def c(a, b, c, d=1, e=2, *rest) + end + + def d(a, b: 42) + end + + def e(a, b:42, **c) + end + + def f(a, b, c=1, *rest, d: 3) + end + + def test_method_err_mess + assert_equal "1 for 0", err_mess(:a, 1) + assert_equal "10 for 7..9", err_mess(:b, 10) + assert_equal "2 for 3+", err_mess(:c, 2) + assert_equal "2 for 1", err_mess(:d, 2) + assert_equal "0 for 1", err_mess(:d, 0) + assert_equal "2 for 1", err_mess(:e, 2) + assert_equal "0 for 1", err_mess(:e, 0) + assert_equal "1 for 2+", err_mess(:f, 1) + end + + def test_proc_err_mess + assert_equal "0 for 1..2", err_mess(->(b, c=42){}, 0) + assert_equal "1 for 2+", err_mess(->(a, b, c=42, *d){}, 1) + assert_equal "3 for 4+", err_mess(->(a, b, *c, d, e){}, 3) + assert_equal "3 for 1..2", err_mess(->(b, c=42){}, 3) + assert_equal "1 for 0", err_mess(->(&block){}, 1) + # Double checking: + p = Proc.new{|b, c=42| :ok} + assert_equal :ok, p.call(1, 2, 3) + assert_equal :ok, p.call + end + + def test_message_change_issue_6085 + assert_equal "3 for 1..2", err_mess{ SignalException.new(1, "", nil) } + assert_equal "1 for 0", err_mess{ Hash.new(1){} } + assert_equal "3 for 1..2", err_mess{ Module.send :define_method, 1, 2, 3 } + assert_equal "1 for 2", err_mess{ "".sub!(//) } + assert_equal "0 for 1..2", err_mess{ "".sub!{} } + assert_equal "0 for 1+", err_mess{ exec } + assert_equal "0 for 1+", err_mess{ Struct.new } + end +end diff --git a/jni/ruby/test/ruby/test_array.rb b/jni/ruby/test/ruby/test_array.rb new file mode 100644 index 0000000..8c8b63c --- /dev/null +++ b/jni/ruby/test/ruby/test_array.rb @@ -0,0 +1,2533 @@ +# coding: US-ASCII +require 'test/unit' + +class TestArray < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + @cls = Array + end + + def teardown + $VERBOSE = @verbose + end + + def test_percent_i + assert_equal([:foo, :bar], %i[foo bar]) + assert_equal([:"\"foo"], %i["foo]) + end + + def test_percent_I + x = 10 + assert_equal([:foo, :b10], %I[foo b#{x}]) + assert_equal([:"\"foo10"], %I["foo#{x}]) + end + + def test_0_literal + assert_equal([1, 2, 3, 4], [1, 2] + [3, 4]) + assert_equal([1, 2, 1, 2], [1, 2] * 2) + assert_equal("1:2", [1, 2] * ":") + + assert_equal([1, 2].hash, [1, 2].hash) + + assert_equal([2,3], [1,2,3] & [2,3,4]) + assert_equal([1,2,3,4], [1,2,3] | [2,3,4]) + assert_equal([1,2,3] - [2,3], [1]) + + x = [0, 1, 2, 3, 4, 5] + assert_equal(2, x[2]) + assert_equal([1, 2, 3], x[1..3]) + assert_equal([1, 2, 3], x[1,3]) + + x[0, 2] = 10 + assert_equal([10, 2, 3, 4, 5], x) + + x[0, 0] = -1 + assert_equal([-1, 10, 2, 3, 4, 5], x) + + x[-1, 1] = 20 + assert_equal(20, x[-1]) + assert_equal(20, x.pop) + end + + def test_array_andor_0 + assert_equal([2], ([1,2,3]&[2,4,6])) + assert_equal([1,2,3,4,6], ([1,2,3]|[2,4,6])) + end + + def test_compact_0 + a = [nil, 1, nil, nil, 5, nil, nil] + assert_equal [1, 5], a.compact + assert_equal [nil, 1, nil, nil, 5, nil, nil], a + a.compact! + assert_equal [1, 5], a + end + + def test_uniq_0 + x = [1, 1, 4, 2, 5, 4, 5, 1, 2] + x.uniq! + assert_equal([1, 4, 2, 5], x) + end + + def test_empty_0 + assert_equal true, [].empty? + assert_equal false, [1].empty? + assert_equal false, [1, 1, 4, 2, 5, 4, 5, 1, 2].empty? + end + + def test_sort_0 + x = ["it", "came", "to", "pass", "that", "..."] + x = x.sort.join(" ") + assert_equal("... came it pass that to", x) + x = [2,5,3,1,7] + x.sort!{|a,b| a<=>b} # sort with condition + assert_equal([1,2,3,5,7], x) + x.sort!{|a,b| b-a} # reverse sort + assert_equal([7,5,3,2,1], x) + end + + def test_split_0 + x = "The Book of Mormon" + assert_equal(x.reverse, x.split(//).reverse!.join) + assert_equal(x.reverse, x.reverse!) + assert_equal("g:n:i:r:t:s: :e:t:y:b: :1", "1 byte string".split(//).reverse.join(":")) + x = "a b c d" + assert_equal(['a', 'b', 'c', 'd'], x.split) + assert_equal(['a', 'b', 'c', 'd'], x.split(' ')) + end + + def test_misc_0 + assert(defined? "a".chomp, '"a".chomp is not defined') + assert_equal(["a", "b", "c"], "abc".scan(/./)) + assert_equal([["1a"], ["2b"], ["3c"]], "1a2b3c".scan(/(\d.)/)) + # non-greedy match + assert_equal([["a", "12"], ["b", "22"]], "a=12;b=22".scan(/(.*?)=(\d*);?/)) + + x = [1] + assert_equal('1:1:1:1:1', (x * 5).join(":")) + assert_equal('1', (x * 1).join(":")) + assert_equal('', (x * 0).join(":")) + + *x = *(1..7).to_a + assert_equal(7, x.size) + assert_equal([1, 2, 3, 4, 5, 6, 7], x) + + x = [1,2,3] + x[1,0] = x + assert_equal([1,1,2,3,2,3], x) + + x = [1,2,3] + x[-1,0] = x + assert_equal([1,2,1,2,3,3], x) + + x = [1,2,3] + x.concat(x) + assert_equal([1,2,3,1,2,3], x) + + x = [1,2,3] + x.clear + assert_equal([], x) + + x = [1,2,3] + y = x.dup + x << 4 + y << 5 + assert_equal([1,2,3,4], x) + assert_equal([1,2,3,5], y) + end + + def test_beg_end_0 + x = [1, 2, 3, 4, 5] + + assert_equal(1, x.first) + assert_equal([1], x.first(1)) + assert_equal([1, 2, 3], x.first(3)) + + assert_equal(5, x.last) + assert_equal([5], x.last(1)) + assert_equal([3, 4, 5], x.last(3)) + + assert_equal(1, x.shift) + assert_equal([2, 3, 4], x.shift(3)) + assert_equal([5], x) + + assert_equal([2, 3, 4, 5], x.unshift(2, 3, 4)) + assert_equal([1, 2, 3, 4, 5], x.unshift(1)) + assert_equal([1, 2, 3, 4, 5], x) + + assert_equal(5, x.pop) + assert_equal([3, 4], x.pop(2)) + assert_equal([1, 2], x) + + assert_equal([1, 2, 3, 4], x.push(3, 4)) + assert_equal([1, 2, 3, 4, 5], x.push(5)) + assert_equal([1, 2, 3, 4, 5], x) + end + + def test_find_all_0 + assert_respond_to([], :find_all) + assert_respond_to([], :select) # Alias + assert_equal([], [].find_all{ |obj| obj == "foo"}) + + x = ["foo", "bar", "baz", "baz", 1, 2, 3, 3, 4] + assert_equal(["baz","baz"], x.find_all{ |obj| obj == "baz" }) + assert_equal([3,3], x.find_all{ |obj| obj == 3 }) + end + + def test_fill_0 + assert_equal([-1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1)) + assert_equal([0, 1, 2, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3)) + assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3, 2)) + assert_equal([0, 1, 2, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3, 5)) + assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2, 2)) + assert_equal([0, 1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 2, 5)) + assert_equal([0, 1, 2, 3, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, -2, 1)) + assert_equal([0, 1, 2, 3, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, -2, 3)) + assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3..4)) + assert_equal([0, 1, 2, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3...4)) + assert_equal([0, 1, -1, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2..-2)) + assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2...-2)) + assert_equal([10, 11, 12, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill{|i| i+10}) + assert_equal([0, 1, 2, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill(3){|i| i+10}) + assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3, 2){|i| i+10}) + assert_equal([0, 1, 2, 13, 14, 15, 16, 17], [0, 1, 2, 3, 4, 5].fill(3, 5){|i| i+10}) + assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3..4){|i| i+10}) + assert_equal([0, 1, 2, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(3...4){|i| i+10}) + assert_equal([0, 1, 12, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(2..-2){|i| i+10}) + assert_equal([0, 1, 12, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(2...-2){|i| i+10}) + end + + # From rubicon + + def test_00_new + a = @cls.new() + assert_instance_of(@cls, a) + assert_equal(0, a.length) + assert_nil(a[0]) + end + + def test_01_square_brackets + a = @cls[ 5, 4, 3, 2, 1 ] + assert_instance_of(@cls, a) + assert_equal(5, a.length) + 5.times { |i| assert_equal(5-i, a[i]) } + assert_nil(a[6]) + end + + def test_AND # '&' + assert_equal(@cls[1, 3], @cls[ 1, 1, 3, 5 ] & @cls[ 1, 2, 3 ]) + assert_equal(@cls[], @cls[ 1, 1, 3, 5 ] & @cls[ ]) + assert_equal(@cls[], @cls[ ] & @cls[ 1, 2, 3 ]) + assert_equal(@cls[], @cls[ 1, 2, 3 ] & @cls[ 4, 5, 6 ]) + end + + def test_MUL # '*' + assert_equal(@cls[], @cls[]*3) + assert_equal(@cls[1, 1, 1], @cls[1]*3) + assert_equal(@cls[1, 2, 1, 2, 1, 2], @cls[1, 2]*3) + assert_equal(@cls[], @cls[1, 2, 3] * 0) + assert_raise(ArgumentError) { @cls[1, 2]*(-3) } + + assert_equal('1-2-3-4-5', @cls[1, 2, 3, 4, 5] * '-') + assert_equal('12345', @cls[1, 2, 3, 4, 5] * '') + + end + + def test_PLUS # '+' + assert_equal(@cls[], @cls[] + @cls[]) + assert_equal(@cls[1], @cls[1] + @cls[]) + assert_equal(@cls[1], @cls[] + @cls[1]) + assert_equal(@cls[1, 1], @cls[1] + @cls[1]) + assert_equal(@cls['cat', 'dog', 1, 2, 3], %w(cat dog) + (1..3).to_a) + end + + def test_MINUS # '-' + assert_equal(@cls[], @cls[1] - @cls[1]) + assert_equal(@cls[1], @cls[1, 2, 3, 4, 5] - @cls[2, 3, 4, 5]) + # Ruby 1.8 feature change + #assert_equal(@cls[1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5]) + assert_equal(@cls[1, 1, 1, 1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5]) + a = @cls[] + 1000.times { a << 1 } + assert_equal(1000, a.length) + #assert_equal(@cls[1], a - @cls[2]) + assert_equal(@cls[1] * 1000, a - @cls[2]) + #assert_equal(@cls[1], @cls[1, 2, 1] - @cls[2]) + assert_equal(@cls[1, 1], @cls[1, 2, 1] - @cls[2]) + assert_equal(@cls[1, 2, 3], @cls[1, 2, 3] - @cls[4, 5, 6]) + end + + def test_LSHIFT # '<<' + a = @cls[] + a << 1 + assert_equal(@cls[1], a) + a << 2 << 3 + assert_equal(@cls[1, 2, 3], a) + a << nil << 'cat' + assert_equal(@cls[1, 2, 3, nil, 'cat'], a) + a << a + assert_equal(@cls[1, 2, 3, nil, 'cat', a], a) + end + + def test_CMP # '<=>' + assert_equal(0, @cls[] <=> @cls[]) + assert_equal(0, @cls[1] <=> @cls[1]) + assert_equal(0, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'cat']) + assert_equal(-1, @cls[] <=> @cls[1]) + assert_equal(1, @cls[1] <=> @cls[]) + assert_equal(-1, @cls[1, 2, 3] <=> @cls[1, 2, 3, 'cat']) + assert_equal(1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3]) + assert_equal(-1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'dog']) + assert_equal(1, @cls[1, 2, 3, 'dog'] <=> @cls[1, 2, 3, 'cat']) + end + + def test_EQUAL # '==' + assert_operator(@cls[], :==, @cls[]) + assert_operator(@cls[1], :==, @cls[1]) + assert_operator(@cls[1, 1, 2, 2], :==, @cls[1, 1, 2, 2]) + assert_operator(@cls[1.0, 1.0, 2.0, 2.0], :==, @cls[1, 1, 2, 2]) + end + + def test_VERY_EQUAL # '===' + assert_operator(@cls[], :===, @cls[]) + assert_operator(@cls[1], :===, @cls[1]) + assert_operator(@cls[1, 1, 2, 2], :===, @cls[1, 1, 2, 2]) + assert_operator(@cls[1.0, 1.0, 2.0, 2.0], :===, @cls[1, 1, 2, 2]) + end + + def test_AREF # '[]' + a = @cls[*(1..100).to_a] + + assert_equal(1, a[0]) + assert_equal(100, a[99]) + assert_nil(a[100]) + assert_equal(100, a[-1]) + assert_equal(99, a[-2]) + assert_equal(1, a[-100]) + assert_nil(a[-101]) + assert_nil(a[-101,0]) + assert_nil(a[-101,1]) + assert_nil(a[-101,-1]) + assert_nil(a[10,-1]) + + assert_equal(@cls[1], a[0,1]) + assert_equal(@cls[100], a[99,1]) + assert_equal(@cls[], a[100,1]) + assert_equal(@cls[100], a[99,100]) + assert_equal(@cls[100], a[-1,1]) + assert_equal(@cls[99], a[-2,1]) + assert_equal(@cls[], a[-100,0]) + assert_equal(@cls[1], a[-100,1]) + + assert_equal(@cls[10, 11, 12], a[9, 3]) + assert_equal(@cls[10, 11, 12], a[-91, 3]) + + assert_equal(@cls[1], a[0..0]) + assert_equal(@cls[100], a[99..99]) + assert_equal(@cls[], a[100..100]) + assert_equal(@cls[100], a[99..200]) + assert_equal(@cls[100], a[-1..-1]) + assert_equal(@cls[99], a[-2..-2]) + + assert_equal(@cls[10, 11, 12], a[9..11]) + assert_equal(@cls[10, 11, 12], a[-91..-89]) + + assert_nil(a[10, -3]) + # Ruby 1.8 feature change: + # Array#[size..x] returns [] instead of nil. + #assert_nil(a[10..7]) + assert_equal [], a[10..7] + + assert_raise(TypeError) {a['cat']} + end + + def test_ASET # '[]=' + a = @cls[*(0..99).to_a] + assert_equal(0, a[0] = 0) + assert_equal(@cls[0] + @cls[*(1..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(0, a[10,10] = 0) + assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(0, a[-1] = 0) + assert_equal(@cls[*(0..98).to_a] + @cls[0], a) + + a = @cls[*(0..99).to_a] + assert_equal(0, a[-10, 10] = 0) + assert_equal(@cls[*(0..89).to_a] + @cls[0], a) + + a = @cls[*(0..99).to_a] + assert_equal(0, a[0,1000] = 0) + assert_equal(@cls[0] , a) + + a = @cls[*(0..99).to_a] + assert_equal(0, a[10..19] = 0) + assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) + + b = @cls[*%w( a b c )] + a = @cls[*(0..99).to_a] + assert_equal(b, a[0,1] = b) + assert_equal(b + @cls[*(1..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(b, a[10,10] = b) + assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(b, a[-1, 1] = b) + assert_equal(@cls[*(0..98).to_a] + b, a) + + a = @cls[*(0..99).to_a] + assert_equal(b, a[-10, 10] = b) + assert_equal(@cls[*(0..89).to_a] + b, a) + + a = @cls[*(0..99).to_a] + assert_equal(b, a[0,1000] = b) + assert_equal(b , a) + + a = @cls[*(0..99).to_a] + assert_equal(b, a[10..19] = b) + assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) + + # Ruby 1.8 feature change: + # assigning nil does not remove elements. +=begin + a = @cls[*(0..99).to_a] + assert_equal(nil, a[0,1] = nil) + assert_equal(@cls[*(1..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(nil, a[10,10] = nil) + assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(nil, a[-1, 1] = nil) + assert_equal(@cls[*(0..98).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(nil, a[-10, 10] = nil) + assert_equal(@cls[*(0..89).to_a], a) + + a = @cls[*(0..99).to_a] + assert_equal(nil, a[0,1000] = nil) + assert_equal(@cls[] , a) + + a = @cls[*(0..99).to_a] + assert_equal(nil, a[10..19] = nil) + assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) +=end + + a = @cls[1, 2, 3] + a[1, 0] = a + assert_equal([1, 1, 2, 3, 2, 3], a) + + a = @cls[1, 2, 3] + a[-1, 0] = a + assert_equal([1, 2, 1, 2, 3, 3], a) + + a = @cls[] + a[5,0] = [5] + assert_equal([nil, nil, nil, nil, nil, 5], a) + + a = @cls[1] + a[1,0] = [2] + assert_equal([1, 2], a) + + a = @cls[1] + a[1,1] = [2] + assert_equal([1, 2], a) + end + + def test_assoc + a1 = @cls[*%w( cat feline )] + a2 = @cls[*%w( dog canine )] + a3 = @cls[*%w( mule asinine )] + + a = @cls[ a1, a2, a3 ] + + assert_equal(a1, a.assoc('cat')) + assert_equal(a3, a.assoc('mule')) + assert_equal(nil, a.assoc('asinine')) + assert_equal(nil, a.assoc('wombat')) + assert_equal(nil, a.assoc(1..2)) + end + + def test_at + a = @cls[*(0..99).to_a] + assert_equal(0, a.at(0)) + assert_equal(10, a.at(10)) + assert_equal(99, a.at(99)) + assert_equal(nil, a.at(100)) + assert_equal(99, a.at(-1)) + assert_equal(0, a.at(-100)) + assert_equal(nil, a.at(-101)) + assert_raise(TypeError) { a.at('cat') } + end + + def test_clear + a = @cls[1, 2, 3] + b = a.clear + assert_equal(@cls[], a) + assert_equal(@cls[], b) + assert_equal(a.__id__, b.__id__) + end + + def test_clone + for taint in [ false, true ] + for frozen in [ false, true ] + a = @cls[*(0..99).to_a] + a.taint if taint + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert_not_equal(a.__id__, b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + end + + def test_collect + a = @cls[ 1, 'cat', 1..1 ] + assert_equal([ Fixnum, String, Range], a.collect {|e| e.class} ) + assert_equal([ 99, 99, 99], a.collect { 99 } ) + + assert_equal([], @cls[].collect { 99 }) + + # Ruby 1.9 feature change: + # Enumerable#collect without block returns an Enumerator. + #assert_equal([1, 2, 3], @cls[1, 2, 3].collect) + assert_kind_of Enumerator, @cls[1, 2, 3].collect + end + + # also update map! + def test_collect! + a = @cls[ 1, 'cat', 1..1 ] + assert_equal([ Fixnum, String, Range], a.collect! {|e| e.class} ) + assert_equal([ Fixnum, String, Range], a) + + a = @cls[ 1, 'cat', 1..1 ] + assert_equal([ 99, 99, 99], a.collect! { 99 } ) + assert_equal([ 99, 99, 99], a) + + a = @cls[ ] + assert_equal([], a.collect! { 99 }) + assert_equal([], a) + end + + def test_compact + a = @cls[ 1, nil, nil, 2, 3, nil, 4 ] + assert_equal(@cls[1, 2, 3, 4], a.compact) + + a = @cls[ nil, 1, nil, 2, 3, nil, 4 ] + assert_equal(@cls[1, 2, 3, 4], a.compact) + + a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ] + assert_equal(@cls[1, 2, 3, 4], a.compact) + + a = @cls[ 1, 2, 3, 4 ] + assert_equal(@cls[1, 2, 3, 4], a.compact) + end + + def test_compact! + a = @cls[ 1, nil, nil, 2, 3, nil, 4 ] + assert_equal(@cls[1, 2, 3, 4], a.compact!) + assert_equal(@cls[1, 2, 3, 4], a) + + a = @cls[ nil, 1, nil, 2, 3, nil, 4 ] + assert_equal(@cls[1, 2, 3, 4], a.compact!) + assert_equal(@cls[1, 2, 3, 4], a) + + a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ] + assert_equal(@cls[1, 2, 3, 4], a.compact!) + assert_equal(@cls[1, 2, 3, 4], a) + + a = @cls[ 1, 2, 3, 4 ] + assert_equal(nil, a.compact!) + assert_equal(@cls[1, 2, 3, 4], a) + end + + def test_concat + assert_equal(@cls[1, 2, 3, 4], @cls[1, 2].concat(@cls[3, 4])) + assert_equal(@cls[1, 2, 3, 4], @cls[].concat(@cls[1, 2, 3, 4])) + assert_equal(@cls[1, 2, 3, 4], @cls[1, 2, 3, 4].concat(@cls[])) + assert_equal(@cls[], @cls[].concat(@cls[])) + assert_equal(@cls[@cls[1, 2], @cls[3, 4]], @cls[@cls[1, 2]].concat(@cls[@cls[3, 4]])) + + a = @cls[1, 2, 3] + a.concat(a) + assert_equal([1, 2, 3, 1, 2, 3], a) + + assert_raise(TypeError) { [0].concat(:foo) } + assert_raise(RuntimeError) { [0].freeze.concat(:foo) } + end + + def test_count + a = @cls[1, 2, 3, 1, 2] + assert_equal(5, a.count) + assert_equal(2, a.count(1)) + assert_equal(3, a.count {|x| x % 2 == 1 }) + assert_equal(2, a.count(1) {|x| x % 2 == 1 }) + assert_raise(ArgumentError) { a.count(0, 1) } + + bug8654 = '[ruby-core:56072]' + assert_in_out_err [], <<-EOS, ["0"], [], bug8654 + a1 = [] + a2 = Array.new(100) { |i| i } + a2.count do |i| + p i + a2.replace(a1) if i == 0 + end + EOS + + assert_in_out_err [], <<-EOS, ["[]", "0"], [], bug8654 + ARY = Array.new(100) { |i| i } + class Fixnum + alias old_equal == + def == other + ARY.replace([]) if self.equal?(0) + p ARY + self.equal?(other) + end + end + p ARY.count(42) + EOS + end + + def test_delete + a = @cls[*('cab'..'cat').to_a] + assert_equal('cap', a.delete('cap')) + assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal('cab', a.delete('cab')) + assert_equal(@cls[*('cac'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal('cat', a.delete('cat')) + assert_equal(@cls[*('cab'..'cas').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(nil, a.delete('cup')) + assert_equal(@cls[*('cab'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(99, a.delete('cup') { 99 } ) + assert_equal(@cls[*('cab'..'cat').to_a], a) + + o = Object.new + def o.==(other); true; end + o2 = Object.new + def o2.==(other); true; end + a = @cls[1, o, o2, 2] + assert_equal(o2, a.delete(42)) + assert_equal([1, 2], a) + end + + def test_delete_at + a = @cls[*(1..5).to_a] + assert_equal(3, a.delete_at(2)) + assert_equal(@cls[1, 2, 4, 5], a) + + a = @cls[*(1..5).to_a] + assert_equal(4, a.delete_at(-2)) + assert_equal(@cls[1, 2, 3, 5], a) + + a = @cls[*(1..5).to_a] + assert_equal(nil, a.delete_at(5)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[*(1..5).to_a] + assert_equal(nil, a.delete_at(-6)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + end + + # also reject! + def test_delete_if + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.delete_if { false }) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.delete_if { true }) + assert_equal(@cls[], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.delete_if { |i| i > 3 }) + assert_equal(@cls[1, 2, 3], a) + + bug2545 = '[ruby-core:27366]' + a = @cls[ 5, 6, 7, 8, 9, 10 ] + assert_equal(9, a.delete_if {|i| break i if i > 8; assert_equal(a[0], i) || true if i < 7}) + assert_equal(@cls[7, 8, 9, 10], a, bug2545) + end + + def test_dup + for taint in [ false, true ] + for frozen in [ false, true ] + a = @cls[*(0..99).to_a] + a.taint if taint + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert_not_equal(a.__id__, b.__id__) + assert_equal(false, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + end + + def test_each + a = @cls[*%w( ant bat cat dog )] + i = 0 + a.each { |e| + assert_equal(a[i], e) + i += 1 + } + assert_equal(4, i) + + a = @cls[] + i = 0 + a.each { |e| + assert_equal(a[i], e) + i += 1 + } + assert_equal(0, i) + + assert_equal(a, a.each {}) + end + + def test_each_index + a = @cls[*%w( ant bat cat dog )] + i = 0 + a.each_index { |ind| + assert_equal(i, ind) + i += 1 + } + assert_equal(4, i) + + a = @cls[] + i = 0 + a.each_index { |ind| + assert_equal(i, ind) + i += 1 + } + assert_equal(0, i) + + assert_equal(a, a.each_index {}) + end + + def test_empty? + assert_empty(@cls[]) + assert_not_empty(@cls[1]) + end + + def test_eql? + assert_send([@cls[], :eql?, @cls[]]) + assert_send([@cls[1], :eql?, @cls[1]]) + assert_send([@cls[1, 1, 2, 2], :eql?, @cls[1, 1, 2, 2]]) + assert_not_send([@cls[1.0, 1.0, 2.0, 2.0], :eql?, @cls[1, 1, 2, 2]]) + end + + def test_fill + assert_equal(@cls[], @cls[].fill(99)) + assert_equal(@cls[], @cls[].fill(99, 0)) + assert_equal(@cls[99], @cls[].fill(99, 0, 1)) + assert_equal(@cls[99], @cls[].fill(99, 0..0)) + + assert_equal(@cls[99], @cls[1].fill(99)) + assert_equal(@cls[99], @cls[1].fill(99, 0)) + assert_equal(@cls[99], @cls[1].fill(99, 0, 1)) + assert_equal(@cls[99], @cls[1].fill(99, 0..0)) + + assert_equal(@cls[99, 99], @cls[1, 2].fill(99)) + assert_equal(@cls[99, 99], @cls[1, 2].fill(99, 0)) + assert_equal(@cls[99, 99], @cls[1, 2].fill(99, nil)) + assert_equal(@cls[1, 99], @cls[1, 2].fill(99, 1, nil)) + assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0, 1)) + assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0..0)) + end + + def test_first + assert_equal(3, @cls[3, 4, 5].first) + assert_equal(nil, @cls[].first) + end + + def test_flatten + a1 = @cls[ 1, 2, 3] + a2 = @cls[ 5, 6 ] + a3 = @cls[ 4, a2 ] + a4 = @cls[ a1, a3 ] + assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten) + assert_equal(@cls[ a1, a3], a4) + + a5 = @cls[ a1, @cls[], a3 ] + assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten) + assert_equal(@cls[], @cls[].flatten) + assert_equal(@cls[], + @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten) + + assert_raise(TypeError, "[ruby-dev:31197]") { [[]].flatten("") } + + a6 = @cls[[1, 2], 3] + a6.taint + a7 = a6.flatten + assert_equal(true, a7.tainted?) + + a8 = @cls[[1, 2], 3] + a9 = a8.flatten(0) + assert_equal(a8, a9) + assert_not_same(a8, a9) + end + + def test_flatten! + a1 = @cls[ 1, 2, 3] + a2 = @cls[ 5, 6 ] + a3 = @cls[ 4, a2 ] + a4 = @cls[ a1, a3 ] + assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten!) + assert_equal(@cls[1, 2, 3, 4, 5, 6], a4) + + a5 = @cls[ a1, @cls[], a3 ] + assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten!) + assert_nil(a5.flatten!(0), '[ruby-core:23382]') + assert_equal(@cls[1, 2, 3, 4, 5, 6], a5) + + assert_nil(@cls[].flatten!) + assert_equal(@cls[], + @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten!) + + assert_nil(@cls[].flatten!(0), '[ruby-core:23382]') + end + + def test_flatten_with_callcc + need_continuation + o = Object.new + def o.to_ary() callcc {|k| @cont = k; [1,2,3]} end + begin + assert_equal([10, 20, 1, 2, 3, 30, 1, 2, 3, 40], [10, 20, o, 30, o, 40].flatten) + rescue => e + else + o.instance_eval {@cont}.call + end + assert_instance_of(RuntimeError, e, '[ruby-dev:34798]') + assert_match(/reentered/, e.message, '[ruby-dev:34798]') + end + + def test_permutation_with_callcc + need_continuation + n = 1000 + cont = nil + ary = [1,2,3] + begin + ary.permutation { + callcc {|k| cont = k} unless cont + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e) + assert_match(/reentered/, e.message) + end + + def test_product_with_callcc + need_continuation + n = 1000 + cont = nil + ary = [1,2,3] + begin + ary.product { + callcc {|k| cont = k} unless cont + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e) + assert_match(/reentered/, e.message) + end + + def test_combination_with_callcc + need_continuation + n = 1000 + cont = nil + ary = [1,2,3] + begin + ary.combination(2) { + callcc {|k| cont = k} unless cont + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e) + assert_match(/reentered/, e.message) + end + + def test_repeated_permutation_with_callcc + need_continuation + n = 1000 + cont = nil + ary = [1,2,3] + begin + ary.repeated_permutation(2) { + callcc {|k| cont = k} unless cont + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e) + assert_match(/reentered/, e.message) + end + + def test_repeated_combination_with_callcc + need_continuation + n = 1000 + cont = nil + ary = [1,2,3] + begin + ary.repeated_combination(2) { + callcc {|k| cont = k} unless cont + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e) + assert_match(/reentered/, e.message) + end + + def test_hash + a1 = @cls[ 'cat', 'dog' ] + a2 = @cls[ 'cat', 'dog' ] + a3 = @cls[ 'dog', 'cat' ] + assert_equal(a1.hash, a2.hash) + assert_not_equal(a1.hash, a3.hash) + bug9231 = '[ruby-core:58993] [Bug #9231]' + assert_not_equal(false.hash, @cls[].hash, bug9231) + end + + def test_include? + a = @cls[ 'cat', 99, /a/, @cls[ 1, 2, 3] ] + assert_include(a, 'cat') + assert_include(a, 99) + assert_include(a, /a/) + assert_include(a, [1,2,3]) + assert_not_include(a, 'ca') + assert_not_include(a, [1,2]) + end + + def test_index + a = @cls[ 'cat', 99, /a/, 99, @cls[ 1, 2, 3] ] + assert_equal(0, a.index('cat')) + assert_equal(1, a.index(99)) + assert_equal(4, a.index([1,2,3])) + assert_nil(a.index('ca')) + assert_nil(a.index([1,2])) + + assert_equal(1, a.index(99) {|x| x == 'cat' }) + end + + def test_values_at + a = @cls[*('a'..'j').to_a] + assert_equal(@cls['a', 'c', 'e'], a.values_at(0, 2, 4)) + assert_equal(@cls['j', 'h', 'f'], a.values_at(-1, -3, -5)) + assert_equal(@cls['h', nil, 'a'], a.values_at(-3, 99, 0)) + end + + def test_join + $, = "" + a = @cls[] + assert_equal("", a.join) + assert_equal("", a.join(',')) + assert_equal(Encoding::US_ASCII, a.join.encoding) + + $, = "" + a = @cls[1, 2] + assert_equal("12", a.join) + assert_equal("12", a.join(nil)) + assert_equal("1,2", a.join(',')) + + $, = "" + a = @cls[1, 2, 3] + assert_equal("123", a.join) + assert_equal("123", a.join(nil)) + assert_equal("1,2,3", a.join(',')) + + $, = ":" + a = @cls[1, 2, 3] + assert_equal("1:2:3", a.join) + assert_equal("1:2:3", a.join(nil)) + assert_equal("1,2,3", a.join(',')) + + $, = "" + a = @cls[1, 2, 3] + a.taint + s = a.join + assert_equal(true, s.tainted?) + + bug5902 = '[ruby-core:42161]' + sep = ":".taint + + s = @cls[].join(sep) + assert_equal(false, s.tainted?, bug5902) + s = @cls[1].join(sep) + assert_equal(false, s.tainted?, bug5902) + s = @cls[1, 2].join(sep) + assert_equal(true, s.tainted?, bug5902) + + e = ''.force_encoding('EUC-JP') + u = ''.force_encoding('UTF-8') + assert_equal(Encoding::US_ASCII, [[]].join.encoding) + assert_equal(Encoding::US_ASCII, [1, [u]].join.encoding) + assert_equal(Encoding::UTF_8, [u, [e]].join.encoding) + assert_equal(Encoding::UTF_8, [u, [1]].join.encoding) + bug5379 = '[ruby-core:39776]' + assert_equal(Encoding::US_ASCII, [[], u, nil].join.encoding, bug5379) + assert_equal(Encoding::UTF_8, [[], "\u3042", nil].join.encoding, bug5379) + ensure + $, = nil + end + + def test_last + assert_equal(nil, @cls[].last) + assert_equal(1, @cls[1].last) + assert_equal(99, @cls[*(3..99).to_a].last) + end + + def test_length + assert_equal(0, @cls[].length) + assert_equal(1, @cls[1].length) + assert_equal(2, @cls[1, nil].length) + assert_equal(2, @cls[nil, 1].length) + assert_equal(234, @cls[*(0..233).to_a].length) + end + + # also update collect! + def test_map! + a = @cls[ 1, 'cat', 1..1 ] + assert_equal(@cls[ Fixnum, String, Range], a.map! {|e| e.class} ) + assert_equal(@cls[ Fixnum, String, Range], a) + + a = @cls[ 1, 'cat', 1..1 ] + assert_equal(@cls[ 99, 99, 99], a.map! { 99 } ) + assert_equal(@cls[ 99, 99, 99], a) + + a = @cls[ ] + assert_equal(@cls[], a.map! { 99 }) + assert_equal(@cls[], a) + end + + def test_pack + a = @cls[*%w( cat wombat x yy)] + assert_equal("catwomx yy ", a.pack("A3A3A3A3")) + assert_equal("cat", a.pack("A*")) + assert_equal("cwx yy ", a.pack("A3@1A3@2A3A3")) + assert_equal("catwomx\000\000yy\000", a.pack("a3a3a3a3")) + assert_equal("cat", a.pack("a*")) + assert_equal("ca", a.pack("a2")) + assert_equal("cat\000\000", a.pack("a5")) + + assert_equal("\x61", @cls["01100001"].pack("B8")) + assert_equal("\x61", @cls["01100001"].pack("B*")) + assert_equal("\x61", @cls["0110000100110111"].pack("B8")) + assert_equal("\x61\x37", @cls["0110000100110111"].pack("B16")) + assert_equal("\x61\x37", @cls["01100001", "00110111"].pack("B8B8")) + assert_equal("\x60", @cls["01100001"].pack("B4")) + assert_equal("\x40", @cls["01100001"].pack("B2")) + + assert_equal("\x86", @cls["01100001"].pack("b8")) + assert_equal("\x86", @cls["01100001"].pack("b*")) + assert_equal("\x86", @cls["0110000100110111"].pack("b8")) + assert_equal("\x86\xec", @cls["0110000100110111"].pack("b16")) + assert_equal("\x86\xec", @cls["01100001", "00110111"].pack("b8b8")) + assert_equal("\x06", @cls["01100001"].pack("b4")) + assert_equal("\x02", @cls["01100001"].pack("b2")) + + assert_equal("ABC", @cls[ 65, 66, 67 ].pack("C3")) + assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("C*")) + assert_equal("ABC", @cls[ 65, 66, 67 ].pack("c3")) + assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("c*")) + + + assert_equal("AB\n\x10", @cls["4142", "0a", "12"].pack("H4H2H1")) + assert_equal("AB\n\x02", @cls["1424", "a0", "21"].pack("h4h2h1")) + + assert_equal("abc=02def=\ncat=\n=01=\n", + @cls["abc\002def", "cat", "\001"].pack("M9M3M4")) + + assert_equal("aGVsbG8K\n", @cls["hello\n"].pack("m")) + assert_equal(",:&5L;&\\*:&5L;&\\*\n", @cls["hello\nhello\n"].pack("u")) + + assert_equal("\u{a9 42 2260}", @cls[0xa9, 0x42, 0x2260].pack("U*")) + + + format = "c2x5CCxsdils_l_a6"; + # Need the expression in here to force ary[5] to be numeric. This avoids + # test2 failing because ary2 goes str->numeric->str and ary does not. + ary = [1, -100, 127, 128, 32767, 987.654321098/100.0, + 12345, 123456, -32767, -123456, "abcdef"] + x = ary.pack(format) + ary2 = x.unpack(format) + + assert_equal(ary.length, ary2.length) + assert_equal(ary.join(':'), ary2.join(':')) + assert_not_nil(x =~ /def/) + +=begin + skipping "Not tested: + D,d & double-precision float, native format\\ + E & double-precision float, little-endian byte order\\ + e & single-precision float, little-endian byte order\\ + F,f & single-precision float, native format\\ + G & double-precision float, network (big-endian) byte order\\ + g & single-precision float, network (big-endian) byte order\\ + I & unsigned integer\\ + i & integer\\ + L & unsigned long\\ + l & long\\ + + N & long, network (big-endian) byte order\\ + n & short, network (big-endian) byte-order\\ + P & pointer to a structure (fixed-length string)\\ + p & pointer to a null-terminated string\\ + S & unsigned short\\ + s & short\\ + V & long, little-endian byte order\\ + v & short, little-endian byte order\\ + X & back up a byte\\ + x & null byte\\ + Z & ASCII string (null padded, count is width)\\ +" +=end + end + + def test_pop + a = @cls[ 'cat', 'dog' ] + assert_equal('dog', a.pop) + assert_equal(@cls['cat'], a) + assert_equal('cat', a.pop) + assert_equal(@cls[], a) + assert_nil(a.pop) + assert_equal(@cls[], a) + end + + def test_push + a = @cls[1, 2, 3] + assert_equal(@cls[1, 2, 3, 4, 5], a.push(4, 5)) + assert_equal(@cls[1, 2, 3, 4, 5, nil], a.push(nil)) + # Ruby 1.8 feature: + # Array#push accepts any number of arguments. + #assert_raise(ArgumentError, "a.push()") { a.push() } + a.push + assert_equal @cls[1, 2, 3, 4, 5, nil], a + a.push 6, 7 + assert_equal @cls[1, 2, 3, 4, 5, nil, 6, 7], a + end + + def test_rassoc + a1 = @cls[*%w( cat feline )] + a2 = @cls[*%w( dog canine )] + a3 = @cls[*%w( mule asinine )] + a = @cls[ a1, a2, a3 ] + + assert_equal(a1, a.rassoc('feline')) + assert_equal(a3, a.rassoc('asinine')) + assert_equal(nil, a.rassoc('dog')) + assert_equal(nil, a.rassoc('mule')) + assert_equal(nil, a.rassoc(1..2)) + end + + # also delete_if + def test_reject! + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(nil, a.reject! { false }) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.reject! { true }) + assert_equal(@cls[], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.reject! { |i| i > 3 }) + assert_equal(@cls[1, 2, 3], a) + + bug2545 = '[ruby-core:27366]' + a = @cls[ 5, 6, 7, 8, 9, 10 ] + assert_equal(9, a.reject! {|i| break i if i > 8; assert_equal(a[0], i) || true if i < 7}) + assert_equal(@cls[7, 8, 9, 10], a, bug2545) + end + + def test_replace + a = @cls[ 1, 2, 3] + a_id = a.__id__ + assert_equal(@cls[4, 5, 6], a.replace(@cls[4, 5, 6])) + assert_equal(@cls[4, 5, 6], a) + assert_equal(a_id, a.__id__) + assert_equal(@cls[], a.replace(@cls[])) + + fa = a.dup.freeze + assert_nothing_raised(RuntimeError) { a.replace(a) } + assert_raise(RuntimeError) { fa.replace(fa) } + assert_raise(ArgumentError) { fa.replace() } + assert_raise(TypeError) { a.replace(42) } + assert_raise(RuntimeError) { fa.replace(42) } + end + + def test_reverse + a = @cls[*%w( dog cat bee ant )] + assert_equal(@cls[*%w(ant bee cat dog)], a.reverse) + assert_equal(@cls[*%w(dog cat bee ant)], a) + assert_equal(@cls[], @cls[].reverse) + end + + def test_reverse! + a = @cls[*%w( dog cat bee ant )] + assert_equal(@cls[*%w(ant bee cat dog)], a.reverse!) + assert_equal(@cls[*%w(ant bee cat dog)], a) + # Ruby 1.8 feature change: + # Array#reverse always returns self. + #assert_nil(@cls[].reverse!) + assert_equal @cls[], @cls[].reverse! + end + + def test_reverse_each + a = @cls[*%w( dog cat bee ant )] + i = a.length + a.reverse_each { |e| + i -= 1 + assert_equal(a[i], e) + } + assert_equal(0, i) + + a = @cls[] + i = 0 + a.reverse_each { |e| + i += 1 + assert(false, "Never get here") + } + assert_equal(0, i) + end + + def test_rindex + a = @cls[ 'cat', 99, /a/, 99, [ 1, 2, 3] ] + assert_equal(0, a.rindex('cat')) + assert_equal(3, a.rindex(99)) + assert_equal(4, a.rindex([1,2,3])) + assert_nil(a.rindex('ca')) + assert_nil(a.rindex([1,2])) + + assert_equal(3, a.rindex(99) {|x| x == [1,2,3] }) + end + + def test_shift + a = @cls[ 'cat', 'dog' ] + assert_equal('cat', a.shift) + assert_equal(@cls['dog'], a) + assert_equal('dog', a.shift) + assert_equal(@cls[], a) + assert_nil(a.shift) + assert_equal(@cls[], a) + end + + def test_size + assert_equal(0, @cls[].size) + assert_equal(1, @cls[1].size) + assert_equal(100, @cls[*(0..99).to_a].size) + end + + def test_slice + a = @cls[*(1..100).to_a] + + assert_equal(1, a.slice(0)) + assert_equal(100, a.slice(99)) + assert_nil(a.slice(100)) + assert_equal(100, a.slice(-1)) + assert_equal(99, a.slice(-2)) + assert_equal(1, a.slice(-100)) + assert_nil(a.slice(-101)) + + assert_equal(@cls[1], a.slice(0,1)) + assert_equal(@cls[100], a.slice(99,1)) + assert_equal(@cls[], a.slice(100,1)) + assert_equal(@cls[100], a.slice(99,100)) + assert_equal(@cls[100], a.slice(-1,1)) + assert_equal(@cls[99], a.slice(-2,1)) + + assert_equal(@cls[10, 11, 12], a.slice(9, 3)) + assert_equal(@cls[10, 11, 12], a.slice(-91, 3)) + + assert_nil(a.slice(-101, 2)) + + assert_equal(@cls[1], a.slice(0..0)) + assert_equal(@cls[100], a.slice(99..99)) + assert_equal(@cls[], a.slice(100..100)) + assert_equal(@cls[100], a.slice(99..200)) + assert_equal(@cls[100], a.slice(-1..-1)) + assert_equal(@cls[99], a.slice(-2..-2)) + + assert_equal(@cls[10, 11, 12], a.slice(9..11)) + assert_equal(@cls[10, 11, 12], a.slice(-91..-89)) + + assert_nil(a.slice(-101..-1)) + + assert_nil(a.slice(10, -3)) + # Ruby 1.8 feature change: + # Array#slice[size..x] always returns []. + #assert_nil(a.slice(10..7)) + assert_equal @cls[], a.slice(10..7) + end + + def test_slice! + a = @cls[1, 2, 3, 4, 5] + assert_equal(3, a.slice!(2)) + assert_equal(@cls[1, 2, 4, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(4, a.slice!(-2)) + assert_equal(@cls[1, 2, 3, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(@cls[3,4], a.slice!(2,2)) + assert_equal(@cls[1, 2, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(@cls[4,5], a.slice!(-2,2)) + assert_equal(@cls[1, 2, 3], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(@cls[3,4], a.slice!(2..3)) + assert_equal(@cls[1, 2, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(nil, a.slice!(20)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(nil, a.slice!(-6)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(nil, a.slice!(-6..4)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[1, 2, 3, 4, 5] + assert_equal(nil, a.slice!(-6,2)) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + assert_raise(ArgumentError) { @cls[1].slice! } + assert_raise(ArgumentError) { @cls[1].slice!(0, 0, 0) } + end + + def test_sort + a = @cls[ 4, 1, 2, 3 ] + assert_equal(@cls[1, 2, 3, 4], a.sort) + assert_equal(@cls[4, 1, 2, 3], a) + + assert_equal(@cls[4, 3, 2, 1], a.sort { |x, y| y <=> x} ) + assert_equal(@cls[4, 1, 2, 3], a) + + assert_equal(@cls[1, 2, 3, 4], a.sort { |x, y| (x - y) * (2**100) }) + + a.fill(1) + assert_equal(@cls[1, 1, 1, 1], a.sort) + + assert_equal(@cls[], @cls[].sort) + end + + def test_sort! + a = @cls[ 4, 1, 2, 3 ] + assert_equal(@cls[1, 2, 3, 4], a.sort!) + assert_equal(@cls[1, 2, 3, 4], a) + + assert_equal(@cls[4, 3, 2, 1], a.sort! { |x, y| y <=> x} ) + assert_equal(@cls[4, 3, 2, 1], a) + + a.fill(1) + assert_equal(@cls[1, 1, 1, 1], a.sort!) + + assert_equal(@cls[1], @cls[1].sort!) + assert_equal(@cls[], @cls[].sort!) + + a = @cls[4, 3, 2, 1] + a.sort! {|m, n| a.replace([9, 8, 7, 6]); m <=> n } + assert_equal([1, 2, 3, 4], a) + + a = @cls[4, 3, 2, 1] + a.sort! {|m, n| a.replace([9, 8, 7]); m <=> n } + assert_equal([1, 2, 3, 4], a) + end + + def test_sort_with_callcc + need_continuation + n = 1000 + cont = nil + ary = (1..100).to_a + begin + ary.sort! {|a,b| + callcc {|k| cont = k} unless cont + assert_equal(100, ary.size, '[ruby-core:16679]') + a <=> b + } + rescue => e + end + n -= 1 + cont.call if 0 < n + assert_instance_of(RuntimeError, e, '[ruby-core:16679]') + assert_match(/reentered/, e.message, '[ruby-core:16679]') + end + + def test_sort_with_replace + xary = (1..100).to_a + 100.times do + ary = (1..100).to_a + ary.sort! {|a,b| ary.replace(xary); a <=> b} + GC.start + assert_equal(xary, ary, '[ruby-dev:34732]') + end + end + + def test_sort_bang_with_freeze + ary = [] + o1 = Object.new + o1.singleton_class.class_eval { + define_method(:<=>) {|v| + ary.freeze + 1 + } + } + o2 = o1.dup + ary << o1 << o2 + orig = ary.dup + assert_raise(RuntimeError, "frozen during comparison") {ary.sort!} + assert_equal(orig, ary, "must not be modified once frozen") + end + + def test_to_a + a = @cls[ 1, 2, 3 ] + a_id = a.__id__ + assert_equal(a, a.to_a) + assert_equal(a_id, a.to_a.__id__) + end + + def test_to_ary + a = [ 1, 2, 3 ] + b = @cls[*a] + + a_id = a.__id__ + assert_equal(a, b.to_ary) + if (@cls == Array) + assert_equal(a_id, a.to_ary.__id__) + end + + o = Object.new + def o.to_ary + [4, 5] + end + assert_equal([1, 2, 3, 4, 5], a.concat(o)) + + o = Object.new + def o.to_ary + foo_bar() + end + assert_match(/foo_bar/, assert_raise(NoMethodError) {a.concat(o)}.message) + end + + def test_to_s + $, = "" + a = @cls[] + assert_equal("[]", a.to_s) + + $, = "" + a = @cls[1, 2] + assert_equal("[1, 2]", a.to_s) + + $, = "" + a = @cls[1, 2, 3] + assert_equal("[1, 2, 3]", a.to_s) + + $, = ":" + a = @cls[1, 2, 3] + assert_equal("[1, 2, 3]", a.to_s) + ensure + $, = nil + end + + def test_to_h + kvp = Object.new + def kvp.to_ary + [:obtained, :via_to_ary] + end + array = [ + [:key, :value], + kvp, + ] + assert_equal({key: :value, obtained: :via_to_ary}, array.to_h) + + e = assert_raise(TypeError) { + [[:first_one, :ok], :not_ok].to_h + } + assert_equal "wrong element type Symbol at 1 (expected array)", e.message + e = assert_raise(ArgumentError) { + [[:first_one, :ok], [1, 2], [:not_ok]].to_h + } + assert_equal "wrong array length at 2 (expected 2, was 1)", e.message + end + + def test_uniq + a = [] + b = a.uniq + assert_equal([], a) + assert_equal([], b) + assert_not_same(a, b) + + a = [1] + b = a.uniq + assert_equal([1], a) + assert_equal([1], b) + assert_not_same(a, b) + + a = [1,1] + b = a.uniq + assert_equal([1,1], a) + assert_equal([1], b) + assert_not_same(a, b) + + a = [1,2] + b = a.uniq + assert_equal([1,2], a) + assert_equal([1,2], b) + assert_not_same(a, b) + + a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ] + b = a.dup + assert_equal(@cls[1, 2, 3, 4, nil], a.uniq) + assert_equal(b, a) + + c = @cls["a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl"] + d = c.dup + assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c.uniq {|s| s[/^\w+/]}) + assert_equal(d, c) + + assert_equal(@cls[1, 2, 3], @cls[1, 2, 3].uniq) + + a = %w(a a) + b = a.uniq + assert_equal(%w(a a), a) + assert(a.none?(&:frozen?)) + assert_equal(%w(a), b) + assert(b.none?(&:frozen?)) + + bug9340 = "[ruby-core:59457]" + ary = [bug9340, bug9340.dup, bug9340.dup] + assert_equal 1, ary.uniq.size + assert_same bug9340, ary.uniq[0] + end + + def test_uniq_with_block + a = [] + b = a.uniq {|v| v.even? } + assert_equal([], a) + assert_equal([], b) + assert_not_same(a, b) + + a = [1] + b = a.uniq {|v| v.even? } + assert_equal([1], a) + assert_equal([1], b) + assert_not_same(a, b) + + a = [1,3] + b = a.uniq {|v| v.even? } + assert_equal([1,3], a) + assert_equal([1], b) + assert_not_same(a, b) + + a = %w(a a) + b = a.uniq {|v| v } + assert_equal(%w(a a), a) + assert(a.none?(&:frozen?)) + assert_equal(%w(a), b) + assert(b.none?(&:frozen?)) + end + + def test_uniq! + a = [] + b = a.uniq! + assert_equal(nil, b) + + a = [1] + b = a.uniq! + assert_equal(nil, b) + + a = [1,1] + b = a.uniq! + assert_equal([1], a) + assert_equal([1], b) + assert_same(a, b) + + a = [1,2] + b = a.uniq! + assert_equal([1,2], a) + assert_equal(nil, b) + + a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ] + assert_equal(@cls[1, 2, 3, 4, nil], a.uniq!) + assert_equal(@cls[1, 2, 3, 4, nil], a) + + c = @cls["a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl"] + assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c.uniq! {|s| s[/^\w+/]}) + assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c) + + c = @cls["a:def", "b:abc", "c:jkl"] + assert_equal(nil, c.uniq! {|s| s[/^\w+/]}) + assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c) + + assert_nil(@cls[1, 2, 3].uniq!) + + f = a.dup.freeze + assert_raise(ArgumentError) { a.uniq!(1) } + assert_raise(ArgumentError) { f.uniq!(1) } + assert_raise(RuntimeError) { f.uniq! } + + assert_nothing_raised do + a = [ {c: "b"}, {c: "r"}, {c: "w"}, {c: "g"}, {c: "g"} ] + a.sort_by!{|e| e[:c]} + a.uniq! {|e| e[:c]} + end + + a = %w(a a) + b = a.uniq + assert_equal(%w(a a), a) + assert(a.none?(&:frozen?)) + assert_equal(%w(a), b) + assert(b.none?(&:frozen?)) + end + + def test_uniq_bang_with_block + a = [] + b = a.uniq! {|v| v.even? } + assert_equal(nil, b) + + a = [1] + b = a.uniq! {|v| v.even? } + assert_equal(nil, b) + + a = [1,3] + b = a.uniq! {|v| v.even? } + assert_equal([1], a) + assert_equal([1], b) + assert_same(a, b) + + a = [1,2] + b = a.uniq! {|v| v.even? } + assert_equal([1,2], a) + assert_equal(nil, b) + + a = %w(a a) + b = a.uniq! {|v| v } + assert_equal(%w(a), b) + assert_same(a, b) + assert b.none?(&:frozen?) + end + + def test_uniq_bang_with_freeze + ary = [1,2] + orig = ary.dup + assert_raise(RuntimeError, "frozen during comparison") { + ary.uniq! {|v| ary.freeze; 1} + } + assert_equal(orig, ary, "must not be modified once frozen") + end + + def test_unshift + a = @cls[] + assert_equal(@cls['cat'], a.unshift('cat')) + assert_equal(@cls['dog', 'cat'], a.unshift('dog')) + assert_equal(@cls[nil, 'dog', 'cat'], a.unshift(nil)) + assert_equal(@cls[@cls[1,2], nil, 'dog', 'cat'], a.unshift(@cls[1, 2])) + end + + def test_OR # '|' + assert_equal(@cls[], @cls[] | @cls[]) + assert_equal(@cls[1], @cls[1] | @cls[]) + assert_equal(@cls[1], @cls[] | @cls[1]) + assert_equal(@cls[1], @cls[1] | @cls[1]) + + assert_equal(@cls[1,2], @cls[1] | @cls[2]) + assert_equal(@cls[1,2], @cls[1, 1] | @cls[2, 2]) + assert_equal(@cls[1,2], @cls[1, 2] | @cls[1, 2]) + + a = %w(a b c) + b = %w(a b c d e) + c = a | b + assert_equal(c, b) + assert_not_same(c, b) + assert_equal(%w(a b c), a) + assert_equal(%w(a b c d e), b) + assert(a.none?(&:frozen?)) + assert(b.none?(&:frozen?)) + assert(c.none?(&:frozen?)) + end + + def test_OR_in_order + obj1, obj2 = Class.new do + attr_reader :name + def initialize(name) @name = name; end + def inspect; "test_OR_in_order(#{@name})"; end + def hash; 0; end + def eql?(a) true; end + break [new("1"), new("2")] + end + assert_equal([obj1], [obj1]|[obj2]) + end + + def test_combination + assert_equal(@cls[[]], @cls[1,2,3,4].combination(0).to_a) + assert_equal(@cls[[1],[2],[3],[4]], @cls[1,2,3,4].combination(1).to_a) + assert_equal(@cls[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], @cls[1,2,3,4].combination(2).to_a) + assert_equal(@cls[[1,2,3],[1,2,4],[1,3,4],[2,3,4]], @cls[1,2,3,4].combination(3).to_a) + assert_equal(@cls[[1,2,3,4]], @cls[1,2,3,4].combination(4).to_a) + assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a) + end + + def test_product + assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]], + @cls[1,2,3].product([4,5])) + assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2])) + + assert_equal(@cls[[1,3,5],[1,3,6],[1,4,5],[1,4,6], + [2,3,5],[2,3,6],[2,4,5],[2,4,6]], + @cls[1,2].product([3,4],[5,6])) + assert_equal(@cls[[1],[2]], @cls[1,2].product) + assert_equal(@cls[], @cls[1,2].product([])) + + bug3394 = '[ruby-dev:41540]' + acc = [] + EnvUtil.under_gc_stress {[1,2].product([3,4,5],[6,8]){|array| acc << array}} + assert_equal([[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8], + [2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]], + acc, bug3394) + + def (o = Object.new).to_ary; GC.start; [3,4] end + acc = [1,2].product(*[o]*10) + assert_equal([1,2].product([3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4]), + acc) + + a = [] + [1, 2].product([0, 1, 2, 3, 4][1, 4]) {|x| a << x } + a.all? {|x| assert_not_include(x, 0)} + end + + def test_permutation + a = @cls[1,2,3] + assert_equal(@cls[[]], a.permutation(0).to_a) + assert_equal(@cls[[1],[2],[3]], a.permutation(1).to_a.sort) + assert_equal(@cls[[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], + a.permutation(2).to_a.sort) + assert_equal(@cls[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], + a.permutation(3).sort.to_a) + assert_equal(@cls[], a.permutation(4).to_a) + assert_equal(@cls[], a.permutation(-1).to_a) + assert_equal("abcde".each_char.to_a.permutation(5).sort, + "edcba".each_char.to_a.permutation(5).sort) + assert_equal(@cls[].permutation(0).to_a, @cls[[]]) + + a = @cls[1, 2, 3, 4] + b = @cls[] + a.permutation {|x| b << x; a.replace(@cls[9, 8, 7, 6]) } + assert_equal(@cls[9, 8, 7, 6], a) + assert_equal(@cls[1, 2, 3, 4].permutation.to_a, b) + + bug3708 = '[ruby-dev:42067]' + assert_equal(b, @cls[0, 1, 2, 3, 4][1, 4].permutation.to_a, bug3708) + + bug9932 = '[ruby-core:63103] [Bug #9932]' + assert_separately([], <<-"end;") # do + assert_nothing_raised(SystemStackError, "#{bug9932}") do + assert_equal(:ok, Array.new(100_000, nil).permutation {break :ok}) + end + end; + end + + def test_repeated_permutation + a = @cls[1,2] + assert_equal(@cls[[]], a.repeated_permutation(0).to_a) + assert_equal(@cls[[1],[2]], a.repeated_permutation(1).to_a.sort) + assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], + a.repeated_permutation(2).to_a.sort) + assert_equal(@cls[[1,1,1],[1,1,2],[1,2,1],[1,2,2], + [2,1,1],[2,1,2],[2,2,1],[2,2,2]], + a.repeated_permutation(3).to_a.sort) + assert_equal(@cls[], a.repeated_permutation(-1).to_a) + assert_equal("abcde".each_char.to_a.repeated_permutation(5).sort, + "edcba".each_char.to_a.repeated_permutation(5).sort) + assert_equal(@cls[].repeated_permutation(0).to_a, @cls[[]]) + assert_equal(@cls[].repeated_permutation(1).to_a, @cls[]) + + a = @cls[1, 2, 3, 4] + b = @cls[] + a.repeated_permutation(4) {|x| b << x; a.replace(@cls[9, 8, 7, 6]) } + assert_equal(@cls[9, 8, 7, 6], a) + assert_equal(@cls[1, 2, 3, 4].repeated_permutation(4).to_a, b) + + a = @cls[0, 1, 2, 3, 4][1, 4].repeated_permutation(2) + assert_empty(a.reject {|x| !x.include?(0)}) + + assert_separately([], <<-"end;") # do + assert_nothing_raised(SystemStackError) do + assert_equal(:ok, Array.new(100_000, nil).repeated_permutation(500_000) {break :ok}) + end + end; + end + + def test_repeated_combination + a = @cls[1,2,3] + assert_equal(@cls[[]], a.repeated_combination(0).to_a) + assert_equal(@cls[[1],[2],[3]], a.repeated_combination(1).to_a.sort) + assert_equal(@cls[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]], + a.repeated_combination(2).to_a.sort) + assert_equal(@cls[[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], + [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]], + a.repeated_combination(3).to_a.sort) + assert_equal(@cls[[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3], + [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3], + [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]], + a.repeated_combination(4).to_a.sort) + assert_equal(@cls[], a.repeated_combination(-1).to_a) + assert_equal("abcde".each_char.to_a.repeated_combination(5).map{|e|e.sort}.sort, + "edcba".each_char.to_a.repeated_combination(5).map{|e|e.sort}.sort) + assert_equal(@cls[].repeated_combination(0).to_a, @cls[[]]) + assert_equal(@cls[].repeated_combination(1).to_a, @cls[]) + + a = @cls[1, 2, 3, 4] + b = @cls[] + a.repeated_combination(4) {|x| b << x; a.replace(@cls[9, 8, 7, 6]) } + assert_equal(@cls[9, 8, 7, 6], a) + assert_equal(@cls[1, 2, 3, 4].repeated_combination(4).to_a, b) + + a = @cls[0, 1, 2, 3, 4][1, 4].repeated_combination(2) + assert_empty(a.reject {|x| !x.include?(0)}) + + assert_separately([], <<-"end;") # do + assert_nothing_raised(SystemStackError) do + assert_equal(:ok, Array.new(100_000, nil).repeated_combination(500_000) {break :ok}) + end + end; + end + + def test_take + assert_equal([1,2,3], [1,2,3,4,5,0].take(3)) + assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) } + assert_equal([1,2], [1,2].take(1000000000), '[ruby-dev:34123]') + end + + def test_take_while + assert_equal([1,2], [1,2,3,4,5,0].take_while {|i| i < 3 }) + end + + def test_drop + assert_equal([4,5,0], [1,2,3,4,5,0].drop(3)) + assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].drop(-1) } + assert_equal([], [1,2].drop(1000000000), '[ruby-dev:34123]') + end + + def test_drop_while + assert_equal([3,4,5,0], [1,2,3,4,5,0].drop_while {|i| i < 3 }) + end + + LONGP = [127, 63, 31, 15, 7].map {|x| 2**x-1 }.find do |x| + begin + [].first(x) + rescue ArgumentError + true + rescue RangeError + false + end + end + + def test_ary_new + assert_raise(ArgumentError) { [].to_enum.first(-1) } + assert_raise(ArgumentError) { [].to_enum.first(LONGP) } + end + + def test_try_convert + assert_equal([1], Array.try_convert([1])) + assert_equal(nil, Array.try_convert("1")) + end + + def test_initialize + assert_nothing_raised { [].instance_eval { initialize } } + assert_nothing_raised { Array.new { } } + assert_equal([1, 2, 3], Array.new([1, 2, 3])) + assert_raise(ArgumentError) { Array.new(-1, 1) } + assert_raise(ArgumentError) { Array.new(LONGP, 1) } + assert_equal([1, 1, 1], Array.new(3, 1)) + assert_equal([1, 1, 1], Array.new(3) { 1 }) + assert_equal([1, 1, 1], Array.new(3, 1) { 1 }) + end + + def test_aset_error + assert_raise(IndexError) { [0][-2] = 1 } + assert_raise(IndexError) { [0][LONGP] = 2 } + assert_raise(IndexError) { [0][(LONGP + 1) / 2 - 1] = 2 } + assert_raise(IndexError) { [0][LONGP..-1] = 2 } + a = [0] + a[2] = 4 + assert_equal([0, nil, 4], a) + assert_raise(ArgumentError) { [0][0, 0, 0] = 0 } + assert_raise(ArgumentError) { [0].freeze[0, 0, 0] = 0 } + assert_raise(TypeError) { [0][:foo] = 0 } + assert_raise(RuntimeError) { [0].freeze[:foo] = 0 } + end + + def test_first2 + assert_equal([0], [0].first(2)) + assert_raise(ArgumentError) { [0].first(-1) } + end + + def test_last2 + assert_equal([0], [0].last(2)) + assert_raise(ArgumentError) { [0].last(-1) } + end + + def test_shift2 + assert_equal(0, ([0] * 16).shift) + # check + a = [0, 1, 2] + a[3] = 3 + a.shift(2) + assert_equal([2, 3], a) + end + + def test_unshift_error + assert_raise(RuntimeError) { [].freeze.unshift('cat') } + assert_raise(RuntimeError) { [].freeze.unshift() } + end + + def test_aref + assert_raise(ArgumentError) { [][0, 0, 0] } + end + + def test_fetch + assert_equal(1, [].fetch(0, 0) { 1 }) + assert_equal(1, [0, 1].fetch(-1)) + assert_raise(IndexError) { [0, 1].fetch(2) } + assert_raise(IndexError) { [0, 1].fetch(-3) } + assert_equal(2, [0, 1].fetch(2, 2)) + end + + def test_index2 + a = [0, 1, 2] + assert_equal(a, a.index.to_a) + assert_equal(1, a.index {|x| x == 1 }) + end + + def test_rindex2 + a = [0, 1, 2] + assert_equal([2, 1, 0], a.rindex.to_a) + assert_equal(1, a.rindex {|x| x == 1 }) + + a = [0, 1] + e = a.rindex + assert_equal(1, e.next) + a.clear + assert_raise(StopIteration) { e.next } + + o = Object.new + class << o; self; end.class_eval do + define_method(:==) {|x| a.clear; false } + end + a = [nil, o] + assert_equal(nil, a.rindex(0)) + end + + def test_ary_to_ary + o = Object.new + def o.to_ary; [1, 2, 3]; end + a, b, c = o + assert_equal([1, 2, 3], [a, b, c]) + end + + def test_splice + a = [0] + assert_raise(IndexError) { a[-2, 0] = nil } + end + + def test_insert + a = [0] + assert_equal([0], a.insert(1)) + assert_equal([0, 1], a.insert(1, 1)) + assert_raise(ArgumentError) { a.insert } + assert_equal([0, 1, 2], a.insert(-1, 2)) + assert_equal([0, 1, 3, 2], a.insert(-2, 3)) + assert_raise(RuntimeError) { [0].freeze.insert(0)} + assert_raise(ArgumentError) { [0].freeze.insert } + end + + def test_join2 + a = [] + a << a + assert_raise(ArgumentError){a.join} + + def (a = Object.new).to_ary + [self] + end + assert_raise(ArgumentError, '[ruby-core:24150]'){[a].join} + assert_equal("12345", [1,[2,[3,4],5]].join) + end + + def test_to_a2 + klass = Class.new(Array) + a = klass.new.to_a + assert_equal([], a) + assert_equal(Array, a.class) + end + + def test_values_at2 + a = [0, 1, 2, 3, 4, 5] + assert_equal([1, 2, 3], a.values_at(1..3)) + assert_equal([nil, nil], a.values_at(7..8)) + bug6203 = '[ruby-core:43678]' + assert_equal([4, 5, nil, nil], a.values_at(4..7), bug6203) + assert_equal([nil], a.values_at(2**31-1)) + end + + def test_select + assert_equal([0, 2], [0, 1, 2, 3].select {|x| x % 2 == 0 }) + end + + # also keep_if + def test_select! + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(nil, a.select! { true }) + assert_equal(a, a.keep_if { true }) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.select! { false }) + assert_equal(@cls[], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.select! { |i| i > 3 }) + assert_equal(@cls[4, 5], a) + end + + def test_delete2 + a = [0] * 1024 + [1] + [0] * 1024 + a.delete(0) + assert_equal([1], a) + end + + def test_reject + assert_equal([1, 3], [0, 1, 2, 3].reject {|x| x % 2 == 0 }) + end + + def test_reject_with_callcc + need_continuation + bug9727 = '[ruby-dev:48101] [Bug #9727]' + cont = nil + a = [*1..10].reject do |i| + callcc {|c| cont = c} if !cont and i == 10 + false + end + if a.size < 1000 + a.unshift(:x) + cont.call + end + assert_equal(1000, a.size, bug9727) + assert_equal([:x, *1..10], a.uniq, bug9727) + end + + def test_zip + assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]], + [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"])) + a = [] + [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"]) {|x| a << x } + assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]], a) + + ary = Object.new + def ary.to_a; [1, 2]; end + assert_raise(TypeError) {%w(a b).zip(ary)} + def ary.each; [3, 4].each{|e|yield e}; end + assert_equal([['a', 3], ['b', 4]], %w(a b).zip(ary)) + def ary.to_ary; [5, 6]; end + assert_equal([['a', 5], ['b', 6]], %w(a b).zip(ary)) + end + + def test_zip_bug + bug8153 = "ruby-core:53650" + r = 1..1 + def r.respond_to?(*) + super + end + assert_equal [[42, 1]], [42].zip(r), bug8153 + end + + def test_transpose + assert_equal([[1, :a], [2, :b], [3, :c]], + [[1, 2, 3], [:a, :b, :c]].transpose) + assert_raise(IndexError) { [[1, 2, 3], [:a, :b]].transpose } + end + + def test_clear2 + assert_equal([], ([0] * 1024).clear) + end + + def test_fill2 + assert_raise(ArgumentError) { [].fill(0, 1, LONGP) } + end + + def test_times + assert_raise(ArgumentError) { [0, 0, 0, 0] * ((LONGP + 1) / 4) } + end + + def test_equal + o = Object.new + def o.to_ary; end + def o.==(x); :foo; end + assert_equal([0, 1, 2], o) + assert_not_equal([0, 1, 2], [0, 1, 3]) + end + + A = Array.new(3, &:to_s) + B = A.dup + + def test_equal_resize + o = Object.new + def o.==(o) + A.clear + B.clear + true + end + A[1] = o + assert_equal(A, B) + end + + def test_flatten_error + a = [] + a << a + assert_raise(ArgumentError) { a.flatten } + + f = [].freeze + assert_raise(ArgumentError) { a.flatten!(1, 2) } + assert_raise(TypeError) { a.flatten!(:foo) } + assert_raise(ArgumentError) { f.flatten!(1, 2) } + assert_raise(RuntimeError) { f.flatten! } + assert_raise(RuntimeError) { f.flatten!(:foo) } + end + + def test_shuffle + 100.times do + assert_equal([0, 1, 2], [2, 1, 0].shuffle.sort) + end + + gen = Random.new(0) + assert_raise(ArgumentError) {[1, 2, 3].shuffle(1, random: gen)} + srand(0) + 100.times do + assert_equal([0, 1, 2].shuffle, [0, 1, 2].shuffle(random: gen)) + end + + assert_raise_with_message(ArgumentError, /unknown keyword/) do + [0, 1, 2].shuffle(xawqij: "a") + end + assert_raise_with_message(ArgumentError, /unknown keyword/) do + [0, 1, 2].shuffle!(xawqij: "a") + end + end + + def test_shuffle_random + gen = proc do + 10000000 + end + class << gen + alias rand call + end + assert_raise(RangeError) { + [*0..2].shuffle(random: gen) + } + + ary = (0...10000).to_a + gen = proc do + ary.replace([]) + 0.5 + end + class << gen + alias rand call + end + assert_raise(RuntimeError) {ary.shuffle!(random: gen)} + + zero = Object.new + def zero.to_int + 0 + end + gen_to_int = proc do |max| + zero + end + class << gen_to_int + alias rand call + end + ary = (0...10000).to_a + assert_equal(ary.rotate, ary.shuffle(random: gen_to_int)) + end + + def test_sample + 100.times do + assert_include([0, 1, 2], [2, 1, 0].sample) + samples = [2, 1, 0].sample(2) + samples.each{|sample| + assert_include([0, 1, 2], sample) + } + end + + srand(0) + a = (1..18).to_a + (0..20).each do |n| + 100.times do + b = a.sample(n) + assert_equal([n, 18].min, b.size) + assert_equal(a, (a | b).sort) + assert_equal(b.sort, (a & b).sort) + end + + h = Hash.new(0) + 1000.times do + a.sample(n).each {|x| h[x] += 1 } + end + assert_operator(h.values.min * 2, :>=, h.values.max) if n != 0 + end + + assert_raise(ArgumentError, '[ruby-core:23374]') {[1, 2].sample(-1)} + + gen = Random.new(0) + srand(0) + a = (1..18).to_a + (0..20).each do |n| + 100.times do |i| + assert_equal(a.sample(n), a.sample(n, random: gen), "#{i}/#{n}") + end + end + + assert_raise_with_message(ArgumentError, /unknown keyword/) do + [0, 1, 2].sample(xawqij: "a") + end + end + + def test_sample_random + ary = (0...10000).to_a + assert_raise(ArgumentError) {ary.sample(1, 2, random: nil)} + gen0 = proc do |max| + max/2 + end + class << gen0 + alias rand call + end + gen1 = proc do |max| + ary.replace([]) + max/2 + end + class << gen1 + alias rand call + end + assert_equal(5000, ary.sample(random: gen0)) + assert_nil(ary.sample(random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000], ary.sample(1, random: gen0)) + assert_equal([], ary.sample(1, random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000, 4999], ary.sample(2, random: gen0)) + assert_equal([], ary.sample(2, random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000, 4999, 5001], ary.sample(3, random: gen0)) + assert_equal([], ary.sample(3, random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000, 4999, 5001, 4998], ary.sample(4, random: gen0)) + assert_equal([], ary.sample(4, random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000, 4999, 5001, 4998, 5002, 4997, 5003, 4996, 5004, 4995], ary.sample(10, random: gen0)) + assert_equal([], ary.sample(10, random: gen1)) + assert_equal([], ary) + ary = (0...10000).to_a + assert_equal([5000, 0, 5001, 2, 5002, 4, 5003, 6, 5004, 8, 5005], ary.sample(11, random: gen0)) + ary.sample(11, random: gen1) # implementation detail, may change in the future + assert_equal([], ary) + + half = Object.new + def half.to_int + 5000 + end + gen_to_int = proc do |max| + half + end + class << gen_to_int + alias rand call + end + ary = (0...10000).to_a + assert_equal(5000, ary.sample(random: gen_to_int)) + end + + def test_cycle + a = [] + [0, 1, 2].cycle do |i| + a << i + break if a.size == 10 + end + assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], a) + + a = [0, 1, 2] + assert_nil(a.cycle { a.clear }) + + a = [] + [0, 1, 2].cycle(3) {|i| a << i } + assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2], a) + end + + def test_reverse_each2 + a = [0, 1, 2, 3, 4, 5] + r = [] + a.reverse_each do |x| + r << x + a.pop + a.pop + end + assert_equal([5, 3, 1], r) + end + + def test_combination2 + assert_equal(:called, (0..100).to_a.combination(50) { break :called }, "[ruby-core:29240] ... must be yielded even if 100C50 > signed integer") + end + + def test_combination_clear + bug9939 = '[ruby-core:63149] [Bug #9939]' + assert_separately([], <<-'end;') + 100_000.times {Array.new(1000)} + a = [*0..100] + a.combination(3) {|*,x| a.clear} + end; + end + + def test_product2 + a = (0..100).to_a + assert_raise(RangeError) do + a.product(a, a, a, a, a, a, a, a, a, a) + end + assert_nothing_raised(RangeError) do + a.product(a, a, a, a, a, a, a, a, a, a) { break } + end + end + + class Array2 < Array + end + + def test_array_subclass + assert_equal(Array2, Array2[1,2,3].uniq.class, "[ruby-dev:34581]") + assert_equal(Array2, Array2[1,2][0,1].class) # embeded + assert_equal(Array2, Array2[*(1..100)][1..99].class) #not embeded + end + + def test_inspect + a = @cls[1, 2, 3] + a.taint + s = a.inspect + assert_equal(true, s.tainted?) + end + + def test_initialize2 + a = [1] * 1000 + a.instance_eval { initialize } + assert_equal([], a) + end + + def test_shift_shared_ary + a = (1..100).to_a + b = [] + b.replace(a) + assert_equal((1..10).to_a, a.shift(10)) + assert_equal((11..100).to_a, a) + end + + def test_replace_shared_ary + a = [1] * 100 + b = [] + b.replace(a) + a.replace([1, 2, 3]) + assert_equal([1, 2, 3], a) + assert_equal([1] * 100, b) + end + + def test_fill_negative_length + a = (1..10).to_a + a.fill(:foo, 5, -3) + assert_equal((1..10).to_a, a) + end + + def test_slice_frozen_array + a = [1,2,3,4,5].freeze + assert_equal([1,2,3,4], a[0,4]) + assert_equal([2,3,4,5], a[1,4]) + end + + def test_sort_by! + a = [1,3,5,2,4] + a.sort_by! {|x| -x } + assert_equal([5,4,3,2,1], a) + end + + def test_rotate + a = [1,2,3,4,5].freeze + assert_equal([2,3,4,5,1], a.rotate) + assert_equal([5,1,2,3,4], a.rotate(-1)) + assert_equal([3,4,5,1,2], a.rotate(2)) + assert_equal([4,5,1,2,3], a.rotate(-2)) + assert_equal([4,5,1,2,3], a.rotate(13)) + assert_equal([3,4,5,1,2], a.rotate(-13)) + a = [1].freeze + assert_equal([1], a.rotate) + assert_equal([1], a.rotate(2)) + assert_equal([1], a.rotate(-4)) + assert_equal([1], a.rotate(13)) + assert_equal([1], a.rotate(-13)) + a = [].freeze + assert_equal([], a.rotate) + assert_equal([], a.rotate(2)) + assert_equal([], a.rotate(-4)) + assert_equal([], a.rotate(13)) + assert_equal([], a.rotate(-13)) + a = [1,2,3] + assert_raise(ArgumentError) { a.rotate(1, 1) } + assert_equal([1,2,3,4,5].rotate(2**31-1), [1,2,3,4,5].rotate(2**31-0.1)) + assert_equal([1,2,3,4,5].rotate(-2**31), [1,2,3,4,5].rotate(-2**31-0.9)) + end + + def test_rotate! + a = [1,2,3,4,5] + assert_equal([2,3,4,5,1], a.rotate!) + assert_equal([2,3,4,5,1], a) + assert_equal([4,5,1,2,3], a.rotate!(2)) + assert_equal([5,1,2,3,4], a.rotate!(-4)) + assert_equal([3,4,5,1,2], a.rotate!(13)) + assert_equal([5,1,2,3,4], a.rotate!(-13)) + a = [1] + assert_equal([1], a.rotate!) + assert_equal([1], a.rotate!(2)) + assert_equal([1], a.rotate!(-4)) + assert_equal([1], a.rotate!(13)) + assert_equal([1], a.rotate!(-13)) + a = [] + assert_equal([], a.rotate!) + assert_equal([], a.rotate!(2)) + assert_equal([], a.rotate!(-4)) + assert_equal([], a.rotate!(13)) + assert_equal([], a.rotate!(-13)) + a = [].freeze + assert_raise_with_message(RuntimeError, /can\'t modify frozen/) {a.rotate!} + a = [1,2,3] + assert_raise(ArgumentError) { a.rotate!(1, 1) } + end + + def test_bsearch_typechecks_return_values + assert_raise(TypeError) do + [1, 2, 42, 100, 666].bsearch{ "not ok" } + end + assert_equal [1, 2, 42, 100, 666].bsearch{}, [1, 2, 42, 100, 666].bsearch{false} + end + + def test_bsearch_with_no_block + enum = [1, 2, 42, 100, 666].bsearch + assert_nil enum.size + assert_equal 42, enum.each{|x| x >= 33 } + end + + def test_bsearch_in_find_minimum_mode + a = [0, 4, 7, 10, 12] + assert_equal(4, a.bsearch {|x| x >= 4 }) + assert_equal(7, a.bsearch {|x| x >= 6 }) + assert_equal(0, a.bsearch {|x| x >= -1 }) + assert_equal(nil, a.bsearch {|x| x >= 100 }) + end + + def test_bsearch_in_find_any_mode + a = [0, 4, 7, 10, 12] + assert_include([4, 7], a.bsearch {|x| 1 - x / 4 }) + assert_equal(nil, a.bsearch {|x| 4 - x / 2 }) + assert_equal(nil, a.bsearch {|x| 1 }) + assert_equal(nil, a.bsearch {|x| -1 }) + + assert_include([4, 7], a.bsearch {|x| (1 - x / 4) * (2**100) }) + assert_equal(nil, a.bsearch {|x| 1 * (2**100) }) + assert_equal(nil, a.bsearch {|x| (-1) * (2**100) }) + + assert_include([4, 7], a.bsearch {|x| (2**100).coerce((1 - x / 4) * (2**100)).first }) + end + + def test_shared_marking + reduce = proc do |s| + s.gsub(/(verify_internal_consistency_reachable_i:\sWB\smiss\s\S+\s\(T_ARRAY\)\s->\s)\S+\s\((proc|T_NONE)\)\n + \K(?:\1\S+\s\(\2\)\n)*/x) do + "...(snip #{$&.count("\n")} lines)...\n" + end + end + begin + assert_normal_exit(<<-EOS, '[Bug #9718]', timeout: 5, stdout_filter: reduce) + queue = [] + 50.times do + 10_000.times do + queue << lambda{} + end + GC.start(full_mark: false, immediate_sweep: true) + GC.verify_internal_consistency + queue.shift.call + end + EOS + rescue Timeout::Error => e + skip e.message + end + end + + sizeof_long = [0].pack("l!").size + sizeof_voidp = [""].pack("p").size + if sizeof_long < sizeof_voidp + ARY_MAX = (1<<(8*sizeof_long-1)) / sizeof_voidp - 1 + Bug11235 = '[ruby-dev:49043] [Bug #11235]' + + def test_push_over_ary_max + assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;") + a = Array.new(ARGV[0].to_i) + assert_raise(IndexError, ARGV[1]) {0x1000.times {a.push(1)}} + end; + end + + def test_unshift_over_ary_max + assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;") + a = Array.new(ARGV[0].to_i) + assert_raise(IndexError, ARGV[1]) {0x1000.times {a.unshift(1)}} + end; + end + + def test_splice_over_ary_max + assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;") + a = Array.new(ARGV[0].to_i) + assert_raise(IndexError, ARGV[1]) {a[0, 0] = Array.new(0x1000)} + end; + end + end + + private + def need_continuation + unless respond_to?(:callcc, true) + EnvUtil.suppress_warning {require 'continuation'} + end + end +end diff --git a/jni/ruby/test/ruby/test_assignment.rb b/jni/ruby/test/ruby/test_assignment.rb new file mode 100644 index 0000000..9c0fd48 --- /dev/null +++ b/jni/ruby/test/ruby/test_assignment.rb @@ -0,0 +1,760 @@ +require 'test/unit' + +class TestAssignment < Test::Unit::TestCase + def test_assign + a=[]; a[0] ||= "bar"; + assert_equal("bar", a[0]) + h={}; h["foo"] ||= "bar"; + assert_equal("bar", h["foo"]) + + aa = 5 + aa ||= 25 + assert_equal(5, aa) + bb ||= 25 + assert_equal(25, bb) + cc &&=33 + assert_nil(cc) + cc = 5 + cc &&=44 + assert_equal(44, cc) + end + + def test_assign_simple + a = nil; assert_nil(a) + a = 1; assert_equal(1, a) + a = []; assert_equal([], a) + a = [1]; assert_equal([1], a) + a = [nil]; assert_equal([nil], a) + a = [[]]; assert_equal([[]], a) + a = [1,2]; assert_equal([1,2], a) + a = [*[]]; assert_equal([], a) + a = [*[1]]; assert_equal([1], a) + a = [*[1,2]]; assert_equal([1,2], a) + end + + def test_assign_splat + a = *[]; assert_equal([], a) + a = *[1]; assert_equal([1], a) + a = *[nil]; assert_equal([nil], a) + a = *[[]]; assert_equal([[]], a) + a = *[1,2]; assert_equal([1,2], a) + a = *[*[]]; assert_equal([], a) + a = *[*[1]]; assert_equal([1], a) + a = *[*[1,2]]; assert_equal([1,2], a) + end + + def test_assign_ary + *a = nil; assert_equal([nil], a) + *a = 1; assert_equal([1], a) + *a = []; assert_equal([], a) + *a = [1]; assert_equal([1], a) + *a = [nil]; assert_equal([nil], a) + *a = [[]]; assert_equal([[]], a) + *a = [1,2]; assert_equal([1,2], a) + *a = [*[]]; assert_equal([], a) + *a = [*[1]]; assert_equal([1], a) + *a = [*[1,2]]; assert_equal([1,2], a) + end + + def test_assign_ary_splat + *a = *[]; assert_equal([], a) + *a = *[1]; assert_equal([1], a) + *a = *[nil]; assert_equal([nil], a) + *a = *[[]]; assert_equal([[]], a) + *a = *[1,2]; assert_equal([1,2], a) + *a = *[*[]]; assert_equal([], a) + *a = *[*[1]]; assert_equal([1], a) + *a = *[*[1,2]]; assert_equal([1,2], a) + end + + def test_massign_simple + a,b,*c = nil; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = 1; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = []; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = [1]; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = [nil]; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = [[]]; assert_equal([[],nil,[]], [a,b,c]) + a,b,*c = [1,2]; assert_equal([1,2,[]], [a,b,c]) + a,b,*c = [*[]]; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = [*[1]]; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = [*[1,2]]; assert_equal([1,2,[]], [a,b,c]) + 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]) + a,b,*c = *[nil]; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = *[[]]; assert_equal([[],nil,[]], [a,b,c]) + a,b,*c = *[1,2]; assert_equal([1,2,[]], [a,b,c]) + a,b,*c = *[*[]]; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = *[*[1]]; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c]) + end + + def test_assign_abbreviated + bug2050 = '[ruby-core:25629]' + a = Hash.new {[]} + b = [1, 2] + assert_equal([1, 2, 3], a[:x] += [*b, 3], bug2050) + assert_equal([1, 2, 3], a[:x], bug2050) + assert_equal([1, 2, 3, [1, 2, 3]], a[:x] <<= [*b, 3], bug2050) + assert_equal([1, 2, 3, [1, 2, 3]], a[:x], bug2050) + end + + def test_assign_private_self + bug9907 = '[ruby-core:62949] [Bug #9907]' + + o = Object.new + class << o + private + def foo; 42; end + def [](i); 42; end + def foo=(a); 42; end + def []=(i, a); 42; end + end + + assert_raise(NoMethodError) { + o.instance_eval {o.foo = 1} + } + assert_nothing_raised(NoMethodError) { + assert_equal(1, o.instance_eval {self.foo = 1}) + } + + assert_raise(NoMethodError) { + o.instance_eval {o[0] = 1} + } + assert_nothing_raised(NoMethodError) { + assert_equal(1, o.instance_eval {self[0] = 1}) + } + + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(43, o.instance_eval {self.foo += 1}) + } + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(1, o.instance_eval {self.foo &&= 1}) + } + + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(43, o.instance_eval {self[0] += 1}) + } + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(1, o.instance_eval {self[0] &&= 1}) + } + end + + def test_yield + def f; yield(nil); end; f {|a| assert_nil(a)}; undef f + def f; yield(1); end; f {|a| assert_equal(1, a)}; undef f + def f; yield([]); end; f {|a| assert_equal([], a)}; undef f + def f; yield([1]); end; f {|a| assert_equal([1], a)}; undef f + def f; yield([nil]); end; f {|a| assert_equal([nil], a)}; undef f + def f; yield([[]]); end; f {|a| assert_equal([[]], a)}; undef f + def f; yield([*[]]); end; f {|a| assert_equal([], a)}; undef f + def f; yield([*[1]]); end; f {|a| assert_equal([1], a)}; undef f + def f; yield([*[1,2]]); end; f {|a| assert_equal([1,2], a)}; undef f + + def f; yield(*[1]); end; f {|a| assert_equal(1, a)}; undef f + def f; yield(*[nil]); end; f {|a| assert_equal(nil, a)}; undef f + def f; yield(*[[]]); end; f {|a| assert_equal([], a)}; undef f + def f; yield(*[*[1]]); end; f {|a| assert_equal(1, a)}; undef f + + def f; yield; end; f {|*a| assert_equal([], a)}; undef f + def f; yield(nil); end; f {|*a| assert_equal([nil], a)}; undef f + def f; yield(1); end; f {|*a| assert_equal([1], a)}; undef f + def f; yield([]); end; f {|*a| assert_equal([[]], a)}; undef f + def f; yield([1]); end; f {|*a| assert_equal([[1]], a)}; undef f + def f; yield([nil]); end; f {|*a| assert_equal([[nil]], a)}; undef f + def f; yield([[]]); end; f {|*a| assert_equal([[[]]], a)}; undef f + def f; yield([1,2]); end; f {|*a| assert_equal([[1,2]], a)}; undef f + def f; yield([*[]]); end; f {|*a| assert_equal([[]], a)}; undef f + def f; yield([*[1]]); end; f {|*a| assert_equal([[1]], a)}; undef f + def f; yield([*[1,2]]); end; f {|*a| assert_equal([[1,2]], a)}; undef f + + def f; yield(*[]); end; f {|*a| assert_equal([], a)}; undef f + def f; yield(*[1]); end; f {|*a| assert_equal([1], a)}; undef f + def f; yield(*[nil]); end; f {|*a| assert_equal([nil], a)}; undef f + def f; yield(*[[]]); end; f {|*a| assert_equal([[]], a)}; undef f + def f; yield(*[*[]]); end; f {|*a| assert_equal([], a)}; undef f + def f; yield(*[*[1]]); end; f {|*a| assert_equal([1], a)}; undef f + def f; yield(*[*[1,2]]); end; f {|*a| assert_equal([1,2], a)}; undef f + + def f; yield; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(nil); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(1); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f + def f; yield([]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield([1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f + def f; yield([nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield([[]]); end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])}; undef f + def f; yield([*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield([*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f + def f; yield([*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f + + def f; yield(*[]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(*[1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f + def f; yield(*[nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(*[[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(*[*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f + def f; yield(*[*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f + def f; yield(*[*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f + end + + def test_return + def r; return; end; a = r(); assert_nil(a); undef r + def r; return nil; end; a = r(); assert_nil(a); undef r + def r; return 1; end; a = r(); assert_equal(1, a); undef r + def r; return []; end; a = r(); assert_equal([], a); undef r + def r; return [1]; end; a = r(); assert_equal([1], a); undef r + def r; return [nil]; end; a = r(); assert_equal([nil], a); undef r + def r; return [[]]; end; a = r(); assert_equal([[]], a); undef r + def r; return [*[]]; end; a = r(); assert_equal([], a); undef r + def r; return [*[1]]; end; a = r(); assert_equal([1], a); undef r + def r; return [*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r + + def r; return *[]; end; a = r(); assert_equal([], a); undef r + def r; return *[1]; end; a = r(); assert_equal([1], a); undef r + def r; return *[nil]; end; a = r(); assert_equal([nil], a); undef r + def r; return *[[]]; end; a = r(); assert_equal([[]], a); undef r + def r; return *[*[]]; end; a = r(); assert_equal([], a); undef r + def r; return *[*[1]]; end; a = r(); assert_equal([1], a); undef r + def r; return *[*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r + + def r; return *[[]]; end; a = *r(); assert_equal([[]], a); undef r + def r; return *[*[1,2]]; end; a = *r(); assert_equal([1,2], a); undef r + + def r; return; end; *a = r(); assert_equal([nil], a); undef r + def r; return nil; end; *a = r(); assert_equal([nil], a); undef r + def r; return 1; end; *a = r(); assert_equal([1], a); undef r + def r; return []; end; *a = r(); assert_equal([], a); undef r + def r; return [1]; end; *a = r(); assert_equal([1], a); undef r + def r; return [nil]; end; *a = r(); assert_equal([nil], a); undef r + def r; return [[]]; end; *a = r(); assert_equal([[]], a); undef r + def r; return [1,2]; end; *a = r(); assert_equal([1,2], a); undef r + def r; return [*[]]; end; *a = r(); assert_equal([], a); undef r + def r; return [*[1]]; end; *a = r(); assert_equal([1], a); undef r + def r; return [*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r + + def r; return *[]; end; *a = r(); assert_equal([], a); undef r + def r; return *[1]; end; *a = r(); assert_equal([1], a); undef r + def r; return *[nil]; end; *a = r(); assert_equal([nil], a); undef r + def r; return *[[]]; end; *a = r(); assert_equal([[]], a); undef r + def r; return *[1,2]; end; *a = r(); assert_equal([1,2], a); undef r + def r; return *[*[]]; end; *a = r(); assert_equal([], a); undef r + def r; return *[*[1]]; end; *a = r(); assert_equal([1], a); undef r + def r; return *[*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r + + def r; return *[[]]; end; *a = *r(); assert_equal([[]], a); undef r + def r; return *[1,2]; end; *a = *r(); assert_equal([1,2], a); undef r + def r; return *[*[1,2]]; end; *a = *r(); assert_equal([1,2], a); undef r + + def r; return; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return 1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r + def r; return []; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return [1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r + def r; return [nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return [[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r + def r; return [1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r + def r; return [*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return [*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r + def r; return [*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r + + def r; return *[]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return *[1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r + def r; return *[nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return *[[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r + def r; return *[1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r + def r; return *[*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r + def r; return *[*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r + def r; return *[*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r + + def r; return 1, *[]; end; a,b = r(); assert_equal([1,nil], [a,b]); undef r + def r; return 1,2,*[1]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r + def r; return 1,2,3,*[1,2]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r + end + + def test_lambda + f = lambda {|r,| assert_equal([], r)} + f.call([], *[]) + + f = lambda {|r,*l| assert_equal([], r); assert_equal([1], l)} + f.call([], *[1]) + + f = lambda{|x| x} + assert_equal(42, f.call(42)) + assert_equal([42], f.call([42])) + assert_equal([[42]], f.call([[42]])) + assert_equal([42,55], f.call([42,55])) + + f = lambda{|x,| x} + assert_equal(42, f.call(42)) + assert_equal([42], f.call([42])) + assert_equal([[42]], f.call([[42]])) + assert_equal([42,55], f.call([42,55])) + + f = lambda{|*x| x} + assert_equal([42], f.call(42)) + assert_equal([[42]], f.call([42])) + assert_equal([[[42]]], f.call([[42]])) + assert_equal([[42,55]], f.call([42,55])) + assert_equal([42,55], f.call(42,55)) + end + + def test_multi + a,=*[1] + assert_equal(1, a) + a,=*[[1]] + assert_equal([1], a) + a,=*[[[1]]] + assert_equal([[1]], a) + + x, (y, z) = 1, 2, 3 + assert_equal([1,2,nil], [x,y,z]) + x, (y, z) = 1, [2,3] + assert_equal([1,2,3], [x,y,z]) + x, (y, z) = 1, [2] + assert_equal([1,2,nil], [x,y,z]) + end + + def test_break + a = loop do break; end; assert_nil(a) + a = loop do break nil; end; assert_nil(a) + a = loop do break 1; end; assert_equal(1, a) + a = loop do break []; end; assert_equal([], a) + a = loop do break [1]; end; assert_equal([1], a) + a = loop do break [nil]; end; assert_equal([nil], a) + a = loop do break [[]]; end; assert_equal([[]], a) + a = loop do break [*[]]; end; assert_equal([], a) + a = loop do break [*[1]]; end; assert_equal([1], a) + a = loop do break [*[1,2]]; end; assert_equal([1,2], a) + + a = loop do break *[]; end; assert_equal([], a) + a = loop do break *[1]; end; assert_equal([1], a) + a = loop do break *[nil]; end; assert_equal([nil], a) + a = loop do break *[[]]; end; assert_equal([[]], a) + a = loop do break *[*[]]; end; assert_equal([], a) + a = loop do break *[*[1]]; end; assert_equal([1], a) + a = loop do break *[*[1,2]]; end; assert_equal([1,2], a) + + *a = loop do break; end; assert_equal([nil], a) + *a = loop do break nil; end; assert_equal([nil], a) + *a = loop do break 1; end; assert_equal([1], a) + *a = loop do break []; end; assert_equal([], a) + *a = loop do break [1]; end; assert_equal([1], a) + *a = loop do break [nil]; end; assert_equal([nil], a) + *a = loop do break [[]]; end; assert_equal([[]], a) + *a = loop do break [1,2]; end; assert_equal([1,2], a) + *a = loop do break [*[]]; end; assert_equal([], a) + *a = loop do break [*[1]]; end; assert_equal([1], a) + *a = loop do break [*[1,2]]; end; assert_equal([1,2], a) + + *a = loop do break *[]; end; assert_equal([], a) + *a = loop do break *[1]; end; assert_equal([1], a) + *a = loop do break *[nil]; end; assert_equal([nil], a) + *a = loop do break *[[]]; end; assert_equal([[]], a) + *a = loop do break *[1,2]; end; assert_equal([1,2], a) + *a = loop do break *[*[]]; end; assert_equal([], a) + *a = loop do break *[*[1]]; end; assert_equal([1], a) + *a = loop do break *[*[1,2]]; end; assert_equal([1,2], a) + + *a = *loop do break *[[]]; end; assert_equal([[]], a) + *a = *loop do break *[1,2]; end; assert_equal([1,2], a) + *a = *loop do break *[*[1,2]]; end; assert_equal([1,2], a) + + a,b,*c = loop do break; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break nil; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break 1; end; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = loop do break []; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break [1]; end; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = loop do break [nil]; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break [[]]; end; assert_equal([[],nil,[]], [a,b,c]) + a,b,*c = loop do break [1,2]; end; assert_equal([1,2,[]], [a,b,c]) + a,b,*c = loop do break [*[]]; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break [*[1]]; end; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = loop do break [*[1,2]]; end; assert_equal([1,2,[]], [a,b,c]) + + a,b,*c = loop do break *[]; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break *[1]; end; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = loop do break *[nil]; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break *[[]]; end; assert_equal([[],nil,[]], [a,b,c]) + a,b,*c = loop do break *[1,2]; end; assert_equal([1,2,[]], [a,b,c]) + a,b,*c = loop do break *[*[]]; end; assert_equal([nil,nil,[]], [a,b,c]) + a,b,*c = loop do break *[*[1]]; end; assert_equal([1,nil,[]], [a,b,c]) + a,b,*c = loop do break *[*[1,2]]; end; assert_equal([1,2,[]], [a,b,c]) + end + + def test_next + def r(val); a = yield(); assert_equal(val, a); end + r(nil){next} + r(nil){next nil} + r(1){next 1} + r([]){next []} + r([1]){next [1]} + r([nil]){next [nil]} + r([[]]){next [[]]} + r([]){next [*[]]} + r([1]){next [*[1]]} + r([1,2]){next [*[1,2]]} + + r([]){next *[]} + r([1]){next *[1]} + r([nil]){next *[nil]} + r([[]]){next *[[]]} + r([]){next *[*[]]} + r([1]){next *[*[1]]} + r([1,2]){next *[*[1,2]]} + undef r + + def r(val); *a = yield(); assert_equal(val, a); end + r([nil]){next} + r([nil]){next nil} + r([1]){next 1} + r([]){next []} + r([1]){next [1]} + r([nil]){next [nil]} + r([[]]){next [[]]} + r([1,2]){next [1,2]} + r([]){next [*[]]} + r([1]){next [*[1]]} + r([1,2]){next [*[1,2]]} + undef r + + def r(val); *a = *yield(); assert_equal(val, a); end + r([[]]){next *[[]]} + r([1,2]){next *[1,2]} + r([1,2]){next *[*[1,2]]} + undef r + + def r(val); a,b,*c = yield(); assert_equal(val, [a,b,c]); end + r([nil,nil,[]]){next} + r([nil,nil,[]]){next nil} + r([1,nil,[]]){next 1} + r([nil,nil,[]]){next []} + r([1,nil,[]]){next [1]} + r([nil,nil,[]]){next [nil]} + r([[],nil,[]]){next [[]]} + r([1,2,[]]){next [1,2]} + r([nil,nil,[]]){next [*[]]} + r([1,nil,[]]){next [*[1]]} + r([1,2,[]]){next [*[1,2]]} + undef r + + def r(val); a,b,*c = *yield(); assert_equal(val, [a,b,c]); end + r([[],nil,[]]){next *[[]]} + r([1,2,[]]){next *[1,2]} + r([1,2,[]]){next *[*[1,2]]} + undef r + end + + def test_massign + a = nil + assert(defined?(a)) + assert_nil(a) + + # multiple asignment + a, b = 1, 2 + assert_equal 1, a + assert_equal 2, b + + a, b, c = 1, 2, 3 + assert_equal 1, a + assert_equal 2, b + assert_equal 3, c + + a = 1 + b = 2 + a, b = b, a + assert_equal 2, a + assert_equal 1, b + + a, = 1, 2 + assert_equal 1, a + + a, = 1, 2, 3 + assert_equal 1, a + + a, * = 1, 2, 3 + assert_equal 1, a + + a, *b = 1, 2, 3 + assert_equal 1, a + assert_equal [2, 3], b + + # not supported yet + #a, *b, c = 1, 2, 3, 4 + #assert_equal 1, a + #assert_equal [2,3], b + #assert_equal 4, c + + a = 1, 2 + assert_equal [1, 2], a + + a = [1, 2], [3, 4] + assert_equal [[1,2], [3,4]], a + + a, (b, c), d = 1, [2, 3], 4 + assert_equal 1, a + assert_equal 2, b + assert_equal 3, c + assert_equal 4, d + + *a = 1, 2, 3 + assert_equal([1, 2, 3], a) + + *a = 4 + assert_equal([4], a) + + *a = nil + assert_equal([nil], a) + + a, b = 1 + assert_equal 1, a + assert_nil b + + a, b = [1, 2] + assert_equal 1, a + assert_equal 2, b + end + + def test_nested_massign + (a, b), c = [[1, 2], 3]; assert_equal [1,2,3], [a,b,c] + a, (b, c) = [[1, 2], 3]; assert_equal [[1,2], 3, nil], [a,b,c] + a, (b, c) = [1, [2, 3]]; assert_equal [1,2,3], [a,b,c] + (a, b), *c = [[1, 2], 3]; assert_equal [1,2,[3]], [a,b,c] + (a,b),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,3,4,5],[a,b,c,d,e] + (a,*b),c,(d,e,*) = [[1,2],3,[4,5]]; assert_equal [1,[2],3,4,5],[a,b,c,d,e] + (a,b),c,(d,*e) = [[1,2,3],4,[5,6,7,8]]; assert_equal [1,2,4,5,[6,7,8]],[a,b,c,d,e] + (a,(b1,b2)),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,nil,3,4,5],[a,b1,b2,c,d,e] + (a,(b1,b2)),c,(d,e) = [[1,[21,22]],3,[4,5]]; assert_equal [1,21,22,3,4,5],[a,b1,b2,c,d,e] + end + + class MyObj + def to_ary + [[1,2],[3,4]] + end + end + + def test_to_ary_splat + a, b = MyObj.new + assert_equal [[1,2],[3,4]], [a,b] + end + + A = 1 + B = 2 + X, Y = A, B + class Base + A = 3 + B = 4 + end + + def test_const_massign + assert_equal [1,2], [X,Y] + a, b = Base::A, Base::B + assert_equal [3,4], [a,b] + end +end + +require_relative 'sentence' +class TestAssignmentGen < Test::Unit::TestCase + Syntax = { + :exp => [["0"], + ["nil"], + ["false"], + ["[]"], + ["[",:exps,"]"]], + :exps => [[:exp], + [:exp,",",:exps]], + :arg => [[:exp]], + :mrhs => [[:args,",",:arg], + [:args,",","*",:arg], + ["*",:arg]], + :args => [[:arg], + ["*",:arg], + [:args,",",:arg], + [:args,",","*",:arg]], + :mlhs => [[:mlhs_basic], + ["(",:mlhs_inner,")"]], + :mlhs_inner => [[:mlhs_basic], + ["(",:mlhs_inner,")"]], + :mlhs_basic => [[:mlhs_head], + [:mlhs_head,:mlhs_item], + [:mlhs_head,"*",:mlhs_node], + [:mlhs_head,"*",:mlhs_node,",",:mlhs_post], + [:mlhs_head,"*"], + [:mlhs_head,"*",",", :mlhs_post], + [ "*",:mlhs_node], + [ "*",:mlhs_node,",",:mlhs_post], + [ "*"], + [ "*",",", :mlhs_post]], + :mlhs_head => [[:mlhs_item,","], + [:mlhs_head,:mlhs_item,","]], + :mlhs_post => [[:mlhs_item], + [:mlhs_post,",",:mlhs_item]], + :mlhs_item => [[:mlhs_node], + ["(",:mlhs_inner,")"]], + :mlhs_node => [["var"]], + :xassign => [["var"," = ",:exp], + ["var"," = ",:mrhs], + [:mlhs," = ",:exp], + [:mlhs," = ",:mrhs]], + } + + def rename_var(obj) + vars = [] + r = obj.subst('var') { + var = "v#{vars.length}" + vars << var + var + } + return r, vars + end + + def expand_except_paren(obj) + return obj if obj.respond_to? :to_str + obj.expand {|s| + !(s[0] == '(' && s[-1] == ')') && + !(s[0] == '[' && s[-1] == ']') + } + end + + def extract_single_element(ary) + raise "not a single element array: #{ary.inspect}" if ary.length != 1 + ary[0] + end + + def emu_assign_ary(lhs, rv, h) + rv = rv.respond_to?(:to_ary) ? rv : [rv] + rv = rv.dup + a = [[]] + lhs.each {|e| + if e == ',' + a << [] + else + a.last << e + end + } + a.pop if a.last == [] + pre = [] + star = post = nil + a.each {|e| + if post + post << e + elsif e[0] == '*' + star = e + post = [] + else + pre << e + end + } + pre.map! {|e| extract_single_element(e) } + if star + if star == ['*'] + star = nil + else + star = extract_single_element(star[1..-1]) + end + end + post.map! {|e| extract_single_element(e) } if post + + until pre.empty? + emu_assign_single(pre.shift, rv.shift, h) + end + + if post + if rv.length < post.length + until post.empty? + emu_assign_single(post.shift, rv.shift, h) + end + else + until post.empty? + emu_assign_single(post.pop, rv.pop, h) + end + end + end + + if star + emu_assign_single(star, rv, h) + end + end + + def emu_assign_single(lhs, rv, h={}) + if lhs.respond_to? :to_str + if /\A[a-z0-9]+\z/ =~ lhs + h[lhs] = rv + else + raise "unexpected lhs string: #{lhs.inspect}" + end + elsif Sentence === lhs + if lhs[0] == '(' && lhs[-1] == ')' + emu_assign_ary(lhs[1...-1], rv, h) + elsif lhs.length == 1 && String === lhs[0] && /\A[a-z0-9]+\z/ =~ lhs[0] + h[lhs[0]] = rv + else + raise "unexpected lhs sentence: #{lhs.inspect}" + end + else + raise "unexpected lhs: #{lhs.inspect}" + end + h + end + + def emu_assign(assign) + lhs = expand_except_paren(assign[0]) + rhs = expand_except_paren(assign[2]) + lopen = Sentence === lhs && lhs[-1] != ')' && lhs.any? {|e| e == '*' || e == ',' } + ropen = Sentence === rhs && rhs[-1] != ']' && rhs.any? {|e| e == '*' || e == ',' } + lhs = Sentence.new(['(']+lhs.to_a+[')']) if lopen + begin + rv = eval((ropen ? ["[",assign[2],"]"] : assign[2]).join('')) + rescue Exception + rv = $!.message + end + emu_assign_single(lhs, rv) + end + + def do_assign(assign, vars) + assign = assign.to_s + code1 = "#{assign}; [#{vars.join(",")}]" + assign.gsub!(/\bv\d+\b/, "o.a") + code2 = "o=[];class << o; self end.send(:define_method,:a=){|v|self << v};#{assign};o" + begin + vals1 = eval(code1) + rescue Exception + return {:ex=>$!.message} + end + begin + vals2 = eval(code2) + rescue Exception + return {:ex=>$!.message} + end + assert_equal(vals1, vals2, code1) + vals = vals1 + h = {} + [vars, vals].transpose.each {|k,v| h[k] = v } + h + end + + def check(assign) + assign, vars = rename_var(assign) + sent = assign.to_s + bruby = do_assign(assign, vars).to_a.sort + bemu = emu_assign(assign).to_a.sort + assert_equal(bemu, bruby, sent) + end + + def test_assignment + syntax = Sentence.expand_syntax(Syntax) + Sentence.each(syntax, :xassign, 4) {|assign| + check(assign) + } + end + + def test_optimized_aset + bug9448 = Class.new do + def []=(key, new_value) + '[ruby-core:60071] [Bug #9448]' + end + end + o = bug9448.new + assert_equal("ok", o['current'] = "ok") + end +end diff --git a/jni/ruby/test/ruby/test_autoload.rb b/jni/ruby/test/ruby/test_autoload.rb new file mode 100644 index 0000000..da8855b --- /dev/null +++ b/jni/ruby/test/ruby/test_autoload.rb @@ -0,0 +1,207 @@ +require 'test/unit' +require 'tempfile' +require 'thread' + +class TestAutoload < Test::Unit::TestCase + def test_autoload_so + # Date is always available, unless excluded intentionally. + assert_in_out_err([], <<-INPUT, [], []) + autoload :Date, "date" + begin Date; rescue LoadError; end + INPUT + end + + def test_non_realpath_in_loadpath + require 'tmpdir' + tmpdir = Dir.mktmpdir('autoload') + tmpdirs = [tmpdir] + tmpdirs.unshift(tmpdir + '/foo') + Dir.mkdir(tmpdirs[0]) + tmpfiles = [tmpdir + '/foo.rb', tmpdir + '/foo/bar.rb'] + open(tmpfiles[0] , 'w') do |f| + f.puts <<-INPUT +$:.unshift(File.expand_path('..', __FILE__)+'/./foo') +module Foo + autoload :Bar, 'bar' +end +p Foo::Bar + INPUT + end + open(tmpfiles[1], 'w') do |f| + f.puts 'class Foo::Bar; end' + end + assert_in_out_err([tmpfiles[0]], "", ["Foo::Bar"], []) + ensure + File.unlink(*tmpfiles) rescue nil if tmpfiles + tmpdirs.each {|dir| Dir.rmdir(dir)} + end + + def test_autoload_p + bug4565 = '[ruby-core:35679]' + + require 'tmpdir' + Dir.mktmpdir('autoload') {|tmpdir| + tmpfile = tmpdir + '/foo.rb' + a = Module.new do + autoload :X, tmpfile + end + b = Module.new do + include a + end + assert_equal(true, a.const_defined?(:X)) + assert_equal(true, b.const_defined?(:X)) + assert_equal(tmpfile, a.autoload?(:X), bug4565) + assert_equal(tmpfile, b.autoload?(:X), bug4565) + } + end + + def test_autoload_with_unqualified_file_name # [ruby-core:69206] + lp = $LOAD_PATH.dup + lf = $LOADED_FEATURES.dup + + Dir.mktmpdir('autoload') { |tmpdir| + $LOAD_PATH << tmpdir + + Dir.chdir(tmpdir) do + eval <<-END + class ::Object + module A + autoload :C, 'b' + end + end + END + + File.open('b.rb', 'w') {|file| file.puts 'module A; class C; end; end'} + assert_kind_of Class, ::A::C + end + } + ensure + $LOAD_PATH.replace lp + $LOADED_FEATURES.replace lf + Object.send(:remove_const, :A) if Object.const_defined?(:A) + end + + def test_require_explicit + Tempfile.create(['autoload', '.rb']) {|file| + file.puts 'class Object; AutoloadTest = 1; end' + file.close + add_autoload(file.path) + begin + assert_nothing_raised do + assert(require file.path) + assert_equal(1, ::AutoloadTest) + end + ensure + remove_autoload_constant + end + } + end + + def test_threaded_accessing_constant + # Suppress "warning: loading in progress, circular require considered harmful" + EnvUtil.default_warning { + Tempfile.create(['autoload', '.rb']) {|file| + file.puts 'sleep 0.5; class AutoloadTest; X = 1; end' + file.close + add_autoload(file.path) + begin + assert_nothing_raised do + t1 = Thread.new { ::AutoloadTest::X } + t2 = Thread.new { ::AutoloadTest::X } + [t1, t2].each(&:join) + end + ensure + remove_autoload_constant + end + } + } + end + + def test_threaded_accessing_inner_constant + # Suppress "warning: loading in progress, circular require considered harmful" + EnvUtil.default_warning { + Tempfile.create(['autoload', '.rb']) {|file| + file.puts 'class AutoloadTest; sleep 0.5; X = 1; end' + file.close + add_autoload(file.path) + begin + assert_nothing_raised do + t1 = Thread.new { ::AutoloadTest::X } + t2 = Thread.new { ::AutoloadTest::X } + [t1, t2].each(&:join) + end + ensure + remove_autoload_constant + end + } + } + end + + def test_nameerror_when_autoload_did_not_define_the_constant + Tempfile.create(['autoload', '.rb']) {|file| + file.puts '' + file.close + add_autoload(file.path) + begin + assert_raise(NameError) do + AutoloadTest + end + ensure + remove_autoload_constant + end + } + end + + def test_override_autoload + Tempfile.create(['autoload', '.rb']) {|file| + file.puts '' + file.close + add_autoload(file.path) + begin + eval %q(class AutoloadTest; end) + assert_equal(Class, AutoloadTest.class) + ensure + remove_autoload_constant + end + } + end + + def test_override_while_autoloading + Tempfile.create(['autoload', '.rb']) {|file| + file.puts 'class AutoloadTest; sleep 0.5; end' + file.close + add_autoload(file.path) + begin + # while autoloading... + t = Thread.new { AutoloadTest } + sleep 0.1 + # override it + EnvUtil.suppress_warning { + eval %q(AutoloadTest = 1) + } + t.join + assert_equal(1, AutoloadTest) + ensure + remove_autoload_constant + end + } + end + + def add_autoload(path) + (@autoload_paths ||= []) << path + eval <<-END + class ::Object + autoload :AutoloadTest, #{path.dump} + end + END + end + + def remove_autoload_constant + $".replace($" - @autoload_paths) + eval <<-END + class ::Object + remove_const(:AutoloadTest) + end + END + end +end diff --git a/jni/ruby/test/ruby/test_backtrace.rb b/jni/ruby/test/ruby/test_backtrace.rb new file mode 100644 index 0000000..ad1ea80 --- /dev/null +++ b/jni/ruby/test/ruby/test_backtrace.rb @@ -0,0 +1,246 @@ +require 'test/unit' +require 'thread' + +class TestBacktrace < Test::Unit::TestCase + def test_exception + bt = Fiber.new{ + begin + raise + rescue => e + e.backtrace + end + }.resume + assert_equal(1, bt.size) + assert_match(/.+:\d+:.+/, bt[0]) + end + + def helper_test_exception_backtrace_locations + raise + end + + def test_exception_backtrace_locations + backtrace, backtrace_locations = Fiber.new{ + begin + raise + rescue => e + [e.backtrace, e.backtrace_locations] + end + }.resume + assert_equal(backtrace, backtrace_locations.map{|e| e.to_s}) + + backtrace, backtrace_locations = Fiber.new{ + begin + begin + helper_test_exception_backtrace_locations + rescue + raise + end + rescue => e + [e.backtrace, e.backtrace_locations] + end + }.resume + assert_equal(backtrace, backtrace_locations.map{|e| e.to_s}) + end + + def call_helper_test_exception_backtrace_locations + helper_test_exception_backtrace_locations(:bad_argument) + end + + def test_argument_error_backtrace_locations + backtrace, backtrace_locations = Fiber.new{ + begin + helper_test_exception_backtrace_locations(1) + rescue ArgumentError => e + [e.backtrace, e.backtrace_locations] + end + }.resume + assert_equal(backtrace, backtrace_locations.map{|e| e.to_s}) + + backtrace, backtrace_locations = Fiber.new{ + begin + call_helper_test_exception_backtrace_locations + rescue ArgumentError => e + [e.backtrace, e.backtrace_locations] + end + }.resume + assert_equal(backtrace, backtrace_locations.map{|e| e.to_s}) + end + + def test_caller_lev + cs = [] + Fiber.new{ + Proc.new{ + cs << caller(0) + cs << caller(1) + cs << caller(2) + cs << caller(3) + cs << caller(4) + cs << caller(5) + }.call + }.resume + assert_equal(3, cs[0].size) + assert_equal(2, cs[1].size) + assert_equal(1, cs[2].size) + assert_equal(0, cs[3].size) + assert_equal(nil, cs[4]) + + # + max = 7 + rec = lambda{|n| + if n > 0 + 1.times{ + rec[n-1] + } + else + (max*3).times{|i| + total_size = caller(0).size + c = caller(i) + if c + assert_equal(total_size - i, caller(i).size, "[ruby-dev:45673]") + end + } + end + } + Fiber.new{ + rec[max] + }.resume + end + + def test_caller_lev_and_n + m = 10 + rec = lambda{|n| + if n < 0 + (m*6).times{|lev| + (m*6).times{|i| + t = caller(0).size + r = caller(lev, i) + r = r.size if r.respond_to? :size + + # STDERR.puts [t, lev, i, r].inspect + if i == 0 + assert_equal(0, r, [t, lev, i, r].inspect) + elsif t < lev + assert_equal(nil, r, [t, lev, i, r].inspect) + else + if t - lev > i + assert_equal(i, r, [t, lev, i, r].inspect) + else + assert_equal(t - lev, r, [t, lev, i, r].inspect) + end + end + } + } + else + rec[n-1] + end + } + rec[m] + end + + def test_caller_with_nil_length + assert_equal caller(0), caller(0, nil) + end + + def test_caller_locations + cs = caller(0); locs = caller_locations(0).map{|loc| + loc.to_s + } + assert_equal(cs, locs) + end + + def test_caller_locations_with_range + cs = caller(0,2); locs = caller_locations(0..1).map { |loc| + loc.to_s + } + assert_equal(cs, locs) + end + + def test_caller_locations_to_s_inspect + cs = caller(0); locs = caller_locations(0) + cs.zip(locs){|str, loc| + assert_equal(str, loc.to_s) + assert_equal(str.inspect, loc.inspect) + } + end + + def th_rec q, n=10 + if n > 1 + th_rec q, n-1 + else + q.pop + end + end + + def test_thread_backtrace + begin + q = Queue.new + th = Thread.new{ + th_rec q + } + sleep 0.5 + th_backtrace = th.backtrace + th_locations = th.backtrace_locations + + assert_equal(10, th_backtrace.count{|e| e =~ /th_rec/}) + assert_equal(th_backtrace, th_locations.map{|e| e.to_s}) + assert_equal(th_backtrace, th.backtrace(0)) + assert_equal(th_locations.map{|e| e.to_s}, + th.backtrace_locations(0).map{|e| e.to_s}) + th_backtrace.size.times{|n| + assert_equal(n, th.backtrace(0, n).size) + assert_equal(n, th.backtrace_locations(0, n).size) + } + n = th_backtrace.size + assert_equal(n, th.backtrace(0, n + 1).size) + assert_equal(n, th.backtrace_locations(0, n + 1).size) + ensure + q << true + th.join + end + end + + def test_thread_backtrace_locations_with_range + begin + q = Queue.new + th = Thread.new{ + th_rec q + } + sleep 0.5 + bt = th.backtrace(0,2) + locs = th.backtrace_locations(0..1).map { |loc| + loc.to_s + } + assert_equal(bt, locs) + ensure + q << true + th.join + end + end + + def test_core_backtrace_alias + obj = BasicObject.new + e = assert_raise(NameError) do + class << obj + alias foo bar + end + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end + + def test_core_backtrace_undef + obj = BasicObject.new + e = assert_raise(NameError) do + class << obj + undef foo + end + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end + + def test_core_backtrace_hash_merge + e = assert_raise(TypeError) do + {**nil} + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end +end diff --git a/jni/ruby/test/ruby/test_basicinstructions.rb b/jni/ruby/test/ruby/test_basicinstructions.rb new file mode 100644 index 0000000..4a1dc9c --- /dev/null +++ b/jni/ruby/test/ruby/test_basicinstructions.rb @@ -0,0 +1,700 @@ +require 'test/unit' + +ConstTest = 3 +class Class + alias _remove_const remove_const + public :_remove_const +end + +class TestBasicInstructions < Test::Unit::TestCase + + def test_immediates + assert_equal((1==1), true) + assert_equal((1==2), false) + assert_equal [][0], nil + assert_equal "sym".intern, :sym + assert_equal "sym".intern, :"sym" + assert_equal 1234 + 0, 1234 + assert_equal 1234, 1_2_3_4 + assert_equal 41, 0b0101001 + assert_equal 420, 0644 + assert_equal 18, 0x12 + assert_equal 123456789012345678901234567890 + 0, + 123456789012345678901234567890 + assert_equal 1.234 + 0.0, 1.234 + end + + def test_self + assert_equal self, self + assert_equal false, (self == false) # Qfalse==0 in C + assert_equal false, (self == nil) + assert_equal false, (self == 0) + end + + def test_string + expected = "str" + "ing" + assert_equal expected, 'string' + assert_equal expected, "string" + assert_equal expected, %q(string) + assert_equal expected, %Q(string) + assert_equal expected, %(string) + end + + def test_dstring + assert_equal "2", "#{1+1}" + s = "OK" + assert_equal "OK", "#{s}" + assert_equal "OKx", "#{s}x" + assert_equal "xOK", "x#{s}" + assert_equal "xOKx", "x#{s}x" + end + + def test_dsym + assert_equal :a3c, :"a#{1+2}c" + s = "sym" + assert_equal :sym, :"#{s}" + assert_equal :sym, :"#{"#{"#{s}"}"}" + end + + def test_xstr + assert_equal 'hoge', `echo hoge`.chomp + assert_equal '3', `echo #{1 + 2}`.chomp + hoge = 'huga' + assert_equal 'huga', `echo #{hoge}`.chomp + end + + def test_regexp + assert_equal(/test/, /test/) + assert_equal 'test', /test/.source + assert_equal 'TEST', /TEST/.source + assert_equal true, !!(/test/ =~ 'test') + assert_equal false, !!(/test/ =~ 'does not match') + + re = /test/ + assert_equal re, re + assert_equal 'test', re.source + assert_equal true, !!(re =~ 'test') + assert_equal false, !!(re =~ 'does not match') + + assert_equal(/x#{1+1}x/, /x#{1+1}x/) + s = "OK" + assert_equal(/x#{s}x/, /x#{s}x/) + assert_equal true, !!(/x#{s}x/ =~ "xOKx") + assert_equal false, !!(/x#{s}x/ =~ "does not match") + + s = "OK" + prev = nil + 3.times do + re = /#{s}/o + assert_same prev, re if prev + prev = re + end + end + + def test_array + assert_equal [], [] + assert_equal 0, [].size + assert_equal [1, 2, 3], [1, 2, 3] + assert_equal [3, 7, 11], [1+2, 3+4, 5+6] + assert_equal [[1], [2], [3]], [[1], [2], [3]] + + a = [1, 2, 3] + assert_equal 1, a[0] + assert_equal 2, a[1] + assert_equal 3, a[2] + assert_nil a[3] + + a = %w( a b c ) + assert_equal 'a', a[0] + assert_equal 'b', a[1] + assert_equal 'c', a[2] + assert_nil a[3] + end + + def test_hash + assert_equal({}, {}) + assert_equal({1=>2}, {1=>2}) + assert_equal({1=>2, 3=>4}, {1=>2, 3=>4}) + assert_equal({1=>2, 3=>4}, {3=>4, 1=>2}) + # assert_equal({1=>2, 3=>4}, {1,2, 3,4}) # 1.9 doesn't support + assert_equal({"key"=>"val"}, {"key"=>"val"}) + end + + def test_range + assert_equal((1..3), (1..3)) + assert_equal((1...3), (1...3)) + assert_not_equal((1...3), (1..3)) + assert_not_equal((1..3), (1...3)) + assert_equal((1..3), (1..2+1)) + assert_equal((1...3), (1...2+1)) + assert_equal(('a'..'z'), ('a'..'z')) + end + + def test_not + assert_equal true, !nil + assert_equal true, !false + assert_equal false, !true + assert_equal false, !3 + assert_equal false, !(1+1) + + assert_equal false, !!nil + assert_equal false, !!false + assert_equal true, !!true + assert_equal true, !!3 + assert_equal true, !!(1+1) + + assert_equal true, (not nil) + assert_equal true, (not false) + assert_equal false, (not true) + assert_equal false, (not 3) + assert_equal false, (not (1 + 1)) + + assert_equal false, (not not nil) + assert_equal false, (not not false) + assert_equal true, (not not true) + assert_equal true, (not not 3) + assert_equal true, (not not (1+1)) + end + + def test_local_variable + a = 7 + assert_equal 7, a + assert_equal a, a + b = 17 + assert_equal 7, a + assert_equal 17, b + assert_equal a, a + assert_equal b, b + assert_not_equal a, b + assert_not_equal b, a + a = b + assert_equal 17, a + assert_equal 17, b + assert_equal a, a + assert_equal b, b + assert_equal a, b + assert_equal b, a + c = 28 + assert_equal 17, a + assert_equal 17, b + assert_equal 28, c + assert_equal a, a + assert_equal b, b + assert_equal a, b + assert_equal c, c + assert_not_equal a, c + assert_not_equal b, c + a = b = c + assert_equal 28, a + assert_equal 28, b + assert_equal 28, c + assert_equal a, a + assert_equal b, b + assert_equal a, b + assert_equal b, a + assert_equal a, c + assert_equal c, a + assert_equal b, c + assert_equal c, b + + a = 1 + b = 2 + c = 3 + set_lvar_in_another_method + assert_equal 1, a + assert_equal 2, b + assert_equal 3, c + end + + def set_lvar_in_another_method + assert_raise(NameError) { a } + assert_raise(NameError) { b } + assert_raise(NameError) { c } + a = "NOT OK" + b = "NOT OK" + c = "NOT OK" + end + + class Const + $Const = self + C = 'Const::C' + def self.c() C end + def c() C end + + class A + C = 'Const::A::C' + def self.c() C end + def c() C end + CC = 'Const::A::CC' + def self.cc() CC end + def cc() CC end + + class B + C = 'Const::A::B::C' + def self.c() C end + def c() C end + def self.cc() CC end + def cc() CC end + end + end + + class AA < A + def self.cc() CC end + def cc() CC end + end + + class AAA < AA + def self.cc() CC end + def cc() CC end + end + end + C = 0 + + def test_const_path + do_test_const_path + do_test_const_path + do_test_const_path + end + + def do_test_const_path + assert_equal 0, C + assert_equal 0, C + assert_equal 3, ::ConstTest + assert_equal 3, ::ConstTest + assert_equal $Const, Const + + assert_equal 'Const::C', Const::C + assert_equal 'Const::C', Const::C + assert_equal 'Const::A::C', Const::A::C + assert_equal 'Const::A::C', Const::A::C + assert_equal 'Const::A::B::C', Const::A::B::C + assert_equal 'Const::A::B::C', Const::A::B::C + + Const::A::B._remove_const :C + assert_equal 'Const::C', Const::C + assert_equal 'Const::A::C', Const::A::C + assert_raise(NameError) { Const::A::B::C } + + Const::A._remove_const :C + assert_equal 'Const::C', Const::C + assert_raise(NameError) { Const::A::C } + assert_raise(NameError) { Const::A::B::C } + + Const._remove_const :C + assert_raise(NameError) { Const::C } + assert_raise(NameError) { Const::A::C } + assert_raise(NameError) { Const::A::B::C } + + Const::A.const_set :C, 'Const::A::C' + assert_raise(NameError) { Const::C } + assert_equal 'Const::A::C', Const::A::C + assert_raise(NameError) { Const::A::B::C } + + Const::A::B.const_set :C, 'Const::A::B::C' + assert_raise(NameError) { Const::C } + assert_equal 'Const::A::C', Const::A::C + assert_equal 'Const::A::B::C', Const::A::B::C + + Const.const_set :C, 'Const::C' + assert_equal 'Const::C', Const::C + assert_equal 'Const::A::C', Const::A::C + assert_equal 'Const::A::B::C', Const::A::B::C + end + + def test_const_cref + do_test_const_cref + do_test_const_cref + do_test_const_cref + end + + def do_test_const_cref + assert_equal 'Const::C', Const.new.c + assert_equal 'Const::A::C', Const::A.new.c + assert_equal 'Const::A::B::C', Const::A::B.new.c + + assert_equal 'Const::C', Const.c + assert_equal 'Const::A::C', Const::A.c + assert_equal 'Const::A::B::C', Const::A::B.c + + Const::A::B._remove_const :C + assert_equal 'Const::C', Const.c + assert_equal 'Const::A::C', Const::A.c + assert_equal 'Const::A::C', Const::A::B.c + assert_equal 'Const::C', Const.new.c + assert_equal 'Const::A::C', Const::A.new.c + assert_equal 'Const::A::C', Const::A::B.new.c + + Const::A._remove_const :C + assert_equal 'Const::C', Const.c + assert_equal 'Const::C', Const::A.c + assert_equal 'Const::C', Const::A::B.c + assert_equal 'Const::C', Const.new.c + assert_equal 'Const::C', Const::A.new.c + assert_equal 'Const::C', Const::A::B.new.c + + Const::A::B.const_set :C, 'Const::A::B::C' + assert_equal 'Const::C', Const.c + assert_equal 'Const::C', Const::A.c + assert_equal 'Const::A::B::C', Const::A::B.c + assert_equal 'Const::C', Const.new.c + assert_equal 'Const::C', Const::A.new.c + assert_equal 'Const::A::B::C', Const::A::B.new.c + + Const::A.const_set :C, 'Const::A::C' + assert_equal 'Const::C', Const.c + assert_equal 'Const::A::C', Const::A.c + assert_equal 'Const::A::B::C', Const::A::B.c + assert_equal 'Const::C', Const.new.c + assert_equal 'Const::A::C', Const::A.new.c + assert_equal 'Const::A::B::C', Const::A::B.new.c + ensure + # reset + Const.const_set :C, 'Const::C' unless Const.const_defined?(:C) + Const::A.const_set :C, 'Const::A::C' unless Const::A.const_defined?(:C) + Const::A::B.const_set :C, 'Const::A::B::C' unless Const::A::B.const_defined?(:C) + end + + def test_const_inherit + do_test_const_inherit + do_test_const_inherit + do_test_const_inherit + end + + def do_test_const_inherit + assert_equal 'Const::A::CC', Const::A.cc + assert_equal 'Const::A::CC', Const::AA.cc + assert_equal 'Const::A::CC', Const::AAA.cc + assert_equal 'Const::A::CC', Const::A.new.cc + assert_equal 'Const::A::CC', Const::AA.new.cc + assert_equal 'Const::A::CC', Const::AAA.new.cc + + Const::AA.const_set :CC, 'Const::AA::CC' + assert_equal 'Const::A::CC', Const::A.cc + assert_equal 'Const::AA::CC', Const::AA.cc + assert_equal 'Const::AA::CC', Const::AAA.cc + assert_equal 'Const::A::CC', Const::A.new.cc + assert_equal 'Const::AA::CC', Const::AA.new.cc + assert_equal 'Const::AA::CC', Const::AAA.new.cc + + Const::AAA.const_set :CC, 'Const::AAA::CC' + assert_equal 'Const::A::CC', Const::A.cc + assert_equal 'Const::AA::CC', Const::AA.cc + assert_equal 'Const::AAA::CC', Const::AAA.cc + assert_equal 'Const::A::CC', Const::A.new.cc + assert_equal 'Const::AA::CC', Const::AA.new.cc + assert_equal 'Const::AAA::CC', Const::AAA.new.cc + + Const::AA._remove_const :CC + assert_equal 'Const::A::CC', Const::A.cc + assert_equal 'Const::A::CC', Const::AA.cc + assert_equal 'Const::AAA::CC', Const::AAA.cc + assert_equal 'Const::A::CC', Const::A.new.cc + assert_equal 'Const::A::CC', Const::AA.new.cc + assert_equal 'Const::AAA::CC', Const::AAA.new.cc + + Const::AAA._remove_const :CC + assert_equal 'Const::A::CC', Const::A.cc + assert_equal 'Const::A::CC', Const::AA.cc + assert_equal 'Const::A::CC', Const::AAA.cc + assert_equal 'Const::A::CC', Const::A.new.cc + assert_equal 'Const::A::CC', Const::AA.new.cc + assert_equal 'Const::A::CC', Const::AAA.new.cc + end + + def test_global_variable + $gvar1 = 1 + assert_equal 1, $gvar1 + $gvar1 = 2 + assert_equal 2, $gvar1 + $gvar2 = 77 + assert_equal 2, $gvar1 + assert_equal 77, $gvar2 + $gvar2 = $gvar1 + assert_equal 2, $gvar1 + assert_equal 2, $gvar2 + $gvar1 = 1 + assert_equal 1, $gvar1 + assert_equal 2, $gvar2 + set_gvar_in_another_method + assert_equal "OK1", $gvar1 + assert_equal "OK2", $gvar2 + end + + def set_gvar_in_another_method + assert_equal 1, $gvar1 + assert_equal 2, $gvar2 + $gvar1 = "OK1" + $gvar2 = "OK2" + end + + class CVarA + @@cv = 'CVarA@@cv' + def self.cv() @@cv end + def self.cv=(v) @@cv = v end + class << self + def cv2() @@cv end + end + def cv() @@cv end + def cv=(v) @@cv = v end + end + + class CVarB < CVarA + def self.cvB() @@cv end + def self.cvB=(v) @@cv = v end + class << self + def cvB2() @@cv end + end + def cvB() @@cv end + def cvB=(v) @@cv = v end + end + + def test_class_variable + assert_equal 'CVarA@@cv', CVarA.cv + assert_equal 'CVarA@@cv', CVarA.cv2 + assert_equal 'CVarA@@cv', CVarA.new.cv + CVarA.cv = 'singleton' + assert_equal 'singleton', CVarA.cv + assert_equal 'singleton', CVarA.cv2 + assert_equal 'singleton', CVarA.new.cv + CVarA.new.cv = 'instance' + assert_equal 'instance', CVarA.cv + assert_equal 'instance', CVarA.cv2 + assert_equal 'instance', CVarA.new.cv + + CVarA.cv = 'CVarA@@cv' + CVarB.cv = 'B/singleton' + assert_equal 'B/singleton', CVarB.cv + assert_equal 'B/singleton', CVarB.cv2 + assert_equal 'B/singleton', CVarB.new.cv + assert_equal 'B/singleton', CVarA.cv + assert_equal 'B/singleton', CVarA.cv2 + assert_equal 'B/singleton', CVarA.new.cv + CVarB.new.cv = 'B/instance' + assert_equal 'B/instance', CVarB.cv + assert_equal 'B/instance', CVarB.cv2 + assert_equal 'B/instance', CVarB.new.cv + assert_equal 'B/instance', CVarA.cv + assert_equal 'B/instance', CVarA.cv2 + assert_equal 'B/instance', CVarA.new.cv + + CVarA.cv = 'CVarA@@cv' + assert_equal('CVarA@@cv', CVarB.cvB) + assert_equal('CVarA@@cv', CVarB.cvB2) + assert_equal('CVarA@@cv', CVarB.new.cvB) + CVarB.cvB = 'B/singleton' + assert_equal 'B/singleton', CVarB.cvB + assert_equal 'B/singleton', CVarB.cvB2 + assert_equal 'B/singleton', CVarB.new.cvB + assert_equal 'B/singleton', CVarA.cv + assert_equal 'B/singleton', CVarA.cv2 + assert_equal 'B/singleton', CVarA.new.cv + CVarB.new.cvB = 'B/instance' + assert_equal 'B/instance', CVarB.cvB + assert_equal 'B/instance', CVarB.cvB2 + assert_equal 'B/instance', CVarB.new.cvB + assert_equal 'B/instance', CVarA.cv + assert_equal 'B/instance', CVarA.cv2 + assert_equal 'B/instance', CVarA.new.cv + + CVarA.cv = 'CVarA@@cv' + CVarB.cvB = 'CVarB@@cv' + end + + class OP + attr_reader :x + attr_accessor :foo + def x=(x) + @x = x + :Bug1996 + end + Bug1996 = '[ruby-dev:39163], [ruby-core:25143]' + def [](i) + @x + end + def []=(i, x) + @x = x + :Bug2050 + end + Bug2050 = '[ruby-core:25387]' + end + + def test_opassign2_1 + x = nil + assert_equal 1, x ||= 1 + assert_equal 1, x + assert_equal 2, x &&= 2 + assert_equal 2, x + assert_equal 2, x ||= 3 + assert_equal 2, x + assert_equal 4, x &&= 4 + assert_equal 4, x + assert_equal 5, x += 1 + assert_equal 5, x + assert_equal 4, x -= 1 + assert_equal 4, x + end + + def test_opassign2_2 + y = OP.new + y.x = nil + assert_equal 1, y.x ||= 1, OP::Bug1996 + assert_equal 1, y.x + assert_equal 2, y.x &&= 2, OP::Bug1996 + assert_equal 2, y.x + assert_equal 2, y.x ||= 3 + assert_equal 2, y.x + assert_equal 4, y.x &&= 4, OP::Bug1996 + assert_equal 4, y.x + assert_equal 5, y.x += 1, OP::Bug1996 + assert_equal 5, y.x + assert_equal 4, y.x -= 1, OP::Bug1996 + assert_equal 4, y.x + end + + def test_opassign2_3 + z = OP.new + z.x = OP.new + z.x.x = nil + assert_equal 1, z.x.x ||= 1, OP::Bug1996 + assert_equal 1, z.x.x + assert_equal 2, z.x.x &&= 2, OP::Bug1996 + assert_equal 2, z.x.x + assert_equal 2, z.x.x ||= 3 + assert_equal 2, z.x.x + assert_equal 4, z.x.x &&= 4, OP::Bug1996 + assert_equal 4, z.x.x + assert_equal 5, z.x.x += 1, OP::Bug1996 + assert_equal 5, z.x.x + assert_equal 4, z.x.x -= 1, OP::Bug1996 + assert_equal 4, z.x.x + end + + def test_opassign1_1 + a = [] + a[0] = nil + assert_equal 1, a[0] ||= 1 + assert_equal 1, a[0] + assert_equal 2, a[0] &&= 2 + assert_equal 2, a[0] + assert_equal 2, a[0] ||= 3 + assert_equal 2, a[0] + assert_equal 4, a[0] &&= 4 + assert_equal 4, a[0] + assert_equal 5, a[0] += 1 + assert_equal 5, a[0] + assert_equal 4, a[0] -= 1 + assert_equal 4, a[0] + end + + def test_opassign1_2 + x = OP.new + x[0] = nil + assert_equal 1, x[0] ||= 1, OP::Bug2050 + assert_equal 1, x[0] + assert_equal 2, x[0] &&= 2, OP::Bug2050 + assert_equal 2, x[0] + assert_equal 2, x[0] ||= 3, OP::Bug2050 + assert_equal 2, x[0] + assert_equal 4, x[0] &&= 4, OP::Bug2050 + assert_equal 4, x[0] + assert_equal 5, x[0] += 1, OP::Bug2050 + assert_equal 5, x[0] + assert_equal 4, x[0] -= 1, OP::Bug2050 + assert_equal 4, x[0] + end + + def test_send_opassign + return if defined?(RUBY_ENGINE) and RUBY_ENGINE != "ruby" + + bug7773 = '[ruby-core:51821]' + x = OP.new + assert_equal 42, x.foo = 42, bug7773 + assert_equal 42, x.foo, bug7773 + assert_equal -6, x.send(:foo=, -6), bug7773 + assert_equal -6, x.foo, bug7773 + assert_equal :Bug1996, x.send(:x=, :case_when_setter_returns_other_value), bug7773 + assert_equal :case_when_setter_returns_other_value, x.x, bug7773 + end + + def test_backref + /re/ =~ 'not match' + assert_nil $~ + assert_nil $` + assert_nil $& + assert_nil $' + assert_nil $+ + assert_nil $1 + assert_nil $2 + assert_nil $3 + assert_nil $4 + assert_nil $5 + assert_nil $6 + assert_nil $7 + assert_nil $8 + assert_nil $9 + + /(a)(b)(c)(d)(e)(f)(g)(h)(i)/ =~ 'xabcdefghiy' + assert_not_nil $~ + assert_instance_of MatchData, $~ + assert_equal 'abcdefghi', $~[0] + assert_equal 'a', $~[1] + assert_equal 'b', $~[2] + assert_equal 'c', $~[3] + assert_equal 'd', $~[4] + assert_equal 'e', $~[5] + assert_equal 'f', $~[6] + assert_equal 'g', $~[7] + assert_equal 'h', $~[8] + assert_equal 'i', $~[9] + assert_equal 'x', $` + assert_equal 'abcdefghi', $& + assert_equal "y", $' + assert_equal 'i', $+ + assert_equal 'a', $1 + assert_equal 'b', $2 + assert_equal 'c', $3 + assert_equal 'd', $4 + assert_equal 'e', $5 + assert_equal 'f', $6 + assert_equal 'g', $7 + assert_equal 'h', $8 + assert_equal 'i', $9 + + /re/ =~ 'not match' + assert_nil $~ + assert_nil $` + assert_nil $& + assert_nil $' + assert_nil $+ + assert_nil $1 + assert_nil $2 + assert_nil $3 + assert_nil $4 + assert_nil $5 + assert_nil $6 + assert_nil $7 + assert_nil $8 + assert_nil $9 + end + + def test_array_splat + feature1125 = '[ruby-core:21901]' + + a = [] + assert_equal [], [*a] + assert_equal [1], [1, *a] + assert_not_same(a, [*a], feature1125) + a = [2] + assert_equal [2], [*a] + assert_equal [1, 2], [1, *a] + assert_not_same(a, [*a], feature1125) + a = [2, 3] + assert_equal [2, 3], [*a] + assert_equal [1, 2, 3], [1, *a] + assert_not_same(a, [*a], feature1125) + + a = nil + assert_equal [], [*a] + assert_equal [1], [1, *a] + end +end diff --git a/jni/ruby/test/ruby/test_beginendblock.rb b/jni/ruby/test/ruby/test_beginendblock.rb new file mode 100644 index 0000000..9c9d6b5 --- /dev/null +++ b/jni/ruby/test/ruby/test_beginendblock.rb @@ -0,0 +1,190 @@ +require 'test/unit' +require 'tempfile' +require 'timeout' + +class TestBeginEndBlock < Test::Unit::TestCase + DIR = File.dirname(File.expand_path(__FILE__)) + + def q(content) + "\"#{content}\"" + end + + def test_beginendblock + ruby = EnvUtil.rubybin + target = File.join(DIR, 'beginmainend.rb') + result = IO.popen([ruby, target]){|io|io.read} + assert_equal(%w(b1 b2-1 b2 main b3-1 b3 b4 e1 e1-1 e4 e4-2 e4-1 e4-1-1 e3 e2), result.split) + + Tempfile.create(self.class.name) {|input| + inputpath = input.path + result = IO.popen([ruby, "-n", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read} + assert_equal(%w(:begin), result.split) + result = IO.popen([ruby, "-p", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read} + assert_equal(%w(:begin), result.split) + input.puts "foo\nbar" + input.close + result = IO.popen([ruby, "-n", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read} + assert_equal(%w(:begin :end), result.split) + result = IO.popen([ruby, "-p", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read} + assert_equal(%w(:begin foo bar :end), result.split) + } + end + + def test_begininmethod + assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do + eval("def foo; BEGIN {}; end") + end + + assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do + eval('eval("def foo; BEGIN {}; end")') + end + end + + def test_begininclass + assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do + eval("class TestBeginEndBlock; BEGIN {}; end") + end + end + + def test_endblockwarn + ruby = EnvUtil.rubybin + # Use Tempfile to create temporary file path. + Tempfile.create(self.class.name) {|launcher| + Tempfile.create(self.class.name) {|errout| + + launcher << <<EOF +# -*- coding: #{ruby.encoding.name} -*- +errout = ARGV.shift +STDERR.reopen(File.open(errout, "w")) +STDERR.sync = true +Dir.chdir(#{q(DIR)}) +system("#{ruby}", "endblockwarn_rb") +EOF + launcher.close + launcherpath = launcher.path + errout.close + erroutpath = errout.path + system(ruby, launcherpath, erroutpath) + expected = <<EOW +endblockwarn_rb:2: warning: END in method; use at_exit +(eval):2: warning: END in method; use at_exit +EOW + assert_equal(expected, File.read(erroutpath)) + } + } + end + + def test_raise_in_at_exit + ruby = EnvUtil.rubybin + out = IO.popen([ruby, '-e', 'STDERR.reopen(STDOUT)', + '-e', 'at_exit{raise %[SomethingBad]}', + '-e', 'raise %[SomethingElse]']) {|f| + f.read + } + status = $? + assert_match(/SomethingBad/, out, "[ruby-core:9675]") + assert_match(/SomethingElse/, out, "[ruby-core:9675]") + assert_not_predicate(status, :success?) + end + + def test_exitcode_in_at_exit + bug8501 = '[ruby-core:55365] [Bug #8501]' + ruby = EnvUtil.rubybin + out = IO.popen([ruby, '-e', 'STDERR.reopen(STDOUT)', + '-e', 'o = Object.new; def o.inspect; raise "[Bug #8501]"; end', + '-e', 'at_exit{o.nope}']) {|f| + f.read + } + status = $? + assert_match(/undefined method `nope'/, out, bug8501) + assert_not_predicate(status, :success?, bug8501) + end + + def test_propagate_exit_code + ruby = EnvUtil.rubybin + assert_equal false, system(ruby, '-e', 'at_exit{exit 2}') + assert_equal 2, $?.exitstatus + assert_nil $?.termsig + end + + def test_propagate_signaled + ruby = EnvUtil.rubybin + out = IO.popen( + [ruby, + '-e', 'trap(:INT, "DEFAULT")', + '-e', 'STDERR.reopen(STDOUT)', + '-e', 'at_exit{Process.kill(:INT, $$); sleep 5 }']) {|f| + timeout(10) { + f.read + } + } + assert_match(/Interrupt$/, out) + Process.kill(0, 0) rescue return # check if signal works + assert_nil $?.exitstatus + assert_equal Signal.list["INT"], $?.termsig + end + + def test_endblock_raise + ruby = EnvUtil.rubybin + th = nil + out = IO.popen( + [ruby, + '-e', 'class C; def write(x); puts x; STDOUT.flush; sleep 0.01; end; end', + '-e', '$stderr = C.new', + '-e', 'END {raise "e1"}; END {puts "e2"}', + '-e', 'END {raise "e3"}; END {puts "e4"}', + '-e', 'END {raise "e5"}; END {puts "e6"}']) {|f| + th = Thread.new {sleep 5; Process.kill :KILL, f.pid} + f.read + } + assert_match(/e1/, out) + assert_match(/e6/, out) + ensure + th.kill.join if th.alive? + end + + def test_nested_at_exit + Tempfile.create(["test_nested_at_exit_", ".rb"]) {|t| + t.puts "at_exit { puts :outer0 }" + t.puts "at_exit { puts :outer1_begin; at_exit { puts :inner1 }; puts :outer1_end }" + t.puts "at_exit { puts :outer2_begin; at_exit { puts :inner2 }; puts :outer2_end }" + t.puts "at_exit { puts :outer3 }" + t.flush + + expected = [ "outer3", + "outer2_begin", + "outer2_end", + "inner2", + "outer1_begin", + "outer1_end", + "inner1", + "outer0" ] + + assert_in_out_err(t.path, "", expected, [], "[ruby-core:35237]") + } + end + + def test_rescue_at_exit + bug5218 = '[ruby-core:43173][Bug #5218]' + cmd = [ + "raise 'X' rescue nil", + "nil", + "exit(42)", + ] + %w[at_exit END].each do |ex| + out, err, status = EnvUtil.invoke_ruby(cmd.map {|s|["-e", "#{ex} {#{s}}"]}.flatten, "", true, true) + assert_equal(["", "", 42], [out, err, status.exitstatus], "#{bug5218}: #{ex}") + end + end + + def test_callcc_at_exit + bug9110 = '[ruby-core:58329][Bug #9110]' + script = <<EOS +require "continuation" +c = nil +at_exit { c.call } +at_exit { callcc {|_c| c = _c } } +EOS + assert_normal_exit(script, bug9110) + end +end diff --git a/jni/ruby/test/ruby/test_bignum.rb b/jni/ruby/test/ruby/test_bignum.rb new file mode 100644 index 0000000..2c6eda0 --- /dev/null +++ b/jni/ruby/test/ruby/test_bignum.rb @@ -0,0 +1,711 @@ +require 'test/unit' + +class TestBignum < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + @fmax = Float::MAX.to_i + @fmax2 = @fmax * 2 + @big = (1 << 63) - 1 + end + + def teardown + $VERBOSE = @verbose + end + + def fact(n) + return 1 if n == 0 + f = 1 + while n>0 + f *= n + n -= 1 + end + return f + end + + def test_bignum + $x = fact(40) + assert_equal($x, $x) + assert_equal($x, fact(40)) + assert_operator($x, :<, $x+2) + assert_operator($x, :>, $x-2) + assert_equal(815915283247897734345611269596115894272000000000, $x) + assert_not_equal(815915283247897734345611269596115894272000000001, $x) + assert_equal(815915283247897734345611269596115894272000000001, $x+1) + assert_equal(335367096786357081410764800000, $x/fact(20)) + $x = -$x + assert_equal(-815915283247897734345611269596115894272000000000, $x) + assert_equal(2-(2**32), -(2**32-2)) + assert_equal(2**32 - 5, (2**32-3)-2) + + for i in 1000..1014 + assert_equal(2 ** i, 1 << i) + end + + n1 = 1 << 1000 + for i in 1000..1014 + assert_equal(n1, 1 << i) + n1 *= 2 + end + + n2=n1 + for i in 1..10 + n1 = n1 / 2 + n2 = n2 >> 1 + assert_equal(n1, n2) + end + + for i in 4000..4096 + n1 = 1 << i; + assert_equal(n1-1, (n1**2-1) / (n1+1)) + end + end + + def test_calc + b = 10**80 + a = b * 9 + 7 + assert_equal(7, a.modulo(b)) + assert_equal(-b + 7, a.modulo(-b)) + assert_equal(b + -7, (-a).modulo(b)) + assert_equal(-7, (-a).modulo(-b)) + assert_equal(7, a.remainder(b)) + assert_equal(7, a.remainder(-b)) + assert_equal(-7, (-a).remainder(b)) + assert_equal(-7, (-a).remainder(-b)) + + assert_equal(10000000000000000000100000000000000000000, 10**40+10**20) + assert_equal(100000000000000000000, 10**40/10**20) + + a = 677330545177305025495135714080 + b = 14269972710765292560 + assert_equal(0, a % b) + assert_equal(0, -a % b) + end + + def shift_test(a) + b = a / (2 ** 32) + c = a >> 32 + assert_equal(b, c) + + b = a * (2 ** 32) + c = a << 32 + assert_equal(b, c) + end + + def test_shift + shift_test(-4518325415524767873) + shift_test(-0xfffffffffffffffff) + end + + def test_to_s + assert_equal("fvvvvvvvvvvvv" ,18446744073709551615.to_s(32), "[ruby-core:10686]") + assert_equal("g000000000000" ,18446744073709551616.to_s(32), "[ruby-core:10686]") + assert_equal("3w5e11264sgsf" ,18446744073709551615.to_s(36), "[ruby-core:10686]") + assert_equal("3w5e11264sgsg" ,18446744073709551616.to_s(36), "[ruby-core:10686]") + assert_equal("nd075ib45k86f" ,18446744073709551615.to_s(31), "[ruby-core:10686]") + assert_equal("nd075ib45k86g" ,18446744073709551616.to_s(31), "[ruby-core:10686]") + assert_equal("1777777777777777777777" ,18446744073709551615.to_s(8)) + assert_equal("-1777777777777777777777" ,-18446744073709551615.to_s(8)) + assert_match(/\A10{99}1\z/, (10**100+1).to_s) + assert_match(/\A10{900}9{100}\z/, (10**1000+(10**100-1)).to_s) + end + + b = 2**64 + b *= b until Bignum === b + + T_ZERO = b.coerce(0).first + T_ONE = b.coerce(1).first + T_MONE = b.coerce(-1).first + T31 = b.coerce(2**31).first # 2147483648 + T31P = b.coerce(T31 - 1).first # 2147483647 + T32 = b.coerce(2**32).first # 4294967296 + T32P = b.coerce(T32 - 1).first # 4294967295 + T64 = b.coerce(2**64).first # 18446744073709551616 + T64P = b.coerce(T64 - 1).first # 18446744073709551615 + T1024 = b.coerce(2**1024).first + T1024P = b.coerce(T1024 - 1).first + + f = b + while Bignum === f-1 + f = f >> 1 + end + FIXNUM_MAX = f-1 + + def test_prepare + assert_instance_of(Bignum, T_ZERO) + assert_instance_of(Bignum, T_ONE) + assert_instance_of(Bignum, T_MONE) + assert_instance_of(Bignum, T31) + assert_instance_of(Bignum, T31P) + assert_instance_of(Bignum, T32) + assert_instance_of(Bignum, T32P) + assert_instance_of(Bignum, T64) + assert_instance_of(Bignum, T64P) + assert_instance_of(Bignum, T1024) + assert_instance_of(Bignum, T1024P) + end + + def test_big_2comp + assert_equal("-4294967296", (~T32P).to_s) + assert_equal("..f00000000", "%x" % -T32) + end + + def test_int2inum + assert_equal([T31P], [T31P].pack("I").unpack("I")) + assert_equal([T31P], [T31P].pack("i").unpack("i")) + end + + def test_quad_pack + assert_equal([ 1], [ 1].pack("q").unpack("q")) + assert_equal([- 1], [- 1].pack("q").unpack("q")) + assert_equal([ T31P], [ T31P].pack("q").unpack("q")) + assert_equal([-T31P], [-T31P].pack("q").unpack("q")) + assert_equal([ T64P], [ T64P].pack("Q").unpack("Q")) + assert_equal([ 0], [ T64 ].pack("Q").unpack("Q")) + end + + def test_str_to_inum + assert_equal(1, " +1".to_i) + assert_equal(-1, " -1".to_i) + assert_equal(0, "++1".to_i) + assert_equal(73, "111".oct) + assert_equal(273, "0x111".oct) + assert_equal(7, "0b111".oct) + assert_equal(73, "0o111".oct) + assert_equal(111, "0d111".oct) + assert_equal(73, "0111".oct) + assert_equal(111, Integer("111")) + assert_equal(13, "111".to_i(3)) + assert_raise(ArgumentError) { "111".to_i(37) } + assert_equal(1333, "111".to_i(36)) + assert_equal(1057, "111".to_i(32)) + assert_equal(0, "00a".to_i) + assert_equal(1, Integer("1 ")) + assert_raise(ArgumentError) { Integer("1_") } + assert_raise(ArgumentError) { Integer("1__") } + assert_raise(ArgumentError) { Integer("1_0 x") } + assert_equal(T31P, "1111111111111111111111111111111".to_i(2)) + assert_equal(0_2, '0_2'.to_i) + assert_equal(00_2, '00_2'.to_i) + assert_equal(00_02, '00_02'.to_i) + end + + def test_to_s2 + assert_raise(ArgumentError) { T31P.to_s(37) } + assert_equal("9" * 32768, (10**32768-1).to_s) + assert_raise(RangeError) { Process.wait(1, T64P) } + assert_equal("0", T_ZERO.to_s) + assert_equal("1", T_ONE.to_s) + end + + def test_to_f + assert_nothing_raised { T31P.to_f.to_i } + assert_raise(FloatDomainError) { (1024**1024).to_f.to_i } + assert_equal(1, (2**50000).to_f.infinite?) + assert_equal(-1, (-(2**50000)).to_f.infinite?) + end + + def test_cmp + assert_operator(T31P, :>, 1) + assert_operator(T31P, :<, 2147483648.0) + assert_operator(T31P, :<, T64P) + assert_operator(T64P, :>, T31P) + assert_raise(ArgumentError) { T31P < "foo" } + assert_operator(T64, :<, (1.0/0.0)) + assert_not_operator(T64, :>, (1.0/0.0)) + end + + def test_eq + assert_not_equal(T31P, 1) + assert_equal(T31P, 2147483647.0) + assert_not_equal(T31P, "foo") + assert_not_equal(2**77889, (1.0/0.0), '[ruby-core:31603]') + end + + def test_eql + assert_send([T31P, :eql?, T31P]) + end + + def test_convert + assert_equal([255], [T_MONE].pack("C").unpack("C")) + assert_equal([0], [T32].pack("C").unpack("C")) + assert_raise(RangeError) { 0.to_s(T32) } + end + + def test_sub + assert_equal(-T31, T32 - (T32 + T31)) + x = 2**100 + assert_equal(1, (x+2) - (x+1)) + assert_equal(-1, (x+1) - (x+2)) + assert_equal(0, (2**100) - (2.0**100)) + o = Object.new + def o.coerce(x); [x, 2**100+2]; end + assert_equal(-1, (2**100+1) - o) + assert_equal(-1, T_ONE - 2) + end + + def test_plus + assert_equal(T32.to_f, T32P + 1.0) + assert_raise(TypeError) { T32 + "foo" } + assert_equal(1267651809154049016125877911552, (2**100) + (2**80)) + assert_equal(1267651809154049016125877911552, (2**80) + (2**100)) + assert_equal(2**101, (2**100) + (2.0**100)) + o = Object.new + def o.coerce(x); [x, 2**80]; end + assert_equal(1267651809154049016125877911552, (2**100) + o) + end + + def test_minus + assert_equal(T32P.to_f, T32 - 1.0) + assert_raise(TypeError) { T32 - "foo" } + end + + def test_mul + assert_equal(T32.to_f, T32 * 1.0) + assert_raise(TypeError) { T32 * "foo" } + o = Object.new + def o.coerce(x); [x, 2**100]; end + assert_equal(2**180, (2**80) * o) + end + + def test_mul_balance + assert_equal(3**7000, (3**5000) * (3**2000)) + end + + def test_mul_large_numbers + a = %w[ + 32580286268570032115047167942578356789222410206194227403993117616454027392 + 62501901985861926098797067562795526004375784403965882943322008991129440928 + 33855888840298794008677656280486901895499985197580043127115026675632969396 + 55040226415022070581995493731570435346323030715226718346725312551631168110 + 83966158581772380474470605428802018934282425947323171408377505151988776271 + 85865548747366001752375899635539662017095652855537225416899242508164949615 + 96848508410008685252121247181772953744297349638273854170932226446528911938 + 03430429031094465344063914822790537339912760237589085026016396616506014081 + 53557719631183538265614091691713138728177917059624255801026099255450058876 + 97412698978242128457751836011774504753020608663272925708049430557191193188 + 23212591809241860763625985763438355314593186083254640117460724730431447842 + 15432124830037389073162094304199742919767272162759192882136828372588787906 + 96027938532441670018954643423581446981760344524184231299785949158765352788 + 38452309862972527623669323263424418781899966895996672291193305401609553502 + 63893514163147729201340204483973131948541009975283778189609285614445485714 + 63843850089417416331356938086609682943037801440660232801570877143192251897 + 63026816485314923378023904237699794122181407920355722922555234540701118607 + 37971417665315821995516986204709574657462370947443531049033704997194647442 + 13711787319587466437795542850136751816475182349380345341647976135081955799 + 56787050815348701001765730577514591032367920292271016649813170789854524395 + 72571698998841196411826453893352760318867994518757872432266374568779920489 + 55597104558927387008506485038236352630863481679853742412042588244086070827 + 43705456833283086410967648483312972903432798923897357373793064381177468258 + 69131640408147806442422254638590386673344704147156793990832671592488742473 + 31524606724894164324227362735271650556732855509929890983919463699819116427 + ].join.to_i + b = %w[ + 31519454770031243652776765515030872050264386564379909299874378289835540661 + 99756262835346828114038365624177182230027040172583473561802565238817167503 + 85144159132462819032164726177606533272071955542237648482852154879445654746 + 25061253606344846225905712926863168413666058602449408307586532461776530803 + 56810626880722653177544008166119272373179841889454920521993413902672848145 + 77974951972342194855267960390195830413354782136431833731467699250684103370 + 98571305167189174270854698169136844578685346745340041520068176478277580590 + 43810457765638903028049263788987034217272442328962400931269515791911786205 + 15357047519615932249418012945178659435259428163356223753159488306813844040 + 93609959555018799309373542926110109744437994067754004273450659607204900586 + 28878103661124568217617766580438460505513654179249613168352070584906185237 + 34829991855182473813233425492094534396541544295119674419522772382981982574 + 64708442087451070125274285088681225122475041996116377707892328889948526913 + 82239084041628877737628853240361038273348062246951097300286513836140601495 + 63604611754185656404194406869925540477185577643853560887894081047256701731 + 66884554460428760857958761948461476977864005799494946578017758268987123749 + 85937011490156431231903167442071541493304390639100774497107347884381581049 + 85451663323551635322518839895028929788021096587229364219084708576998525298 + 39594168681411529110089531428721005176467479027585291807482375043729783455 + 35827667428080449919778142400266842990117940984804919512360370451936835708 + 76338722049621773169385978521438867493162717866679193103745711403152099047 + 27294943901673885707639094215339506973982546487889199083181789561917985023 + 82368442718514694400160954955539704757794969665555505203532944598698824542 + 00599461848630034847211204029842422678421808487300084850702007663003230882 + 16645745324467830796203354080471008809087072562876681588151822072260738003 + ].join.to_i + c = %w[ + 10269128594368631269792194698469828812223242061960065022209211719149714886 + 03494742299892841188636314745174778237781513956755034582435818316155459882 + 71422025990633195596790290038198841087091600598192959108790192789550336119 + 13849937951116346796903163312950010689963716629093190601532313463306463573 + 64436438673379454947908896258675634478867189655764364639888427350090856831 + 84369949421175534994092429682748078316130135651006102162888937624830856951 + 64818150356583421988135211585954838926347035741143424980258821170351244310 + 33072045488402539147707418016613224788469923473310249137422855065567940804 + 75231970365923936034328561426062696074717204901606475826224235014948198414 + 19979210494282212322919438926816203585575357874850252052656098969732107129 + 30639419804565653489687198910271702181183420960744232756057631336661646896 + 48734093497394719644969417287962767186599484579769717220518657324467736902 + 16947995288312851432262922140679347615046098863974141226499783975470926697 + 95970415188661518504275964397022973192968233221707696639386238428211541334 + 69925631385166494600401675904803418143232703594169525858261988389529181035 + 06048776134746377586210180203524132714354779486439559392942733781343640971 + 02430607931736785273011780813863748280091795277451796799961887248262211653 + 38966967509803488282644299584920109534552889962877144862747797551711984992 + 00726518175235286668236031649728858774545087668286506201943248842967749907 + 05345423019480534625965140632428736051632750698608916592720742728646191514 + 86268964807395494825321744802493138032936406889713953832376411900451422777 + 06372983421062172556566901346288286168790235741528630664513209619789835729 + 36999522461733403414326366959273556098219489572448083984779946889707480205 + 42459898495081687425132939473146331452400120169525968892769310016015870148 + 66821361032541586130017904207971120217385522074967066199941112154460026348 + 07223950375610474071278649031647998546085807777970592429037128484222394216 + 33776560239741740193444702279919018283324070210090106960567819910943036248 + 16660475627526085805165023447934326510232828674828006752369603151390527384 + 16810180735871644266726954590262010744712519045524839388305761859432443670 + 05188791334908140831469790180096209292338569623252372975043915954675335333 + 66614002146554533771788633057869340167604765688639181655208751680821446276 + 75871494160208888666798836473728725968253820774671626436794492530356258709 + 62318715778035246655925307167306434486713879511272648637608703497794724929 + 54912261106702913491290913962825303534484477936036071463820553314826894581 + 36951927032835690160443252405644718368516656317176848748544135126122940034 + 68454782581240953957381976073459570718038035358630417744490242611126043987 + 89191812971310096496208294948623403471433467614886863238916702384858514703 + 24327715474804343531844042107910755966152655912676456945146277848606406879 + 49724219295823540160221752189725460676360350860849986313532861445465771187 + 86822806696323658053947125253562001971534265078959827450518368635828010637 + 91977444206363529864361796188661941906329947840521598310396004328950804758 + 79728679236044038853668859284513594307352133390781441610395116807369310560 + 35193762565748328526426224069629084264376146174383444988110993194030351064 + 29660536743256949099972314033972121470913480844652490838985461134989129492 + 75577567064571716731774820127381261057956083604361635892088585967074514802 + 51958582645785905276289980534832170529946494815794770854644518463332458915 + 77572397432680871220602513555535017751714443325264019171753694163676670792 + 04353584782364068773777058727187323211012094819929720407636607815292764459 + 21851731257845562153822058534043916834839514338448582518847879059020959697 + 90538105704766415685100946308842788321400392381169436435078204622400475281 + ].join.to_i + assert_equal(c, a*b, '[ruby-core:48552]') + end + + def test_divrem + assert_equal(0, T32 / T64) + end + + def test_divide + bug5490 = '[ruby-core:40429]' + assert_raise(ZeroDivisionError, bug5490) {T1024./(0)} + assert_equal(Float::INFINITY, T1024./(0.0), bug5490) + end + + def test_div + assert_equal(T32.to_f, T32 / 1.0) + assert_raise(TypeError) { T32 / "foo" } + assert_equal(0x20000000, 0x40000001.div(2.0), "[ruby-dev:34553]") + bug5490 = '[ruby-core:40429]' + assert_raise(ZeroDivisionError, bug5490) {T1024.div(0)} + assert_raise(ZeroDivisionError, bug5490) {T1024.div(0.0)} + end + + def test_idiv + assert_equal(715827882, 1073741824.div(Rational(3,2)), ' [ruby-dev:34066]') + end + + def test_modulo + assert_raise(TypeError) { T32 % "foo" } + end + + def test_remainder + assert_equal(0, T32.remainder(1)) + assert_raise(TypeError) { T32.remainder("foo") } + end + + def test_divmod + assert_equal([T32, 0], T32.divmod(1)) + assert_equal([2, 0], T32.divmod(T31)) + assert_raise(TypeError) { T32.divmod("foo") } + end + + def test_quo + assert_kind_of(Float, T32.quo(1.0)) + + assert_equal(T32.to_f, T32.quo(1)) + assert_equal(T32.to_f, T32.quo(1.0)) + assert_equal(T32.to_f, T32.quo(T_ONE)) + + assert_raise(TypeError) { T32.quo("foo") } + + assert_equal(1024**1024, (1024**1024).quo(1)) + assert_equal(Float::INFINITY, (1024**1024).quo(1.0)) + assert_equal(1024**1024*2, (1024**1024*2).quo(1)) + inf = 1 / 0.0; nan = inf / inf + + assert_send([(1024**1024*2).quo(nan), :nan?]) + end + + def test_pow + assert_equal(1.0, T32 ** 0.0) + assert_equal(1.0 / T32, T32 ** -1) + assert_equal(1, (T32 ** T32).infinite?) + assert_equal(1, (T32 ** (2**30-1)).infinite?) + + ### rational changes the behavior of Bignum#** + #assert_raise(TypeError) { T32**"foo" } + assert_raise(TypeError, ArgumentError) { T32**"foo" } + + feature3429 = '[ruby-core:30735]' + assert_instance_of(Bignum, (2 ** 7830457), feature3429) + end + + def test_and + assert_equal(0, T32 & 1) + assert_equal(-T32, (-T32) & (-T31)) + assert_equal(0, T32 & T64) + end + + def test_or + assert_equal(T32 + 1, T32 | 1) + assert_equal(T32 + T31, T32 | T31) + assert_equal(-T31, (-T32) | (-T31)) + assert_equal(T64 + T32, T32 | T64) + assert_equal(FIXNUM_MAX, T_ZERO | FIXNUM_MAX) + end + + def test_xor + assert_equal(T32 + 1, T32 ^ 1) + assert_equal(T32 + T31, T32 ^ T31) + assert_equal(T31, (-T32) ^ (-T31)) + assert_equal(T64 + T32, T32 ^ T64) + end + + class DummyNumeric < Numeric + def to_int + 1 + end + end + + def test_and_with_float + assert_raise(TypeError) { T1024 & 1.5 } + end + + def test_and_with_rational + assert_raise(TypeError, "#1792") { T1024 & Rational(3, 2) } + end + + def test_and_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { T1024 & DummyNumeric.new } + end + + def test_or_with_float + assert_raise(TypeError) { T1024 | 1.5 } + end + + def test_or_with_rational + assert_raise(TypeError, "#1792") { T1024 | Rational(3, 2) } + end + + def test_or_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { T1024 | DummyNumeric.new } + end + + def test_xor_with_float + assert_raise(TypeError) { T1024 ^ 1.5 } + end + + def test_xor_with_rational + assert_raise(TypeError, "#1792") { T1024 ^ Rational(3, 2) } + end + + def test_xor_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { T1024 ^ DummyNumeric.new } + end + + def test_shift2 + assert_equal(2**33, (2**32) << 1) + assert_equal(2**31, (2**32) << -1) + assert_equal(2**33, (2**32) << 1.0) + assert_equal(2**31, (2**32) << -1.0) + assert_equal(2**33, (2**32) << T_ONE) + assert_equal(2**31, (2**32) << T_MONE) + assert_equal(2**31, (2**32) >> 1) + assert_equal(2**33, (2**32) >> -1) + assert_equal(2**31, (2**32) >> 1.0) + assert_equal(2**33, (2**32) >> -1.0) + assert_equal(2**31, (2**32) >> T_ONE) + assert_equal(2**33, (2**32) >> T_MONE) + assert_equal( 0, (2**32) >> (2**32)) + assert_equal(-1, -(2**32) >> (2**32)) + assert_equal( 0, (2**32) >> 128) + assert_equal(-1, -(2**32) >> 128) + assert_equal( 0, (2**31) >> 32) + assert_equal(-1, -(2**31) >> 32) + end + + def test_shift_bigshift + big = 2**300 + assert_equal(2**65538 / (2**65537), 2**65538 >> big.coerce(65537).first) + end + + def test_aref + assert_equal(0, (2**32)[0]) + assert_equal(0, (2**32)[2**32]) + assert_equal(0, (2**32)[-(2**32)]) + assert_equal(0, (2**32)[T_ZERO]) + assert_equal(0, (-(2**64))[0]) + assert_equal(1, (-2**256)[256]) + end + + def test_hash + assert_nothing_raised { T31P.hash } + end + + def test_coerce + assert_equal([T64P, T31P], T31P.coerce(T64P)) + assert_raise(TypeError) { T31P.coerce(nil) } + end + + def test_abs + assert_equal(T31P, (-T31P).abs) + end + + def test_size + assert_kind_of(Integer, T31P.size) + end + + def test_odd + assert_equal(true, (2**32+1).odd?) + assert_equal(false, (2**32).odd?) + end + + def test_even + assert_equal(false, (2**32+1).even?) + assert_equal(true, (2**32).even?) + end + + def test_interrupt_during_to_s + if defined?(Bignum::GMP_VERSION) + return # GMP doesn't support interrupt during an operation. + end + time = Time.now + start_flag = false + end_flag = false + num = (65536 ** 65536) + thread = Thread.new do + start_flag = true + num.to_s + end_flag = true + end + sleep 0.001 until start_flag + thread.raise + thread.join rescue nil + time = Time.now - time + skip "too fast cpu" if end_flag + assert_operator(time, :<, 10) + end + + def test_interrupt_during_bigdivrem + if defined?(Bignum::GMP_VERSION) + return # GMP doesn't support interrupt during an operation. + end + return unless Process.respond_to?(:kill) + begin + trace = [] + oldtrap = Signal.trap(:INT) {|sig| trace << :int } + a = 456 ** 100 + b = 123 ** 100 + c = nil + 100.times do |n| + a **= 3 + b **= 3 + trace.clear + th = Thread.new do + sleep 0.1; Process.kill :INT, $$ + sleep 0.1; Process.kill :INT, $$ + end + c = a / b + trace << :end + th.join + if trace == [:int, :int, :end] + assert_equal(a / b, c) + return + end + end + skip "cannot create suitable test case" + ensure + Signal.trap(:INT, oldtrap) if oldtrap + end + end + + def test_too_big_to_s + if (big = 2**31-1).is_a?(Fixnum) + return + end + assert_raise_with_message(RangeError, /too big to convert/) {(1 << big).to_s} + end + + def test_fix_fdiv + assert_not_equal(0, 1.fdiv(@fmax2)) + assert_in_delta(0.5, 1.fdiv(@fmax2) * @fmax, 0.01) + end + + def test_big_fdiv + assert_equal(1, @big.fdiv(@big)) + assert_not_equal(0, @big.fdiv(@fmax2)) + assert_not_equal(0, @fmax2.fdiv(@big)) + assert_not_equal(0, @fmax2.fdiv(@fmax2)) + assert_in_delta(0.5, @fmax.fdiv(@fmax2), 0.01) + assert_in_delta(1.0, @fmax2.fdiv(@fmax2), 0.01) + end + + def test_float_fdiv + b = 1E+300.to_i + assert_equal(b, (b ** 2).fdiv(b)) + assert_send([@big.fdiv(0.0 / 0.0), :nan?]) + assert_in_delta(1E+300, (10**500).fdiv(1E+200), 1E+285) + end + + def test_obj_fdiv + o = Object.new + def o.coerce(x); [x, 2**100]; end + assert_equal((2**200).to_f, (2**300).fdiv(o)) + end + + def test_singleton_method + # this test assumes 32bit/64bit platform + assert_raise(TypeError) { a = 1 << 64; def a.foo; end } + end + + def test_frozen + assert_equal(true, (2**100).frozen?) + end + + def test_bitwise_and_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 & obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 & 10, T1024 & obj) + end + + def test_bitwise_or_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 | obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 | 10, T1024 | obj) + end + + def test_bitwise_xor_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 ^ obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 ^ 10, T1024 ^ obj) + end +end diff --git a/jni/ruby/test/ruby/test_call.rb b/jni/ruby/test/ruby/test_call.rb new file mode 100644 index 0000000..5b81eb1 --- /dev/null +++ b/jni/ruby/test/ruby/test_call.rb @@ -0,0 +1,34 @@ +require 'test/unit' + +class TestCall < Test::Unit::TestCase + def aaa(a, b=100, *rest) + res = [a, b] + res += rest if rest + return res + end + + def test_call + assert_raise(ArgumentError) {aaa()} + assert_raise(ArgumentError) {aaa} + + assert_equal([1, 100], aaa(1)) + assert_equal([1, 2], aaa(1, 2)) + assert_equal([1, 2, 3, 4], aaa(1, 2, 3, 4)) + assert_equal([1, 2, 3, 4], aaa(1, *[2, 3, 4])) + end + + def test_callinfo + bug9622 = '[ruby-core:61422] [Bug #9622]' + o = Class.new do + def foo(*args) + bar(:foo, *args) + end + def bar(name) + name + end + end.new + e = assert_raise(ArgumentError) {o.foo(100)} + assert_nothing_raised(ArgumentError) {o.foo} + assert_raise_with_message(ArgumentError, e.message, bug9622) {o.foo(100)} + end +end diff --git a/jni/ruby/test/ruby/test_case.rb b/jni/ruby/test/ruby/test_case.rb new file mode 100644 index 0000000..f20d1df --- /dev/null +++ b/jni/ruby/test/ruby/test_case.rb @@ -0,0 +1,124 @@ +require 'test/unit' + +class TestCase < Test::Unit::TestCase + def test_case + case 5 + when 1, 2, 3, 4, 6, 7, 8 + assert(false) + when 5 + assert(true) + end + + case 5 + when 5 + assert(true) + when 1..10 + assert(false) + end + + case 5 + when 1..10 + assert(true) + else + assert(false) + end + + case 5 + when 5 + assert(true) + else + assert(false) + end + + case "foobar" + when /^f.*r$/ + assert(true) + else + assert(false) + end + + case + when true + assert(true) + when false, nil + assert(false) + else + assert(false) + end + + case "+" + when *%w/. +/ + assert(true) + else + assert(false) + end + + case + when *[], false + assert(false) + else + assert(true) + end + + case + when *false, [] + assert(true) + else + assert(false) + end + + assert_raise(NameError) do + case + when false, *x, false + end + end + end + + def test_deoptimization + assert_in_out_err(['-e', <<-EOS], '', %w[42], []) + class Symbol; undef ===; def ===(o); p 42; true; end; end; case :foo; when :foo; end + EOS + + assert_in_out_err(['-e', <<-EOS], '', %w[42], []) + class Fixnum; undef ===; def ===(o); p 42; true; end; end; case 1; when 1; end + EOS + end + + def test_optimization + case 1 + when 0.9, 1.1 + assert(false) + when 1.0 + assert(true) + else + assert(false) + end + case 536870912 + when 536870911.9, 536870912.1 + assert(false) + when 536870912.0 + assert(true) + else + assert(false) + end + end + + def test_method_missing + flag = false + + case 1 + when Class.new(BasicObject) { def method_missing(*) true end }.new + flag = true + end + + assert(flag) + end + + def test_nomethoderror + assert_raise(NoMethodError) { + case 1 + when Class.new(BasicObject) { }.new + end + } + end +end diff --git a/jni/ruby/test/ruby/test_class.rb b/jni/ruby/test/ruby/test_class.rb new file mode 100644 index 0000000..e17f56f --- /dev/null +++ b/jni/ruby/test/ruby/test_class.rb @@ -0,0 +1,402 @@ +require 'test/unit' + +class TestClass < Test::Unit::TestCase + # ------------------ + # Various test classes + # ------------------ + + class ClassOne + attr :num_args + @@subs = [] + def initialize(*args) + @num_args = args.size + @args = args + end + def [](n) + @args[n] + end + def ClassOne.inherited(klass) + @@subs.push klass + end + def subs + @@subs + end + end + + class ClassTwo < ClassOne + end + + class ClassThree < ClassOne + end + + class ClassFour < ClassThree + end + + # ------------------ + # Start of tests + # ------------------ + + def test_s_inherited + assert_equal([ClassTwo, ClassThree, ClassFour], ClassOne.new.subs) + end + + def test_s_new + c = Class.new + assert_same(Class, c.class) + assert_same(Object, c.superclass) + + c = Class.new(Fixnum) + assert_same(Class, c.class) + assert_same(Fixnum, c.superclass) + end + + def test_00_new_basic + a = ClassOne.new + assert_equal(ClassOne, a.class) + assert_equal(0, a.num_args) + + a = ClassOne.new(1, 2, 3) + assert_equal(3, a.num_args) + assert_equal(1, a[0]) + end + + def test_01_new_inherited + a = ClassTwo.new + assert_equal(ClassTwo, a.class) + assert_equal(0, a.num_args) + + a = ClassTwo.new(1, 2, 3) + assert_equal(3, a.num_args) + assert_equal(1, a[0]) + end + + def test_superclass + assert_equal(ClassOne, ClassTwo.superclass) + assert_equal(Object, ClassTwo.superclass.superclass) + assert_equal(BasicObject, ClassTwo.superclass.superclass.superclass) + end + + def test_class_cmp + assert_raise(TypeError) { Class.new <= 1 } + assert_raise(TypeError) { Class.new >= 1 } + assert_nil(Class.new <=> 1) + end + + def test_class_initialize + assert_raise(TypeError) do + Class.new.instance_eval { initialize } + end + end + + def test_instanciate_singleton_class + c = class << Object.new; self; end + assert_raise(TypeError) { c.new } + end + + def test_superclass_of_basicobject + assert_equal(nil, BasicObject.superclass) + end + + def test_module_function + c = Class.new + assert_raise(TypeError) do + Module.instance_method(:module_function).bind(c).call(:foo) + end + end + + def test_extend_object + c = Class.new + assert_raise(TypeError) do + Module.instance_method(:extend_object).bind(c).call(Object.new) + end + end + + def test_append_features + c = Class.new + assert_raise(TypeError) do + Module.instance_method(:append_features).bind(c).call(Module.new) + end + end + + def test_prepend_features + c = Class.new + assert_raise(TypeError) do + Module.instance_method(:prepend_features).bind(c).call(Module.new) + end + end + + def test_module_specific_methods + assert_empty(Class.private_instance_methods(true) & + [:module_function, :extend_object, :append_features, :prepend_features]) + end + + def test_method_redefinition + feature2155 = '[ruby-dev:39400]' + + line = __LINE__+4 + stderr = EnvUtil.verbose_warning do + Class.new do + def foo; end + def foo; end + end + end + assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) + assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) + + assert_warning '' do + Class.new do + def foo; end + alias bar foo + def foo; end + end + end + + assert_warning '' do + Class.new do + def foo; end + alias bar foo + alias bar foo + end + end + + line = __LINE__+4 + stderr = EnvUtil.verbose_warning do + Class.new do + define_method(:foo) do end + def foo; end + end + end + assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) + assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) + + assert_warning '' do + Class.new do + define_method(:foo) do end + alias bar foo + alias bar foo + end + end + + assert_warning '' do + Class.new do + def foo; end + undef foo + end + end + end + + def test_check_inheritable + assert_raise(TypeError) { Class.new(Object.new) } + + o = Object.new + c = class << o; self; end + assert_raise(TypeError) { Class.new(c) } + assert_raise(TypeError) { Class.new(Class) } + assert_raise(TypeError) { eval("class Foo < Class; end") } + end + + def test_initialize_copy + c = Class.new + assert_raise(TypeError) { c.instance_eval { initialize_copy(1) } } + + o = Object.new + c = class << o; self; end + assert_raise(TypeError) { c.dup } + + assert_raise(TypeError) { BasicObject.dup } + end + + def test_singleton_class + assert_raise(TypeError) { 1.extend(Module.new) } + assert_raise(TypeError) { 1.0.extend(Module.new) } + assert_raise(TypeError) { (2.0**1000).extend(Module.new) } + assert_raise(TypeError) { :foo.extend(Module.new) } + + assert_in_out_err([], <<-INPUT, %w(:foo :foo true true), []) + module Foo; def foo; :foo; end; end + false.extend(Foo) + true.extend(Foo) + p false.foo + p true.foo + p FalseClass.include?(Foo) + p TrueClass.include?(Foo) + INPUT + end + + def test_uninitialized + assert_raise(TypeError) { Class.allocate.new } + assert_raise(TypeError) { Class.allocate.superclass } + bug6863 = '[ruby-core:47148]' + assert_raise(TypeError, bug6863) { Class.new(Class.allocate) } + end + + def test_nonascii_name + c = eval("class ::C\u{df}; self; end") + assert_equal("C\u{df}", c.name, '[ruby-core:24600]') + c = eval("class C\u{df}; self; end") + assert_equal("TestClass::C\u{df}", c.name, '[ruby-core:24600]') + end + + def test_invalid_jump_from_class_definition + assert_raise(SyntaxError) { eval("class C; next; end") } + assert_raise(SyntaxError) { eval("class C; break; end") } + assert_raise(SyntaxError) { eval("class C; redo; end") } + assert_raise(SyntaxError) { eval("class C; retry; end") } + assert_raise(SyntaxError) { eval("class C; return; end") } + assert_raise(SyntaxError) { eval("class C; yield; end") } + end + + def test_clone + original = Class.new { + def foo + return super() + end + } + mod = Module.new { + def foo + return "mod#foo" + end + } + copy = original.clone + copy.send(:include, mod) + assert_equal("mod#foo", copy.new.foo) + end + + def test_nested_class_removal + assert_normal_exit('File.__send__(:remove_const, :Stat); at_exit{File.stat(".")}; GC.start') + end + + class PrivateClass + end + private_constant :PrivateClass + + def test_redefine_private_class + assert_raise(NameError) do + eval("class ::TestClass::PrivateClass; end") + end + eval <<-END + class ::TestClass + class PrivateClass + def foo; 42; end + end + end + END + assert_equal(42, PrivateClass.new.foo) + end + + StrClone = String.clone + Class.new(StrClone) + + def test_cloned_class + bug5274 = StrClone.new("[ruby-dev:44460]") + assert_equal(bug5274, Marshal.load(Marshal.dump(bug5274))) + end + + def test_cannot_reinitialize_class_with_initialize_copy # [ruby-core:50869] + assert_in_out_err([], <<-'end;', ["Object"], []) + class Class + def initialize_copy(*); super; end + end + + class A; end + class B; end + + A.send(:initialize_copy, Class.new(B)) rescue nil + + p A.superclass + end; + end + + module M + C = 1 + + def self.m + C + end + end + + def test_constant_access_from_method_in_cloned_module # [ruby-core:47834] + m = M.dup + assert_equal 1, m::C + assert_equal 1, m.m + end + + def test_invalid_superclass + assert_raise(TypeError) do + eval <<-'end;' + class C < nil + end + end; + end + + assert_raise(TypeError) do + eval <<-'end;' + class C < false + end + end; + end + + assert_raise(TypeError) do + eval <<-'end;' + class C < true + end + end; + end + + assert_raise(TypeError) do + eval <<-'end;' + class C < 0 + end + end; + end + + assert_raise(TypeError) do + eval <<-'end;' + class C < "" + end + end; + end + end + + def test_cloned_singleton_method_added + bug5283 = '[ruby-dev:44477]' + added = [] + c = Class.new + c.singleton_class.class_eval do + define_method(:singleton_method_added) {|mid| added << [self, mid]} + def foo; :foo; end + end + added.clear + d = c.clone + assert_empty(added.grep(->(k) {c == k[0]}), bug5283) + assert_equal(:foo, d.foo) + end + + def test_singleton_class_p + feature7609 = '[ruby-core:51087] [Feature #7609]' + assert_predicate(self.singleton_class, :singleton_class?, feature7609) + assert_not_predicate(self.class, :singleton_class?, feature7609) + end + + def test_freeze_to_s + assert_nothing_raised("[ruby-core:41858] [Bug #5828]") { + Class.new.freeze.clone.to_s + } + end + + def test_singleton_class_of_frozen_object + obj = Object.new + c = obj.singleton_class + obj.freeze + assert_raise_with_message(RuntimeError, /frozen object/) { + c.class_eval {def f; end} + } + end + + def test_singleton_class_message + c = Class.new.freeze + assert_raise_with_message(RuntimeError, /frozen Class/) { + def c.f; end + } + end +end diff --git a/jni/ruby/test/ruby/test_clone.rb b/jni/ruby/test/ruby/test_clone.rb new file mode 100644 index 0000000..c5e2469 --- /dev/null +++ b/jni/ruby/test/ruby/test_clone.rb @@ -0,0 +1,28 @@ +require 'test/unit' + +class TestClone < Test::Unit::TestCase + module M001; end + module M002; end + module M003; include M002; end + module M002; include M001; end + module M003; include M002; end + + def test_clone + foo = Object.new + def foo.test + "test" + end + bar = foo.clone + def bar.test2 + "test2" + end + + assert_equal("test2", bar.test2) + assert_equal("test", bar.test) + assert_equal("test", foo.test) + + assert_raise(NoMethodError) {foo.test2} + + assert_equal([M003, M002, M001], M003.ancestors) + end +end diff --git a/jni/ruby/test/ruby/test_comparable.rb b/jni/ruby/test/ruby/test_comparable.rb new file mode 100644 index 0000000..efa630f --- /dev/null +++ b/jni/ruby/test/ruby/test_comparable.rb @@ -0,0 +1,94 @@ +require 'test/unit' + +class TestComparable < Test::Unit::TestCase + def setup + @o = Object.new + @o.extend(Comparable) + end + def cmp(b) + class << @o; self; end.class_eval { + undef :<=> + define_method(:<=>, b) + } + end + + def test_equal + cmp->(x) do 0; end + assert_equal(true, @o == nil) + cmp->(x) do 1; end + assert_equal(false, @o == nil) + cmp->(x) do raise NotImplementedError, "Not a RuntimeError" end + assert_raise(NotImplementedError) { @o == nil } + bug7688 = '[ruby-core:51389] [Bug #7688]' + cmp->(x) do raise StandardError, "A standard error should be rescued"; end + warn = /Comparable#== will no more rescue exceptions .+ in the next release/ + assert_warn(warn, bug7688) { @o == nil } + end + + def test_gt + cmp->(x) do 1; end + assert_equal(true, @o > nil) + cmp->(x) do 0; end + assert_equal(false, @o > nil) + cmp->(x) do -1; end + assert_equal(false, @o > nil) + end + + def test_ge + cmp->(x) do 1; end + assert_equal(true, @o >= nil) + cmp->(x) do 0; end + assert_equal(true, @o >= nil) + cmp->(x) do -1; end + assert_equal(false, @o >= nil) + end + + def test_lt + cmp->(x) do 1; end + assert_equal(false, @o < nil) + cmp->(x) do 0; end + assert_equal(false, @o < nil) + cmp->(x) do -1; end + assert_equal(true, @o < nil) + end + + def test_le + cmp->(x) do 1; end + assert_equal(false, @o <= nil) + cmp->(x) do 0; end + assert_equal(true, @o <= nil) + cmp->(x) do -1; end + assert_equal(true, @o <= nil) + end + + def test_between + cmp->(x) do 0 <=> x end + assert_equal(false, @o.between?(1, 2)) + assert_equal(false, @o.between?(-2, -1)) + assert_equal(true, @o.between?(-1, 1)) + assert_equal(true, @o.between?(0, 0)) + end + + def test_err + assert_raise(ArgumentError) { 1.0 < nil } + assert_raise(ArgumentError) { 1.0 < Object.new } + e = EnvUtil.labeled_class("E\u{30a8 30e9 30fc}") + assert_raise_with_message(ArgumentError, /E\u{30a8 30e9 30fc}/) { + 1.0 < e.new + } + end + + def test_inversed_compare + bug7870 = '[ruby-core:52305] [Bug #7870]' + assert_nothing_raised(SystemStackError, bug7870) { + assert_nil(Time.new <=> "") + } + end + + def test_no_cmp + bug9003 = '[ruby-core:57736] [Bug #9003]' + assert_nothing_raised(SystemStackError, bug9003) { + @o <=> @o.dup + } + end +end diff --git a/jni/ruby/test/ruby/test_complex.rb b/jni/ruby/test/ruby/test_complex.rb new file mode 100644 index 0000000..1cbab2d --- /dev/null +++ b/jni/ruby/test/ruby/test_complex.rb @@ -0,0 +1,1014 @@ +require 'test/unit' +require 'cmath' + +class ComplexSub < Complex; end + +class Complex_Test < Test::Unit::TestCase + + def test_rationalize + assert_equal(1.quo(3), Complex(1/3.0, 0).rationalize, '[ruby-core:38885]') + assert_equal(1.quo(5), Complex(0.2, 0).rationalize, '[ruby-core:38885]') + assert_equal(5.quo(2), Complex(2.5, 0).rationalize(0), '[ruby-core:40667]') + end + + def test_compsub + c = ComplexSub.__send__(:convert, 1) + + assert_kind_of(Numeric, c) + + assert_instance_of(ComplexSub, c) + + c2 = c + 1 + assert_instance_of(ComplexSub, c2) + c2 = c - 1 + assert_instance_of(ComplexSub, c2) + + c3 = c - c2 + assert_instance_of(ComplexSub, c3) + + s = Marshal.dump(c) + c5 = Marshal.load(s) + assert_equal(c, c5) + assert_instance_of(ComplexSub, c5) + + c1 = Complex(1) + assert_equal(c1.hash, c.hash, '[ruby-dev:38850]') + assert_equal([true, true], [c.eql?(c1), c1.eql?(c)]) + end + + def test_eql_p + c = Complex(0) + c2 = Complex(0) + c3 = Complex(1) + + assert_equal(true, c.eql?(c2)) + assert_equal(false, c.eql?(c3)) + + assert_equal(false, c.eql?(0)) + end + + def test_hash + assert_instance_of(Fixnum, Complex(1,2).hash) + assert_instance_of(Fixnum, Complex(1.0,2.0).hash) + + h = {} + h[Complex(0)] = 0 + h[Complex(0,1)] = 1 + h[Complex(1,0)] = 2 + h[Complex(1,1)] = 3 + + assert_equal(4, h.size) + assert_equal(2, h[Complex(1,0)]) + + h[Complex(0,0)] = 9 + assert_equal(4, h.size) + + h[Complex(0.0,0.0)] = 9.0 + assert_equal(5, h.size) + + if (0.0/0).nan? && !((0.0/0).eql?(0.0/0)) + h = {} + 3.times{h[Complex(0.0/0)] = 1} + assert_equal(3, h.size) + end + end + + def test_freeze + c = Complex(1) + c.freeze + assert_equal(true, c.frozen?) + assert_instance_of(String, c.to_s) + end + + def test_conv + c = Complex(0,0) + assert_equal(Complex(0,0), c) + + c = Complex(2**32, 2**32) + assert_equal(Complex(2**32,2**32), c) + assert_equal([2**32,2**32], [c.real,c.imag]) + + c = Complex(-2**32, 2**32) + assert_equal(Complex(-2**32,2**32), c) + assert_equal([-2**32,2**32], [c.real,c.imag]) + + c = Complex(2**32, -2**32) + assert_equal(Complex(2**32,-2**32), c) + assert_equal([2**32,-2**32], [c.real,c.imag]) + + c = Complex(-2**32, -2**32) + assert_equal(Complex(-2**32,-2**32), c) + assert_equal([-2**32,-2**32], [c.real,c.imag]) + + c = Complex(Complex(1,2),2) + assert_equal(Complex(1,4), c) + + c = Complex(2,Complex(1,2)) + assert_equal(Complex(0,1), c) + + c = Complex(Complex(1,2),Complex(1,2)) + assert_equal(Complex(-1,3), c) + + c = Complex::I + assert_equal(Complex(0,1), c) + + assert_equal(Complex(1),Complex(1)) + assert_equal(Complex(1),Complex('1')) + assert_equal(Complex(3.0,3.0),Complex('3.0','3.0')) + assert_equal(Complex(1,1),Complex('3/3','3/3')) + assert_raise(TypeError){Complex(nil)} + assert_raise(TypeError){Complex(Object.new)} + assert_raise(ArgumentError){Complex()} + assert_raise(ArgumentError){Complex(1,2,3)} + + if (0.0/0).nan? + assert_nothing_raised{Complex(0.0/0)} + end + if (1.0/0).infinite? + assert_nothing_raised{Complex(1.0/0)} + end + end + + def test_attr + c = Complex(4) + + assert_equal(4, c.real) + assert_equal(0, c.imag) + + c = Complex(4,5) + + assert_equal(4, c.real) + assert_equal(5, c.imag) + + if -0.0.to_s == '-0.0' + c = Complex(-0.0,-0.0) + + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + end + + c = Complex(4) + + assert_equal(4, c.real) + assert_equal(0, c.imag) + assert_equal(c.imag, c.imaginary) + + c = Complex(4,5) + + assert_equal(4, c.real) + assert_equal(5, c.imag) + assert_equal(c.imag, c.imaginary) + + if -0.0.to_s == '-0.0' + c = Complex(-0.0,-0.0) + + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + assert_equal(c.imag.to_s, c.imaginary.to_s) + end + + c = Complex(4) + + assert_equal(4, c.real) + assert_equal(c.imag, c.imaginary) + assert_equal(0, c.imag) + + c = Complex(4,5) + + assert_equal(4, c.real) + assert_equal(5, c.imag) + assert_equal(c.imag, c.imaginary) + + c = Complex(-0.0,-0.0) + + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + assert_equal(c.imag.to_s, c.imaginary.to_s) + end + + def test_attr2 + c = Complex(1) + + assert_equal(false, c.integer?) + assert_equal(false, c.real?) + + assert_equal(true, Complex(0).zero?) + assert_equal(true, Complex(0,0).zero?) + assert_equal(false, Complex(1,0).zero?) + assert_equal(false, Complex(0,1).zero?) + assert_equal(false, Complex(1,1).zero?) + + assert_equal(nil, Complex(0).nonzero?) + assert_equal(nil, Complex(0,0).nonzero?) + assert_equal(Complex(1,0), Complex(1,0).nonzero?) + assert_equal(Complex(0,1), Complex(0,1).nonzero?) + assert_equal(Complex(1,1), Complex(1,1).nonzero?) + end + + def test_rect + assert_equal([1,2], Complex.rectangular(1,2).rectangular) + assert_equal([1,2], Complex.rect(1,2).rect) + end + + def test_polar + assert_equal([1,2], Complex.polar(1,2).polar) + end + + def test_uplus + assert_equal(Complex(1), +Complex(1)) + assert_equal(Complex(-1), +Complex(-1)) + assert_equal(Complex(1,1), +Complex(1,1)) + assert_equal(Complex(-1,1), +Complex(-1,1)) + assert_equal(Complex(1,-1), +Complex(1,-1)) + assert_equal(Complex(-1,-1), +Complex(-1,-1)) + + if -0.0.to_s == '-0.0' + c = +Complex(0.0,0.0) + assert_equal('0.0', c.real.to_s) + assert_equal('0.0', c.imag.to_s) + + c = +Complex(-0.0,-0.0) + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + end + end + + def test_negate + assert_equal(Complex(-1), -Complex(1)) + assert_equal(Complex(1), -Complex(-1)) + assert_equal(Complex(-1,-1), -Complex(1,1)) + assert_equal(Complex(1,-1), -Complex(-1,1)) + assert_equal(Complex(-1,1), -Complex(1,-1)) + assert_equal(Complex(1,1), -Complex(-1,-1)) + + if -0.0.to_s == '-0.0' + c = -Complex(0.0,0.0) + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + + c = -Complex(-0.0,-0.0) + assert_equal('0.0', c.real.to_s) + assert_equal('0.0', c.imag.to_s) + end + end + + def test_add + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(3,5), c + c2) + + assert_equal(Complex(3,2), c + 2) + assert_equal(Complex(3.0,2), c + 2.0) + + assert_equal(Complex(Rational(3,1),Rational(2)), c + Rational(2)) + assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3)) + end + + def test_sub + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(-1,-1), c - c2) + + assert_equal(Complex(-1,2), c - 2) + assert_equal(Complex(-1.0,2), c - 2.0) + + assert_equal(Complex(Rational(-1,1),Rational(2)), c - Rational(2)) + assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3)) + end + + def test_mul + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(-4,7), c * c2) + + assert_equal(Complex(2,4), c * 2) + assert_equal(Complex(2.0,4.0), c * 2.0) + + assert_equal(Complex(Rational(2,1),Rational(4)), c * Rational(2)) + assert_equal(Complex(Rational(2,3),Rational(4,3)), c * Rational(2,3)) + end + + def test_div + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2) + + c = Complex(1.0,2.0) + c2 = Complex(2.0,3.0) + + r = c / c2 + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(Rational(1,2),1), c / 2) + assert_equal(Complex(0.5,1.0), c / 2.0) + + assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2)) + assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3)) + end + + def test_quo + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(Rational(8,13),Rational(1,13)), c.quo(c2)) + + c = Complex(1.0,2.0) + c2 = Complex(2.0,3.0) + + r = c.quo(c2) + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(Rational(1,2),1), c.quo(2)) + assert_equal(Complex(0.5,1.0), c.quo(2.0)) + + assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2)) + assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3)) + end + + def test_fdiv + c = Complex(1,2) + c2 = Complex(2,3) + + r = c.fdiv(c2) + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + + c = Complex(1.0,2.0) + c2 = Complex(2.0,3.0) + + r = c.fdiv(c2) + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + + c = Complex(1,2) + c2 = Complex(2,3) + + assert_equal(Complex(0.5,1.0), c.fdiv(2)) + assert_equal(Complex(0.5,1.0), c.fdiv(2.0)) + end + + def test_expt + c = Complex(1,2) + c2 = Complex(2,3) + + r = c ** c2 + assert_in_delta(-0.015, r.real, 0.001) + assert_in_delta(-0.179, r.imag, 0.001) + + assert_equal(Complex(-3,4), c ** 2) + assert_equal(Complex(Rational(-3,25),Rational(-4,25)), c ** -2) + + r = c ** 2.0 + assert_in_delta(-3.0, r.real, 0.001) + assert_in_delta(4.0, r.imag, 0.001) + + r = c ** -2.0 + assert_in_delta(-0.12, r.real, 0.001) + assert_in_delta(-0.16, r.imag, 0.001) + + assert_equal(Complex(-3,4), c ** Rational(2)) + assert_equal(Complex(Rational(-3,25),Rational(-4,25)), + c ** Rational(-2)) # why failed? + + r = c ** Rational(2,3) + assert_in_delta(1.264, r.real, 0.001) + assert_in_delta(1.150, r.imag, 0.001) + + r = c ** Rational(-2,3) + assert_in_delta(0.432, r.real, 0.001) + assert_in_delta(-0.393, r.imag, 0.001) + end + + def test_cmp + assert_raise(NoMethodError){1 <=> Complex(1,1)} + assert_raise(NoMethodError){Complex(1,1) <=> 1} + assert_raise(NoMethodError){Complex(1,1) <=> Complex(1,1)} + end + + def test_eqeq + assert_equal(Complex(1), Complex(1,0)) + assert_equal(Complex(-1), Complex(-1,0)) + + assert_not_equal(Complex(1), Complex(2,1)) + assert_operator(Complex(2,1), :!=, Complex(1)) + assert_not_equal(nil, Complex(1)) + assert_not_equal('', Complex(1)) + + nan = 0.0 / 0 + if nan.nan? && nan != nan + assert_not_equal(Complex(nan, 0), Complex(nan, 0)) + assert_not_equal(Complex(0, nan), Complex(0, nan)) + assert_not_equal(Complex(nan, nan), Complex(nan, nan)) + end + end + + def test_coerce + assert_equal([Complex(2),Complex(1)], Complex(1).coerce(2)) + assert_equal([Complex(2.2),Complex(1)], Complex(1).coerce(2.2)) + assert_equal([Complex(Rational(2)),Complex(1)], + Complex(1).coerce(Rational(2))) + assert_equal([Complex(2),Complex(1)], Complex(1).coerce(Complex(2))) + end + + class ObjectX + def + (x) Rational(1) end + alias - + + alias * + + alias / + + alias quo + + alias ** + + def coerce(x) [x, Complex(1)] end + end + + def test_coerce2 + x = ObjectX.new + %w(+ - * / quo **).each do |op| + assert_kind_of(Numeric, Complex(1).__send__(op, x)) + end + end + + def test_math + c = Complex(1,2) + + assert_in_delta(2.236, c.abs, 0.001) + assert_in_delta(2.236, c.magnitude, 0.001) + assert_equal(5, c.abs2) + + assert_equal(c.abs, Math.sqrt(c * c.conj)) + assert_equal(c.abs, Math.sqrt(c.real**2 + c.imag**2)) + assert_equal(c.abs2, c * c.conj) + assert_equal(c.abs2, c.real**2 + c.imag**2) + + assert_in_delta(1.107, c.arg, 0.001) + assert_in_delta(1.107, c.angle, 0.001) + assert_in_delta(1.107, c.phase, 0.001) + + r = c.polar + assert_in_delta(2.236, r[0], 0.001) + assert_in_delta(1.107, r[1], 0.001) + assert_equal(Complex(1,-2), c.conjugate) + assert_equal(Complex(1,-2), c.conj) + + assert_equal(Complex(1,2), c.numerator) + assert_equal(1, c.denominator) + end + + def test_to_s + c = Complex(1,2) + + assert_instance_of(String, c.to_s) + assert_equal('1+2i', c.to_s) + + assert_equal('0+2i', Complex(0,2).to_s) + assert_equal('0-2i', Complex(0,-2).to_s) + assert_equal('1+2i', Complex(1,2).to_s) + assert_equal('-1+2i', Complex(-1,2).to_s) + assert_equal('-1-2i', Complex(-1,-2).to_s) + assert_equal('1-2i', Complex(1,-2).to_s) + assert_equal('-1-2i', Complex(-1,-2).to_s) + + assert_equal('0+2.0i', Complex(0,2.0).to_s) + assert_equal('0-2.0i', Complex(0,-2.0).to_s) + assert_equal('1.0+2.0i', Complex(1.0,2.0).to_s) + assert_equal('-1.0+2.0i', Complex(-1.0,2.0).to_s) + assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s) + assert_equal('1.0-2.0i', Complex(1.0,-2.0).to_s) + assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s) + + assert_equal('0+2/1i', Complex(0,Rational(2)).to_s) + assert_equal('0-2/1i', Complex(0,Rational(-2)).to_s) + assert_equal('1+2/1i', Complex(1,Rational(2)).to_s) + assert_equal('-1+2/1i', Complex(-1,Rational(2)).to_s) + assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s) + assert_equal('1-2/1i', Complex(1,Rational(-2)).to_s) + assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s) + + assert_equal('0+2/3i', Complex(0,Rational(2,3)).to_s) + assert_equal('0-2/3i', Complex(0,Rational(-2,3)).to_s) + assert_equal('1+2/3i', Complex(1,Rational(2,3)).to_s) + assert_equal('-1+2/3i', Complex(-1,Rational(2,3)).to_s) + assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s) + assert_equal('1-2/3i', Complex(1,Rational(-2,3)).to_s) + assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s) + + nan = 0.0 / 0 + inf = 1.0 / 0 + if nan.nan? + assert_equal('NaN+NaN*i', Complex(nan,nan).to_s) + end + if inf.infinite? + assert_equal('Infinity+Infinity*i', Complex(inf,inf).to_s) + assert_equal('Infinity-Infinity*i', Complex(inf,-inf).to_s) + end + end + + def test_inspect + c = Complex(1,2) + + assert_instance_of(String, c.inspect) + assert_equal('(1+2i)', c.inspect) + end + + def test_marshal + c = Complex(1,2) + c.instance_eval{@ivar = 9} + + s = Marshal.dump(c) + c2 = Marshal.load(s) + assert_equal(c, c2) + assert_equal(9, c2.instance_variable_get(:@ivar)) + assert_instance_of(Complex, c2) + + c = Complex(Rational(1,2),Rational(2,3)) + + s = Marshal.dump(c) + c2 = Marshal.load(s) + assert_equal(c, c2) + assert_instance_of(Complex, c2) + + bug3656 = '[ruby-core:31622]' + c = Complex(1,2) + c.freeze + assert_predicate(c, :frozen?) + result = c.marshal_load([2,3]) rescue :fail + assert_equal(:fail, result, bug3656) + assert_equal(Complex(1,2), c) + end + + def test_marshal_compatibility + bug6625 = '[ruby-core:45775]' + dump = "\x04\x08o:\x0cComplex\x07:\x0a@reali\x06:\x0b@imagei\x07" + assert_nothing_raised(bug6625) do + assert_equal(Complex(1, 2), Marshal.load(dump), bug6625) + end + end + + def test_parse + assert_equal(Complex(5), '5'.to_c) + assert_equal(Complex(-5), '-5'.to_c) + assert_equal(Complex(5,3), '5+3i'.to_c) + assert_equal(Complex(-5,3), '-5+3i'.to_c) + assert_equal(Complex(5,-3), '5-3i'.to_c) + assert_equal(Complex(-5,-3), '-5-3i'.to_c) + assert_equal(Complex(0,3), '3i'.to_c) + assert_equal(Complex(0,-3), '-3i'.to_c) + assert_equal(Complex(5,1), '5+i'.to_c) + assert_equal(Complex(0,1), 'i'.to_c) + assert_equal(Complex(0,1), '+i'.to_c) + assert_equal(Complex(0,-1), '-i'.to_c) + + assert_equal(Complex(5,3), '5+3I'.to_c) + assert_equal(Complex(5,3), '5+3j'.to_c) + assert_equal(Complex(5,3), '5+3J'.to_c) + assert_equal(Complex(0,3), '3I'.to_c) + assert_equal(Complex(0,3), '3j'.to_c) + assert_equal(Complex(0,3), '3J'.to_c) + assert_equal(Complex(0,1), 'I'.to_c) + assert_equal(Complex(0,1), 'J'.to_c) + + assert_equal(Complex(5.0), '5.0'.to_c) + assert_equal(Complex(-5.0), '-5.0'.to_c) + assert_equal(Complex(5.0,3.0), '5.0+3.0i'.to_c) + assert_equal(Complex(-5.0,3.0), '-5.0+3.0i'.to_c) + assert_equal(Complex(5.0,-3.0), '5.0-3.0i'.to_c) + assert_equal(Complex(-5.0,-3.0), '-5.0-3.0i'.to_c) + assert_equal(Complex(0.0,3.0), '3.0i'.to_c) + assert_equal(Complex(0.0,-3.0), '-3.0i'.to_c) + + assert_equal(Complex(5.1), '5.1'.to_c) + assert_equal(Complex(-5.2), '-5.2'.to_c) + assert_equal(Complex(5.3,3.4), '5.3+3.4i'.to_c) + assert_equal(Complex(-5.5,3.6), '-5.5+3.6i'.to_c) + assert_equal(Complex(5.3,-3.4), '5.3-3.4i'.to_c) + assert_equal(Complex(-5.5,-3.6), '-5.5-3.6i'.to_c) + assert_equal(Complex(0.0,3.1), '3.1i'.to_c) + assert_equal(Complex(0.0,-3.2), '-3.2i'.to_c) + + assert_equal(Complex(5.0), '5e0'.to_c) + assert_equal(Complex(-5.0), '-5e0'.to_c) + assert_equal(Complex(5.0,3.0), '5e0+3e0i'.to_c) + assert_equal(Complex(-5.0,3.0), '-5e0+3e0i'.to_c) + assert_equal(Complex(5.0,-3.0), '5e0-3e0i'.to_c) + assert_equal(Complex(-5.0,-3.0), '-5e0-3e0i'.to_c) + assert_equal(Complex(0.0,3.0), '3e0i'.to_c) + assert_equal(Complex(0.0,-3.0), '-3e0i'.to_c) + + assert_equal(Complex(5e1), '5e1'.to_c) + assert_equal(Complex(-5e2), '-5e2'.to_c) + assert_equal(Complex(5e3,3e4), '5e003+3e4i'.to_c) + assert_equal(Complex(-5e5,3e6), '-5e5+3e006i'.to_c) + assert_equal(Complex(5e3,-3e4), '5e003-3e4i'.to_c) + assert_equal(Complex(-5e5,-3e6), '-5e5-3e006i'.to_c) + assert_equal(Complex(0.0,3e1), '3e1i'.to_c) + assert_equal(Complex(0.0,-3e2), '-3e2i'.to_c) + + assert_equal(Complex(0.33), '.33'.to_c) + assert_equal(Complex(0.33), '0.33'.to_c) + assert_equal(Complex(-0.33), '-.33'.to_c) + assert_equal(Complex(-0.33), '-0.33'.to_c) + assert_equal(Complex(-0.33), '-0.3_3'.to_c) + + assert_equal(Complex.polar(10,10), '10@10'.to_c) + assert_equal(Complex.polar(-10,-10), '-10@-10'.to_c) + assert_equal(Complex.polar(10.5,10.5), '10.5@10.5'.to_c) + assert_equal(Complex.polar(-10.5,-10.5), '-10.5@-10.5'.to_c) + + assert_equal(Complex(5), Complex('5')) + assert_equal(Complex(-5), Complex('-5')) + assert_equal(Complex(5,3), Complex('5+3i')) + assert_equal(Complex(-5,3), Complex('-5+3i')) + assert_equal(Complex(5,-3), Complex('5-3i')) + assert_equal(Complex(-5,-3), Complex('-5-3i')) + assert_equal(Complex(0,3), Complex('3i')) + assert_equal(Complex(0,-3), Complex('-3i')) + assert_equal(Complex(5,1), Complex('5+i')) + assert_equal(Complex(0,1), Complex('i')) + assert_equal(Complex(0,1), Complex('+i')) + assert_equal(Complex(0,-1), Complex('-i')) + + assert_equal(Complex(5,3), Complex('5+3I')) + assert_equal(Complex(5,3), Complex('5+3j')) + assert_equal(Complex(5,3), Complex('5+3J')) + assert_equal(Complex(0,3), Complex('3I')) + assert_equal(Complex(0,3), Complex('3j')) + assert_equal(Complex(0,3), Complex('3J')) + assert_equal(Complex(0,1), Complex('I')) + assert_equal(Complex(0,1), Complex('J')) + + assert_equal(Complex(5.0), Complex('5.0')) + assert_equal(Complex(-5.0), Complex('-5.0')) + assert_equal(Complex(5.0,3.0), Complex('5.0+3.0i')) + assert_equal(Complex(-5.0,3.0), Complex('-5.0+3.0i')) + assert_equal(Complex(5.0,-3.0), Complex('5.0-3.0i')) + assert_equal(Complex(-5.0,-3.0), Complex('-5.0-3.0i')) + assert_equal(Complex(0.0,3.0), Complex('3.0i')) + assert_equal(Complex(0.0,-3.0), Complex('-3.0i')) + + assert_equal(Complex(5.1), Complex('5.1')) + assert_equal(Complex(-5.2), Complex('-5.2')) + assert_equal(Complex(5.3,3.4), Complex('5.3+3.4i')) + assert_equal(Complex(-5.5,3.6), Complex('-5.5+3.6i')) + assert_equal(Complex(5.3,-3.4), Complex('5.3-3.4i')) + assert_equal(Complex(-5.5,-3.6), Complex('-5.5-3.6i')) + assert_equal(Complex(0.0,3.1), Complex('3.1i')) + assert_equal(Complex(0.0,-3.2), Complex('-3.2i')) + + assert_equal(Complex(5.0), Complex('5e0')) + assert_equal(Complex(-5.0), Complex('-5e0')) + assert_equal(Complex(5.0,3.0), Complex('5e0+3e0i')) + assert_equal(Complex(-5.0,3.0), Complex('-5e0+3e0i')) + assert_equal(Complex(5.0,-3.0), Complex('5e0-3e0i')) + assert_equal(Complex(-5.0,-3.0), Complex('-5e0-3e0i')) + assert_equal(Complex(0.0,3.0), Complex('3e0i')) + assert_equal(Complex(0.0,-3.0), Complex('-3e0i')) + + assert_equal(Complex(5e1), Complex('5e1')) + assert_equal(Complex(-5e2), Complex('-5e2')) + assert_equal(Complex(5e3,3e4), Complex('5e003+3e4i')) + assert_equal(Complex(-5e5,3e6), Complex('-5e5+3e006i')) + assert_equal(Complex(5e3,-3e4), Complex('5e003-3e4i')) + assert_equal(Complex(-5e5,-3e6), Complex('-5e5-3e006i')) + assert_equal(Complex(0.0,3e1), Complex('3e1i')) + assert_equal(Complex(0.0,-3e2), Complex('-3e2i')) + + assert_equal(Complex(0.33), Complex('.33')) + assert_equal(Complex(0.33), Complex('0.33')) + assert_equal(Complex(-0.33), Complex('-.33')) + assert_equal(Complex(-0.33), Complex('-0.33')) + assert_equal(Complex(-0.33), Complex('-0.3_3')) + + assert_equal(Complex.polar(10,10), Complex('10@10')) + assert_equal(Complex.polar(-10,-10), Complex('-10@-10')) + assert_equal(Complex.polar(10.5,10.5), Complex('10.5@10.5')) + assert_equal(Complex.polar(-10.5,-10.5), Complex('-10.5@-10.5')) + + assert_equal(Complex(0), ''.to_c) + assert_equal(Complex(0), ' '.to_c) + assert_equal(Complex(5), "\f\n\r\t\v5\0".to_c) + assert_equal(Complex(0), '_'.to_c) + assert_equal(Complex(0), '_5'.to_c) + assert_equal(Complex(5), '5_'.to_c) + assert_equal(Complex(5), '5x'.to_c) + assert_equal(Complex(5), '5+_3i'.to_c) + assert_equal(Complex(5), '5+3_i'.to_c) + assert_equal(Complex(5,3), '5+3i_'.to_c) + assert_equal(Complex(5,3), '5+3ix'.to_c) + assert_raise(ArgumentError){ Complex('')} + assert_raise(ArgumentError){ Complex('_')} + assert_raise(ArgumentError){ Complex("\f\n\r\t\v5\0")} + assert_raise(ArgumentError){ Complex('_5')} + assert_raise(ArgumentError){ Complex('5_')} + assert_raise(ArgumentError){ Complex('5x')} + assert_raise(ArgumentError){ Complex('5+_3i')} + assert_raise(ArgumentError){ Complex('5+3_i')} + assert_raise(ArgumentError){ Complex('5+3i_')} + assert_raise(ArgumentError){ Complex('5+3ix')} + + assert_equal(Complex(Rational(1,5)), '1/5'.to_c) + assert_equal(Complex(Rational(-1,5)), '-1/5'.to_c) + assert_equal(Complex(Rational(1,5),3), '1/5+3i'.to_c) + assert_equal(Complex(Rational(1,5),-3), '1/5-3i'.to_c) + assert_equal(Complex(Rational(-1,5),3), '-1/5+3i'.to_c) + assert_equal(Complex(Rational(-1,5),-3), '-1/5-3i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c) + assert_equal(Complex.polar(Rational(1,5),Rational(3,2)), Complex('1/5@3/2')) + assert_equal(Complex.polar(Rational(-1,5),Rational(-3,2)), Complex('-1/5@-3/2')) + + end + + def test_respond + c = Complex(1,1) + assert_equal(false, c.respond_to?(:%)) + assert_equal(false, c.respond_to?(:<)) + assert_equal(false, c.respond_to?(:<=)) + assert_equal(false, c.respond_to?(:<=>)) + assert_equal(false, c.respond_to?(:>)) + assert_equal(false, c.respond_to?(:>=)) + assert_equal(false, c.respond_to?(:between?)) + assert_equal(false, c.respond_to?(:div)) + assert_equal(false, c.respond_to?(:divmod)) + assert_equal(false, c.respond_to?(:floor)) + assert_equal(false, c.respond_to?(:ceil)) + assert_equal(false, c.respond_to?(:modulo)) + assert_equal(false, c.respond_to?(:remainder)) + assert_equal(false, c.respond_to?(:round)) + assert_equal(false, c.respond_to?(:step)) + assert_equal(false, c.respond_to?(:tunrcate)) + + assert_equal(false, c.respond_to?(:positive?)) + assert_equal(false, c.respond_to?(:negative?)) + assert_equal(false, c.respond_to?(:sign)) + + assert_equal(false, c.respond_to?(:quotient)) + assert_equal(false, c.respond_to?(:quot)) + assert_equal(false, c.respond_to?(:quotrem)) + + assert_equal(false, c.respond_to?(:gcd)) + assert_equal(false, c.respond_to?(:lcm)) + assert_equal(false, c.respond_to?(:gcdlcm)) + end + + def test_to_i + assert_equal(3, Complex(3).to_i) + assert_equal(3, Integer(Complex(3))) + assert_raise(RangeError){Complex(3,2).to_i} + assert_raise(RangeError){Integer(Complex(3,2))} + end + + def test_to_f + assert_equal(3.0, Complex(3).to_f) + assert_equal(3.0, Float(Complex(3))) + assert_raise(RangeError){Complex(3,2).to_f} + assert_raise(RangeError){Float(Complex(3,2))} + end + + def test_to_r + assert_equal(Rational(3), Complex(3).to_r) + assert_equal(Rational(3), Rational(Complex(3))) + assert_raise(RangeError){Complex(3,2).to_r} + assert_raise(RangeError){Rational(Complex(3,2))} + end + + def test_to_c + c = nil.to_c + assert_equal([0,0], [c.real, c.imag]) + + c = 0.to_c + assert_equal([0,0], [c.real, c.imag]) + + c = 1.to_c + assert_equal([1,0], [c.real, c.imag]) + + c = 1.1.to_c + assert_equal([1.1, 0], [c.real, c.imag]) + + c = Rational(1,2).to_c + assert_equal([Rational(1,2), 0], [c.real, c.imag]) + + c = Complex(1,2).to_c + assert_equal([1, 2], [c.real, c.imag]) + + if (0.0/0).nan? + assert_nothing_raised{(0.0/0).to_c} + end + if (1.0/0).infinite? + assert_nothing_raised{(1.0/0).to_c} + end + end + + def test_supp + assert_equal(true, 1.real?) + assert_equal(true, 1.1.real?) + + assert_equal(1, 1.real) + assert_equal(0, 1.imag) + assert_equal(0, 1.imaginary) + + assert_equal(1.1, 1.1.real) + assert_equal(0, 1.1.imag) + assert_equal(0, 1.1.imaginary) + + assert_equal(1, 1.magnitude) + assert_equal(1, -1.magnitude) + assert_equal(1, 1.0.magnitude) + assert_equal(1, -1.0.magnitude) + + assert_equal(4, 2.abs2) + assert_equal(4, -2.abs2) + assert_equal(4.0, 2.0.abs2) + assert_equal(4.0, -2.0.abs2) + + assert_equal(0, 1.arg) + assert_equal(0, 1.angle) + assert_equal(0, 1.phase) + + assert_equal(0, 1.0.arg) + assert_equal(0, 1.0.angle) + assert_equal(0, 1.0.phase) + + if (0.0/0).nan? + nan = 0.0/0 + assert_same(nan, nan.arg) + assert_same(nan, nan.angle) + assert_same(nan, nan.phase) + end + + assert_equal(Math::PI, -1.arg) + assert_equal(Math::PI, -1.angle) + assert_equal(Math::PI, -1.phase) + + assert_equal(Math::PI, -1.0.arg) + assert_equal(Math::PI, -1.0.angle) + assert_equal(Math::PI, -1.0.phase) + + assert_equal([1,0], 1.rect) + assert_equal([-1,0], -1.rect) + assert_equal([1,0], 1.rectangular) + assert_equal([-1,0], -1.rectangular) + + assert_equal([1.0,0], 1.0.rect) + assert_equal([-1.0,0], -1.0.rect) + assert_equal([1.0,0], 1.0.rectangular) + assert_equal([-1.0,0], -1.0.rectangular) + + assert_equal([1,0], 1.polar) + assert_equal([1, Math::PI], -1.polar) + + assert_equal([1.0,0], 1.0.polar) + assert_equal([1.0, Math::PI], -1.0.polar) + + assert_equal(1, 1.conjugate) + assert_equal(-1, -1.conjugate) + assert_equal(1, 1.conj) + assert_equal(-1, -1.conj) + + assert_equal(1.1, 1.1.conjugate) + assert_equal(-1.1, -1.1.conjugate) + assert_equal(1.1, 1.1.conj) + assert_equal(-1.1, -1.1.conj) + + assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) + + assert_equal(0.5, 1.fdiv(2)) + assert_equal(5000000000.0, 10000000000.fdiv(2)) + assert_equal(0.5, 1.0.fdiv(2)) + assert_equal(0.25, Rational(1,2).fdiv(2)) + assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) + + unless $".grep(/(?:\A|(?<!add)\/)complex/).empty? + assert_equal(Complex(0,2), CMath.sqrt(-4.0)) + assert_equal(Complex(0,2), CMath.sqrt(-4)) + assert_equal(Complex(0,2), CMath.sqrt(Rational(-4))) + + assert_equal(Complex(0,3), CMath.sqrt(-9.0)) + assert_equal(Complex(0,3), CMath.sqrt(-9)) + assert_equal(Complex(0,3), CMath.sqrt(Rational(-9))) + + c = CMath.sqrt(Complex(1, 2)) + assert_in_delta(1.272, c.real, 0.001) + assert_in_delta(0.786, c.imag, 0.001) + + c = CMath.sqrt(-9) + assert_in_delta(0.0, c.real, 0.001) + assert_in_delta(3.0, c.imag, 0.001) + + c = CMath.exp(Complex(1, 2)) + assert_in_delta(-1.131, c.real, 0.001) + assert_in_delta(2.471, c.imag, 0.001) + + c = CMath.sin(Complex(1, 2)) + assert_in_delta(3.165, c.real, 0.001) + assert_in_delta(1.959, c.imag, 0.001) + + c = CMath.cos(Complex(1, 2)) + assert_in_delta(2.032, c.real, 0.001) + assert_in_delta(-3.051, c.imag, 0.001) + + c = CMath.tan(Complex(1, 2)) + assert_in_delta(0.033, c.real, 0.001) + assert_in_delta(1.014, c.imag, 0.001) + + c = CMath.sinh(Complex(1, 2)) + assert_in_delta(-0.489, c.real, 0.001) + assert_in_delta(1.403, c.imag, 0.001) + + c = CMath.cosh(Complex(1, 2)) + assert_in_delta(-0.642, c.real, 0.001) + assert_in_delta(1.068, c.imag, 0.001) + + c = CMath.tanh(Complex(1, 2)) + assert_in_delta(1.166, c.real, 0.001) + assert_in_delta(-0.243, c.imag, 0.001) + + c = CMath.log(Complex(1, 2)) + assert_in_delta(0.804, c.real, 0.001) + assert_in_delta(1.107, c.imag, 0.001) + + c = CMath.log(Complex(1, 2), Math::E) + assert_in_delta(0.804, c.real, 0.001) + assert_in_delta(1.107, c.imag, 0.001) + + c = CMath.log(-1) + assert_in_delta(0.0, c.real, 0.001) + assert_in_delta(Math::PI, c.imag, 0.001) + + c = CMath.log(8, 2) + assert_in_delta(3.0, c.real, 0.001) + assert_in_delta(0.0, c.imag, 0.001) + + c = CMath.log(-8, -2) + assert_in_delta(1.092, c.real, 0.001) + assert_in_delta(-0.420, c.imag, 0.001) + + c = CMath.log10(Complex(1, 2)) + assert_in_delta(0.349, c.real, 0.001) + assert_in_delta(0.480, c.imag, 0.001) + + c = CMath.asin(Complex(1, 2)) + assert_in_delta(0.427, c.real, 0.001) + assert_in_delta(1.528, c.imag, 0.001) + + c = CMath.acos(Complex(1, 2)) + assert_in_delta(1.143, c.real, 0.001) + assert_in_delta(-1.528, c.imag, 0.001) + + c = CMath.atan(Complex(1, 2)) + assert_in_delta(1.338, c.real, 0.001) + assert_in_delta(0.402, c.imag, 0.001) + + c = CMath.atan2(Complex(1, 2), 1) + assert_in_delta(1.338, c.real, 0.001) + assert_in_delta(0.402, c.imag, 0.001) + + c = CMath.asinh(Complex(1, 2)) + assert_in_delta(1.469, c.real, 0.001) + assert_in_delta(1.063, c.imag, 0.001) + + c = CMath.acosh(Complex(1, 2)) + assert_in_delta(1.528, c.real, 0.001) + assert_in_delta(1.143, c.imag, 0.001) + + c = CMath.atanh(Complex(1, 2)) + assert_in_delta(0.173, c.real, 0.001) + assert_in_delta(1.178, c.imag, 0.001) + end + + end + + def test_ruby19 + assert_raise(NoMethodError){ Complex.new(1) } + assert_raise(NoMethodError){ Complex.new!(1) } + assert_raise(NoMethodError){ Complex.reduce(1) } + end + + def test_fixed_bug + assert_equal(Complex(1), 1 ** Complex(1)) + assert_equal('-1.0-0.0i', Complex(-1.0, -0.0).to_s) + assert_in_delta(Math::PI, Complex(-0.0).arg, 0.001) + assert_equal(Complex(2e3, 2e4), '2e3+2e4i'.to_c) + assert_raise(ArgumentError){ Complex('--8i')} + end + + def test_known_bug + end + +end diff --git a/jni/ruby/test/ruby/test_complex2.rb b/jni/ruby/test/ruby/test_complex2.rb new file mode 100644 index 0000000..3ee7810 --- /dev/null +++ b/jni/ruby/test/ruby/test_complex2.rb @@ -0,0 +1,735 @@ +require 'test/unit' + +class Complex_Test2 < Test::Unit::TestCase + + def test_kumi + skip unless defined?(Rational) + + assert_equal(Complex(1, 0), +Complex(1, 0)) + assert_equal(Complex(-1, 0), -Complex(1, 0)) + assert_equal(Complex(2, 0), + Complex(1, 0) + Complex(1, 0)) + assert_equal(Complex(0, 0), + Complex(1, 0) - Complex(1, 0)) + assert_equal(Complex(1, 0), + Complex(1, 0) * Complex(1, 0)) + assert_equal(Complex(1, 0), + Complex(1, 0) / Complex(1, 0)) + assert_equal(Complex(1073741790, 0), + Complex(1, 0) + Complex(1073741789, 0)) + assert_equal(Complex(-1073741788, 0), + Complex(1, 0) - Complex(1073741789, 0)) + assert_equal(Complex(1073741789, 0), + Complex(1, 0) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1, 1073741789), 0), + Complex(1, 0) / Complex(1073741789, 0)) + assert_equal(Complex(1073741828, 0), + Complex(1, 0) + Complex(1073741827, 0)) + assert_equal(Complex(-1073741826, 0), + Complex(1, 0) - Complex(1073741827, 0)) + assert_equal(Complex(1073741827, 0), + Complex(1, 0) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1, 1073741827), 0), + Complex(1, 0) / Complex(1073741827, 0)) + assert_equal(Complex(1073741790, 1073741789), + Complex(1, 0) + Complex(1073741789, 1073741789)) + assert_equal(Complex(-1073741788, -1073741789), + Complex(1, 0) - Complex(1073741789, 1073741789)) + assert_equal(Complex(1073741789, 1073741789), + Complex(1, 0) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1, 2147483578), Rational(-1, 2147483578)), + Complex(1, 0) / Complex(1073741789, 1073741789)) + assert_equal(Complex(1073741790, 1073741827), + Complex(1, 0) + Complex(1073741789, 1073741827)) + assert_equal(Complex(-1073741788, -1073741827), + Complex(1, 0) - Complex(1073741789, 1073741827)) + assert_equal(Complex(1073741789, 1073741827), + Complex(1, 0) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1073741789, 2305842940494218450), Rational(-1073741827, 2305842940494218450)), + Complex(1, 0) / Complex(1073741789, 1073741827)) + assert_equal(Complex(1073741828, 1073741827), + Complex(1, 0) + Complex(1073741827, 1073741827)) + assert_equal(Complex(-1073741826, -1073741827), + Complex(1, 0) - Complex(1073741827, 1073741827)) + assert_equal(Complex(1073741827, 1073741827), + Complex(1, 0) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1, 2147483654), Rational(-1, 2147483654)), + Complex(1, 0) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741789, 1073741827)), + Complex(1, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(38, 1073741827), Rational(-1073741789, 1073741827)), + Complex(1, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), + Complex(1, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1073741827, 2147483578), Rational(-1073741827, 2147483578)), + Complex(1, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(2147483616, 1073741789), Rational(1073741827, 1073741789)), + Complex(1, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-38, 1073741789), Rational(-1073741827, 1073741789)), + Complex(1, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), + Complex(1, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741789, 2147483654), Rational(-1073741789, 2147483654)), + Complex(1, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741827, 1073741789)), + Complex(1, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(38, 1073741827), Rational(-1073741827, 1073741789)), + Complex(1, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)), + Complex(1, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1329227869515035739611240300898290063, 2658455833113515253509575011810600482), Rational(-1329227963598474519442525600436190287, 2658455833113515253509575011810600482)), + Complex(1, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741789, 0), +Complex(1073741789, 0)) + assert_equal(Complex(-1073741789, 0), -Complex(1073741789, 0)) + assert_equal(Complex(1073741790, 0), + Complex(1073741789, 0) + Complex(1, 0)) + assert_equal(Complex(1073741788, 0), + Complex(1073741789, 0) - Complex(1, 0)) + assert_equal(Complex(1073741789, 0), + Complex(1073741789, 0) * Complex(1, 0)) + assert_equal(Complex(1073741789, 0), + Complex(1073741789, 0) / Complex(1, 0)) + assert_equal(Complex(2147483578, 0), + Complex(1073741789, 0) + Complex(1073741789, 0)) + assert_equal(Complex(0, 0), + Complex(1073741789, 0) - Complex(1073741789, 0)) + assert_equal(Complex(1152921429444920521, 0), + Complex(1073741789, 0) * Complex(1073741789, 0)) + assert_equal(Complex(1, 0), + Complex(1073741789, 0) / Complex(1073741789, 0)) + assert_equal(Complex(2147483616, 0), + Complex(1073741789, 0) + Complex(1073741827, 0)) + assert_equal(Complex(-38, 0), + Complex(1073741789, 0) - Complex(1073741827, 0)) + assert_equal(Complex(1152921470247108503, 0), + Complex(1073741789, 0) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), 0), + Complex(1073741789, 0) / Complex(1073741827, 0)) + assert_equal(Complex(2147483578, 1073741789), + Complex(1073741789, 0) + Complex(1073741789, 1073741789)) + assert_equal(Complex(0, -1073741789), + Complex(1073741789, 0) - Complex(1073741789, 1073741789)) + assert_equal(Complex(1152921429444920521, 1152921429444920521), + Complex(1073741789, 0) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1, 2), Rational(-1, 2)), + Complex(1073741789, 0) / Complex(1073741789, 1073741789)) + assert_equal(Complex(2147483578, 1073741827), + Complex(1073741789, 0) + Complex(1073741789, 1073741827)) + assert_equal(Complex(0, -1073741827), + Complex(1073741789, 0) - Complex(1073741789, 1073741827)) + assert_equal(Complex(1152921429444920521, 1152921470247108503), + Complex(1073741789, 0) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921429444920521, 2305842940494218450), Rational(-1152921470247108503, 2305842940494218450)), + Complex(1073741789, 0) / Complex(1073741789, 1073741827)) + assert_equal(Complex(2147483616, 1073741827), + Complex(1073741789, 0) + Complex(1073741827, 1073741827)) + assert_equal(Complex(-38, -1073741827), + Complex(1073741789, 0) - Complex(1073741827, 1073741827)) + assert_equal(Complex(1152921470247108503, 1152921470247108503), + Complex(1073741789, 0) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1073741789, 2147483654), Rational(-1073741789, 2147483654)), + Complex(1073741789, 0) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1073741827)), + Complex(1073741789, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(-1073741789, 1073741827)), + Complex(1073741789, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921429444920521, 1073741827), Rational(1152921429444920521, 1073741827)), + Complex(1073741789, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1073741827, 2), Rational(-1073741827, 2)), + Complex(1073741789, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1073741827, 1073741789)), + Complex(1073741789, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(-1073741827, 1073741789)), + Complex(1073741789, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741827, 1073741827), + Complex(1073741789, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921429444920521, 2147483654), Rational(-1152921429444920521, 2147483654)), + Complex(1073741789, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741827, 1073741789)), + Complex(1073741789, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(-1073741827, 1073741789)), + Complex(1073741789, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921429444920521, 1073741827), 1073741827), + Complex(1073741789, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1427247510601733037449111325195428279286542707, 2658455833113515253509575011810600482), Rational(-1427247611623052908177132720890654139107803443, 2658455833113515253509575011810600482)), + Complex(1073741789, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741827, 0), +Complex(1073741827, 0)) + assert_equal(Complex(-1073741827, 0), -Complex(1073741827, 0)) + assert_equal(Complex(1073741828, 0), + Complex(1073741827, 0) + Complex(1, 0)) + assert_equal(Complex(1073741826, 0), + Complex(1073741827, 0) - Complex(1, 0)) + assert_equal(Complex(1073741827, 0), + Complex(1073741827, 0) * Complex(1, 0)) + assert_equal(Complex(1073741827, 0), + Complex(1073741827, 0) / Complex(1, 0)) + assert_equal(Complex(2147483616, 0), + Complex(1073741827, 0) + Complex(1073741789, 0)) + assert_equal(Complex(38, 0), + Complex(1073741827, 0) - Complex(1073741789, 0)) + assert_equal(Complex(1152921470247108503, 0), + Complex(1073741827, 0) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1073741827, 1073741789), 0), + Complex(1073741827, 0) / Complex(1073741789, 0)) + assert_equal(Complex(2147483654, 0), + Complex(1073741827, 0) + Complex(1073741827, 0)) + assert_equal(Complex(0, 0), + Complex(1073741827, 0) - Complex(1073741827, 0)) + assert_equal(Complex(1152921511049297929, 0), + Complex(1073741827, 0) * Complex(1073741827, 0)) + assert_equal(Complex(1, 0), + Complex(1073741827, 0) / Complex(1073741827, 0)) + assert_equal(Complex(2147483616, 1073741789), + Complex(1073741827, 0) + Complex(1073741789, 1073741789)) + assert_equal(Complex(38, -1073741789), + Complex(1073741827, 0) - Complex(1073741789, 1073741789)) + assert_equal(Complex(1152921470247108503, 1152921470247108503), + Complex(1073741827, 0) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1073741827, 2147483578), Rational(-1073741827, 2147483578)), + Complex(1073741827, 0) / Complex(1073741789, 1073741789)) + assert_equal(Complex(2147483616, 1073741827), + Complex(1073741827, 0) + Complex(1073741789, 1073741827)) + assert_equal(Complex(38, -1073741827), + Complex(1073741827, 0) - Complex(1073741789, 1073741827)) + assert_equal(Complex(1152921470247108503, 1152921511049297929), + Complex(1073741827, 0) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921470247108503, 2305842940494218450), Rational(-1152921511049297929, 2305842940494218450)), + Complex(1073741827, 0) / Complex(1073741789, 1073741827)) + assert_equal(Complex(2147483654, 1073741827), + Complex(1073741827, 0) + Complex(1073741827, 1073741827)) + assert_equal(Complex(0, -1073741827), + Complex(1073741827, 0) - Complex(1073741827, 1073741827)) + assert_equal(Complex(1152921511049297929, 1152921511049297929), + Complex(1073741827, 0) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1, 2), Rational(-1, 2)), + Complex(1073741827, 0) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741789, 1073741827)), + Complex(1073741827, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(-1073741789, 1073741827)), + Complex(1073741827, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(1073741789, 1073741789), + Complex(1073741827, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921511049297929, 2147483578), Rational(-1152921511049297929, 2147483578)), + Complex(1073741827, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1073741789)), + Complex(1073741827, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921469173366676, 1073741789), Rational(-1073741827, 1073741789)), + Complex(1073741827, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921511049297929, 1073741789), Rational(1152921511049297929, 1073741789)), + Complex(1073741827, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741789, 2), Rational(-1073741789, 2)), + Complex(1073741827, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741827, 1073741789)), + Complex(1073741827, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(-1073741827, 1073741789)), + Complex(1073741827, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741789, Rational(1152921511049297929, 1073741789)), + Complex(1073741827, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1427247561112392079020469430422559713421565101, 2658455833113515253509575011810600482), Rational(-1427247662133715524919164459706626955683034349, 2658455833113515253509575011810600482)), + Complex(1073741827, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741789, 1073741789), +Complex(1073741789, 1073741789)) + assert_equal(Complex(-1073741789, -1073741789), -Complex(1073741789, 1073741789)) + assert_equal(Complex(1073741790, 1073741789), + Complex(1073741789, 1073741789) + Complex(1, 0)) + assert_equal(Complex(1073741788, 1073741789), + Complex(1073741789, 1073741789) - Complex(1, 0)) + assert_equal(Complex(1073741789, 1073741789), + Complex(1073741789, 1073741789) * Complex(1, 0)) + assert_equal(Complex(1073741789, 1073741789), + Complex(1073741789, 1073741789) / Complex(1, 0)) + assert_equal(Complex(2147483578, 1073741789), + Complex(1073741789, 1073741789) + Complex(1073741789, 0)) + assert_equal(Complex(0, 1073741789), + Complex(1073741789, 1073741789) - Complex(1073741789, 0)) + assert_equal(Complex(1152921429444920521, 1152921429444920521), + Complex(1073741789, 1073741789) * Complex(1073741789, 0)) + assert_equal(Complex(1, 1), + Complex(1073741789, 1073741789) / Complex(1073741789, 0)) + assert_equal(Complex(2147483616, 1073741789), + Complex(1073741789, 1073741789) + Complex(1073741827, 0)) + assert_equal(Complex(-38, 1073741789), + Complex(1073741789, 1073741789) - Complex(1073741827, 0)) + assert_equal(Complex(1152921470247108503, 1152921470247108503), + Complex(1073741789, 1073741789) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), + Complex(1073741789, 1073741789) / Complex(1073741827, 0)) + assert_equal(Complex(2147483578, 2147483578), + Complex(1073741789, 1073741789) + Complex(1073741789, 1073741789)) + assert_equal(Complex(0, 0), + Complex(1073741789, 1073741789) - Complex(1073741789, 1073741789)) + assert_equal(Complex(0, 2305842858889841042), + Complex(1073741789, 1073741789) * Complex(1073741789, 1073741789)) + assert_equal(Complex(1, 0), + Complex(1073741789, 1073741789) / Complex(1073741789, 1073741789)) + assert_equal(Complex(2147483578, 2147483616), + Complex(1073741789, 1073741789) + Complex(1073741789, 1073741827)) + assert_equal(Complex(0, -38), + Complex(1073741789, 1073741789) - Complex(1073741789, 1073741827)) + assert_equal(Complex(-40802187982, 2305842899692029024), + Complex(1073741789, 1073741789) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921449846014512, 1152921470247109225), Rational(-20401093991, 1152921470247109225)), + Complex(1073741789, 1073741789) / Complex(1073741789, 1073741827)) + assert_equal(Complex(2147483616, 2147483616), + Complex(1073741789, 1073741789) + Complex(1073741827, 1073741827)) + assert_equal(Complex(-38, -38), + Complex(1073741789, 1073741789) - Complex(1073741827, 1073741827)) + assert_equal(Complex(0, 2305842940494217006), + Complex(1073741789, 1073741789) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1073741789, 1073741827), 0), + Complex(1073741789, 1073741789) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850292, 1073741827)), + Complex(1073741789, 1073741789) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921469173366714, 1073741827)), + Complex(1073741789, 1073741789) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, Rational(2305842858889841042, 1073741827)), + Complex(1073741789, 1073741789) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(1073741827, 0), + Complex(1073741789, 1073741789) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921430518662348, 1073741789)), + Complex(1073741789, 1073741789) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(1152921428371178694, 1073741789)), + Complex(1073741789, 1073741789) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, 2147483654), + Complex(1073741789, 1073741789) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921429444920521, 1073741827), 0), + Complex(1073741789, 1073741789) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921430518662348, 1073741789)), + Complex(1073741789, 1073741789) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921428371178694, 1073741789)), + Complex(1073741789, 1073741789) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1073741827), Rational(2305842940494218450, 1073741827)), + Complex(1073741789, 1073741789) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1427247561112392972813122023043041209197173075, 1329227916556757626754787505905300241), Rational(-50510659935364010697847612929910630368, 1329227916556757626754787505905300241)), + Complex(1073741789, 1073741789) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741789, 1073741827), +Complex(1073741789, 1073741827)) + assert_equal(Complex(-1073741789, -1073741827), -Complex(1073741789, 1073741827)) + assert_equal(Complex(1073741790, 1073741827), + Complex(1073741789, 1073741827) + Complex(1, 0)) + assert_equal(Complex(1073741788, 1073741827), + Complex(1073741789, 1073741827) - Complex(1, 0)) + assert_equal(Complex(1073741789, 1073741827), + Complex(1073741789, 1073741827) * Complex(1, 0)) + assert_equal(Complex(1073741789, 1073741827), + Complex(1073741789, 1073741827) / Complex(1, 0)) + assert_equal(Complex(2147483578, 1073741827), + Complex(1073741789, 1073741827) + Complex(1073741789, 0)) + assert_equal(Complex(0, 1073741827), + Complex(1073741789, 1073741827) - Complex(1073741789, 0)) + assert_equal(Complex(1152921429444920521, 1152921470247108503), + Complex(1073741789, 1073741827) * Complex(1073741789, 0)) + assert_equal(Complex(1, Rational(1073741827, 1073741789)), + Complex(1073741789, 1073741827) / Complex(1073741789, 0)) + assert_equal(Complex(2147483616, 1073741827), + Complex(1073741789, 1073741827) + Complex(1073741827, 0)) + assert_equal(Complex(-38, 1073741827), + Complex(1073741789, 1073741827) - Complex(1073741827, 0)) + assert_equal(Complex(1152921470247108503, 1152921511049297929), + Complex(1073741789, 1073741827) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), 1), + Complex(1073741789, 1073741827) / Complex(1073741827, 0)) + assert_equal(Complex(2147483578, 2147483616), + Complex(1073741789, 1073741827) + Complex(1073741789, 1073741789)) + assert_equal(Complex(0, 38), + Complex(1073741789, 1073741827) - Complex(1073741789, 1073741789)) + assert_equal(Complex(-40802187982, 2305842899692029024), + Complex(1073741789, 1073741827) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1073741808, 1073741789), Rational(19, 1073741789)), + Complex(1073741789, 1073741827) / Complex(1073741789, 1073741789)) + assert_equal(Complex(2147483578, 2147483654), + Complex(1073741789, 1073741827) + Complex(1073741789, 1073741827)) + assert_equal(Complex(0, 0), + Complex(1073741789, 1073741827) - Complex(1073741789, 1073741827)) + assert_equal(Complex(-81604377408, 2305842940494217006), + Complex(1073741789, 1073741827) * Complex(1073741789, 1073741827)) + assert_equal(Complex(1, 0), + Complex(1073741789, 1073741827) / Complex(1073741789, 1073741827)) + assert_equal(Complex(2147483616, 2147483654), + Complex(1073741789, 1073741827) + Complex(1073741827, 1073741827)) + assert_equal(Complex(-38, 0), + Complex(1073741789, 1073741827) - Complex(1073741827, 1073741827)) + assert_equal(Complex(-40802189426, 2305842981296406432), + Complex(1073741789, 1073741827) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1073741808, 1073741827), Rational(19, 1073741827)), + Complex(1073741789, 1073741827) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921512123039718, 1073741827)), + Complex(1073741789, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921509975556140, 1073741827)), + Complex(1073741789, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(-40802187982, 1073741827), Rational(2305842899692029024, 1073741827)), + Complex(1073741789, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921490648203216, 1073741789), Rational(20401094713, 1073741789)), + Complex(1073741789, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921471320850330, 1073741789)), + Complex(1073741789, 1073741827) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(1152921469173366676, 1073741789)), + Complex(1073741789, 1073741827) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-40802189426, 1073741789), Rational(2305842981296406432, 1073741789)), + Complex(1073741789, 1073741827) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921449846014512, 1073741827), Rational(20401093991, 1073741827)), + Complex(1073741789, 1073741827) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850330, 1073741789)), + Complex(1073741789, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921469173366676, 1073741789)), + Complex(1073741789, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-131433047608170424214, 1152921470247108503), 2147483616), + Complex(1073741789, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1427247586367724281184137892451027617484788528, 1329227916556757626754787505905300241), Rational(-25255330414578331645234047212843119171, 1329227916556757626754787505905300241)), + Complex(1073741789, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741827, 1073741827), +Complex(1073741827, 1073741827)) + assert_equal(Complex(-1073741827, -1073741827), -Complex(1073741827, 1073741827)) + assert_equal(Complex(1073741828, 1073741827), + Complex(1073741827, 1073741827) + Complex(1, 0)) + assert_equal(Complex(1073741826, 1073741827), + Complex(1073741827, 1073741827) - Complex(1, 0)) + assert_equal(Complex(1073741827, 1073741827), + Complex(1073741827, 1073741827) * Complex(1, 0)) + assert_equal(Complex(1073741827, 1073741827), + Complex(1073741827, 1073741827) / Complex(1, 0)) + assert_equal(Complex(2147483616, 1073741827), + Complex(1073741827, 1073741827) + Complex(1073741789, 0)) + assert_equal(Complex(38, 1073741827), + Complex(1073741827, 1073741827) - Complex(1073741789, 0)) + assert_equal(Complex(1152921470247108503, 1152921470247108503), + Complex(1073741827, 1073741827) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), + Complex(1073741827, 1073741827) / Complex(1073741789, 0)) + assert_equal(Complex(2147483654, 1073741827), + Complex(1073741827, 1073741827) + Complex(1073741827, 0)) + assert_equal(Complex(0, 1073741827), + Complex(1073741827, 1073741827) - Complex(1073741827, 0)) + assert_equal(Complex(1152921511049297929, 1152921511049297929), + Complex(1073741827, 1073741827) * Complex(1073741827, 0)) + assert_equal(Complex(1, 1), + Complex(1073741827, 1073741827) / Complex(1073741827, 0)) + assert_equal(Complex(2147483616, 2147483616), + Complex(1073741827, 1073741827) + Complex(1073741789, 1073741789)) + assert_equal(Complex(38, 38), + Complex(1073741827, 1073741827) - Complex(1073741789, 1073741789)) + assert_equal(Complex(0, 2305842940494217006), + Complex(1073741827, 1073741827) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1073741827, 1073741789), 0), + Complex(1073741827, 1073741827) / Complex(1073741789, 1073741789)) + assert_equal(Complex(2147483616, 2147483654), + Complex(1073741827, 1073741827) + Complex(1073741789, 1073741827)) + assert_equal(Complex(38, 0), + Complex(1073741827, 1073741827) - Complex(1073741789, 1073741827)) + assert_equal(Complex(-40802189426, 2305842981296406432), + Complex(1073741827, 1073741827) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921490648203216, 1152921470247109225), Rational(-20401094713, 1152921470247109225)), + Complex(1073741827, 1073741827) / Complex(1073741789, 1073741827)) + assert_equal(Complex(2147483654, 2147483654), + Complex(1073741827, 1073741827) + Complex(1073741827, 1073741827)) + assert_equal(Complex(0, 0), + Complex(1073741827, 1073741827) - Complex(1073741827, 1073741827)) + assert_equal(Complex(0, 2305843022098595858), + Complex(1073741827, 1073741827) * Complex(1073741827, 1073741827)) + assert_equal(Complex(1, 0), + Complex(1073741827, 1073741827) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921512123039718, 1073741827)), + Complex(1073741827, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(1152921509975556140, 1073741827)), + Complex(1073741827, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, 2147483578), + Complex(1073741827, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921511049297929, 1073741789), 0), + Complex(1073741827, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1152921471320850330, 1073741789)), + Complex(1073741827, 1073741827) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921469173366676, 1073741789), Rational(1152921469173366676, 1073741789)), + Complex(1073741827, 1073741827) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, Rational(2305843022098595858, 1073741789)), + Complex(1073741827, 1073741827) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(1073741789, 0), + Complex(1073741827, 1073741827) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921471320850330, 1073741789)), + Complex(1073741827, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(1152921469173366676, 1073741789)), + Complex(1073741827, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1073741789), Rational(2305842940494218450, 1073741789)), + Complex(1073741827, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1427247611623053801969816945064593334552299725, 1329227916556757626754787505905300241), Rational(-50510661722949347514642033621130734624, 1329227916556757626754787505905300241)), + Complex(1073741827, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), +Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(-1073741789, 1073741827), Rational(-1073741789, 1073741827)), -Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1, 0)) + assert_equal(Complex(Rational(-38, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1, 0)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 0)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 0)) + assert_equal(Complex(Rational(1152921429444920521, 1073741827), Rational(1152921429444920521, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1, 1073741827), Rational(1, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 0)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741827, 0)) + assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(1073741789, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741827, 0)) + assert_equal(Complex(1073741789, 1073741789), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1073741789, 1152921511049297929), Rational(1073741789, 1152921511049297929)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741827, 0)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850292, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921469173366714, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 1073741789)) + assert_equal(Complex(0, Rational(2305842858889841042, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1, 1073741827), 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921512123039718, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921509975556140, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-40802187982, 1073741827), Rational(2305842899692029024, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921449846014512, 1237940005850657200720054075), Rational(-20401093991, 1237940005850657200720054075)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921512123039718, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(-1152921509975556140, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741827, 1073741827)) + assert_equal(Complex(0, 2147483578), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1073741789, 1152921511049297929), 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2147483578, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, Rational(2305842858889841042, 1152921511049297929)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(1, 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2305842940494218450, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1152921470247108503), Rational(-81604377408, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, 2), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921429444920521, 1152921511049297929), 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2305842940494218450, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, Rational(-81604377408, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1152921511049297929), Rational(2305842940494218450, 1152921511049297929)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1329227869515036572020512360130906225, 1329227916556757626754787505905300241), Rational(-47041717725097069072123994784, 1329227916556757626754787505905300241)), + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), +Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-1073741827, 1073741789), Rational(-1073741827, 1073741789)), -Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2147483616, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1, 0)) + assert_equal(Complex(Rational(38, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1, 0)) + assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1, 0)) + assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1, 0)) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 0)) + assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 0)) + assert_equal(Complex(1073741827, 1073741827), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1073741827, 1152921429444920521), Rational(1073741827, 1152921429444920521)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 0)) + assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741827, 0)) + assert_equal(Complex(Rational(-1152921469173366676, 1073741789), Rational(1073741827, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741827, 0)) + assert_equal(Complex(Rational(1152921511049297929, 1073741789), Rational(1152921511049297929, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1, 1073741789), Rational(1, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741827, 0)) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921430518662348, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(-1152921428371178694, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741789)) + assert_equal(Complex(0, 2147483654), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1073741827, 1152921429444920521), 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921471320850330, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(-1152921469173366676, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-40802189426, 1073741789), Rational(2305842981296406432, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921490648203216, 1237939962039641331329903525), Rational(-20401094713, 1237939962039641331329903525)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1152921471320850330, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(-1152921469173366676, 1073741789), Rational(-1152921469173366676, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741827, 1073741827)) + assert_equal(Complex(0, Rational(2305843022098595858, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1, 1073741789), 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2305842940494218450, 1152921470247108503)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(81604377408, 1152921470247108503), Rational(81604377408, 1152921470247108503)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, 2), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921511049297929, 1152921429444920521), 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(2147483654, 1073741789), Rational(2147483654, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, Rational(2305843022098595858, 1152921429444920521)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(1, 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2147483654, 1073741789)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(81604377408, 1152921470247108503), 0), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1152921429444920521), Rational(2305842940494218450, 1152921429444920521)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1329227963598475351851856578029295025, 1329227916556757626754787505905300241), Rational(-47041721054734275145774394016, 1329227916556757626754787505905300241)), + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)), +Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-1073741789, 1073741827), Rational(-1073741827, 1073741789)), -Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1, 0)) + assert_equal(Complex(Rational(-38, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1, 0)) + assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1, 0)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 0)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 0)) + assert_equal(Complex(Rational(1152921429444920521, 1073741827), 1073741827), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 0)) + assert_equal(Complex(Rational(1, 1073741827), Rational(1073741827, 1152921429444920521)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 0)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741827, 0)) + assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(1073741827, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741827, 0)) + assert_equal(Complex(1073741789, Rational(1152921511049297929, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741827, 0)) + assert_equal(Complex(Rational(1073741789, 1152921511049297929), Rational(1, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741827, 0)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921430518662348, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921428371178694, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(-81604377408, 1073741827), Rational(2305842940494218450, 1073741827)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1152921470247109225, 1237939962039640556088331867), Rational(40802188704, 1237939962039640556088331867)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741789)) + assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850330, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921469173366676, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(-131433047608170424214, 1152921470247108503), 2147483616), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1237939983945150041266564176, 1329227916556755129526882950667240175), Rational(19, 1152921470247109225)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741827)) + assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921471320850330, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(-1152921469173366676, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(-81604377408, 1073741789), Rational(2305842940494218450, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(1152921470247109225, 1237940005850656425478454981), Rational(40802188704, 1237940005850656425478454981)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741827, 1073741827)) + assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2305842940494218450, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(0, Rational(81604377408, 1152921470247108503)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(-81604377408, 1152921511049297929), Rational(2305842940494218450, 1152921511049297929)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(1152921470247109225, 1152921429444920521), Rational(40802188704, 1152921429444920521)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827))) + assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2147483654, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1152921470247108503), 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-81604377408, 1152921429444920521), Rational(2305842940494218450, 1152921429444920521)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(1152921470247109225, 1152921511049297929), Rational(40802188704, 1152921511049297929)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2147483654, 1073741789)), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(0, 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(Rational(-188166877559662688435796777600, 1329227916556754297117581432254901009), 2), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + assert_equal(Complex(1, 0), + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789))) + end + + def test_kumi2 + assert_equal('0.0+0.0i', (+Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0-0.0i', (-Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) * Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(-0.0, +0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(+0.0, +0.0) * Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) * Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(-0.0, -0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, +0.0) * Complex(-0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (+Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (-Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) + Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) - Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) * Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) + Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) - Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(-0.0, +0.0) * Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) + Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) - Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) * Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) + Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) - Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) * Complex(-0.0, -0.0)).to_s) + assert_equal('0.0-0.0i', (+Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (-Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) + Complex(+0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) - Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) * Complex(+0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) + Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) - Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) * Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) + Complex(+0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) - Complex(+0.0, -0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) * Complex(+0.0, -0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) + Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) - Complex(-0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(+0.0, -0.0) * Complex(-0.0, -0.0)).to_s) + assert_equal('-0.0-0.0i', (+Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (-Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) + Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0-0.0i', (Complex(-0.0, -0.0) - Complex(+0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) * Complex(+0.0, +0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) + Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) - Complex(-0.0, +0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) * Complex(-0.0, +0.0)).to_s) + assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) + Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) - Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) * Complex(+0.0, -0.0)).to_s) + assert_equal('-0.0-0.0i', (Complex(-0.0, -0.0) + Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) - Complex(-0.0, -0.0)).to_s) + assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) * Complex(-0.0, -0.0)).to_s) + end + +end diff --git a/jni/ruby/test/ruby/test_complexrational.rb b/jni/ruby/test/ruby/test_complexrational.rb new file mode 100644 index 0000000..cef4074 --- /dev/null +++ b/jni/ruby/test/ruby/test_complexrational.rb @@ -0,0 +1,407 @@ +require 'test/unit' + +class ComplexRational_Test < Test::Unit::TestCase + + def test_rat_srat + skip unless defined?(Rational) + + c = SimpleRat(1,3) + cc = Rational(3,2) + + assert_kind_of(Numeric, c) + assert_kind_of(Numeric, cc) + + assert_instance_of(SimpleRat, c) + assert_instance_of(Rational, cc) + + assert_equal(SimpleRat(1,3), +c) + assert_equal(SimpleRat(-1,3), -c) + + assert_equal(SimpleRat(7,3), c + 2) + assert_equal(SimpleRat(-5,3), c - 2) + assert_equal(SimpleRat(2,3), c * 2) + assert_equal(SimpleRat(1,6), c / 2) + assert_equal(SimpleRat(1,9), c ** 2) + assert_equal(-1, c <=> 2) + + assert_equal(SimpleRat(7,3), 2 + c) + assert_equal(SimpleRat(5,3), 2 - c) + assert_equal(SimpleRat(2,3), 2 * c) + assert_equal(SimpleRat(6,1), 2 / c) + assert_in_delta(1.2599, 2 ** c, 0.001) + assert_equal(1, 2 <=> c) + + assert_equal(SimpleRat(11,6), c + cc) + assert_equal(SimpleRat(-7,6), c - cc) + assert_equal(SimpleRat(1,2), c * cc) + assert_equal(SimpleRat(2,9), c / cc) + assert_in_delta(0.1924, c ** cc, 0.001) + assert_equal(-1, c <=> cc) + + assert_equal(SimpleRat(11,6), cc + c) + assert_equal(SimpleRat(7,6), cc - c) + assert_equal(SimpleRat(1,2), cc * c) + assert_equal(SimpleRat(9,2), cc / c) + assert_in_delta(1.1447, cc ** c, 0.001) + assert_equal(1, cc <=> c) + + assert_equal(SimpleRat, (+c).class) + assert_equal(SimpleRat, (-c).class) + + assert_equal(SimpleRat, (c + 2).class) + assert_equal(SimpleRat, (c - 2).class) + assert_equal(SimpleRat, (c * 2).class) + assert_equal(SimpleRat, (c / 2).class) + assert_equal(SimpleRat, (c ** 2).class) + + assert_equal(SimpleRat, (2 + c).class) + assert_equal(SimpleRat, (2 - c).class) + assert_equal(SimpleRat, (2 * c).class) + assert_equal(SimpleRat, (2 / c).class) + assert_equal(Float, (2 ** c).class) + + assert_equal(SimpleRat, (c + cc).class) + assert_equal(SimpleRat, (c - cc).class) + assert_equal(SimpleRat, (c * cc).class) + assert_equal(SimpleRat, (c / cc).class) + assert_equal(Float, (c ** cc).class) + + assert_equal(SimpleRat, (cc + c).class) + assert_equal(SimpleRat, (cc - c).class) + assert_equal(SimpleRat, (cc * c).class) + assert_equal(SimpleRat, (cc / c).class) + assert_equal(Float, (cc ** c).class) + + assert_equal(0, Rational(2,3) <=> SimpleRat(2,3)) + assert_equal(0, SimpleRat(2,3) <=> Rational(2,3)) + assert_equal(Rational(2,3), SimpleRat(2,3)) + assert_equal(SimpleRat(2,3), Rational(2,3)) + + assert_equal(SimpleRat, (c + 0).class) + assert_equal(SimpleRat, (c - 0).class) + assert_equal(SimpleRat, (c * 0).class) + assert_equal(SimpleRat, (c * 1).class) + assert_equal(SimpleRat, (0 + c).class) + assert_equal(SimpleRat, (0 - c).class) + assert_equal(SimpleRat, (0 * c).class) + assert_equal(SimpleRat, (1 * c).class) + end + + def test_comp_srat + skip unless defined?(Rational) + + c = Complex(SimpleRat(2,3),SimpleRat(1,2)) + cc = Complex(Rational(3,2),Rational(2,1)) + + assert_equal(Complex(SimpleRat(2,3),SimpleRat(1,2)), +c) + assert_equal(Complex(SimpleRat(-2,3),SimpleRat(-1,2)), -c) + + assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), c + 2) + assert_equal(Complex(SimpleRat(-4,3),SimpleRat(1,2)), c - 2) + assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), c * 2) + assert_equal(Complex(SimpleRat(1,3),SimpleRat(1,4)), c / 2) + assert_equal(Complex(SimpleRat(7,36),SimpleRat(2,3)), c ** 2) + assert_raise(NoMethodError){c <=> 2} + + assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), 2 + c) + assert_equal(Complex(SimpleRat(4,3),SimpleRat(-1,2)), 2 - c) + assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), 2 * c) + assert_equal(Complex(SimpleRat(48,25),SimpleRat(-36,25)), 2 / c) + r = 2 ** c + assert_in_delta(1.4940, r.real, 0.001) + assert_in_delta(0.5392, r.imag, 0.001) + assert_raise(NoMethodError){2 <=> c} + + assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), c + cc) + assert_equal(Complex(SimpleRat(-5,6),SimpleRat(-3,2)), c - cc) + assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), c * cc) + assert_equal(Complex(SimpleRat(8,25),SimpleRat(-7,75)), c / cc) + r = c ** cc + assert_in_delta(0.1732, r.real, 0.001) + assert_in_delta(0.1186, r.imag, 0.001) + assert_raise(NoMethodError){c <=> cc} + + assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), cc + c) + assert_equal(Complex(SimpleRat(5,6),SimpleRat(3,2)), cc - c) + assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), cc * c) + assert_equal(Complex(SimpleRat(72,25),SimpleRat(21,25)), cc / c) + r = cc ** c + assert_in_delta(0.5498, r.real, 0.001) + assert_in_delta(1.0198, r.imag, 0.001) + assert_raise(NoMethodError){cc <=> c} + + assert_equal([SimpleRat,SimpleRat], + (+c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (-c).instance_eval{[real.class, imag.class]}) + + assert_equal([SimpleRat,SimpleRat], + (c + 2).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c - 2).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c * 2).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c / 2).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c ** 2).instance_eval{[real.class, imag.class]}) + + assert_equal([SimpleRat,SimpleRat], + (c + cc).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c - cc).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c * cc).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c / cc).instance_eval{[real.class, imag.class]}) + assert_equal([Float,Float], + (c ** cc).instance_eval{[real.class, imag.class]}) + + assert_equal([SimpleRat,SimpleRat], + (cc + c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (cc - c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (cc * c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (cc / c).instance_eval{[real.class, imag.class]}) + assert_equal([Float,Float], + (cc ** c).instance_eval{[real.class, imag.class]}) + + assert_equal(Complex(SimpleRat(2,3),SimpleRat(3,2)), + Complex(Rational(2,3),Rational(3,2))) + assert_equal(Complex(Rational(2,3),Rational(3,2)), + Complex(SimpleRat(2,3),SimpleRat(3,2))) + + assert_equal([SimpleRat,SimpleRat], + (c + 0).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c - 0).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c * 0).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (c * 1).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (0 + c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (0 - c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (0 * c).instance_eval{[real.class, imag.class]}) + assert_equal([SimpleRat,SimpleRat], + (1 * c).instance_eval{[real.class, imag.class]}) + end + +end + +def SimpleRat(*a) SimpleRat.new(*a) end + +class SimpleRat < Numeric + + def initialize(num, den = 1) + if den == 0 + raise ZeroDivisionError, "divided by zero" + end + if den < 0 + num = -num + den = -den + end + gcd = num.gcd(den) + @num = num.div(gcd) + @den = den.div(gcd) + end + + def numerator() @num end + def denominator() @den end + + def +@ () self end + def -@ () self.class.new(-@num, @den) end + + def + (o) + case o + when SimpleRat, Rational + a = @num * o.denominator + b = o.numerator * @den + self.class.new(a + b, @den * o.denominator) + when Integer + self + self.class.new(o) + when Float + to_f + o + else + x, y = o.coerce(self) + x + y + end + end + + def - (o) + case o + when SimpleRat, Rational + a = @num * o.denominator + b = o.numerator * @den + self.class.new(a - b, @den * o.denominator) + when Integer + self - self.class.new(o) + when Float + to_f - o + else + x, y = o.coerce(self) + x - y + end + end + + def * (o) + case o + when SimpleRat, Rational + a = @num * o.numerator + b = @den * o.denominator + self.class.new(a, b) + when Integer + self * self.class.new(o) + when Float + to_f * o + else + x, y = o.coerce(self) + x * y + end + end + + def quo(o) + case o + when SimpleRat, Rational + a = @num * o.denominator + b = @den * o.numerator + self.class.new(a, b) + when Integer + if o == 0 + raise raise ZeroDivisionError, "divided by zero" + end + self.quo(self.class.new(o)) + when Float + to_f.quo(o) + else + x, y = o.coerce(self) + x.quo(y) + end + end + + alias / quo + + def floor + @num.div(@den) + end + + def ceil + -((-@num).div(@den)) + end + + def truncate + if @num < 0 + return -((-@num).div(@den)) + end + @num.div(@den) + end + + alias to_i truncate + + def round + if @num < 0 + num = -@num + num = num * 2 + @den + den = @den * 2 + -(num.div(den)) + else + num = @num * 2 + @den + den = @den * 2 + num.div(den) + end + end + + def div(o) (self / o).floor end + def quot(o) (self / o).truncate end + + def modulo(o) + q = div(o) + self - o * q + end + + def remainder(o) + q = quot(o) + self - o * q + end + + alias % modulo + + def divmod(o) [div(o), modulo(o)] end + def quotrem(o) [quot(o), remainder(o)] end + + def ** (o) + case o + when SimpleRat, Rational + Float(self) ** o + when Integer + if o > 0 + a = @num ** o + b = @den ** o + elsif o < 0 + a = @den ** -o + b = @num ** -o + else + a = b = 1 + end + self.class.new(a, b) + when Float + to_f ** o + else + x, y = o.coerce(self) + x ** y + end + end + + def <=> (o) + case o + when SimpleRat, Rational + a = @num * o.denominator + b = o.numerator * @den + return a <=> b + when Integer + self <=> self.class.new(o) + when Float + to_f <=> o + else + x, y = o.coerce(self) + x <=> y + end + end + + def == (o) + begin + (self <=> o) == 0 + rescue + false + end + end + + def coerce(o) + case o + when Rational + [self.class.new(o.numerator, o.denominator), self] + when Integer + [self.class.new(o), self] + when Float + [o, self.to_f] + else + super + end + end + + def hash() @num.hash ^ @den.hash end + + def to_f() @num.to_f / @den.to_f end + def to_r() self end + def to_s() format('%s/%s', @num, @den) end + + def inspect() format('#SR(%s)', to_s) end + + def marshal_dump() [@num, @den] end + def marshal_load(a) @num, @den = a end + +end diff --git a/jni/ruby/test/ruby/test_condition.rb b/jni/ruby/test/ruby/test_condition.rb new file mode 100644 index 0000000..ba2e068 --- /dev/null +++ b/jni/ruby/test/ruby/test_condition.rb @@ -0,0 +1,16 @@ +require 'test/unit' + +class TestCondition < Test::Unit::TestCase + + # [should] first test to see if we can run the tests. + + def test_condition + $x = '0'; + + $x == $x && assert(true) + $x != $x && assert(false) + $x == $x || assert(false) + $x != $x || assert(true) + + end +end diff --git a/jni/ruby/test/ruby/test_const.rb b/jni/ruby/test/ruby/test_const.rb new file mode 100644 index 0000000..892d775 --- /dev/null +++ b/jni/ruby/test/ruby/test_const.rb @@ -0,0 +1,72 @@ +# -*- coding: us-ascii -*- +require 'test/unit' + +class TestConst < Test::Unit::TestCase + TEST1 = 1 + TEST2 = 2 + + module Const + TEST3 = 3 + TEST4 = 4 + end + + module Const2 + TEST3 = 6 + TEST4 = 8 + end + + def test_const + assert defined?(TEST1) + assert_equal 1, TEST1 + assert defined?(TEST2) + assert_equal 2, TEST2 + + self.class.class_eval { + include Const + } + assert defined?(TEST1) + assert_equal 1, TEST1 + assert defined?(TEST2) + assert_equal 2, TEST2 + assert defined?(TEST3) + assert_equal 3, TEST3 + assert defined?(TEST4) + assert_equal 4, TEST4 + + self.class.class_eval { + include Const2 + } + STDERR.print "intentionally redefines TEST3, TEST4\n" if $VERBOSE + assert defined?(TEST1) + assert_equal 1, TEST1 + assert defined?(TEST2) + assert_equal 2, TEST2 + assert defined?(TEST3) + assert_equal 6, TEST3 + assert defined?(TEST4) + assert_equal 8, TEST4 + end + + def test_redefinition + c = Class.new + name = "X\u{5b9a 6570}" + c.const_set(name, 1) + prev_line = __LINE__ - 1 + EnvUtil.with_default_internal(Encoding::UTF_8) do + assert_warning(<<-WARNING) {c.const_set(name, 2)} +#{__FILE__}:#{__LINE__-1}: warning: already initialized constant #{c}::#{name} +#{__FILE__}:#{prev_line}: warning: previous definition of #{name} was here +WARNING + end + end + + def test_redefinition_memory_leak + code = <<-PRE +olderr = $stderr.dup +$stderr.reopen(File::NULL, "wb") +350000.times { FOO = :BAR } +$stderr.reopen(olderr) +PRE + assert_no_memory_leak([], '', code, 'redefined constant', timeout: 30) + end +end diff --git a/jni/ruby/test/ruby/test_continuation.rb b/jni/ruby/test/ruby/test_continuation.rb new file mode 100644 index 0000000..8d57b8b --- /dev/null +++ b/jni/ruby/test/ruby/test_continuation.rb @@ -0,0 +1,134 @@ +require 'test/unit' +EnvUtil.suppress_warning {require 'continuation'} +require 'fiber' + +class TestContinuation < Test::Unit::TestCase + def test_create + assert_equal(:ok, callcc{:ok}) + assert_equal(:ok, callcc{|c| c.call :ok}) + end + + def test_call + assert_equal(:ok, callcc{|c| c.call :ok}) + + ary = [] + ary << callcc{|c| + @cont = c + :a + } + @cont.call :b if ary.length < 3 + assert_equal([:a, :b, :b], ary) + end + + def test_check_localvars + vv = 0 + @v = 0 + @ary = [] + [1, 2, 3].each{|i| + callcc {|k| @k = k} + @v += 1 + vv += 1 + } + @ary << [vv, @v] + @k.call if @v < 10 + assert_equal((3..10).map{|e| [e, e]}, @ary) + end + + def test_error + cont = callcc{|c| c} + assert_raise(RuntimeError){ + Thread.new{cont.call}.join + } + assert_raise(LocalJumpError){ + callcc + } + assert_raise(RuntimeError){ + c = nil + Fiber.new do + callcc {|c2| c = c2 } + end.resume + c.call + } + end + + def test_ary_flatten + assert_normal_exit %q{ + require 'continuation' + n = 0 + o = Object.new + def o.to_ary() callcc {|k| $k = k; [1,2,3]} end + [10,20,o,30,o,40].flatten.inspect + n += 1 + $k.call if n < 100 + }, '[ruby-dev:34798]' + end + + def test_marshal_dump + assert_normal_exit %q{ + require 'continuation' + n = 0 + o = Object.new + def o.marshal_dump() callcc {|k| $k = k }; "fofof" end + a = [1,2,3,o,4,5,6] + Marshal.dump(a).inspect + n += 1 + $k.call if n < 100 + }, '[ruby-dev:34802]' + end + + def tracing_with_set_trace_func + orig_thread = Thread.current + cont = nil + func = lambda do |*args| + if orig_thread == Thread.current + if cont + @memo += 1 + c = cont + cont = nil + c.call(nil) + end + end + end + cont = callcc { |cc| cc } + if cont + set_trace_func(func) + else + set_trace_func(nil) + end + end + + def test_tracing_with_set_trace_func + @memo = 0 + tracing_with_set_trace_func + tracing_with_set_trace_func + tracing_with_set_trace_func + assert_equal 3, @memo + end + + def tracing_with_thread_set_trace_func + cont = nil + func = lambda do |*args| + if cont + @memo += 1 + c = cont + cont = nil + c.call(nil) + end + end + cont = callcc { |cc| cc } + if cont + Thread.current.set_trace_func(func) + else + Thread.current.set_trace_func(nil) + end + end + + def test_tracing_with_thread_set_trace_func + @memo = 0 + tracing_with_thread_set_trace_func + tracing_with_thread_set_trace_func + tracing_with_thread_set_trace_func + assert_equal 3, @memo + end +end + diff --git a/jni/ruby/test/ruby/test_defined.rb b/jni/ruby/test/ruby/test_defined.rb new file mode 100644 index 0000000..d5e8418 --- /dev/null +++ b/jni/ruby/test/ruby/test_defined.rb @@ -0,0 +1,211 @@ +require 'test/unit' + +class TestDefined < Test::Unit::TestCase + class Foo + def foo + p :foo + end + protected :foo + def bar(f) + yield(defined?(self.foo)) + yield(defined?(f.foo)) + end + def baz(f) + end + attr_accessor :attr + def attrasgn_test + yield(defined?(self.attr = 1)) + end + end + + def defined_test + return !defined?(yield) + end + + def test_defined + $x = nil + + assert(defined?($x)) # global variable + assert_equal('global-variable', defined?($x))# returns description + + assert_nil(defined?(foo)) # undefined + foo=5 + assert(defined?(foo)) # local variable + + assert(defined?(Array)) # constant + assert(defined?(::Array)) # toplevel constant + assert(defined?(File::Constants)) # nested constant + assert(defined?(Object.new)) # method + assert(defined?(Object::new)) # method + assert(!defined?(Object.print)) # private method + assert(defined?(1 == 2)) # operator expression + + f = Foo.new + assert_nil(defined?(f.foo)) # protected method + f.bar(f) { |v| assert(v) } + assert_nil(defined?(f.quux)) # undefined method + assert_nil(defined?(f.baz(x))) # undefined argument + x = 0 + assert(defined?(f.baz(x))) + assert_nil(defined?(f.quux(x))) + assert(defined?(print(x))) + assert_nil(defined?(quux(x))) + assert(defined?(f.attr = 1)) + f.attrasgn_test { |v| assert(v) } + + assert(defined_test) # not iterator + assert(!defined_test{}) # called as iterator + + /a/ =~ '' + assert_equal nil, defined?($&) + assert_equal nil, defined?($`) + assert_equal nil, defined?($') + assert_equal nil, defined?($+) + assert_equal nil, defined?($1) + assert_equal nil, defined?($2) + /a/ =~ 'a' + assert_equal 'global-variable', defined?($&) + assert_equal 'global-variable', defined?($`) + assert_equal 'global-variable', defined?($') # ' + assert_equal nil, defined?($+) + assert_equal nil, defined?($1) + assert_equal nil, defined?($2) + /(a)/ =~ 'a' + assert_equal 'global-variable', defined?($&) + assert_equal 'global-variable', defined?($`) + assert_equal 'global-variable', defined?($') # ' + assert_equal 'global-variable', defined?($+) + assert_equal 'global-variable', defined?($1) + assert_equal nil, defined?($2) + /(a)b/ =~ 'ab' + assert_equal 'global-variable', defined?($&) + assert_equal 'global-variable', defined?($`) + assert_equal 'global-variable', defined?($') # ' + assert_equal 'global-variable', defined?($+) + assert_equal 'global-variable', defined?($1) + assert_equal nil, defined?($2) + + assert_equal("nil", defined?(nil)) + assert_equal("true", defined?(true)) + assert_equal("false", defined?(false)) + assert_equal("expression", defined?(1)) + + bug8224 = '[ruby-core:54024] [Bug #8224]' + (1..3).each do |level| + expr = "("*level+")"*level + assert_equal("nil", eval("defined? #{expr}"), "#{bug8224} defined? #{expr}") + assert_equal("nil", eval("defined?(#{expr})"), "#{bug8224} defined?(#{expr})") + end + end + + def test_defined_impl_specific + feature7035 = '[ruby-core:47558]' # not spec + assert_predicate(defined?(Foo), :frozen?, feature7035) + assert_same(defined?(Foo), defined?(Array), feature7035) + end + + class TestAutoloadedSuperclass + autoload :A, "a" + end + + class TestAutoloadedSubclass < TestAutoloadedSuperclass + def a? + defined?(A) + end + end + + def test_autoloaded_subclass + bug = "[ruby-core:35509]" + + x = TestAutoloadedSuperclass.new + class << x + def a?; defined?(A); end + end + assert_equal("constant", x.a?, bug) + + assert_equal("constant", TestAutoloadedSubclass.new.a?, bug) + end + + class TestAutoloadedNoload + autoload :A, "a" + def a? + defined?(A) + end + def b? + defined?(A::B) + end + end + + def test_autoloaded_noload + loaded = $".dup + $".clear + loadpath = $:.dup + $:.clear + x = TestAutoloadedNoload.new + assert_equal("constant", x.a?) + assert_nil(x.b?) + assert_equal([], $") + ensure + $".replace(loaded) + $:.replace(loadpath) + end + + def test_exception + bug5786 = '[ruby-dev:45021]' + assert_nil(defined?(raise("[Bug#5786]")::A), bug5786) + end + + def test_define_method + bug6644 = '[ruby-core:45831]' + a = Class.new do + def self.def_f!; + singleton_class.send(:define_method, :f) { defined? super } + end + end + aa = Class.new(a) + a.def_f! + assert_nil(a.f) + assert_nil(aa.f) + aa.def_f! + assert_equal("super", aa.f, bug6644) + assert_nil(a.f, bug6644) + end + + def test_super_in_included_method + c0 = Class.new do + def m + end + end + m1 = Module.new do + def m + defined?(super) + end + end + c = Class.new(c0) do include m1 + def m + super + end + end + assert_equal("super", c.new.m) + end + + def test_super_in_block + bug8367 = '[ruby-core:54769] [Bug #8367]' + c = Class.new do + def x; end + end + + m = Module.new do + def b; yield; end + def x; b {return defined?(super)}; end + end + + o = c.new + o.extend(m) + assert_equal("super", o.x, bug8367) + end + + def test_super_toplevel + assert_separately([], "assert_nil(defined?(super))") + end +end diff --git a/jni/ruby/test/ruby/test_dir.rb b/jni/ruby/test/ruby/test_dir.rb new file mode 100644 index 0000000..85fdd16 --- /dev/null +++ b/jni/ruby/test/ruby/test_dir.rb @@ -0,0 +1,328 @@ +require 'test/unit' + +require 'tmpdir' +require 'fileutils' + +class TestDir < Test::Unit::TestCase + + def setup + @verbose = $VERBOSE + $VERBOSE = nil + @root = File.realpath(Dir.mktmpdir('__test_dir__')) + @nodir = File.join(@root, "dummy") + for i in ?a..?z + if i.ord % 2 == 0 + FileUtils.touch(File.join(@root, i)) + else + FileUtils.mkdir(File.join(@root, i)) + end + end + end + + def teardown + $VERBOSE = @verbose + FileUtils.remove_entry_secure @root if File.directory?(@root) + end + + def test_seek + dir = Dir.open(@root) + begin + cache = [] + loop do + pos = dir.tell + break unless name = dir.read + cache << [pos, name] + end + for x,y in cache.sort_by {|z| z[0] % 3 } # shuffle + dir.seek(x) + assert_equal(y, dir.read) + end + ensure + dir.close + end + end + + def test_nodir + assert_raise(Errno::ENOENT) { Dir.open(@nodir) } + end + + def test_inspect + d = Dir.open(@root) + assert_match(/^#<Dir:#{ Regexp.quote(@root) }>$/, d.inspect) + assert_match(/^#<Dir:.*>$/, Dir.allocate.inspect) + ensure + d.close + end + + def test_path + d = Dir.open(@root) + assert_equal(@root, d.path) + assert_nil(Dir.allocate.path) + ensure + d.close + end + + def test_set_pos + d = Dir.open(@root) + loop do + i = d.pos + break unless x = d.read + d.pos = i + assert_equal(x, d.read) + end + ensure + d.close + end + + def test_rewind + d = Dir.open(@root) + a = (0..5).map { d.read } + d.rewind + b = (0..5).map { d.read } + assert_equal(a, b) + ensure + d.close + end + + def test_chdir + @pwd = Dir.pwd + @env_home = ENV["HOME"] + @env_logdir = ENV["LOGDIR"] + ENV.delete("HOME") + ENV.delete("LOGDIR") + + assert_raise(Errno::ENOENT) { Dir.chdir(@nodir) } + assert_raise(ArgumentError) { Dir.chdir } + ENV["HOME"] = @pwd + Dir.chdir do + assert_equal(@pwd, Dir.pwd) + Dir.chdir(@root) + assert_equal(@root, Dir.pwd) + end + + ensure + begin + Dir.chdir(@pwd) + rescue + abort("cannot return the original directory: #{ @pwd }") + end + if @env_home + ENV["HOME"] = @env_home + else + ENV.delete("HOME") + end + if @env_logdir + ENV["LOGDIR"] = @env_logdir + else + ENV.delete("LOGDIR") + end + end + + def test_chroot_nodir + assert_raise(NotImplementedError, Errno::ENOENT, Errno::EPERM + ) { Dir.chroot(File.join(@nodir, "")) } + end + + def test_close + d = Dir.open(@root) + d.close + assert_raise(IOError) { d.read } + end + + def test_glob + assert_equal((%w(. ..) + (?a..?z).to_a).map{|f| File.join(@root, f) }, + Dir.glob(File.join(@root, "*"), File::FNM_DOTMATCH).sort) + assert_equal([@root] + (?a..?z).map {|f| File.join(@root, f) }.sort, + Dir.glob([@root, File.join(@root, "*")]).sort) + assert_equal([@root] + (?a..?z).map {|f| File.join(@root, f) }.sort, + Dir.glob(@root + "\0\0\0" + File.join(@root, "*")).sort) + + assert_equal((?a..?z).step(2).map {|f| File.join(File.join(@root, f), "") }.sort, + Dir.glob(File.join(@root, "*/")).sort) + assert_equal([File.join(@root, '//a')], Dir.glob(@root + '//a')) + + FileUtils.touch(File.join(@root, "{}")) + assert_equal(%w({} a).map{|f| File.join(@root, f) }, + Dir.glob(File.join(@root, '{\{\},a}'))) + assert_equal([], Dir.glob(File.join(@root, '['))) + assert_equal([], Dir.glob(File.join(@root, '[a-\\'))) + + assert_equal([File.join(@root, "a")], Dir.glob(File.join(@root, 'a\\'))) + assert_equal((?a..?f).map {|f| File.join(@root, f) }.sort, Dir.glob(File.join(@root, '[abc/def]')).sort) + end + + def test_glob_recursive + bug6977 = '[ruby-core:47418]' + bug8006 = '[ruby-core:53108] [Bug #8006]' + Dir.chdir(@root) do + assert_include(Dir.glob("a/**/*", File::FNM_DOTMATCH), "a/.", bug8006) + + FileUtils.mkdir_p("a/b/c/d/e/f") + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/d/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/d/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/b/c/d/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/?/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/**/d/e/f"), bug6977) + assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/**/d/e/f"), bug6977) + + bug8283 = '[ruby-core:54387] [Bug #8283]' + dirs = ["a/.x", "a/b/.y"] + FileUtils.mkdir_p(dirs) + dirs.map {|dir| open("#{dir}/z", "w") {}} + assert_equal([], Dir.glob("a/**/z").sort, bug8283) + assert_equal(["a/.x/z"], Dir.glob("a/**/.x/z"), bug8283) + assert_equal(["a/.x/z"], Dir.glob("a/.x/**/z"), bug8283) + assert_equal(["a/b/.y/z"], Dir.glob("a/**/.y/z"), bug8283) + end + end + + def test_foreach + assert_equal(Dir.foreach(@root).to_a.sort, %w(. ..) + (?a..?z).to_a) + end + + def test_dir_enc + dir = Dir.open(@root, encoding: "UTF-8") + begin + while name = dir.read + assert_equal(Encoding.find("UTF-8"), name.encoding) + end + ensure + dir.close + end + + dir = Dir.open(@root, encoding: "ASCII-8BIT") + begin + while name = dir.read + assert_equal(Encoding.find("ASCII-8BIT"), name.encoding) + end + ensure + dir.close + end + end + + def test_unknown_keywords + bug8060 = '[ruby-dev:47152] [Bug #8060]' + assert_raise_with_message(ArgumentError, /unknown keyword/, bug8060) do + Dir.open(@root, xawqij: "a") {} + end + end + + def test_symlink + begin + ["dummy", *?a..?z].each do |f| + File.symlink(File.join(@root, f), + File.join(@root, "symlink-#{ f }")) + end + rescue NotImplementedError + return + end + + assert_equal([*?a..?z, *"symlink-a".."symlink-z"].each_slice(2).map {|f, _| File.join(@root, f + "/") }.sort, + Dir.glob(File.join(@root, "*/")).sort) + + Dir.glob(File.join(@root, "**/")) + end + + def test_glob_metachar + bug8597 = '[ruby-core:55764] [Bug #8597]' + assert_empty(Dir.glob(File.join(@root, "<")), bug8597) + end + + def test_glob_cases + feature5994 = "[ruby-core:42469] [Feature #5994]" + feature5994 << "\nDir.glob should return the filename with actual cases on the filesystem" + Dir.chdir(File.join(@root, "a")) do + open("FileWithCases", "w") {} + return unless File.exist?("filewithcases") + assert_equal(%w"FileWithCases", Dir.glob("filewithcases"), feature5994) + end + Dir.chdir(@root) do + assert_equal(%w"a/FileWithCases", Dir.glob("A/filewithcases"), feature5994) + end + end + + def test_glob_super_root + bug9648 = '[ruby-core:61552] [Bug #9648]' + roots = Dir.glob("/*") + assert_equal(roots.map {|n| "/..#{n}"}, Dir.glob("/../*"), bug9648) + end + + if /mswin|mingw/ =~ RUBY_PLATFORM + def test_glob_legacy_short_name + bug10819 = '[ruby-core:67954] [Bug #10819]' + skip unless /\A\w:/ =~ ENV["ProgramFiles"] + short = "#$&/PROGRA~1" + skip unless File.directory?(short) + entries = Dir.glob("#{short}/Common*") + assert_not_empty(entries, bug10819) + assert_equal(Dir.glob("#{File.expand_path(short)}/Common*"), entries, bug10819) + end + end + + def test_home + env_home = ENV["HOME"] + env_logdir = ENV["LOGDIR"] + ENV.delete("HOME") + ENV.delete("LOGDIR") + + assert_raise(ArgumentError) { Dir.home } + assert_raise(ArgumentError) { Dir.home("") } + ENV["HOME"] = @nodir + assert_nothing_raised(ArgumentError) { + assert_equal(@nodir, Dir.home) + assert_equal(@nodir, Dir.home("")) + } + %W[no:such:user \u{7559 5b88}:\u{756a}].each do |user| + assert_raise_with_message(ArgumentError, /#{user}/) {Dir.home(user)} + end + ensure + ENV["HOME"] = env_home + ENV["LOGDIR"] = env_logdir + end + + def test_symlinks_not_resolved + Dir.mktmpdir do |dirname| + Dir.chdir(dirname) do + begin + File.symlink('some-dir', 'dir-symlink') + rescue NotImplementedError + return + end + + Dir.mkdir('some-dir') + File.write('some-dir/foo', 'some content') + + assert_equal [ 'dir-symlink', 'some-dir' ], Dir['*'].sort + assert_equal [ 'dir-symlink', 'some-dir', 'some-dir/foo' ], Dir['**/*'].sort + end + end + end + + def test_fileno + Dir.open(".") {|d| + if d.respond_to? :fileno + assert_kind_of(Integer, d.fileno) + else + assert_raise(NotImplementedError) { d.fileno } + end + } + end + + def test_insecure_chdir + assert_raise(SecurityError) do + proc do + $SAFE=3 + Dir.chdir("/") + end.call + end + m = "\u{79fb 52d5}" + d = Class.new(Dir) {singleton_class.class_eval {alias_method m, :chdir}} + assert_raise_with_message(SecurityError, /#{m}/) do + proc do + $SAFE=3 + d.__send__(m, "/") + end.call + end + end +end diff --git a/jni/ruby/test/ruby/test_dir_m17n.rb b/jni/ruby/test/ruby/test_dir_m17n.rb new file mode 100644 index 0000000..04186e5 --- /dev/null +++ b/jni/ruby/test/ruby/test_dir_m17n.rb @@ -0,0 +1,389 @@ +require 'test/unit' +require 'tmpdir' + +class TestDir_M17N < Test::Unit::TestCase + def with_tmpdir + Dir.mktmpdir {|dir| + Dir.chdir(dir) { + yield dir + } + } + end + + def assert_raw_file_name(code, encoding) + with_tmpdir { |dir| + assert_separately(["-E#{encoding}"], <<-EOS, :chdir=>dir) + filename = #{code}.chr('UTF-8').force_encoding("#{encoding}") + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename) + EOS + + assert_separately(%w[-EASCII-8BIT], <<-EOS, :chdir=>dir) + filename = #{code}.chr('UTF-8').force_encoding("ASCII-8BIT") + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + expected_filename = #{code}.chr('UTF-8').encode(Encoding.find("filesystem")) rescue expected_filename = "?" + expected_filename = expected_filename.force_encoding("ASCII-8BIT") + if /mswin|mingw/ =~ RUBY_PLATFORM + case + when ents.include?(filename) + when ents.include?(expected_filename) + filename = expected_filename + else + ents = Dir.entries(".", {:encoding => Encoding.find("filesystem")}) + filename = expected_filename + end + end + assert_include(ents, filename) + EOS + } + end + + ## UTF-8 default_external, no default_internal + + def test_filename_extutf8 + with_tmpdir {|d| + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + filename = "\u3042" + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename) + EOS + } + end + + def test_filename_extutf8_invalid + with_tmpdir {|d| + assert_separately(%w[-EASCII-8BIT], <<-'EOS', :chdir=>d) + filename = "\xff".force_encoding("ASCII-8BIT") # invalid byte sequence as UTF-8 + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + filename = "%FF" if /darwin/ =~ RUBY_PLATFORM && ents.include?("%FF") + assert_include(ents, filename) + EOS + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + filename = "\xff".force_encoding("UTF-8") # invalid byte sequence as UTF-8 + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + filename = "%FF" if /darwin/ =~ RUBY_PLATFORM && ents.include?("%FF") + assert_include(ents, filename) + EOS + } + end unless /mswin|mingw/ =~ RUBY_PLATFORM + + def test_filename_as_bytes_extutf8 + with_tmpdir {|d| + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + filename = "\xc2\xa1".force_encoding("utf-8") + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename) + EOS + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + if /mswin|mingw|darwin/ =~ RUBY_PLATFORM + filename = "\x8f\xa2\xc2".force_encoding("euc-jp") + else + filename = "\xc2\xa1".force_encoding("euc-jp") + end + assert_nothing_raised(Errno::ENOENT) do + open(filename) {} + end + EOS + # no meaning test on windows + unless /mswin|mingw|darwin/ =~ RUBY_PLATFORM + assert_separately(%W[-EUTF-8], <<-'EOS', :chdir=>d) + filename1 = "\xc2\xa1".force_encoding("utf-8") + filename2 = "\xc2\xa1".force_encoding("euc-jp") + filename3 = filename1.encode("euc-jp") + filename4 = filename2.encode("utf-8") + assert_file.stat(filename1) + assert_file.stat(filename2) + assert_file.not_exist?(filename3) + assert_file.not_exist?(filename4) + EOS + end + } + end + + ## UTF-8 default_external, EUC-JP default_internal + + def test_filename_extutf8_inteucjp_representable + with_tmpdir {|d| + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + filename = "\u3042" + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename) + EOS + assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename) + EOS + assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + assert_nothing_raised(Errno::ENOENT) do + open(filename) {} + end + EOS + } + end + + def test_filename_extutf8_inteucjp_unrepresentable + with_tmpdir {|d| + assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d) + filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP + filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP + File.open(filename1, "w") {} + File.open(filename2, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename1) + assert_include(ents, filename2) + EOS + assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d) + filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP + filename2 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + assert_include(ents, filename1) + assert_include(ents, filename2) + EOS + assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d) + filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP + filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP + filename3 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP + assert_file.stat(filename1) + assert_file.stat(filename2) + assert_file.stat(filename3) + EOS + } + end + + ## others + + def test_filename_bytes_euc_jp + with_tmpdir {|d| + assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + ents.each {|e| e.force_encoding("ASCII-8BIT") } + if /darwin/ =~ RUBY_PLATFORM + filename = filename.encode("utf-8") + end + assert_include(ents, filename.force_encoding("ASCII-8BIT")) + EOS + } + end + + def test_filename_euc_jp + with_tmpdir {|d| + assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + if /darwin/ =~ RUBY_PLATFORM + filename = filename.encode("utf-8").force_encoding("euc-jp") + end + assert_include(ents, filename) + EOS + assert_separately(%w[-EASCII-8BIT], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding('ASCII-8BIT') + win_expected_filename = filename.encode(Encoding.find("filesystem"), "euc-jp") rescue "?" + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + unless ents.include?(filename) + case RUBY_PLATFORM + when /darwin/ + filename = filename.encode("utf-8", "euc-jp").b + when /mswin|mingw/ + if ents.include?(win_expected_filename.dup.force_encoding("ASCII-8BIT")) + ents = Dir.entries(".", {:encoding => Encoding.find("filesystem")}) + filename = win_expected_filename + end + end + end + assert_include(ents, filename) + EOS + } + end + + def test_filename_utf8_raw_jp_name + assert_raw_file_name(0x3042, "UTF-8") + end + + def test_filename_utf8_raw_windows_1251_name + assert_raw_file_name(0x0424, "UTF-8") + end + + def test_filename_utf8_raw_windows_1252_name + assert_raw_file_name(0x00c6, "UTF-8") + end + + def test_filename_ext_euc_jp_and_int_utf_8 + with_tmpdir {|d| + assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + if /darwin/ =~ RUBY_PLATFORM + filename = filename.encode("utf-8", "euc-jp").force_encoding("euc-jp") + end + assert_include(ents, filename) + EOS + assert_separately(%w[-EEUC-JP:UTF-8], <<-'EOS', :chdir=>d) + filename = "\u3042" + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + if /darwin/ =~ RUBY_PLATFORM + filename = filename.force_encoding("euc-jp") + end + assert_include(ents, filename) + EOS + } + end + + def test_error_nonascii + bug6071 = '[ruby-dev:45279]' + paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")] + encs = with_tmpdir { + paths.map {|path| + Dir.open(path) rescue $!.message.encoding + } + } + assert_equal(paths.map(&:encoding), encs, bug6071) + end + + def test_inspect_nonascii + bug6072 = '[ruby-dev:45280]' + paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")] + encs = with_tmpdir { + paths.map {|path| + Dir.mkdir(path) + Dir.open(path) {|d| d.inspect.encoding} + } + } + assert_equal(paths.map(&:encoding), encs, bug6072) + end + + def test_glob_incompatible + d = "\u{3042}\u{3044}".encode("utf-16le") + assert_raise(Encoding::CompatibilityError) {Dir.glob(d)} + m = Class.new {define_method(:to_path) {d}} + assert_raise(Encoding::CompatibilityError) {Dir.glob(m.new)} + end + + def test_glob_compose + bug7267 = '[ruby-core:48745] [Bug #7267]' + + pp = Object.new.extend(Test::Unit::Assertions) + def pp.mu_pp(str) #:nodoc: + str.dump + end + + with_tmpdir {|d| + orig = %W"d\u{e9}tente x\u{304c 304e 3050 3052 3054}" + orig.each {|n| open(n, "w") {}} + orig.each do |o| + n = Dir.glob("#{o[0..0]}*")[0] + pp.assert_equal(o, n, bug7267) + end + } + end + + def with_enc_path + with_tmpdir do |d| + names = %W"\u{391 392 393 394 395} \u{3042 3044 3046 3048 304a}" + names.each do |dir| + EnvUtil.with_default_external(Encoding::UTF_8) do + Dir.mkdir(dir) rescue next + begin + yield(dir) + ensure + File.chmod(0700, dir) + end + end + end + end + end + + def test_glob_warning_opendir + with_enc_path do |dir| + open("#{dir}/x", "w") {} + File.chmod(0300, dir) + next if File.readable?(dir) + assert_warning(/#{dir}/) do + Dir.glob("#{dir}/*") + end + end + end + + def test_glob_warning_match_all + with_enc_path do |dir| + open("#{dir}/x", "w") {} + File.chmod(0000, dir) + next if File.readable?(dir) + assert_warning(/#{dir}/) do + Dir.glob("#{dir}/x") + end + end + end + + def test_glob_warning_match_dir + with_enc_path do |dir| + Dir.mkdir("#{dir}/x") + File.chmod(0000, dir) + next if File.readable?(dir) + assert_warning(/#{dir}/) do + Dir.glob("#{dir}/x/") + end + end + end + + def test_glob_escape_multibyte + name = "\x81\\".force_encoding(Encoding::Shift_JIS) + with_tmpdir do + open(name, "w") {} rescue next + match, = Dir.glob("#{name}*") + next unless match and match.encoding == Encoding::Shift_JIS + assert_equal([name], Dir.glob("\\#{name}*")) + end + end + + def test_entries_compose + bug7267 = '[ruby-core:48745] [Bug #7267]' + + pp = Object.new.extend(Test::Unit::Assertions) + def pp.mu_pp(ary) #:nodoc: + '[' << ary.map {|str| "#{str.dump}(#{str.encoding})"}.join(', ') << ']' + end + + with_tmpdir {|d| + orig = %W"d\u{e9}tente x\u{304c 304e 3050 3052 3054}" + orig.each {|n| open(n, "w") {}} + if /mswin|mingw/ =~ RUBY_PLATFORM + opts = {:encoding => Encoding.default_external} + orig.map! {|o| o.encode(Encoding.find("filesystem")) rescue o.tr("^a-z", "?")} + else + enc = Encoding.find("filesystem") + enc = Encoding::ASCII_8BIT if enc == Encoding::US_ASCII + orig.each {|o| o.force_encoding(enc) } + end + ents = Dir.entries(".", opts).reject {|n| /\A\./ =~ n} + ents.sort! + pp.assert_equal(orig, ents, bug7267) + } + end +end diff --git a/jni/ruby/test/ruby/test_econv.rb b/jni/ruby/test/ruby/test_econv.rb new file mode 100644 index 0000000..f423ebf --- /dev/null +++ b/jni/ruby/test/ruby/test_econv.rb @@ -0,0 +1,926 @@ +require 'test/unit' + +class TestEncodingConverter < Test::Unit::TestCase + def check_ec(edst, esrc, eres, dst, src, ec, off, len, opts=nil) + res = ec.primitive_convert(src, dst, off, len, opts) + assert_equal([edst.dup.force_encoding("ASCII-8BIT"), + esrc.dup.force_encoding("ASCII-8BIT"), + eres], + [dst.dup.force_encoding("ASCII-8BIT"), + src.dup.force_encoding("ASCII-8BIT"), + res]) + end + + def assert_econv(converted, eres, obuf_bytesize, ec, consumed, rest, opts=nil) + ec = Encoding::Converter.new(*ec) if Array === ec + i = consumed + rest + o = "" + ret = ec.primitive_convert(i, o, 0, obuf_bytesize, opts) + assert_equal([converted, eres, rest], + [o, ret, i]) + end + + def assert_errinfo(e_res, e_enc1, e_enc2, e_error_bytes, e_readagain_bytes, ec) + assert_equal([e_res, e_enc1, e_enc2, + e_error_bytes && e_error_bytes.dup.force_encoding("ASCII-8BIT"), + e_readagain_bytes && e_readagain_bytes.dup.force_encoding("ASCII-8BIT")], + ec.primitive_errinfo) + end + + def test_s_asciicompat_encoding + assert_equal(Encoding::STATELESS_ISO_2022_JP, Encoding::Converter.asciicompat_encoding("ISO-2022-JP")) + assert_equal(Encoding::STATELESS_ISO_2022_JP, Encoding::Converter.asciicompat_encoding(Encoding::ISO_2022_JP)) + assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-16BE")) + assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-16LE")) + assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-32BE")) + assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-32LE")) + assert_nil(Encoding::Converter.asciicompat_encoding("EUC-JP")) + assert_nil(Encoding::Converter.asciicompat_encoding("UTF-8")) + assert_nil(Encoding::Converter.asciicompat_encoding(Encoding::UTF_8)) + assert_nil(Encoding::Converter.asciicompat_encoding("xml_attr_escape")) + assert_nil(Encoding::Converter.asciicompat_encoding("encoding-not-exist")) + end + + def test_asciicompat_encoding_iso2022jp + acenc = Encoding::Converter.asciicompat_encoding("ISO-2022-JP") + str = "\e$B~~\e(B".force_encoding("iso-2022-jp") + str2 = str.encode(acenc) + str3 = str2.encode("ISO-2022-JP") + assert_equal(str, str3) + end + + def test_s_new + assert_kind_of(Encoding::Converter, Encoding::Converter.new("UTF-8", "EUC-JP")) + assert_kind_of(Encoding::Converter, Encoding::Converter.new(Encoding::UTF_8, Encoding::EUC_JP)) + end + + def test_s_new_convpath + assert_equal([], Encoding::Converter.new([]).convpath) + assert_equal([[Encoding::UTF_8, Encoding::EUC_JP]], + Encoding::Converter.new([["UTF-8", "EUC-JP"]]).convpath) + assert_equal([[Encoding::UTF_8, Encoding::WINDOWS_31J]], + Encoding::Converter.new([["utf-8", "cp932"]]).convpath) + assert_equal([[Encoding::UTF_8, Encoding::EUC_JP]], + Encoding::Converter.new([[Encoding::UTF_8, Encoding::EUC_JP]]).convpath) + assert_equal([[Encoding::ISO_8859_1, Encoding::UTF_8], + [Encoding::UTF_8, Encoding::EUC_JP]], + Encoding::Converter.new([["iso-8859-1", "euc-jp"]]).convpath) + assert_equal([[Encoding::ISO_8859_1, Encoding::UTF_8], + [Encoding::UTF_8, Encoding::EUC_JP], + "universal_newline"], + Encoding::Converter.new([["iso-8859-1", "euc-jp"], "universal_newline"]).convpath) + assert_equal(["universal_newline", + [Encoding::ISO_8859_1, Encoding::UTF_8], + [Encoding::UTF_8, Encoding::EUC_JP], + "universal_newline"], + Encoding::Converter.new(["universal_newline", ["iso-8859-1", "euc-jp"], "universal_newline"]).convpath) + end + + def test_s_new_fail + name1 = "encoding-which-is-not-exist-1" + name2 = "encoding-which-is-not-exist-2" + + assert_raise(Encoding::ConverterNotFoundError) { + Encoding::Converter.new(name1, name2) + } + + encoding_list = Encoding.list.map {|e| e.name } + assert_not_include(encoding_list, name1) + assert_not_include(encoding_list, name2) + end + + def test_newline_converter_with_ascii_incompatible + assert_nothing_raised { + Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR) + } + assert_nothing_raised { + Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::CRLF_NEWLINE_DECORATOR) + } + assert_nothing_raised { + Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::CR_NEWLINE_DECORATOR) + } + + assert_nothing_raised { + Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR) + } + assert_nothing_raised { + Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::CRLF_NEWLINE_DECORATOR) + } + assert_nothing_raised { + Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::CR_NEWLINE_DECORATOR) + } + end + + def test_get_encoding + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + assert_equal(Encoding::UTF_8, ec.source_encoding) + assert_equal(Encoding::EUC_JP, ec.destination_encoding) + end + + def test_result_encoding + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + dst = "".force_encoding("ASCII-8BIT") + assert_equal(Encoding::ASCII_8BIT, dst.encoding) + ec.primitive_convert("\u{3042}", dst, nil, 10) + assert_equal(Encoding::EUC_JP, dst.encoding) + end + + def test_output_region + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + ec.primitive_convert(src="a", dst="b", nil, 1, :partial_input=>true) + assert_equal("ba", dst) + ec.primitive_convert(src="a", dst="b", 0, 1, :partial_input=>true) + assert_equal("a", dst) + ec.primitive_convert(src="a", dst="b", 1, 1, :partial_input=>true) + assert_equal("ba", dst) + assert_raise(ArgumentError) { + ec.primitive_convert(src="a", dst="b", 2, 1, :partial_input=>true) + } + assert_raise(ArgumentError) { + ec.primitive_convert(src="a", dst="b", -1, 1, :partial_input=>true) + } + assert_raise(ArgumentError) { + ec.primitive_convert(src="a", dst="b", 1, -1, :partial_input=>true) + } + end + + def test_nil_source_buffer + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + ret = ec.primitive_convert(nil, "", nil, 10) + assert_equal(:finished, ret) + end + + def test_nil_destination_bytesize + ec = Encoding::Converter.new("Shift_JIS", "UTF-8") + n = 10000 + src = "\xa1".force_encoding("Shift_JIS") * n + ret = ec.primitive_convert(src, dst="", nil, nil) + assert_equal(:finished, ret) + assert_equal("\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst) + end + + def test_nil_destination_bytesize2 + ec = Encoding::Converter.new("Shift_JIS", "UTF-8") + n = 10000 + src = "\xa1".force_encoding("Shift_JIS") * n + ret = ec.primitive_convert(src, dst="") + assert_equal(:finished, ret) + assert_equal("\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst) + end + + def test_nil_destination_bytesize_with_nonnil_byteoffset + ec = Encoding::Converter.new("Shift_JIS", "UTF-8") + n = 2000 + src = "\xa1".force_encoding("Shift_JIS") * n + dst = "abcd" * 2000 + ret = ec.primitive_convert(src, dst, 3, nil) + assert_equal(:finished, ret) + assert_equal("abc" + "\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst) + end + + def test_partial_input + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + ret = ec.primitive_convert(src="", dst="", nil, 10, :partial_input=>true) + assert_equal(:source_buffer_empty, ret) + ret = ec.primitive_convert(src="", dst="", nil, 10) + assert_equal(:finished, ret) + end + + def test_accumulate_dst1 + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + a = ["", "abc\u{3042}def", ec, nil, 1] + check_ec("a", "c\u{3042}def", :destination_buffer_full, *a) + check_ec("ab", "\u{3042}def", :destination_buffer_full, *a) + check_ec("abc", "def", :destination_buffer_full, *a) + check_ec("abc\xA4", "def", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2", "ef", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2d", "f", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2de", "", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2def", "", :finished, *a) + end + + def test_accumulate_dst2 + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + a = ["", "abc\u{3042}def", ec, nil, 2] + check_ec("ab", "\u{3042}def", :destination_buffer_full, *a) + check_ec("abc\xA4", "def", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2d", "f", :destination_buffer_full, *a) + check_ec("abc\xA4\xA2def", "", :finished, *a) + end + + def test_eucjp_to_utf8 + assert_econv("", :finished, 100, ["UTF-8", "EUC-JP"], "", "") + assert_econv("a", :finished, 100, ["UTF-8", "EUC-JP"], "a", "") + end + + def test_iso2022jp + assert_econv("", :finished, 100, ["Shift_JIS", "ISO-2022-JP"], "", "") + end + + def test_iso2022jp_encode + ec = Encoding::Converter.new("EUC-JP", "ISO-2022-JP") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "a"; check_ec("a", "", :source_buffer_empty, *a) + src << "\xA2"; check_ec("a", "", :source_buffer_empty, *a) + src << "\xA4"; check_ec("a\e$B\"$", "", :source_buffer_empty, *a) + src << "\xA1"; check_ec("a\e$B\"$", "", :source_buffer_empty, *a) + src << "\xA2"; check_ec("a\e$B\"$!\"", "", :source_buffer_empty, *a) + src << "b"; check_ec("a\e$B\"$!\"\e(Bb", "", :source_buffer_empty, *a) + src << "\xA2\xA6"; check_ec("a\e$B\"$!\"\e(Bb\e$B\"&", "", :source_buffer_empty, *a) + a[-1] = 0; check_ec("a\e$B\"$!\"\e(Bb\e$B\"&\e(B", "", :finished, *a) + end + + def test_iso2022jp_decode + ec = Encoding::Converter.new("ISO-2022-JP", "EUC-JP") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "a"; check_ec("a", "", :source_buffer_empty, *a) + src << "\e"; check_ec("a", "", :source_buffer_empty, *a) + src << "$"; check_ec("a", "", :source_buffer_empty, *a) + src << "B"; check_ec("a", "", :source_buffer_empty, *a) + src << "\x21"; check_ec("a", "", :source_buffer_empty, *a) + src << "\x22"; check_ec("a\xA1\xA2", "", :source_buffer_empty, *a) + src << "\n"; check_ec("a\xA1\xA2", "", :invalid_byte_sequence, *a) + src << "\x23"; check_ec("a\xA1\xA2", "", :source_buffer_empty, *a) + src << "\x24"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a) + src << "\e"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a) + src << "("; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a) + src << "B"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a) + src << "c"; check_ec("a\xA1\xA2\xA3\xA4c", "", :source_buffer_empty, *a) + src << "\n"; check_ec("a\xA1\xA2\xA3\xA4c\n","", :source_buffer_empty, *a) + end + + def test_invalid + assert_econv("", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "\x80", "") + assert_econv("a", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "a\x80", "") + assert_econv("a", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "a\x80", "\x80") + assert_econv("abc", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "abc\xFF", "def") + assert_econv("abc", :invalid_byte_sequence, 100, ["Shift_JIS", "EUC-JP"], "abc\xFF", "def") + assert_econv("abc", :invalid_byte_sequence, 100, ["ISO-2022-JP", "EUC-JP"], "abc\xFF", "def") + end + + def test_invalid2 + ec = Encoding::Converter.new("Shift_JIS", "EUC-JP") + a = ["", "abc\xFFdef", ec, nil, 1] + check_ec("a", "c\xFFdef", :destination_buffer_full, *a) + check_ec("ab", "\xFFdef", :destination_buffer_full, *a) + check_ec("abc", "def", :invalid_byte_sequence, *a) + check_ec("abcd", "f", :destination_buffer_full, *a) + check_ec("abcde", "", :destination_buffer_full, *a) + check_ec("abcdef", "", :finished, *a) + end + + def test_invalid3 + ec = Encoding::Converter.new("Shift_JIS", "EUC-JP") + a = ["", "abc\xFFdef", ec, nil, 10] + check_ec("abc", "def", :invalid_byte_sequence, *a) + check_ec("abcdef", "", :finished, *a) + end + + def test_invalid4 + ec = Encoding::Converter.new("Shift_JIS", "EUC-JP") + a = ["", "abc\xFFdef", ec, nil, 10, :after_output=>true] + check_ec("a", "bc\xFFdef", :after_output, *a) + check_ec("ab", "c\xFFdef", :after_output, *a) + check_ec("abc", "\xFFdef", :after_output, *a) + check_ec("abc", "def", :invalid_byte_sequence, *a) + check_ec("abcd", "ef", :after_output, *a) + check_ec("abcde", "f", :after_output, *a) + check_ec("abcdef", "", :after_output, *a) + check_ec("abcdef", "", :finished, *a) + end + + def test_invalid_utf16le + ec = Encoding::Converter.new("UTF-16LE", "UTF-8") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "A"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x01"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x02"; check_ec("A", "", :invalid_byte_sequence, *a) + src << "\x03"; check_ec("A\u{0201}", "", :source_buffer_empty, *a) + src << "\x04"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :invalid_byte_sequence, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xdc"; check_ec("A\u{0201}\u{0403}\u{10000}", "", :source_buffer_empty, *a) + end + + def test_invalid_utf16be + ec = Encoding::Converter.new("UTF-16BE", "UTF-8") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "A"; check_ec("A", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x02"; check_ec("A", "", :invalid_byte_sequence, *a) + src << "\x01"; check_ec("A\u{0201}", "", :source_buffer_empty, *a) + src << "\x04"; check_ec("A\u{0201}", "", :source_buffer_empty, *a) + src << "\x03"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :invalid_byte_sequence, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\xdc"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A\u{0201}\u{0403}\u{10000}", "", :source_buffer_empty, *a) + end + + def test_invalid_utf32be + ec = Encoding::Converter.new("UTF-32BE", "UTF-8") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "A"; check_ec("A", "", :source_buffer_empty, *a) + + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\xdc"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :invalid_byte_sequence, *a) + + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "B"; check_ec("AB", "", :source_buffer_empty, *a) + + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + src << "C"; check_ec("ABC", "", :source_buffer_empty, *a) + end + + def test_invalid_utf32le + ec = Encoding::Converter.new("UTF-32LE", "UTF-8") + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "A"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\xdc"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :invalid_byte_sequence, *a) + + src << "B"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("A", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + + src << "C"; check_ec("AB", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a) + src << "\x00"; check_ec("ABC", "", :source_buffer_empty, *a) + end + + def test_errors + ec = Encoding::Converter.new("UTF-16BE", "EUC-JP") + a = ["", "\xFF\xFE\x00A\xDC\x00\x00B", ec, nil, 10] + check_ec("", "\x00A\xDC\x00\x00B", :undefined_conversion, *a) + check_ec("A", "\x00B", :invalid_byte_sequence, *a) # \xDC\x00 is invalid as UTF-16BE + check_ec("AB", "", :finished, *a) + end + + def test_errors2 + ec = Encoding::Converter.new("UTF-16BE", "EUC-JP") + a = ["", "\xFF\xFE\x00A\xDC\x00\x00B", ec, nil, 10, :after_output=>true] + check_ec("", "\x00A\xDC\x00\x00B", :undefined_conversion, *a) + check_ec("A", "\xDC\x00\x00B", :after_output, *a) + check_ec("A", "\x00B", :invalid_byte_sequence, *a) + check_ec("AB", "", :after_output, *a) + check_ec("AB", "", :finished, *a) + end + + def test_universal_newline + ec = Encoding::Converter.new("UTF-8", "EUC-JP", universal_newline: true) + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a) + src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a) + src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a) + src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a) + src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a) + src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a) + end + + def test_universal_newline2 + ec = Encoding::Converter.new("", "", universal_newline: true) + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a) + src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a) + src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a) + src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a) + src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a) + src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a) + end + + def test_universal_newline3 + ec = Encoding::Converter.new("", "", universal_newline: true) + a = ["", src="", ec, nil, 50, :partial_input=>true] + src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a) + src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a) + src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a) + src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a) + src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a) + src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a) + src << "\r"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a) + a[-1] = nil + src << ""; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz\n", "", :finished, *a) + end + + def test_crlf_newline + ec = Encoding::Converter.new("UTF-8", "EUC-JP", crlf_newline: true) + assert_econv("abc\r\ndef", :finished, 50, ec, "abc\ndef", "") + end + + def test_crlf_newline2 + ec = Encoding::Converter.new("", "", crlf_newline: true) + assert_econv("abc\r\ndef", :finished, 50, ec, "abc\ndef", "") + end + + def test_cr_newline + ec = Encoding::Converter.new("UTF-8", "EUC-JP", cr_newline: true) + assert_econv("abc\rdef", :finished, 50, ec, "abc\ndef", "") + end + + def test_cr_newline2 + ec = Encoding::Converter.new("", "", cr_newline: true) + assert_econv("abc\rdef", :finished, 50, ec, "abc\ndef", "") + end + + def test_no_universal_newline1 + ec = Encoding::Converter.new("UTF-8", "EUC-JP", universal_newline: false) + assert_econv("abc\r\ndef", :finished, 50, ec, "abc\r\ndef", "") + end + + def test_no_universal_newline2 + ec = Encoding::Converter.new("", "", universal_newline: false) + assert_econv("abc\r\ndef", :finished, 50, ec, "abc\r\ndef", "") + end + + def test_after_output + ec = Encoding::Converter.new("UTF-8", "EUC-JP") + a = ["", "abc\u{3042}def", ec, nil, 100, :after_output=>true] + check_ec("a", "bc\u{3042}def", :after_output, *a) + check_ec("ab", "c\u{3042}def", :after_output, *a) + check_ec("abc", "\u{3042}def", :after_output, *a) + check_ec("abc\xA4\xA2", "def", :after_output, *a) + check_ec("abc\xA4\xA2d", "ef", :after_output, *a) + check_ec("abc\xA4\xA2de", "f", :after_output, *a) + check_ec("abc\xA4\xA2def", "", :after_output, *a) + check_ec("abc\xA4\xA2def", "", :finished, *a) + end + + def test_errinfo_invalid_euc_jp + ec = Encoding::Converter.new("EUC-JP", "Shift_JIS") + ec.primitive_convert("\xff", "", nil, 10) + assert_errinfo(:invalid_byte_sequence, "EUC-JP", "Shift_JIS", "\xFF", "", ec) + end + + def test_errinfo_invalid_euc_jp2 + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") + ec.primitive_convert("\xff", "", nil, 10) + assert_errinfo(:invalid_byte_sequence, "EUC-JP", "UTF-8", "\xFF", "", ec) + end + + def test_errinfo_undefined_hiragana + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") + ec.primitive_convert("\xa4\xa2", "", nil, 10) + assert_errinfo(:undefined_conversion, "UTF-8", "ISO-8859-1", "\xE3\x81\x82", "", ec) + end + + def test_errinfo_invalid_partial_character + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") + ec.primitive_convert("\xa4", "", nil, 10) + assert_errinfo(:incomplete_input, "EUC-JP", "UTF-8", "\xA4", "", ec) + end + + def test_errinfo_valid_partial_character + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") + ec.primitive_convert("\xa4", "", nil, 10, :partial_input=>true) + assert_errinfo(:source_buffer_empty, nil, nil, nil, nil, ec) + end + + def test_errinfo_invalid_utf16be + ec = Encoding::Converter.new("UTF-16BE", "UTF-8") + ec.primitive_convert(src="\xd8\x00\x00@", "", nil, 10) + assert_errinfo(:invalid_byte_sequence, "UTF-16BE", "UTF-8", "\xD8\x00", "\x00", ec) + assert_equal("@", src) + end + + def test_errinfo_invalid_utf16le + ec = Encoding::Converter.new("UTF-16LE", "UTF-8") + ec.primitive_convert(src="\x00\xd8@\x00", "", nil, 10) + assert_errinfo(:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "@\x00", ec) + assert_equal("", src) + end + + def test_output_iso2022jp + ec = Encoding::Converter.new("EUC-JP", "ISO-2022-JP") + ec.primitive_convert(src="\xa1\xa1", dst="", nil, 10, :partial_input=>true) + assert_equal("\e$B!!".force_encoding("ISO-2022-JP"), dst) + assert_equal(nil, ec.insert_output("???")) + ec.primitive_convert("", dst, nil, 10, :partial_input=>true) + assert_equal("\e$B!!\e(B???".force_encoding("ISO-2022-JP"), dst) + ec.primitive_convert(src="\xa1\xa2", dst, nil, 10, :partial_input=>true) + assert_equal("\e$B!!\e(B???\e$B!\"".force_encoding("ISO-2022-JP"), dst) + + assert_equal(nil, ec.insert_output("\xA1\xA1".force_encoding("EUC-JP"))) + ec.primitive_convert("", dst, nil, 10, :partial_input=>true) + assert_equal("\e$B!!\e(B???\e$B!\"!!".force_encoding("ISO-2022-JP"), dst) + + ec.primitive_convert(src="\xa1\xa3", dst, nil, 10, :partial_input=>true) + assert_equal("\e$B!!\e(B???\e$B!\"!!!\#".force_encoding("ISO-2022-JP"), dst) + + assert_equal(nil, ec.insert_output("\u3042")) + ec.primitive_convert("", dst, nil, 10, :partial_input=>true) + assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"".force_encoding("ISO-2022-JP"), dst) + + assert_raise(Encoding::UndefinedConversionError) { + ec.insert_output("\uFFFD") + } + + assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"".force_encoding("ISO-2022-JP"), dst) + + ec.primitive_convert("", dst, nil, 10) + assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"\e(B".force_encoding("ISO-2022-JP"), dst) + end + + def test_exc_invalid + err = assert_raise(Encoding::InvalidByteSequenceError) { + "abc\xa4def".encode("ISO-8859-1", "EUC-JP") + } + assert_equal("EUC-JP", err.source_encoding_name) + assert_equal("UTF-8", err.destination_encoding_name) + assert_equal(Encoding::EUC_JP, err.source_encoding) + assert_equal(Encoding::UTF_8, err.destination_encoding) + assert_equal("\xA4".force_encoding("ASCII-8BIT"), err.error_bytes) + assert_equal("d", err.readagain_bytes) + assert_equal(false, err.incomplete_input?) + end + + def test_exc_incomplete + err = assert_raise(Encoding::InvalidByteSequenceError) { + "abc\xa4".encode("ISO-8859-1", "EUC-JP") + } + assert_equal("EUC-JP", err.source_encoding_name) + assert_equal("UTF-8", err.destination_encoding_name) + assert_equal(Encoding::EUC_JP, err.source_encoding) + assert_equal(Encoding::UTF_8, err.destination_encoding) + assert_equal("\xA4".force_encoding("ASCII-8BIT"), err.error_bytes) + assert_equal(nil, err.readagain_bytes) + assert_equal(true, err.incomplete_input?) + end + + def test_exc_undef + err = assert_raise(Encoding::UndefinedConversionError) { + "abc\xa4\xa2def".encode("ISO-8859-1", "EUC-JP") + } + assert_equal("UTF-8", err.source_encoding_name) + assert_equal("ISO-8859-1", err.destination_encoding_name) + assert_equal(Encoding::UTF_8, err.source_encoding) + assert_equal(Encoding::ISO_8859_1, err.destination_encoding) + assert_equal("\u{3042}", err.error_char) + end + + def test_putback + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") + ret = ec.primitive_convert(src="abc\xa1def", dst="", nil, 10) + assert_equal(:invalid_byte_sequence, ret) + assert_equal(["abc", "ef"], [dst, src]) + src = ec.putback + src + assert_equal(["abc", "def"], [dst, src]) + ret = ec.primitive_convert(src, dst, nil, 10) + assert_equal(:finished, ret) + assert_equal(["abcdef", ""], [dst, src]) + end + + def test_putback2 + ec = Encoding::Converter.new("utf-16le", "euc-jp") + ret = ec.primitive_convert("\x00\xd8\x21\x00", "", nil, nil) + assert_equal(:invalid_byte_sequence, ret) + assert_equal("\x00".force_encoding("utf-16le"), ec.putback(1)) + assert_equal("\x21".force_encoding("utf-16le"), ec.putback(1)) + assert_equal("", ec.putback(1)) + end + + def test_invalid_replace + ec = Encoding::Converter.new("UTF-8", "EUC-JP", invalid: :replace) + ret = ec.primitive_convert(src="abc\x80def", dst="", nil, 100) + assert_equal(:finished, ret) + assert_equal("", src) + assert_equal("abc?def", dst) + end + + def test_invalid_ignore + ec = Encoding::Converter.new("UTF-8", "EUC-JP", :invalid => :replace, :replace => "") + ret = ec.primitive_convert(src="abc\x80def", dst="", nil, 100) + assert_equal(:finished, ret) + assert_equal("", src) + assert_equal("abcdef", dst) + end + + def test_undef_replace + ec = Encoding::Converter.new("UTF-8", "EUC-JP", :undef => :replace) + ret = ec.primitive_convert(src="abc\u{fffd}def", dst="", nil, 100) + assert_equal(:finished, ret) + assert_equal("", src) + assert_equal("abc?def", dst) + end + + def test_undef_ignore + ec = Encoding::Converter.new("UTF-8", "EUC-JP", :undef => :replace, :replace => "") + ret = ec.primitive_convert(src="abc\u{fffd}def", dst="", nil, 100) + assert_equal(:finished, ret) + assert_equal("", src) + assert_equal("abcdef", dst) + end + + def test_noconv + ec = Encoding::Converter.new("", "") + assert_equal(nil, ec.source_encoding) + assert_equal(nil, ec.destination_encoding) + assert_equal([:source_buffer_empty, nil, nil, nil, nil], ec.primitive_errinfo) + a = ["", "abcdefg", ec, nil, 2] + check_ec("ab", "cdefg", :destination_buffer_full, *a) + check_ec("abcd", "efg", :destination_buffer_full, *a) + check_ec("abcdef", "g", :destination_buffer_full, *a) + check_ec("abcdefg", "", :finished, *a) + end + + def test_noconv_partial + ec = Encoding::Converter.new("", "") + a = ["", "abcdefg", ec, nil, 2, :partial_input=>true] + check_ec("ab", "cdefg", :destination_buffer_full, *a) + check_ec("abcd", "efg", :destination_buffer_full, *a) + check_ec("abcdef", "g", :destination_buffer_full, *a) + check_ec("abcdefg", "", :source_buffer_empty, *a) + end + + def test_noconv_after_output + ec = Encoding::Converter.new("", "") + a = ["", "abcdefg", ec, nil, 2, :after_output=>true] + check_ec("a", "bcdefg", :after_output, *a) + check_ec("ab", "cdefg", :after_output, *a) + check_ec("abc", "defg", :after_output, *a) + check_ec("abcd", "efg", :after_output, *a) + check_ec("abcde", "fg", :after_output, *a) + check_ec("abcdef", "g", :after_output, *a) + check_ec("abcdefg", "", :after_output, *a) + check_ec("abcdefg", "", :finished, *a) + end + + def test_noconv_insert_output + ec = Encoding::Converter.new("", "") + ec.insert_output("xyz") + ret = ec.primitive_convert(src="abc", dst="", nil, 20) + assert_equal(:finished, ret) + assert_equal(["xyzabc", ""], [dst, src]) + end + + def test_convert + ec = Encoding::Converter.new("utf-8", "euc-jp") + assert_raise(Encoding::InvalidByteSequenceError) { ec.convert("a\x80") } + assert_raise(Encoding::UndefinedConversionError) { ec.convert("\ufffd") } + ret = ec.primitive_convert(nil, "", nil, nil) + assert_equal(:finished, ret) + assert_raise(ArgumentError) { ec.convert("a") } + end + + def test_finish_iso2022jp + ec = Encoding::Converter.new("utf-8", "iso-2022-jp") + assert_equal("\e$B$\"".force_encoding("iso-2022-jp"), ec.convert("\u3042")) + assert_equal("\e(B".force_encoding("iso-2022-jp"), ec.finish) + + end + + def test_finish_incomplete_error + ec = Encoding::Converter.new("utf-8", "euc-jp") + ec.convert("\xEF") + assert_raise(Encoding::InvalidByteSequenceError) { ec.finish } + end + + def test_last_error1 + ec = Encoding::Converter.new("sjis", "euc-jp") + assert_equal(nil, ec.last_error) + assert_equal(:incomplete_input, ec.primitive_convert("fo\x81", "", nil, nil)) + assert_kind_of(Encoding::InvalidByteSequenceError, ec.last_error) + end + + def test_last_error2 + ec = Encoding::Converter.new("sjis", "euc-jp") + assert_equal("fo", ec.convert("fo\x81")) + assert_raise(Encoding::InvalidByteSequenceError) { ec.finish } + assert_kind_of(Encoding::InvalidByteSequenceError, ec.last_error) + end + + def test_us_ascii + ec = Encoding::Converter.new("UTF-8", "US-ASCII") + ec.primitive_convert("\u{3042}", "") + err = ec.last_error + assert_kind_of(Encoding::UndefinedConversionError, err) + assert_equal("\u{3042}", err.error_char) + end + + def test_88591 + ec = Encoding::Converter.new("UTF-8", "ISO-8859-1") + ec.primitive_convert("\u{3042}", "") + err = ec.last_error + assert_kind_of(Encoding::UndefinedConversionError, err) + assert_equal("\u{3042}", err.error_char) + end + + def test_get_replacement + ec = Encoding::Converter.new("euc-jp", "iso-8859-1") + assert_equal("?", ec.replacement) + + ec = Encoding::Converter.new("euc-jp", "utf-8") + assert_equal("\uFFFD", ec.replacement) + end + + def test_set_replacement + ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace) + ec.replacement = "<undef>" + assert_equal("a <undef> b", ec.convert("a \u3042 b")) + end + + def test_econv_new_hash + ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace) + assert_equal("a ? b", ec.convert("a \u3042 b")) + ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace, :replace => "X") + assert_equal("a X b", ec.convert("a \u3042 b")) + end + + def test_hex_charref + ec = Encoding::Converter.new("UTF-8", "US-ASCII", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("あ", ec.convert("\u3042")) + + ec = Encoding::Converter.new("UTF-8", "EUC-JP", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("\xa4\xcf\xa4\xa1\xa4\xa4♥\xa1\xa3".force_encoding("euc-jp"), + ec.convert("\u{306f 3041 3044 2665 3002}")) + + ec = Encoding::Converter.new("UTF-8", "ISO-2022-JP", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("\e$B$O$!$$\e(B♥\e$B!#".force_encoding("ISO-2022-JP"), + ec.convert("\u{306f 3041 3044 2665 3002}")) + assert_equal("\e(B".force_encoding("ISO-2022-JP"), + ec.finish) + + ec = Encoding::Converter.new("EUC-JP", "US-ASCII", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("交換法則: n×m=m×n".force_encoding("ISO-8859-1"), + ec.convert("\xB8\xF2\xB4\xB9\xCB\xA1\xC2\xA7: n\xA1\xDFm=m\xA1\xDFn")) + + ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("交換法則: n\xD7m=m\xD7n".force_encoding("ISO-8859-1"), + ec.convert("\xB8\xF2\xB4\xB9\xCB\xA1\xC2\xA7: n\xA1\xDFm=m\xA1\xDFn")) + + ec = Encoding::Converter.new("UTF-8", "US-ASCII", Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal("&", ec.convert("&")) + end + + def test_xml_escape_text + ec = Encoding::Converter.new("", "amp_escape") + assert_equal('&<>"', ec.convert("&<>\"")) + assert_equal('', ec.finish) + + ec = Encoding::Converter.new("", "xml_text_escape") + assert_equal('&<>"', ec.convert("&<>\"")) + assert_equal('', ec.finish) + end + + def test_xml_escape_attr_content + ec = Encoding::Converter.new("", "xml_attr_content_escape") + assert_equal('', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_content_escape") + assert_equal('', ec.convert("")) + assert_equal('', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_content_escape") + assert_equal('"', ec.convert('"')) + assert_equal('', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_content_escape") + assert_equal('&<>"', ec.convert("&<>\"")) + assert_equal('', ec.finish) + end + + def test_xml_escape_attr_quote + ec = Encoding::Converter.new("", "xml_attr_quote") + assert_equal('""', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_quote") + assert_equal('', ec.convert("")) + assert_equal('""', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_quote") + assert_equal('""', ec.convert('"')) + assert_equal('"', ec.finish) + + ec = Encoding::Converter.new("", "xml_attr_quote") + assert_equal('"&<>"', ec.convert("&<>\"")) + assert_equal('"', ec.finish) + end + + def test_xml_escape_with_charref + ec = Encoding::Converter.new("utf-8", "euc-jp", Encoding::Converter::XML_TEXT_DECORATOR|Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal('<♥>&"♡"', ec.convert("<\u2665>&\"\u2661\"")) + assert_equal('', ec.finish) + + ec = Encoding::Converter.new("utf-8", "euc-jp", + Encoding::Converter::XML_ATTR_CONTENT_DECORATOR| + Encoding::Converter::XML_ATTR_QUOTE_DECORATOR| + Encoding::Converter::UNDEF_HEX_CHARREF) + assert_equal('"<♥>&"♡"', ec.convert("<\u2665>&\"\u2661\"")) + assert_equal('"', ec.finish) + + ec = Encoding::Converter.new("utf-8", "iso-2022-jp", Encoding::Converter::XML_TEXT_DECORATOR) + assert_equal("&\e$B$&\e(B&".force_encoding("iso-2022-jp"), ec.convert("&\u3046&")) + assert_equal('', ec.finish) + end + + def test_xml_hasharg + assert_equal("&\e$B$&\e(B♥&\"'".force_encoding("iso-2022-jp"), + "&\u3046\u2665&\"'".encode("iso-2022-jp", xml: :text)) + assert_equal("\"&\e$B$&\e(B♡&"'\"".force_encoding("iso-2022-jp"), + "&\u3046\u2661&\"'".encode("iso-2022-jp", xml: :attr)) + + assert_equal("&\u3046\u2661&\"'".force_encoding("utf-8"), + "&\u3046\u2661&\"'".encode("utf-8", xml: :text)) + end + + def test_iso2022jp_invalid_replace + assert_equal("?x".force_encoding("iso-2022-jp"), + "\222\xA1x".encode("iso-2022-jp", "stateless-iso-2022-jp", :invalid => :replace)) + end + + def test_convpath + eucjp = Encoding::EUC_JP + utf8 = Encoding::UTF_8 + utf16be = Encoding::UTF_16BE + utf16le = Encoding::UTF_16LE + iso88591 = Encoding::ISO_8859_1 + iso2022jp = Encoding::ISO_2022_JP + siso2022jp = Encoding::STATELESS_ISO_2022_JP + + assert_equal([], Encoding::Converter.new("", "").convpath) + assert_equal([[eucjp, utf8], [utf8, iso88591]], + Encoding::Converter.new(eucjp, iso88591).convpath) + assert_equal([[eucjp, siso2022jp], [siso2022jp, iso2022jp]], + Encoding::Converter.new(eucjp, iso2022jp).convpath) + assert_equal([[iso2022jp, siso2022jp], + [siso2022jp, eucjp], + [eucjp, utf8], + [utf8, iso88591]], + Encoding::Converter.new(iso2022jp, iso88591).convpath) + assert_equal(["universal_newline", [utf8, utf16be]], + Encoding::Converter.new(utf8, utf16be, universal_newline: true).convpath) + assert_equal([[utf16be, utf8], "universal_newline"], + Encoding::Converter.new(utf16be, utf8, universal_newline: true).convpath) + assert_equal([[utf16be, utf8], "universal_newline", [utf8, utf16le]], + Encoding::Converter.new(utf16be, utf16le, universal_newline: true).convpath) + end + + def test_search_convpath + eucjp = Encoding::EUC_JP + utf8 = Encoding::UTF_8 + utf32be = Encoding::UTF_32BE + iso88591 = Encoding::ISO_8859_1 + assert_equal([[iso88591,utf8], [utf8,eucjp]], + Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP")) + assert_equal([[iso88591,utf8], [utf8,eucjp]], + Encoding::Converter.search_convpath(iso88591, eucjp)) + assert_equal([[iso88591,utf8], [utf8,eucjp], "universal_newline"], + Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP", universal_newline: true)) + assert_equal([[iso88591,utf8], "universal_newline", [utf8,utf32be]], + Encoding::Converter.search_convpath("ISO-8859-1", "UTF-32BE", universal_newline: true)) + end + + def test_invalid_replace2 + assert_raise(ArgumentError) { + broken = "\x80".force_encoding("euc-jp") + "".encode("euc-jp", :undef => :replace, :replace => broken) + } + end + + def test_newline_option + ec1 = Encoding::Converter.new("", "", universal_newline: true) + ec2 = Encoding::Converter.new("", "", newline: :universal) + assert_equal(ec1, ec2) + assert_raise_with_message(ArgumentError, /\u{3042}/) { + Encoding::Converter.new("", "", newline: "\u{3042}".to_sym) + } + end + + def test_default_external + Encoding.list.grep(->(enc) {/\AISO-8859-\d+\z/i =~ enc.name}) do |enc| + assert_separately(%W[--disable=gems -d - #{enc.name}], <<-EOS, ignore_stderr: true) + Encoding.default_external = ext = ARGV[0] + Encoding.default_internal = int ='utf-8' + assert_nothing_raised do + Encoding::Converter.new(ext, int) + end + EOS + end + end +end diff --git a/jni/ruby/test/ruby/test_encoding.rb b/jni/ruby/test/ruby/test_encoding.rb new file mode 100644 index 0000000..63c56e2 --- /dev/null +++ b/jni/ruby/test/ruby/test_encoding.rb @@ -0,0 +1,123 @@ +require 'test/unit' + +class TestEncoding < Test::Unit::TestCase + + # Test basic encoding methods: list, find, name + def test_encoding + encodings = Encoding.list + assert_equal(encodings.empty?, false) + + encodings.each do |e| + assert_equal(e, Encoding.find(e.name)) + assert_equal(e, Encoding.find(e.name.upcase)) + assert_equal(e, Encoding.find(e.name.capitalize)) + assert_equal(e, Encoding.find(e.name.downcase)) + assert_equal(e, Encoding.find(e)) + end + end + + def test_enc_names + aliases = Encoding.aliases + aliases.each do |a, en| + e = Encoding.find(a) + assert_equal(e.name, en) + assert_include(e.names, a) + end + end + + # Test that Encoding objects can't be copied + # And that they can be compared by object_id + def test_singleton + encodings = Encoding.list + encodings.each do |e| + assert_raise(TypeError) { e.dup } + assert_raise(TypeError) { e.clone } + assert_equal(e.object_id, Marshal.load(Marshal.dump(e)).object_id) + end + end + + def test_find + assert_raise(ArgumentError) { Encoding.find("foobarbazqux") } + assert_nothing_raised{Encoding.find("locale")} + assert_nothing_raised{Encoding.find("filesystem")} + + if /(?:ms|dar)win|mingw/ !~ RUBY_PLATFORM + # Unix's filesystem encoding is default_external + assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS') + exit Encoding.find("filesystem") == Encoding::UTF_8 + Encoding.default_external = Encoding::EUC_JP + exit Encoding.find("filesystem") == Encoding::EUC_JP + EOS + end + + bug5150 = '[ruby-dev:44327]' + assert_raise(TypeError, bug5150) {Encoding.find(1)} + end + + def test_replicate + assert_instance_of(Encoding, Encoding::UTF_8.replicate('UTF-8-ANOTHER')) + assert_instance_of(Encoding, Encoding::ISO_2022_JP.replicate('ISO-2022-JP-ANOTHER')) + bug3127 = '[ruby-dev:40954]' + assert_raise(TypeError, bug3127) {Encoding::UTF_8.replicate(0)} + assert_raise(ArgumentError, bug3127) {Encoding::UTF_8.replicate("\0")} + end + + def test_dummy_p + assert_equal(true, Encoding::ISO_2022_JP.dummy?) + assert_equal(false, Encoding::UTF_8.dummy?) + end + + def test_ascii_compatible_p + assert_equal(true, Encoding::ASCII_8BIT.ascii_compatible?) + assert_equal(true, Encoding::UTF_8.ascii_compatible?) + assert_equal(false, Encoding::UTF_16BE.ascii_compatible?) + assert_equal(false, Encoding::ISO_2022_JP.ascii_compatible?) + end + + def test_name_list + assert_instance_of(Array, Encoding.name_list) + Encoding.name_list.each do |x| + assert_instance_of(String, x) + end + end + + def test_aliases + assert_instance_of(Hash, Encoding.aliases) + Encoding.aliases.each do |k, v| + assert_include(Encoding.name_list, k) + assert_include(Encoding.name_list, v) + assert_instance_of(String, k) + assert_instance_of(String, v) + end + end + + def test_marshal + str = "".force_encoding("EUC-JP") + str2 = Marshal.load(Marshal.dump(str)) + assert_equal(str, str2) + str2 = Marshal.load(Marshal.dump(str2)) + assert_equal(str, str2, '[ruby-dev:38596]') + end + + def test_compatible_p + ua = "abc".force_encoding(Encoding::UTF_8) + assert_equal(Encoding::UTF_8, Encoding.compatible?(ua, :abc)) + assert_equal(nil, Encoding.compatible?(ua, 1)) + bin = "a".force_encoding(Encoding::ASCII_8BIT) + asc = "b".force_encoding(Encoding::US_ASCII) + assert_equal(Encoding::ASCII_8BIT, Encoding.compatible?(bin, asc)) + bin = "\xff".force_encoding(Encoding::ASCII_8BIT).to_sym + asc = "b".force_encoding(Encoding::ASCII_8BIT) + assert_equal(Encoding::ASCII_8BIT, Encoding.compatible?(bin, asc)) + assert_equal(Encoding::UTF_8, Encoding.compatible?("\u{3042}".to_sym, ua.to_sym)) + end + + def test_errinfo_after_autoload + bug9038 = '[ruby-core:57949] [Bug #9038]' + assert_separately(%w[--disable=gems], <<-"end;") + assert_raise_with_message(SyntaxError, /unknown regexp option - Q/, #{bug9038.dump}) { + eval("/regexp/sQ") + } + end; + end +end diff --git a/jni/ruby/test/ruby/test_enum.rb b/jni/ruby/test/ruby/test_enum.rb new file mode 100644 index 0000000..53e24fc --- /dev/null +++ b/jni/ruby/test/ruby/test_enum.rb @@ -0,0 +1,733 @@ +require 'test/unit' +EnvUtil.suppress_warning {require 'continuation'} +require 'stringio' + +class TestEnumerable < Test::Unit::TestCase + def setup + @obj = Object.new + class << @obj + include Enumerable + def each + yield 1 + yield 2 + yield 3 + yield 1 + yield 2 + self + end + end + @empty = Object.new + class << @empty + attr_reader :block + include Enumerable + def each(&block) + @block = block + self + end + end + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def assert_not_warn + begin + org_stderr = $stderr + v = $VERBOSE + $stderr = StringIO.new(warn = '') + $VERBOSE = true + yield + ensure + $stderr = org_stderr + $VERBOSE = v + end + assert_equal("", warn) + end + + def test_grep + assert_equal([1, 2, 1, 2], @obj.grep(1..2)) + a = [] + @obj.grep(2) {|x| a << x } + assert_equal([2, 2], a) + + bug5801 = '[ruby-dev:45041]' + @empty.grep(//) + block = @empty.block + assert_nothing_raised(bug5801) {100.times {block.call}} + + a = [] + lambda = ->(x, i) {a << [x, i]} + @obj.each_with_index.grep(proc{|x,i|x==2}, &lambda) + assert_equal([[2, 1], [2, 4]], a) + end + + def test_count + assert_equal(5, @obj.count) + assert_equal(2, @obj.count(1)) + assert_equal(3, @obj.count {|x| x % 2 == 1 }) + assert_equal(2, @obj.count(1) {|x| x % 2 == 1 }) + assert_raise(ArgumentError) { @obj.count(0, 1) } + + if RUBY_ENGINE == "ruby" + en = Class.new { + include Enumerable + alias :size :count + def each + yield 1 + end + } + assert_equal(1, en.new.count, '[ruby-core:24794]') + end + end + + def test_find + assert_equal(2, @obj.find {|x| x % 2 == 0 }) + assert_equal(nil, @obj.find {|x| false }) + assert_equal(:foo, @obj.find(proc { :foo }) {|x| false }) + cond = ->(x, i) { x % 2 == 0 } + assert_equal([2, 1], @obj.each_with_index.find(&cond)) + end + + def test_find_index + assert_equal(1, @obj.find_index(2)) + assert_equal(1, @obj.find_index {|x| x % 2 == 0 }) + assert_equal(nil, @obj.find_index {|x| false }) + assert_raise(ArgumentError) { @obj.find_index(0, 1) } + assert_equal(1, @obj.find_index(2) {|x| x == 1 }) + end + + def test_find_all + assert_equal([1, 3, 1], @obj.find_all {|x| x % 2 == 1 }) + cond = ->(x, i) { x % 2 == 1 } + assert_equal([[1, 0], [3, 2], [1, 3]], @obj.each_with_index.find_all(&cond)) + end + + def test_reject + assert_equal([2, 3, 2], @obj.reject {|x| x < 2 }) + cond = ->(x, i) {x < 2} + assert_equal([[2, 1], [3, 2], [2, 4]], @obj.each_with_index.reject(&cond)) + end + + def test_to_a + assert_equal([1, 2, 3, 1, 2], @obj.to_a) + end + + def test_to_h + obj = Object.new + def obj.each(*args) + yield(*args) + yield [:key, :value] + yield :other_key, :other_value + kvp = Object.new + def kvp.to_ary + [:obtained, :via_to_ary] + end + yield kvp + end + obj.extend Enumerable + assert_equal({ + :hello => :world, + :key => :value, + :other_key => :other_value, + :obtained => :via_to_ary, + }, obj.to_h(:hello, :world)) + + e = assert_raise(TypeError) { + obj.to_h(:not_an_array) + } + assert_equal "wrong element type Symbol (expected array)", e.message + + e = assert_raise(ArgumentError) { + obj.to_h([1]) + } + assert_equal "element has wrong array length (expected 2, was 1)", e.message + end + + def test_inject + assert_equal(12, @obj.inject {|z, x| z * x }) + assert_equal(48, @obj.inject {|z, x| z * 2 + x }) + assert_equal(12, @obj.inject(:*)) + assert_equal(24, @obj.inject(2) {|z, x| z * x }) + assert_equal(24, @obj.inject(2, :*) {|z, x| z * x }) + assert_equal(nil, @empty.inject() {9}) + end + + def test_partition + assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 }) + cond = ->(x, i) { x % 2 == 1 } + assert_equal([[[1, 0], [3, 2], [1, 3]], [[2, 1], [2, 4]]], @obj.each_with_index.partition(&cond)) + end + + def test_group_by + h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] } + assert_equal(h, @obj.group_by {|x| x }) + + h = {1=>[[1, 0], [1, 3]], 2=>[[2, 1], [2, 4]], 3=>[[3, 2]]} + cond = ->(x, i) { x } + assert_equal(h, @obj.each_with_index.group_by(&cond)) + end + + def test_first + assert_equal(1, @obj.first) + assert_equal([1, 2, 3], @obj.first(3)) + assert_nil(@empty.first) + + bug5801 = '[ruby-dev:45041]' + assert_in_out_err([], <<-'end;', [], /unexpected break/) + empty = Object.new + class << empty + attr_reader :block + include Enumerable + def each(&block) + @block = block + self + end + end + empty.first + empty.block.call + end; + end + + def test_sort + assert_equal([1, 1, 2, 2, 3], @obj.sort) + end + + def test_sort_by + assert_equal([3, 2, 2, 1, 1], @obj.sort_by {|x| -x }) + assert_equal((1..300).to_a.reverse, (1..300).sort_by {|x| -x }) + + cond = ->(x, i) { [-x, i] } + assert_equal([[3, 2], [2, 1], [2, 4], [1, 0], [1, 3]], @obj.each_with_index.sort_by(&cond)) + end + + def test_all + assert_equal(true, @obj.all? {|x| x <= 3 }) + assert_equal(false, @obj.all? {|x| x < 3 }) + assert_equal(true, @obj.all?) + assert_equal(false, [true, true, false].all?) + end + + def test_any + assert_equal(true, @obj.any? {|x| x >= 3 }) + assert_equal(false, @obj.any? {|x| x > 3 }) + assert_equal(true, @obj.any?) + assert_equal(false, [false, false, false].any?) + end + + def test_one + assert(@obj.one? {|x| x == 3 }) + assert(!(@obj.one? {|x| x == 1 })) + assert(!(@obj.one? {|x| x == 4 })) + assert(%w{ant bear cat}.one? {|word| word.length == 4}) + assert(!(%w{ant bear cat}.one? {|word| word.length > 4})) + assert(!(%w{ant bear cat}.one? {|word| word.length < 4})) + assert(!([ nil, true, 99 ].one?)) + assert([ nil, true, false ].one?) + end + + def test_none + assert(@obj.none? {|x| x == 4 }) + assert(!(@obj.none? {|x| x == 1 })) + assert(!(@obj.none? {|x| x == 3 })) + assert(%w{ant bear cat}.none? {|word| word.length == 5}) + assert(!(%w{ant bear cat}.none? {|word| word.length >= 4})) + assert([].none?) + assert([nil].none?) + assert([nil,false].none?) + end + + def test_min + assert_equal(1, @obj.min) + assert_equal(3, @obj.min {|a,b| b <=> a }) + cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } + assert_equal([3, 2], @obj.each_with_index.min(&cond)) + ary = %w(albatross dog horse) + assert_equal("albatross", ary.min) + assert_equal("dog", ary.min {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].min) + assert_equal(%w[albatross dog], ary.min(2)) + assert_equal(%w[dog horse], + ary.min(2) {|a,b| a.length <=> b.length }) + end + + def test_max + assert_equal(3, @obj.max) + assert_equal(1, @obj.max {|a,b| b <=> a }) + cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } + assert_equal([1, 3], @obj.each_with_index.max(&cond)) + ary = %w(albatross dog horse) + assert_equal("horse", ary.max) + assert_equal("albatross", ary.max {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].max{|a,b| b <=> a }) + assert_equal(%w[horse dog], ary.max(2)) + assert_equal(%w[albatross horse], + ary.max(2) {|a,b| a.length <=> b.length }) + end + + def test_minmax + assert_equal([1, 3], @obj.minmax) + assert_equal([3, 1], @obj.minmax {|a,b| b <=> a }) + ary = %w(albatross dog horse) + assert_equal(["albatross", "horse"], ary.minmax) + assert_equal(["dog", "albatross"], ary.minmax {|a,b| a.length <=> b.length }) + assert_equal([1, 3], [2,3,1].minmax) + assert_equal([3, 1], [2,3,1].minmax {|a,b| b <=> a }) + assert_equal([1, 3], [2,2,3,3,1,1].minmax) + end + + def test_min_by + assert_equal(3, @obj.min_by {|x| -x }) + cond = ->(x, i) { -x } + assert_equal([3, 2], @obj.each_with_index.min_by(&cond)) + a = %w(albatross dog horse) + assert_equal("dog", a.min_by {|x| x.length }) + assert_equal(3, [2,3,1].min_by {|x| -x }) + assert_equal(%w[dog horse], a.min_by(2) {|x| x.length }) + end + + def test_max_by + assert_equal(1, @obj.max_by {|x| -x }) + cond = ->(x, i) { -x } + assert_equal([1, 0], @obj.each_with_index.max_by(&cond)) + a = %w(albatross dog horse) + assert_equal("albatross", a.max_by {|x| x.length }) + assert_equal(1, [2,3,1].max_by {|x| -x }) + assert_equal(%w[albatross horse], a.max_by(2) {|x| x.length }) + end + + def test_minmax_by + assert_equal([3, 1], @obj.minmax_by {|x| -x }) + cond = ->(x, i) { -x } + assert_equal([[3, 2], [1, 0]], @obj.each_with_index.minmax_by(&cond)) + a = %w(albatross dog horse) + assert_equal(["dog", "albatross"], a.minmax_by {|x| x.length }) + assert_equal([3, 1], [2,3,1].minmax_by {|x| -x }) + end + + def test_member + assert(@obj.member?(1)) + assert(!(@obj.member?(4))) + assert([1,2,3].member?(1)) + assert(!([1,2,3].member?(4))) + end + + class Foo + include Enumerable + def each + yield 1 + yield 1,2 + end + end + + def test_each_with_index + a = [] + @obj.each_with_index {|x, i| a << [x, i] } + assert_equal([[1,0],[2,1],[3,2],[1,3],[2,4]], a) + + hash = Hash.new + %w(cat dog wombat).each_with_index do |item, index| + hash[item] = index + end + assert_equal({"cat"=>0, "wombat"=>2, "dog"=>1}, hash) + assert_equal([[1, 0], [[1, 2], 1]], Foo.new.each_with_index.to_a) + end + + def test_each_with_object + obj = [0, 1] + ret = (1..10).each_with_object(obj) {|i, memo| + memo[0] += i + memo[1] *= i + } + assert_same(obj, ret) + assert_equal([55, 3628800], ret) + assert_equal([[1, nil], [[1, 2], nil]], Foo.new.each_with_object(nil).to_a) + end + + def test_each_entry + assert_equal([1, 2, 3], [1, 2, 3].each_entry.to_a) + assert_equal([1, [1, 2]], Foo.new.each_entry.to_a) + a = [] + cond = ->(x, i) { a << x } + @obj.each_with_index.each_entry(&cond) + assert_equal([1, 2, 3, 1, 2], a) + end + + def test_each_slice + ary = [] + (1..10).each_slice(3) {|a| ary << a} + assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary) + + bug9749 = '[ruby-core:62060] [Bug #9749]' + ary.clear + (1..10).each_slice(3, &lambda {|a, *| ary << a}) + assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary, bug9749) + end + + def test_each_cons + ary = [] + (1..5).each_cons(3) {|a| ary << a} + assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary) + + bug9749 = '[ruby-core:62060] [Bug #9749]' + ary.clear + (1..5).each_cons(3, &lambda {|a, *| ary << a}) + assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary, bug9749) + end + + def test_zip + assert_equal([[1,1],[2,2],[3,3],[1,1],[2,2]], @obj.zip(@obj)) + a = [] + @obj.zip([:a, :b, :c]) {|x,y| a << [x, y] } + assert_equal([[1,:a],[2,:b],[3,:c],[1,nil],[2,nil]], a) + + a = [] + cond = ->((x, i), y) { a << [x, y, i] } + @obj.each_with_index.zip([:a, :b, :c], &cond) + assert_equal([[1,:a,0],[2,:b,1],[3,:c,2],[1,nil,3],[2,nil,4]], a) + + a = [] + @obj.zip({a: "A", b: "B", c: "C"}) {|x,y| a << [x, y] } + assert_equal([[1,[:a,"A"]],[2,[:b,"B"]],[3,[:c,"C"]],[1,nil],[2,nil]], a) + + ary = Object.new + def ary.to_a; [1, 2]; end + assert_raise(TypeError) {%w(a b).zip(ary)} + def ary.each; [3, 4].each{|e|yield e}; end + assert_equal([[1, 3], [2, 4], [3, nil], [1, nil], [2, nil]], @obj.zip(ary)) + def ary.to_ary; [5, 6]; end + assert_equal([[1, 5], [2, 6], [3, nil], [1, nil], [2, nil]], @obj.zip(ary)) + end + + def test_take + assert_equal([1,2,3], @obj.take(3)) + end + + def test_take_while + assert_equal([1,2], @obj.take_while {|x| x <= 2}) + cond = ->(x, i) {x <= 2} + assert_equal([[1, 0], [2, 1]], @obj.each_with_index.take_while(&cond)) + + bug5801 = '[ruby-dev:45040]' + @empty.take_while {true} + block = @empty.block + assert_nothing_raised(bug5801) {100.times {block.call}} + end + + def test_drop + assert_equal([3,1,2], @obj.drop(2)) + end + + def test_drop_while + assert_equal([3,1,2], @obj.drop_while {|x| x <= 2}) + cond = ->(x, i) {x <= 2} + assert_equal([[3, 2], [1, 3], [2, 4]], @obj.each_with_index.drop_while(&cond)) + end + + def test_cycle + assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10)) + a = [] + @obj.cycle(2) {|x| a << x} + assert_equal([1,2,3,1,2,1,2,3,1,2], a) + a = [] + cond = ->(x, i) {a << x} + @obj.each_with_index.cycle(2, &cond) + assert_equal([1,2,3,1,2,1,2,3,1,2], a) + end + + def test_callcc + assert_raise(RuntimeError) do + c = nil + @obj.sort_by {|x| callcc {|c2| c ||= c2 }; x } + c.call + end + + assert_raise(RuntimeError) do + c = nil + o = Object.new + class << o; self; end.class_eval do + define_method(:<=>) do |x| + callcc {|c2| c ||= c2 } + 0 + end + end + [o, o].sort_by {|x| x } + c.call + end + + assert_raise(RuntimeError) do + c = nil + o = Object.new + class << o; self; end.class_eval do + define_method(:<=>) do |x| + callcc {|c2| c ||= c2 } + 0 + end + end + [o, o, o].sort_by {|x| x } + c.call + end + end + + def test_reverse_each + assert_equal([2,1,3,2,1], @obj.reverse_each.to_a) + end + + def test_chunk + e = [].chunk {|elt| true } + assert_equal([], e.to_a) + + e = @obj.chunk {|elt| elt & 2 == 0 ? false : true } + assert_equal([[false, [1]], [true, [2, 3]], [false, [1]], [true, [2]]], e.to_a) + + e = @obj.chunk(acc: 0) {|elt, h| h[:acc] += elt; h[:acc].even? } + assert_equal([[false, [1,2]], [true, [3]], [false, [1,2]]], e.to_a) + assert_equal([[false, [1,2]], [true, [3]], [false, [1,2]]], e.to_a) # this tests h is duplicated. + + hs = [{}] + e = [:foo].chunk(hs[0]) {|elt, h| + hs << h + true + } + assert_equal([[true, [:foo]]], e.to_a) + assert_equal([[true, [:foo]]], e.to_a) + assert_equal([{}, {}, {}], hs) + assert_not_same(hs[0], hs[1]) + assert_not_same(hs[0], hs[2]) + assert_not_same(hs[1], hs[2]) + + e = @obj.chunk {|elt| elt < 3 ? :_alone : true } + assert_equal([[:_alone, [1]], + [:_alone, [2]], + [true, [3]], + [:_alone, [1]], + [:_alone, [2]]], e.to_a) + + e = @obj.chunk {|elt| elt == 3 ? :_separator : true } + assert_equal([[true, [1, 2]], + [true, [1, 2]]], e.to_a) + + e = @obj.chunk {|elt| elt == 3 ? nil : true } + assert_equal([[true, [1, 2]], + [true, [1, 2]]], e.to_a) + + e = @obj.chunk {|elt| :_foo } + assert_raise(RuntimeError) { e.to_a } + end + + def test_slice_before + e = [].slice_before {|elt| true } + assert_equal([], e.to_a) + + e = @obj.slice_before {|elt| elt.even? } + assert_equal([[1], [2,3,1], [2]], e.to_a) + + e = @obj.slice_before {|elt| elt.odd? } + assert_equal([[1,2], [3], [1,2]], e.to_a) + + e = @obj.slice_before(acc: 0) {|elt, h| h[:acc] += elt; h[:acc].even? } + assert_equal([[1,2], [3,1,2]], e.to_a) + assert_equal([[1,2], [3,1,2]], e.to_a) # this tests h is duplicated. + + hs = [{}] + e = [:foo].slice_before(hs[0]) {|elt, h| + hs << h + true + } + assert_equal([[:foo]], e.to_a) + assert_equal([[:foo]], e.to_a) + assert_equal([{}, {}, {}], hs) + assert_not_same(hs[0], hs[1]) + assert_not_same(hs[0], hs[2]) + assert_not_same(hs[1], hs[2]) + + ss = %w[abc defg h ijk l mno pqr st u vw xy z] + assert_equal([%w[abc defg h], %w[ijk l], %w[mno], %w[pqr st u vw xy z]], + ss.slice_before(/\A...\z/).to_a) + assert_not_warn{ss.slice_before(/\A...\z/).to_a} + end + + def test_slice_after0 + assert_raise(ArgumentError) { [].slice_after } + end + + def test_slice_after1 + e = [].slice_after {|a| flunk "should not be called" } + assert_equal([], e.to_a) + + e = [1,2].slice_after(1) + assert_equal([[1], [2]], e.to_a) + + e = [1,2].slice_after(3) + assert_equal([[1, 2]], e.to_a) + + [true, false].each {|b| + block_results = [true, b] + e = [1,2].slice_after {|a| block_results.shift } + assert_equal([[1], [2]], e.to_a) + assert_equal([], block_results) + + block_results = [false, b] + e = [1,2].slice_after {|a| block_results.shift } + assert_equal([[1, 2]], e.to_a) + assert_equal([], block_results) + } + end + + def test_slice_after_both_pattern_and_block + assert_raise(ArgumentError) { [].slice_after(1) {|a| true } } + end + + def test_slice_after_continuation_lines + lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"] + e = lines.slice_after(/[^\\]\n\z/) + assert_equal([["foo\n"], ["bar\\\n", "baz\n"], ["\n", "qux\n"]], e.to_a) + end + + def test_slice_before_empty_line + lines = ["foo", "", "bar"] + e = lines.slice_after(/\A\s*\z/) + assert_equal([["foo", ""], ["bar"]], e.to_a) + end + + def test_slice_when_0 + e = [].slice_when {|a, b| flunk "should not be called" } + assert_equal([], e.to_a) + end + + def test_slice_when_1 + e = [1].slice_when {|a, b| flunk "should not be called" } + assert_equal([[1]], e.to_a) + end + + def test_slice_when_2 + e = [1,2].slice_when {|a,b| + assert_equal(1, a) + assert_equal(2, b) + true + } + assert_equal([[1], [2]], e.to_a) + + e = [1,2].slice_when {|a,b| + assert_equal(1, a) + assert_equal(2, b) + false + } + assert_equal([[1, 2]], e.to_a) + end + + def test_slice_when_3 + block_invocations = [ + lambda {|a, b| + assert_equal(1, a) + assert_equal(2, b) + true + }, + lambda {|a, b| + assert_equal(2, a) + assert_equal(3, b) + false + } + ] + e = [1,2,3].slice_when {|a,b| + block_invocations.shift.call(a, b) + } + assert_equal([[1], [2, 3]], e.to_a) + assert_equal([], block_invocations) + end + + def test_slice_when_noblock + assert_raise(ArgumentError) { [].slice_when } + end + + def test_slice_when_contiguously_increasing_integers + e = [1,4,9,10,11,12,15,16,19,20,21].slice_when {|i, j| i+1 != j } + assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a) + end + + def test_detect + @obj = ('a'..'z') + assert_equal('c', @obj.detect {|x| x == 'c' }) + + proc = Proc.new {|x| x == 'c' } + assert_equal('c', @obj.detect(&proc)) + + lambda = ->(x) { x == 'c' } + assert_equal('c', @obj.detect(&lambda)) + + assert_equal(['c',2], @obj.each_with_index.detect {|x, i| x == 'c' }) + + proc2 = Proc.new {|x, i| x == 'c' } + assert_equal(['c',2], @obj.each_with_index.detect(&proc2)) + + bug9605 = '[ruby-core:61340]' + lambda2 = ->(x, i) { x == 'c' } + assert_equal(['c',2], @obj.each_with_index.detect(&lambda2)) + end + + def test_select + @obj = ('a'..'z') + assert_equal(['c'], @obj.select {|x| x == 'c' }) + + proc = Proc.new {|x| x == 'c' } + assert_equal(['c'], @obj.select(&proc)) + + lambda = ->(x) { x == 'c' } + assert_equal(['c'], @obj.select(&lambda)) + + assert_equal([['c',2]], @obj.each_with_index.select {|x, i| x == 'c' }) + + proc2 = Proc.new {|x, i| x == 'c' } + assert_equal([['c',2]], @obj.each_with_index.select(&proc2)) + + bug9605 = '[ruby-core:61340]' + lambda2 = ->(x, i) { x == 'c' } + assert_equal([['c',2]], @obj.each_with_index.select(&lambda2)) + end + + def test_map + @obj = ('a'..'e') + assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map {|x| x.upcase }) + + proc = Proc.new {|x| x.upcase } + assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&proc)) + + lambda = ->(x) { x.upcase } + assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&lambda)) + + assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]], + @obj.each_with_index.map {|x, i| [x.upcase, i] }) + + proc2 = Proc.new {|x, i| [x.upcase, i] } + assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]], + @obj.each_with_index.map(&proc2)) + + lambda2 = ->(x, i) { [x.upcase, i] } + assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]], + @obj.each_with_index.map(&lambda2)) + end + + def test_flat_map + @obj = [[1,2], [3,4]] + assert_equal([2,4,6,8], @obj.flat_map {|i| i.map{|j| j*2} }) + + proc = Proc.new {|i| i.map{|j| j*2} } + assert_equal([2,4,6,8], @obj.flat_map(&proc)) + + lambda = ->(i) { i.map{|j| j*2} } + assert_equal([2,4,6,8], @obj.flat_map(&lambda)) + + assert_equal([[1,2],0,[3,4],1], + @obj.each_with_index.flat_map {|x, i| [x,i] }) + + proc2 = Proc.new {|x, i| [x,i] } + assert_equal([[1,2],0,[3,4],1], + @obj.each_with_index.flat_map(&proc2)) + + lambda2 = ->(x, i) { [x,i] } + assert_equal([[1,2],0,[3,4],1], + @obj.each_with_index.flat_map(&lambda2)) + end +end diff --git a/jni/ruby/test/ruby/test_enumerator.rb b/jni/ruby/test/ruby/test_enumerator.rb new file mode 100644 index 0000000..b5ced3b --- /dev/null +++ b/jni/ruby/test/ruby/test_enumerator.rb @@ -0,0 +1,628 @@ +require 'test/unit' + +class TestEnumerator < Test::Unit::TestCase + def setup + @obj = Object.new + class << @obj + include Enumerable + def foo(*a) + a.each {|x| yield x } + end + end + @sized = @obj.clone + def @sized.size + 42 + end + end + + def enum_test obj + obj.map{|e| + e + }.sort + end + + def test_iterators + assert_equal [0, 1, 2], enum_test(3.times) + assert_equal [:x, :y, :z], enum_test([:x, :y, :z].each) + assert_equal [[:x, 1], [:y, 2]], enum_test({:x=>1, :y=>2}.each) + end + + ## Enumerator as Iterator + + def test_next + e = 3.times + 3.times{|i| + assert_equal i, e.next + } + assert_raise(StopIteration){e.next} + end + + def test_loop + e = 3.times + i = 0 + loop{ + assert_equal(i, e.next) + i += 1 + } + end + + def test_nested_iteration + def (o = Object.new).each + yield :ok1 + yield [:ok2, :x].each.next + end + e = o.to_enum + assert_equal :ok1, e.next + assert_equal :ok2, e.next + assert_raise(StopIteration){e.next} + end + + + def test_initialize + assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).to_a) + _, err = capture_io do + assert_equal([1, 2, 3], Enumerator.new(@obj, :foo, 1, 2, 3).to_a) + end + assert_match 'Enumerator.new without a block is deprecated', err + assert_equal([1, 2, 3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)) + assert_raise(ArgumentError) { Enumerator.new } + + enum = @obj.to_enum + assert_raise(NoMethodError) { enum.each {} } + enum.freeze + assert_raise(RuntimeError) { + capture_io do + # warning: Enumerator.new without a block is deprecated; use Object#to_enum + enum.__send__(:initialize, @obj, :foo) + end + } + end + + def test_initialize_copy + assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).dup.to_a) + e = @obj.to_enum(:foo, 1, 2, 3) + assert_nothing_raised { assert_equal(1, e.next) } + assert_raise(TypeError) { e.dup } + + e = Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.dup + assert_nothing_raised { assert_equal(1, e.next) } + assert_raise(TypeError) { e.dup } + end + + def test_gc + assert_nothing_raised do + 1.times do + foo = [1,2,3].to_enum + GC.start + end + GC.start + end + end + + def test_slice + assert_equal([[1,2,3],[4,5,6],[7,8,9],[10]], (1..10).each_slice(3).to_a) + end + + def test_cons + a = [[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7], [6,7,8], [7,8,9], [8,9,10]] + assert_equal(a, (1..10).each_cons(3).to_a) + end + + def test_with_index + assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a) + assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a) + end + + def test_with_index_large_offset + bug8010 = '[ruby-dev:47131] [Bug #8010]' + s = 1 << (8*1.size-2) + assert_equal([[1,s],[2,s+1],[3,s+2]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010) + s <<= 1 + assert_equal([[1,s],[2,s+1],[3,s+2]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010) + end + + def test_with_index_nonnum_offset + bug8010 = '[ruby-dev:47131] [Bug #8010]' + s = Object.new + def s.to_int; 1 end + assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010) + end + + def test_with_index_string_offset + bug8010 = '[ruby-dev:47131] [Bug #8010]' + assert_raise(TypeError, bug8010){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a } + end + + def test_with_index_dangling_memo + bug9178 = '[ruby-core:58692] [Bug #9178]' + assert_separately([], <<-"end;") + bug = "#{bug9178}" + e = [1].to_enum(:chunk).with_index {|c,i| i == 5} + assert_kind_of(Enumerator, e) + assert_equal([false, [1]], e.to_a[0], bug) + end; + end + + def test_with_object + obj = [0, 1] + ret = (1..10).each.with_object(obj) {|i, memo| + memo[0] += i + memo[1] *= i + } + assert_same(obj, ret) + assert_equal([55, 3628800], ret) + + a = [2,5,2,1,5,3,4,2,1,0] + obj = {} + ret = a.delete_if.with_object(obj) {|i, seen| + if seen.key?(i) + true + else + seen[i] = true + false + end + } + assert_same(obj, ret) + assert_equal([2, 5, 1, 3, 4, 0], a) + end + + def test_next_rewind + e = @obj.to_enum(:foo, 1, 2, 3) + assert_equal(1, e.next) + assert_equal(2, e.next) + e.rewind + assert_equal(1, e.next) + assert_equal(2, e.next) + assert_equal(3, e.next) + assert_raise(StopIteration) { e.next } + end + + def test_peek + a = [1] + e = a.each + assert_equal(1, e.peek) + assert_equal(1, e.peek) + assert_equal(1, e.next) + assert_raise(StopIteration) { e.peek } + assert_raise(StopIteration) { e.peek } + end + + def test_peek_modify + o = Object.new + def o.each + yield 1,2 + end + e = o.to_enum + a = e.peek + a << 3 + assert_equal([1,2], e.peek) + end + + def test_peek_values_modify + o = Object.new + def o.each + yield 1,2 + end + e = o.to_enum + a = e.peek_values + a << 3 + assert_equal([1,2], e.peek) + end + + def test_next_after_stopiteration + a = [1] + e = a.each + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } + e.rewind + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } + end + + def test_stop_result + a = [1] + res = a.each {} + e = a.each + assert_equal(1, e.next) + exc = assert_raise(StopIteration) { e.next } + assert_equal(res, exc.result) + end + + def test_next_values + o = Object.new + def o.each + yield + yield 1 + yield 1, 2 + end + e = o.to_enum + assert_equal(nil, e.next) + assert_equal(1, e.next) + assert_equal([1,2], e.next) + e = o.to_enum + assert_equal([], e.next_values) + assert_equal([1], e.next_values) + assert_equal([1,2], e.next_values) + end + + def test_peek_values + o = Object.new + def o.each + yield + yield 1 + yield 1, 2 + end + e = o.to_enum + assert_equal(nil, e.peek) + assert_equal(nil, e.next) + assert_equal(1, e.peek) + assert_equal(1, e.next) + assert_equal([1,2], e.peek) + assert_equal([1,2], e.next) + e = o.to_enum + assert_equal([], e.peek_values) + assert_equal([], e.next_values) + assert_equal([1], e.peek_values) + assert_equal([1], e.next_values) + assert_equal([1,2], e.peek_values) + assert_equal([1,2], e.next_values) + e = o.to_enum + assert_equal([], e.peek_values) + assert_equal(nil, e.next) + assert_equal([1], e.peek_values) + assert_equal(1, e.next) + assert_equal([1,2], e.peek_values) + assert_equal([1,2], e.next) + e = o.to_enum + assert_equal(nil, e.peek) + assert_equal([], e.next_values) + assert_equal(1, e.peek) + assert_equal([1], e.next_values) + assert_equal([1,2], e.peek) + assert_equal([1,2], e.next_values) + end + + def test_each_arg + o = Object.new + def o.each(ary) + ary << 1 + yield + end + ary = [] + e = o.to_enum.each(ary) + e.next + assert_equal([1], ary) + end + + def test_feed + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.next + e.feed 1 + e.next + e.feed 2 + e.next + e.feed 3 + assert_raise(StopIteration) { e.next } + assert_equal([1,2,3], ary) + end + + def test_feed_mixed + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.next + e.feed 1 + e.next + e.next + e.feed 3 + assert_raise(StopIteration) { e.next } + assert_equal([1,nil,3], ary) + end + + def test_feed_twice + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.feed 1 + assert_raise(TypeError) { e.feed 2 } + end + + def test_feed_before_first_next + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.feed 1 + e.next + e.next + assert_equal([1], ary) + end + + def test_rewind_clear_feed + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.next + e.feed 1 + e.next + e.feed 2 + e.rewind + e.next + e.next + assert_equal([1,nil], ary) + end + + def test_feed_yielder + x = nil + e = Enumerator.new {|y| x = y.yield; 10 } + e.next + e.feed 100 + exc = assert_raise(StopIteration) { e.next } + assert_equal(100, x) + assert_equal(10, exc.result) + end + + def test_inspect + e = (0..10).each_cons(2) + assert_equal("#<Enumerator: 0..10:each_cons(2)>", e.inspect) + + e = Enumerator.new {|y| y.yield; 10 } + assert_match(/\A#<Enumerator: .*:each>/, e.inspect) + + a = [] + e = a.each_with_object(a) + a << e + assert_equal("#<Enumerator: [#<Enumerator: ...>]:each_with_object([#<Enumerator: ...>])>", + e.inspect) + end + + def test_inspect_verbose + bug6214 = '[ruby-dev:45449]' + assert_warning("", bug6214) { "".bytes.inspect } + assert_warning("", bug6214) { [].lazy.inspect } + end + + def test_inspect_encoding + c = Class.new{define_method("\u{3042}"){}} + e = c.new.enum_for("\u{3042}") + s = assert_nothing_raised(Encoding::CompatibilityError) {break e.inspect} + assert_equal(Encoding::UTF_8, s.encoding) + assert_match(/\A#<Enumerator: .*:\u{3042}>\z/, s) + end + + def test_generator + # note: Enumerator::Generator is a class just for internal + g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo } + g2 = g.dup + a = [] + assert_equal(:foo, g.each {|x| a << x }) + assert_equal([1, 2, 3], a) + a = [] + assert_equal(:foo, g2.each {|x| a << x }) + assert_equal([1, 2, 3], a) + + g.freeze + assert_raise(RuntimeError) { + g.__send__ :initialize, proc { |y| y << 4 << 5 } + } + end + + def test_generator_args + g = Enumerator::Generator.new {|y, x| y << 1 << 2 << 3; x } + a = [] + assert_equal(:bar, g.each(:bar) {|x| a << x }) + assert_equal([1, 2, 3], a) + end + + def test_yielder + # note: Enumerator::Yielder is a class just for internal + a = [] + y = Enumerator::Yielder.new {|x| a << x } + assert_equal(y, y << 1 << 2 << 3) + assert_equal([1, 2, 3], a) + + a = [] + y = Enumerator::Yielder.new {|x| a << x } + assert_equal([1], y.yield(1)) + assert_equal([1, 2], y.yield(2)) + assert_equal([1, 2, 3], y.yield(3)) + + assert_raise(LocalJumpError) { Enumerator::Yielder.new } + end + + def test_size + assert_equal nil, Enumerator.new{}.size + assert_equal 42, Enumerator.new(->{42}){}.size + obj = Object.new + def obj.call; 42; end + assert_equal 42, Enumerator.new(obj){}.size + assert_equal 42, Enumerator.new(42){}.size + assert_equal 1 << 70, Enumerator.new(1 << 70){}.size + assert_equal Float::INFINITY, Enumerator.new(Float::INFINITY){}.size + assert_equal nil, Enumerator.new(nil){}.size + assert_raise(TypeError) { Enumerator.new("42"){} } + + assert_equal nil, @obj.to_enum(:foo, 0, 1).size + assert_equal 2, @obj.to_enum(:foo, 0, 1){ 2 }.size + end + + def test_size_for_enum_created_by_enumerators + enum = to_enum{ 42 } + assert_equal 42, enum.with_index.size + assert_equal 42, enum.with_object(:foo).size + end + + def test_size_for_enum_created_from_array + arr = %w[hello world] + %i[each each_with_index reverse_each sort_by! sort_by map map! + keep_if reject! reject select! select delete_if].each do |method| + assert_equal arr.size, arr.send(method).size + end + end + + def test_size_for_enum_created_from_enumerable + %i[find_all reject map flat_map partition group_by sort_by min_by max_by + minmax_by each_with_index reverse_each each_entry].each do |method| + assert_equal nil, @obj.send(method).size + assert_equal 42, @sized.send(method).size + end + assert_equal nil, @obj.each_with_object(nil).size + assert_equal 42, @sized.each_with_object(nil).size + end + + def test_size_for_enum_created_from_hash + h = {a: 1, b: 2, c: 3} + methods = %i[delete_if reject reject! select select! keep_if each each_key each_pair] + enums = methods.map {|method| h.send(method)} + s = enums.group_by(&:size) + assert_equal([3], s.keys, ->{s.reject!{|k| k==3}.inspect}) + h[:d] = 4 + s = enums.group_by(&:size) + assert_equal([4], s.keys, ->{s.reject!{|k| k==4}.inspect}) + end + + def test_size_for_enum_created_from_env + %i[each_pair reject! delete_if select select! keep_if].each do |method| + assert_equal ENV.size, ENV.send(method).size + end + end + + def test_size_for_enum_created_from_struct + s = Struct.new(:foo, :bar, :baz).new(1, 2) + %i[each each_pair select].each do |method| + assert_equal 3, s.send(method).size + end + end + + def check_consistency_for_combinatorics(method) + [ [], [:a, :b, :c, :d, :e] ].product([-2, 0, 2, 5, 6]) do |array, arg| + assert_equal array.send(method, arg).to_a.size, array.send(method, arg).size, + "inconsistent size for #{array}.#{method}(#{arg})" + end + end + + def test_size_for_array_combinatorics + check_consistency_for_combinatorics(:permutation) + assert_equal 24, [0, 1, 2, 4].permutation.size + assert_equal 2933197128679486453788761052665610240000000, + (1..42).to_a.permutation(30).size # 1.upto(42).inject(:*) / 1.upto(12).inject(:*) + + check_consistency_for_combinatorics(:combination) + assert_equal 28258808871162574166368460400, + (1..100).to_a.combination(42).size + # 1.upto(100).inject(:*) / 1.upto(42).inject(:*) / 1.upto(58).inject(:*) + + check_consistency_for_combinatorics(:repeated_permutation) + assert_equal 291733167875766667063796853374976, + (1..42).to_a.repeated_permutation(20).size # 42 ** 20 + + check_consistency_for_combinatorics(:repeated_combination) + assert_equal 28258808871162574166368460400, + (1..59).to_a.repeated_combination(42).size + # 1.upto(100).inject(:*) / 1.upto(42).inject(:*) / 1.upto(58).inject(:*) + end + + def test_size_for_cycle + assert_equal Float::INFINITY, [:foo].cycle.size + assert_equal 10, [:foo, :bar].cycle(5).size + assert_equal 0, [:foo, :bar].cycle(-10).size + assert_equal 0, [].cycle.size + assert_equal 0, [].cycle(5).size + + assert_equal nil, @obj.cycle.size + assert_equal nil, @obj.cycle(5).size + assert_equal Float::INFINITY, @sized.cycle.size + assert_equal 126, @sized.cycle(3).size + end + + def test_size_for_loops + assert_equal Float::INFINITY, loop.size + assert_equal 42, 42.times.size + end + + def test_size_for_each_slice + assert_equal nil, @obj.each_slice(3).size + assert_equal 6, @sized.each_slice(7).size + assert_equal 5, @sized.each_slice(10).size + assert_equal 1, @sized.each_slice(70).size + assert_raise(ArgumentError){ @obj.each_slice(0).size } + end + + def test_size_for_each_cons + assert_equal nil, @obj.each_cons(3).size + assert_equal 33, @sized.each_cons(10).size + assert_equal 0, @sized.each_cons(70).size + assert_raise(ArgumentError){ @obj.each_cons(0).size } + end + + def test_size_for_step + assert_equal 42, 5.step(46).size + assert_equal 4, 1.step(10, 3).size + assert_equal 3, 1.step(9, 3).size + assert_equal 0, 1.step(-11).size + assert_equal 0, 1.step(-11, 2).size + assert_equal 7, 1.step(-11, -2).size + assert_equal 7, 1.step(-11.1, -2).size + assert_equal 0, 42.step(Float::INFINITY, -2).size + assert_equal 1, 42.step(55, Float::INFINITY).size + assert_equal 1, 42.step(Float::INFINITY, Float::INFINITY).size + assert_equal 14, 0.1.step(4.2, 0.3).size + assert_equal Float::INFINITY, 42.step(Float::INFINITY, 2).size + + assert_equal 10, (1..10).step.size + assert_equal 4, (1..10).step(3).size + assert_equal 3, (1...10).step(3).size + assert_equal Float::INFINITY, (42..Float::INFINITY).step(2).size + assert_raise(ArgumentError){ (1..10).step(-2).size } + end + + def test_size_for_downup_to + assert_equal 0, 1.upto(-100).size + assert_equal 102, 1.downto(-100).size + assert_equal Float::INFINITY, 42.upto(Float::INFINITY).size + end + + def test_size_for_string + assert_equal 5, 'hello'.each_byte.size + assert_equal 5, 'hello'.each_char.size + assert_equal 5, 'hello'.each_codepoint.size + end + + def test_peek_for_enumerator_objects + e = 2.times + assert_equal(0, e.peek) + e.next + assert_equal(1, e.peek) + e.next + assert_raise(StopIteration) { e.peek } + end +end + diff --git a/jni/ruby/test/ruby/test_env.rb b/jni/ruby/test/ruby/test_env.rb new file mode 100644 index 0000000..88a7631 --- /dev/null +++ b/jni/ruby/test/ruby/test_env.rb @@ -0,0 +1,552 @@ +require 'test/unit' + +class TestEnv < Test::Unit::TestCase + IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM + PATH_ENV = "PATH" + + def setup + @verbose = $VERBOSE + $VERBOSE = nil + @backup = ENV.to_hash + ENV.delete('test') + ENV.delete('TEST') + end + + def teardown + $VERBOSE = @verbose + ENV.clear + @backup.each {|k, v| ENV[k] = v } + end + + def test_bracket + assert_nil(ENV['test']) + assert_nil(ENV['TEST']) + ENV['test'] = 'foo' + assert_equal('foo', ENV['test']) + if IGNORE_CASE + assert_equal('foo', ENV['TEST']) + else + assert_nil(ENV['TEST']) + end + ENV['TEST'] = 'bar' + assert_equal('bar', ENV['TEST']) + if IGNORE_CASE + assert_equal('bar', ENV['test']) + else + assert_equal('foo', ENV['test']) + end + + assert_raise(TypeError) { + tmp = ENV[1] + } + assert_raise(TypeError) { + ENV[1] = 'foo' + } + assert_raise(TypeError) { + ENV['test'] = 0 + } + end + + def test_has_value + val = 'a' + val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) + ENV['test'] = val[0...-1] + + assert_equal(false, ENV.has_value?(val)) + assert_equal(false, ENV.has_value?(val.upcase)) + ENV['test'] = val + assert_equal(true, ENV.has_value?(val)) + assert_equal(false, ENV.has_value?(val.upcase)) + ENV['test'] = val.upcase + assert_equal(false, ENV.has_value?(val)) + assert_equal(true, ENV.has_value?(val.upcase)) + end + + def test_key + val = 'a' + val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) + ENV['test'] = val[0...-1] + + assert_nil(ENV.key(val)) + assert_nil(ENV.index(val)) + assert_nil(ENV.key(val.upcase)) + ENV['test'] = val + if IGNORE_CASE + assert_equal('TEST', ENV.key(val).upcase) + else + assert_equal('test', ENV.key(val)) + end + assert_nil(ENV.key(val.upcase)) + ENV['test'] = val.upcase + assert_nil(ENV.key(val)) + if IGNORE_CASE + assert_equal('TEST', ENV.key(val.upcase).upcase) + else + assert_equal('test', ENV.key(val.upcase)) + end + end + + def test_delete + assert_raise(ArgumentError) { ENV.delete("foo\0bar") } + assert_nil(ENV.delete("TEST")) + assert_nothing_raised { ENV.delete(PATH_ENV) } + end + + def test_getenv + assert_raise(ArgumentError) { ENV["foo\0bar"] } + ENV[PATH_ENV] = "" + assert_equal("", ENV[PATH_ENV]) + assert_nil(ENV[""]) + end + + def test_fetch + ENV["test"] = "foo" + assert_equal("foo", ENV.fetch("test")) + ENV.delete("test") + feature8649 = '[ruby-core:56062] [Feature #8649]' + assert_raise_with_message(KeyError, 'key not found: "test"', feature8649) do + ENV.fetch("test") + end + assert_equal("foo", ENV.fetch("test", "foo")) + assert_equal("bar", ENV.fetch("test") { "bar" }) + assert_equal("bar", ENV.fetch("test", "foo") { "bar" }) + assert_raise(ArgumentError) { ENV.fetch("foo\0bar") } + assert_nothing_raised { ENV.fetch(PATH_ENV, "foo") } + ENV[PATH_ENV] = "" + assert_equal("", ENV.fetch(PATH_ENV)) + end + + def test_aset + assert_nothing_raised { ENV["test"] = nil } + assert_equal(nil, ENV["test"]) + assert_raise(ArgumentError) { ENV["foo\0bar"] = "test" } + assert_raise(ArgumentError) { ENV["test"] = "foo\0bar" } + + begin + # setenv(3) allowed the name includes '=', + # but POSIX.1-2001 says it should fail with EINVAL. + # see also http://togetter.com/li/22380 + ENV["foo=bar"] = "test" + assert_equal("test", ENV["foo=bar"]) + assert_equal("test", ENV["foo"]) + rescue Errno::EINVAL + end + + ENV[PATH_ENV] = "/tmp/".taint + assert_equal("/tmp/", ENV[PATH_ENV]) + end + + def test_keys + a = ENV.keys + assert_kind_of(Array, a) + a.each {|k| assert_kind_of(String, k) } + end + + def test_each_key + ENV.each_key {|k| assert_kind_of(String, k) } + end + + def test_values + a = ENV.values + assert_kind_of(Array, a) + a.each {|k| assert_kind_of(String, k) } + end + + def test_each_value + ENV.each_value {|k| assert_kind_of(String, k) } + end + + def test_each_pair + ENV.each_pair do |k, v| + assert_kind_of(String, k) + assert_kind_of(String, v) + end + end + + def test_reject_bang + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.reject! {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + assert_equal(h1, h2) + + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.delete_if {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + assert_equal(h1, h2) + end + + def test_select_bang + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.select! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + assert_equal(h1, h2) + + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.keep_if {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + assert_equal(h1, h2) + end + + def test_values_at + ENV["test"] = "foo" + assert_equal(["foo", "foo"], ENV.values_at("test", "test")) + end + + def test_select + ENV["test"] = "foo" + h = ENV.select {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } + assert_equal(1, h.size) + k = h.keys.first + v = h.values.first + if IGNORE_CASE + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end + + def test_clear + ENV.clear + assert_equal(0, ENV.size) + end + + def test_to_s + assert_equal("ENV", ENV.to_s) + end + + def test_inspect + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + s = ENV.inspect + if IGNORE_CASE + 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 + + def test_to_a + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + a = ENV.to_a + assert_equal(2, a.size) + if IGNORE_CASE + 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 + + def test_rehash + assert_nil(ENV.rehash) + end + + def test_size + s = ENV.size + ENV["test"] = "foo" + assert_equal(s + 1, ENV.size) + end + + def test_empty_p + ENV.clear + assert_predicate(ENV, :empty?) + ENV["test"] = "foo" + assert_not_predicate(ENV, :empty?) + end + + def test_has_key + assert_not_send([ENV, :has_key?, "test"]) + ENV["test"] = "foo" + assert_send([ENV, :has_key?, "test"]) + assert_raise(ArgumentError) { ENV.has_key?("foo\0bar") } + end + + def test_assoc + assert_nil(ENV.assoc("test")) + ENV["test"] = "foo" + k, v = ENV.assoc("test") + if IGNORE_CASE + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + assert_raise(ArgumentError) { ENV.assoc("foo\0bar") } + end + + def test_has_value2 + ENV.clear + assert_not_send([ENV, :has_value?, "foo"]) + ENV["test"] = "foo" + assert_send([ENV, :has_value?, "foo"]) + end + + def test_rassoc + ENV.clear + assert_nil(ENV.rassoc("foo")) + ENV["foo"] = "bar" + ENV["test"] = "foo" + ENV["baz"] = "qux" + k, v = ENV.rassoc("foo") + if IGNORE_CASE + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end + + def test_to_hash + h = {} + ENV.each {|k, v| h[k] = v } + assert_equal(h, ENV.to_hash) + end + + def test_to_h + assert_equal(ENV.to_hash, ENV.to_h) + end + + def test_reject + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + h2 = ENV.reject {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } + assert_equal(h1, h2) + end + + def check(as, bs) + if IGNORE_CASE + as = as.map {|xs| xs.map {|x| x.upcase } } + bs = bs.map {|xs| xs.map {|x| x.upcase } } + end + assert_equal(as.sort, bs.sort) + end + + def test_shift + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + a = ENV.shift + b = ENV.shift + check([a, b], [%w(foo bar), %w(baz qux)]) + assert_nil(ENV.shift) + end + + def test_invert + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + check(ENV.invert.to_a, [%w(bar foo), %w(qux baz)]) + end + + def test_replace + ENV["foo"] = "xxx" + ENV.replace({"foo"=>"bar", "baz"=>"qux"}) + check(ENV.to_hash.to_a, [%w(foo bar), %w(baz qux)]) + end + + def test_update + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV.update({"baz"=>"quux","a"=>"b"}) + check(ENV.to_hash.to_a, [%w(foo bar), %w(baz quux), %w(a b)]) + + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| v1 ? k + "_" + v1 + "_" + v2 : v2 } + check(ENV.to_hash.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)]) + end + + def test_huge_value + huge_value = "bar" * 40960 + ENV["foo"] = "bar" + if /mswin|mingw/ =~ RUBY_PLATFORM + assert_raise(Errno::EINVAL) { ENV["foo"] = huge_value } + assert_equal("bar", ENV["foo"]) + else + assert_nothing_raised { ENV["foo"] = huge_value } + assert_equal(huge_value, ENV["foo"]) + end + end + + if /mswin|mingw/ =~ RUBY_PLATFORM + def test_win32_blocksize + keys = [] + len = 32767 - ENV.to_a.flatten.inject(0) {|r,e| r + e.bytesize + 1} + val = "bar" * 1000 + key = nil + while (len -= val.size + (key="foo#{len}").size + 2) > 0 + keys << key + ENV[key] = val + end + 1.upto(12) {|i| + assert_raise(Errno::EINVAL) { ENV[key] = val } + } + ensure + keys.each {|k| ENV.delete(k)} + end + end + + def test_frozen + ENV[PATH_ENV] = "/" + ENV.each do |k, v| + assert_predicate(k, :frozen?) + assert_predicate(v, :frozen?) + end + ENV.each_key do |k| + assert_predicate(k, :frozen?) + end + ENV.each_value do |v| + assert_predicate(v, :frozen?) + end + ENV.each_key do |k| + assert_predicate(ENV[k], :frozen?, "[#{k.dump}]") + assert_predicate(ENV.fetch(k), :frozen?, "fetch(#{k.dump})") + end + end + + def test_taint_aref + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO".taint] + end.call + end + end + + def test_taint_fetch + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.fetch("FOO".taint) + end.call + end + end + + def test_taint_assoc + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.assoc("FOO".taint) + end.call + end + end + + def test_taint_rassoc + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.rassoc("FOO".taint) + end.call + end + end + + def test_taint_key + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.key("FOO".taint) + end.call + end + end + + def test_taint_key_p + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.key?("FOO".taint) + end.call + end + end + + def test_taint_value_p + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.value?("FOO".taint) + end.call + end + end + + def test_taint_aset_value + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO"] = "BAR".taint + end.call + end + end + + def test_taint_aset_key + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO".taint] = "BAR" + end.call + end + end + + if RUBY_PLATFORM =~ /bccwin|mswin|mingw/ + def test_memory_leak_aset + bug9977 = '[ruby-dev:48323] [Bug #9977]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9977, limit: 2.0) + ENV.clear + k = 'FOO' + v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV[k] = v} + 500.times(&doit) + end; + end + + def test_memory_leak_select + bug9978 = '[ruby-dev:48325] [Bug #9978]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9978, limit: 2.0) + ENV.clear + k = 'FOO' + (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV.select {break}} + 500.times(&doit) + end; + end + + def test_memory_crash_select + assert_normal_exit(<<-'end;') + 1000.times {ENV["FOO#{i}"] = 'bar'} + ENV.select {ENV.clear} + end; + end + + def test_memory_leak_shift + bug9983 = '[ruby-dev:48332] [Bug #9983]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9983, limit: 2.0) + ENV.clear + k = 'FOO' + v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV[k] = v; ENV.shift} + 500.times(&doit) + end; + end + end +end diff --git a/jni/ruby/test/ruby/test_eval.rb b/jni/ruby/test/ruby/test_eval.rb new file mode 100644 index 0000000..9d8db30 --- /dev/null +++ b/jni/ruby/test/ruby/test_eval.rb @@ -0,0 +1,510 @@ +require 'test/unit' + +class TestEval < Test::Unit::TestCase + + @ivar = 12 + @@cvar = 13 + $gvar__eval = 14 + Const = 15 + + def ruby(*args) + args = ['-e', '$>.write($<.read)'] if args.empty? + ruby = EnvUtil.rubybin + f = IO.popen([ruby] + args, 'r+') + yield(f) + ensure + f.close unless !f || f.closed? + end + + def test_eval_basic + assert_equal nil, eval("nil") + assert_equal true, eval("true") + assert_equal false, eval("false") + assert_equal self, eval("self") + assert_equal 1, eval("1") + assert_equal :sym, eval(":sym") + + assert_equal 11, eval("11") + @ivar = 12 + assert_equal 12, eval("@ivar") + assert_equal 13, eval("@@cvar") + assert_equal 14, eval("$gvar__eval") + assert_equal 15, eval("Const") + + assert_equal 16, eval("7 + 9") + assert_equal 17, eval("17.to_i") + assert_equal "18", eval(%q("18")) + assert_equal "19", eval(%q("1#{9}")) + + 1.times { + assert_equal 12, eval("@ivar") + assert_equal 13, eval("@@cvar") + assert_equal 14, eval("$gvar__eval") + assert_equal 15, eval("Const") + } + end + + def test_eval_binding_basic + assert_equal nil, eval("nil", binding()) + assert_equal true, eval("true", binding()) + assert_equal false, eval("false", binding()) + assert_equal self, eval("self", binding()) + assert_equal 1, eval("1", binding()) + assert_equal :sym, eval(":sym", binding()) + + assert_equal 11, eval("11", binding()) + @ivar = 12 + assert_equal 12, eval("@ivar", binding()) + assert_equal 13, eval("@@cvar", binding()) + assert_equal 14, eval("$gvar__eval", binding()) + assert_equal 15, eval("Const", binding()) + + assert_equal 16, eval("7 + 9", binding()) + assert_equal 17, eval("17.to_i", binding()) + assert_equal "18", eval(%q("18"), binding()) + assert_equal "19", eval(%q("1#{9}"), binding()) + + 1.times { + assert_equal 12, eval("@ivar") + assert_equal 13, eval("@@cvar") + assert_equal 14, eval("$gvar__eval") + assert_equal 15, eval("Const") + } + end + + def test_module_eval_string_basic + c = self.class + assert_equal nil, c.module_eval("nil") + assert_equal true, c.module_eval("true") + assert_equal false, c.module_eval("false") + assert_equal c, c.module_eval("self") + assert_equal :sym, c.module_eval(":sym") + assert_equal 11, c.module_eval("11") + @ivar = 12 + assert_equal 12, c.module_eval("@ivar") + assert_equal 13, c.module_eval("@@cvar") + assert_equal 14, c.module_eval("$gvar__eval") + assert_equal 15, c.module_eval("Const") + assert_equal 16, c.module_eval("7 + 9") + assert_equal 17, c.module_eval("17.to_i") + assert_equal "18", c.module_eval(%q("18")) + assert_equal "19", c.module_eval(%q("1#{9}")) + + @ivar = 12 + 1.times { + assert_equal 12, c.module_eval("@ivar") + assert_equal 13, c.module_eval("@@cvar") + assert_equal 14, c.module_eval("$gvar__eval") + assert_equal 15, c.module_eval("Const") + } + end + + def test_module_eval_block_basic + c = self.class + assert_equal nil, c.module_eval { nil } + assert_equal true, c.module_eval { true } + assert_equal false, c.module_eval { false } + assert_equal c, c.module_eval { self } + assert_equal :sym, c.module_eval { :sym } + assert_equal 11, c.module_eval { 11 } + @ivar = 12 + assert_equal 12, c.module_eval { @ivar } + assert_equal 13, c.module_eval { @@cvar } + assert_equal 14, c.module_eval { $gvar__eval } + assert_equal 15, c.module_eval { Const } + assert_equal 16, c.module_eval { 7 + 9 } + assert_equal 17, c.module_eval { "17".to_i } + assert_equal "18", c.module_eval { "18" } + assert_equal "19", c.module_eval { "1#{9}" } + + @ivar = 12 + 1.times { + assert_equal 12, c.module_eval { @ivar } + assert_equal 13, c.module_eval { @@cvar } + assert_equal 14, c.module_eval { $gvar__eval } + assert_equal 15, c.module_eval { Const } + } + end + + def forall_TYPE + objects = [Object.new, [], nil, true, false] # TODO: check + objects.each do |obj| + obj.instance_variable_set :@ivar, 12 unless obj.frozen? + yield obj + end + end + + def test_instance_eval_string_basic + forall_TYPE do |o| + assert_equal nil, o.instance_eval("nil") + assert_equal true, o.instance_eval("true") + assert_equal false, o.instance_eval("false") + assert_equal o, o.instance_eval("self") + assert_equal 1, o.instance_eval("1") + assert_equal :sym, o.instance_eval(":sym") + + assert_equal 11, o.instance_eval("11") + assert_equal 12, o.instance_eval("@ivar") unless o.frozen? + assert_equal 13, o.instance_eval("@@cvar") + assert_equal 14, o.instance_eval("$gvar__eval") + assert_equal 15, o.instance_eval("Const") + assert_equal 16, o.instance_eval("7 + 9") + assert_equal 17, o.instance_eval("17.to_i") + assert_equal "18", o.instance_eval(%q("18")) + assert_equal "19", o.instance_eval(%q("1#{9}")) + + 1.times { + assert_equal 12, o.instance_eval("@ivar") unless o.frozen? + assert_equal 13, o.instance_eval("@@cvar") + assert_equal 14, o.instance_eval("$gvar__eval") + assert_equal 15, o.instance_eval("Const") + } + end + end + + def test_instance_eval_block_basic + forall_TYPE do |o| + assert_equal nil, o.instance_eval { nil } + assert_equal true, o.instance_eval { true } + assert_equal false, o.instance_eval { false } + assert_equal o, o.instance_eval { self } + assert_equal 1, o.instance_eval { 1 } + assert_equal :sym, o.instance_eval { :sym } + + assert_equal 11, o.instance_eval { 11 } + assert_equal 12, o.instance_eval { @ivar } unless o.frozen? + assert_equal 13, o.instance_eval { @@cvar } + assert_equal 14, o.instance_eval { $gvar__eval } + assert_equal 15, o.instance_eval { Const } + assert_equal 16, o.instance_eval { 7 + 9 } + assert_equal 17, o.instance_eval { 17.to_i } + assert_equal "18", o.instance_eval { "18" } + assert_equal "19", o.instance_eval { "1#{9}" } + + 1.times { + assert_equal 12, o.instance_eval { @ivar } unless o.frozen? + assert_equal 13, o.instance_eval { @@cvar } + assert_equal 14, o.instance_eval { $gvar__eval } + assert_equal 15, o.instance_eval { Const } + } + end + end + + def test_instance_eval_block_self + # instance_eval(&block)'s self must not be sticky (jruby/jruby#2060) + pr = proc { self } + assert_equal self, pr.call + o = Object.new + assert_equal o, o.instance_eval(&pr) + assert_equal self, pr.call + end + + def test_instance_eval_cvar + [Object.new, [], 7, :sym, true, false, nil].each do |obj| + assert_equal(13, obj.instance_eval("@@cvar")) + assert_equal(13, obj.instance_eval{@@cvar}) + # assert_raise(NameError){obj.instance_eval("@@cvar")} + # assert_raise(NameError){obj.instance_eval{@@cvar}} + end + end + + def test_instance_eval_method + bug2788 = '[ruby-core:28324]' + [Object.new, [], nil, true, false].each do |o| + assert_nothing_raised(TypeError, "#{bug2788} (#{o.inspect})") do + o.instance_eval { + def defd_using_instance_eval() :ok end + } + end + assert_equal(:ok, o.defd_using_instance_eval) + class << o + remove_method :defd_using_instance_eval + end + end + end + + def test_instance_eval_on_argf_singleton_class + bug8188 = '[ruby-core:53839] [Bug #8188]' + assert_warning('', bug8188) do + ARGF.singleton_class.instance_eval{} + end + end + + class Foo + Bar = 2 + end + + def test_instance_eval_const + bar = nil + assert_nothing_raised(NameError) do + bar = Foo.new.instance_eval("Bar") + end + assert_equal(2, bar) + end + + # + # From ruby/test/ruby/test_eval.rb + # + + def make_test_binding + local1 = "local1" + lambda { + local2 = "local2" + return binding + }.call + end + + def test_eval_orig + assert_nil(eval("")) + bad=false + eval 'while false; bad = true; print "foo\n" end' + assert(!bad) + + assert(eval('TRUE')) + assert(eval('true')) + assert(!eval('NIL')) + assert(!eval('nil')) + assert(!eval('FALSE')) + assert(!eval('false')) + + $foo = 'assert(true)' + begin + eval $foo + rescue + assert(false) + end + + assert_equal('assert(true)', eval("$foo")) + assert_equal(true, eval("true")) + i = 5 + assert(eval("i == 5")) + assert_equal(5, eval("i")) + assert(eval("defined? i")) + + x = make_test_binding + assert_equal("local1", eval("local1", x)) # normal local var + assert_equal("local2", eval("local2", x)) # nested local var + bad = true + begin + p eval("local1") + rescue NameError # must raise error + bad = false + end + assert(!bad) + + # !! use class_eval to avoid nested definition + x = self.class.class_eval %q( + module EvTest + EVTEST1 = 25 + evtest2 = 125 + binding + end + ) + assert_equal(25, eval("EVTEST1", x)) # constant in module + assert_equal(125, eval("evtest2", x)) # local var in module + bad = true + begin + eval("EVTEST1") + rescue NameError # must raise error + bad = false + end + assert(!bad) + + if false + # Ruby 2.0 doesn't see Proc as Binding + x = proc{} + eval "i4 = 1", x + assert_equal(1, eval("i4", x)) + x = proc{proc{}}.call + eval "i4 = 22", x + assert_equal(22, eval("i4", x)) + t = [] + x = proc{proc{}}.call + eval "(0..9).each{|i5| t[i5] = proc{i5*2}}", x + assert_equal(8, t[4].call) + end + + x = binding + eval "i = 1", x + assert_equal(1, eval("i", x)) + x = proc{binding}.call + eval "i = 22", x + assert_equal(22, eval("i", x)) + t = [] + x = proc{binding}.call + eval "(0..9).each{|i5| t[i5] = proc{i5*2}}", x + assert_equal(8, t[4].call) + x = proc{binding}.call + eval "for i6 in 1..1; j6=i6; end", x + assert(eval("defined? i6", x)) + assert(eval("defined? j6", x)) + + proc { + p = binding + eval "foo11 = 1", p + foo22 = 5 + proc{foo11=22}.call + proc{foo22=55}.call + # assert_equal(eval("foo11"), eval("foo11", p)) + # assert_equal(1, eval("foo11")) + assert_equal(eval("foo22"), eval("foo22", p)) + assert_equal(55, eval("foo22")) + }.call + + if false + # Ruby 2.0 doesn't see Proc as Binding + p1 = proc{i7 = 0; proc{i7}}.call + assert_equal(0, p1.call) + eval "i7=5", p1 + assert_equal(5, p1.call) + assert(!defined?(i7)) + end + + if false + # Ruby 2.0 doesn't see Proc as Binding + p1 = proc{i7 = 0; proc{i7}}.call + i7 = nil + assert_equal(0, p1.call) + eval "i7=1", p1 + assert_equal(1, p1.call) + eval "i7=5", p1 + assert_equal(5, p1.call) + assert_nil(i7) + end + end + + def test_nil_instance_eval_cvar + def nil.test_binding + binding + end + bb = eval("nil.instance_eval \"binding\"", nil.test_binding) + assert_raise(NameError, "[ruby-dev:24103]") { eval("@@a", bb) } + class << nil + remove_method :test_binding + end + end + + def test_fixnum_instance_eval_cvar + assert_raise(NameError, "[ruby-dev:24213]") { 1.instance_eval "@@a" } + end + + def test_cvar_scope_with_instance_eval + # TODO: check + Fixnum.class_eval "@@test_cvar_scope_with_instance_eval = 1" # depends on [ruby-dev:24229] + @@test_cvar_scope_with_instance_eval = 4 + assert_equal(4, 1.instance_eval("@@test_cvar_scope_with_instance_eval"), "[ruby-dev:24223]") + Fixnum.__send__(:remove_class_variable, :@@test_cvar_scope_with_instance_eval) + end + + def test_eval_and_define_method + assert_nothing_raised("[ruby-dev:24228]") { + def temporally_method_for_test_eval_and_define_method(&block) + lambda { + class << Object.new; self end.send(:define_method, :zzz, &block) + } + end + v = eval("temporally_method_for_test_eval_and_define_method {}") + {}[0] = {} + v.call + } + end + + def test_define_method_block + cc = Class.new do + define_method(:foo) {|&block| + block.call if block + } + end + + c = cc.new + x = "ng" + c.foo() {x = "ok"} + assert_equal("ok", x) + end + + def test_define_method_toplevel + feature6609 = '[ruby-core:45715]' + main = eval("self", TOPLEVEL_BINDING) + assert_nothing_raised(NoMethodError, feature6609) do + main.instance_eval do + define_method("feature6609_block") {feature6609} + end + end + assert_equal(feature6609, feature6609_block) + + assert_nothing_raised(NoMethodError, feature6609) do + main.instance_eval do + define_method("feature6609_method", Object.instance_method(:feature6609_block)) + end + end + assert_equal(feature6609, feature6609_method) + end + + def test_eval_using_integer_as_binding + assert_raise(TypeError) { eval("", 1) } + end + + def test_eval_raise + assert_raise(RuntimeError) { eval("raise ''") } + end + + def test_eval_with_toplevel_binding # [ruby-dev:37142] + ruby("-e", "x = 0; eval('p x', TOPLEVEL_BINDING)") do |f| + f.close_write + assert_equal("0", f.read.chomp) + end + end + + def test_eval_ascii_incompatible + assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-16be"))} + assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-16le"))} + assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-32be"))} + assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-32le"))} + end + + def test_instance_eval_method_proc + bug3860 = Class.new do + def initialize(a); + @a=a + end + def get(*args) + @a + end + end + foo = bug3860.new 1 + foo_pr = foo.method(:get).to_proc + result = foo.instance_eval(&foo_pr) + assert_equal(1, result, 'Bug #3786, Bug #3860, [ruby-core:32501]') + end + + def test_file_encoding + fname = "\u{3042}".encode("euc-jp") + assert_equal(fname, eval("__FILE__", nil, fname, 1)) + end + + def test_eval_location_fstring + o = Object.new + o.instance_eval "def foo() end", "generated code" + o.instance_eval "def bar() end", "generated code" + + a, b = o.method(:foo).source_location[0], + o.method(:bar).source_location[0] + + assert_same a, b + end + + def test_gced_binding_block + assert_normal_exit %q{ + def m + binding + end + GC.stress = true + b = nil + tap do + b = m {} + end + 0.times.to_a + b.eval('yield') + }, '[Bug #10368]' + end +end diff --git a/jni/ruby/test/ruby/test_exception.rb b/jni/ruby/test/ruby/test_exception.rb new file mode 100644 index 0000000..c68d226 --- /dev/null +++ b/jni/ruby/test/ruby/test_exception.rb @@ -0,0 +1,701 @@ +require 'test/unit' +require 'tempfile' + +class TestException < Test::Unit::TestCase + def test_exception_rescued + begin + raise "this must be handled" + assert(false) + rescue + assert(true) + end + end + + def test_exception_retry + bad = true + begin + raise "this must be handled no.2" + rescue + if bad + bad = false + retry + assert(false) + end + end + assert(true) + end + + def test_exception_in_rescue + string = "this must be handled no.3" + assert_raise_with_message(RuntimeError, string) do + begin + raise "exception in rescue clause" + rescue + raise string + end + assert(false) + end + end + + def test_exception_in_ensure + string = "exception in ensure clause" + assert_raise_with_message(RuntimeError, string) do + begin + raise "this must be handled no.4" + ensure + assert_instance_of(RuntimeError, $!) + assert_equal("this must be handled no.4", $!.message) + raise "exception in ensure clause" + end + assert(false) + end + end + + def test_exception_ensure + bad = true + begin + begin + raise "this must be handled no.5" + ensure + bad = false + end + rescue + end + assert(!bad) + end + + def test_exception_ensure_2 # just duplication? + bad = true + begin + begin + raise "this must be handled no.6" + ensure + bad = false + end + rescue + end + assert(!bad) + end + + def test_errinfo_in_debug + bug9568 = EnvUtil.labeled_class("[ruby-core:61091] [Bug #9568]", RuntimeError) do + def to_s + require '\0' + rescue LoadError + self.class.to_s + end + end + + err = EnvUtil.verbose_warning do + assert_raise(bug9568) do + $DEBUG, debug = true, $DEBUG + begin + raise bug9568 + ensure + $DEBUG = debug + end + end + end + assert_include(err, bug9568.to_s) + end + + def test_errinfo_encoding_in_debug + exc = Module.new {break class_eval("class C\u{30a8 30e9 30fc} < RuntimeError; self; end".encode(Encoding::EUC_JP))} + exc.inspect + + err = EnvUtil.verbose_warning do + assert_raise(exc) do + $DEBUG, debug = true, $DEBUG + begin + raise exc + ensure + $DEBUG = debug + end + end + end + assert_include(err, exc.to_s) + end + + def test_break_ensure + bad = true + while true + begin + break + ensure + bad = false + end + end + assert(!bad) + end + + def test_catch_no_throw + assert_equal(:foo, catch {:foo}) + end + + def test_catch_throw + result = catch(:foo) { + loop do + loop do + throw :foo, true + break + end + assert(false, "should not reach here") + end + false + } + assert(result) + end + + def test_catch_throw_noarg + assert_nothing_raised(UncaughtThrowError) { + result = catch {|obj| + throw obj, :ok + assert(false, "should not reach here") + } + assert_equal(:ok, result) + } + end + + def test_uncaught_throw + tag = nil + e = assert_raise_with_message(UncaughtThrowError, /uncaught throw/) { + catch("foo") {|obj| + tag = obj.dup + throw tag, :ok + assert(false, "should not reach here") + } + assert(false, "should not reach here") + } + assert_not_nil(tag) + assert_same(tag, e.tag) + assert_equal(:ok, e.value) + end + + def test_catch_throw_in_require + bug7185 = '[ruby-dev:46234]' + Tempfile.create(["dep", ".rb"]) {|t| + t.puts("throw :extdep, 42") + t.close + assert_equal(42, assert_throw(:extdep, bug7185) {require t.path}, bug7185) + } + end + + def test_else_no_exception + begin + assert(true) + rescue + assert(false) + else + assert(true) + end + end + + def test_else_raised + begin + assert(true) + raise + assert(false) + rescue + assert(true) + else + assert(false) + end + end + + def test_else_nested_no_exception + begin + assert(true) + begin + assert(true) + rescue + assert(false) + else + assert(true) + end + assert(true) + rescue + assert(false) + else + assert(true) + end + end + + def test_else_nested_rescued + begin + assert(true) + begin + assert(true) + raise + assert(false) + rescue + assert(true) + else + assert(false) + end + assert(true) + rescue + assert(false) + else + assert(true) + end + end + + def test_else_nested_unrescued + begin + assert(true) + begin + assert(true) + rescue + assert(false) + else + assert(true) + end + assert(true) + raise + assert(false) + rescue + assert(true) + else + assert(false) + end + end + + def test_else_nested_rescued_reraise + begin + assert(true) + begin + assert(true) + raise + assert(false) + rescue + assert(true) + else + assert(false) + end + assert(true) + raise + assert(false) + rescue + assert(true) + else + assert(false) + end + end + + def test_raise_with_wrong_number_of_arguments + assert_raise(TypeError) { raise nil } + assert_raise(TypeError) { raise 1, 1 } + assert_raise(ArgumentError) { raise 1, 1, 1, 1 } + end + + def test_type_error_message_encoding + c = eval("Module.new do break class C\u{4032}; self; end; end") + o = c.new + assert_raise_with_message(TypeError, /C\u{4032}/) do + ""[o] + end + c.class_eval {def to_int; self; end} + assert_raise_with_message(TypeError, /C\u{4032}/) do + ""[o] + end + c.class_eval {def to_a; self; end} + assert_raise_with_message(TypeError, /C\u{4032}/) do + [*o] + end + end + + def test_errat + assert_in_out_err([], "p $@", %w(nil), []) + + assert_in_out_err([], "$@ = 1", [], /\$! not set \(ArgumentError\)$/) + + assert_in_out_err([], <<-INPUT, [], /backtrace must be Array of String \(TypeError\)$/) + begin + raise + rescue + $@ = 1 + end + INPUT + + assert_in_out_err([], <<-INPUT, [], /^foo: unhandled exception$/) + begin + raise + rescue + $@ = 'foo' + raise + end + INPUT + + assert_in_out_err([], <<-INPUT, [], /^foo: unhandled exception\s+from bar\s+from baz$/) + begin + raise + rescue + $@ = %w(foo bar baz) + raise + end + INPUT + end + + def test_thread_signal_location + _, stderr, _ = EnvUtil.invoke_ruby("--disable-gems -d", <<-RUBY, false, true) +Thread.start do + begin + Process.kill(:INT, $$) + ensure + raise "in ensure" + end +end.join + RUBY + assert_not_match(/:0/, stderr, "[ruby-dev:39116]") + end + + def test_errinfo + begin + raise "foo" + assert(false) + rescue => e + assert_equal(e, $!) + 1.times { assert_equal(e, $!) } + end + + assert_equal(nil, $!) + end + + def test_inspect + assert_equal("#<Exception: Exception>", Exception.new.inspect) + + e = Class.new(Exception) + e.class_eval do + def to_s; ""; end + end + assert_equal(e.inspect, e.new.inspect) + end + + def test_to_s + e = StandardError.new("foo") + assert_equal("foo", e.to_s) + + def (s = Object.new).to_s + "bar" + end + e = StandardError.new(s) + assert_equal("bar", e.to_s) + end + + def test_set_backtrace + e = Exception.new + + e.set_backtrace("foo") + assert_equal(["foo"], e.backtrace) + + e.set_backtrace(%w(foo bar baz)) + assert_equal(%w(foo bar baz), e.backtrace) + + assert_raise(TypeError) { e.set_backtrace(1) } + assert_raise(TypeError) { e.set_backtrace([1]) } + end + + def test_exit_success_p + begin + exit + rescue SystemExit => e + end + assert_send([e, :success?], "success by default") + + begin + exit(true) + rescue SystemExit => e + end + assert_send([e, :success?], "true means success") + + begin + exit(false) + rescue SystemExit => e + end + assert_not_send([e, :success?], "false means failure") + + begin + abort + rescue SystemExit => e + end + assert_not_send([e, :success?], "abort means failure") + end + + def test_nomethoderror + bug3237 = '[ruby-core:29948]' + str = "\u2600" + id = :"\u2604" + msg = "undefined method `#{id}' for #{str.inspect}:String" + assert_raise_with_message(NoMethodError, msg, bug3237) do + str.__send__(id) + end + end + + def test_errno + assert_equal(Encoding.find("locale"), Errno::EINVAL.new.message.encoding) + end + + def test_too_many_args_in_eval + bug5720 = '[ruby-core:41520]' + arg_string = (0...140000).to_a.join(", ") + assert_raise(SystemStackError, bug5720) {eval "raise(#{arg_string})"} + end + + def test_systemexit_new + e0 = SystemExit.new + assert_equal(0, e0.status) + assert_equal("SystemExit", e0.message) + ei = SystemExit.new(3) + assert_equal(3, ei.status) + assert_equal("SystemExit", ei.message) + es = SystemExit.new("msg") + assert_equal(0, es.status) + assert_equal("msg", es.message) + eis = SystemExit.new(7, "msg") + assert_equal(7, eis.status) + assert_equal("msg", eis.message) + + bug5728 = '[ruby-dev:44951]' + et = SystemExit.new(true) + assert_equal(true, et.success?, bug5728) + assert_equal("SystemExit", et.message, bug5728) + ef = SystemExit.new(false) + assert_equal(false, ef.success?, bug5728) + assert_equal("SystemExit", ef.message, bug5728) + ets = SystemExit.new(true, "msg") + assert_equal(true, ets.success?, bug5728) + assert_equal("msg", ets.message, bug5728) + efs = SystemExit.new(false, "msg") + assert_equal(false, efs.success?, bug5728) + assert_equal("msg", efs.message, bug5728) + end + + def test_exception_in_name_error_to_str + bug5575 = '[ruby-core:41612]' + Tempfile.create(["test_exception_in_name_error_to_str", ".rb"]) do |t| + t.puts <<-EOC + begin + BasicObject.new.inspect + rescue + $!.inspect + end + EOC + t.close + assert_nothing_raised(NameError, bug5575) do + load(t.path) + end + end + end + + def test_equal + bug5865 = '[ruby-core:41979]' + assert_equal(RuntimeError.new("a"), RuntimeError.new("a"), bug5865) + assert_not_equal(RuntimeError.new("a"), StandardError.new("a"), bug5865) + end + + def test_exception_in_exception_equal + bug5865 = '[ruby-core:41979]' + Tempfile.create(["test_exception_in_exception_equal", ".rb"]) do |t| + t.puts <<-EOC + o = Object.new + def o.exception(arg) + end + _ = RuntimeError.new("a") == o + EOC + t.close + assert_nothing_raised(ArgumentError, bug5865) do + load(t.path) + end + end + end + + Bug4438 = '[ruby-core:35364]' + + def test_rescue_single_argument + assert_raise(TypeError, Bug4438) do + begin + raise + rescue 1 + end + end + end + + def test_rescue_splat_argument + assert_raise(TypeError, Bug4438) do + begin + raise + rescue *Array(1) + end + end + end + + def test_to_s_taintness_propagation + for exc in [Exception, NameError] + m = "abcdefg" + e = exc.new(m) + e.taint + s = e.to_s + assert_equal(false, m.tainted?, + "#{exc}#to_s should not propagate taintness") + assert_equal(false, s.tainted?, + "#{exc}#to_s should not propagate taintness") + end + + o = Object.new + def o.to_str + "foo" + end + o.taint + e = NameError.new(o) + s = e.to_s + assert_equal(false, s.tainted?) + end + + def m + m(&->{return 0}) + 42 + end + + def test_stackoverflow + feature6216 = '[ruby-core:43794] [Feature #6216]' + e = assert_raise(SystemStackError, feature6216) {m} + level = e.backtrace.size + assert_operator(level, :>, 10, feature6216) + + feature6216 = '[ruby-core:63377] [Feature #6216]' + e = assert_raise(SystemStackError, feature6216) {raise e} + assert_equal(level, e.backtrace.size, feature6216) + end + + def test_machine_stackoverflow + bug9109 = '[ruby-dev:47804] [Bug #9109]' + assert_separately(%w[--disable-gem], <<-SRC) + assert_raise(SystemStackError, #{bug9109.dump}) { + h = {a: ->{h[:a].call}} + h[:a].call + } + SRC + rescue SystemStackError + end + + def test_machine_stackoverflow_by_define_method + bug9454 = '[ruby-core:60113] [Bug #9454]' + assert_separately(%w[--disable-gem], <<-SRC) + assert_raise(SystemStackError, #{bug9454.dump}) { + define_method(:foo) {self.foo} + self.foo + } + SRC + rescue SystemStackError + end + + def test_cause + msg = "[Feature #8257]" + cause = nil + e = assert_raise(StandardError) { + begin + raise msg + rescue => e + cause = e.cause + raise StandardError + end + } + assert_nil(cause, msg) + cause = e.cause + assert_instance_of(RuntimeError, cause, msg) + assert_equal(msg, cause.message, msg) + end + + def test_cause_reraised + msg = "[Feature #8257]" + e = assert_raise(RuntimeError) { + begin + raise msg + rescue => e + raise e + end + } + assert_not_same(e, e.cause, "#{msg}: should not be recursive") + end + + def test_raise_with_cause + msg = "[Feature #8257]" + cause = ArgumentError.new("foobar") + e = assert_raise(RuntimeError) {raise msg, cause: cause} + assert_same(cause, e.cause) + end + + def test_cause_with_no_arguments + cause = ArgumentError.new("foobar") + assert_raise_with_message(ArgumentError, /with no arguments/) do + raise cause: cause + end + end + + def test_unknown_option + bug = '[ruby-core:63203] [Feature #8257] should pass unknown options' + + exc = Class.new(RuntimeError) do + attr_reader :arg + def initialize(msg = nil) + @arg = msg + super(msg) + end + end + + e = assert_raise(exc, bug) {raise exc, "foo" => "bar", foo: "bar"} + assert_equal({"foo" => "bar", foo: "bar"}, e.arg, bug) + + e = assert_raise(exc, bug) {raise exc, "foo" => "bar", foo: "bar", cause: "zzz"} + assert_equal({"foo" => "bar", foo: "bar"}, e.arg, bug) + + e = assert_raise(exc, bug) {raise exc, {}} + assert_equal({}, e.arg, bug) + end + + def test_anonymous_message + assert_in_out_err([], "raise Class.new(RuntimeError), 'foo'", [], /foo\n/) + end + + def test_name_error_info + obj = BasicObject.new + e = assert_raise(NameError) { + obj.instance_eval("Object") + } + assert_equal(:Object, e.name) + e = assert_raise(NameError) { + obj.instance_eval {foo} + } + assert_equal(:foo, e.name) + e = assert_raise(NoMethodError) { + obj.foo(1, 2) + } + assert_equal(:foo, e.name) + assert_equal([1, 2], e.args) + end + + def test_output_string_encoding + # "\x82\xa0" in cp932 is "\u3042" (Japanese hiragana 'a') + # change $stderr to force calling rb_io_write() instead of fwrite() + assert_in_out_err(["-Eutf-8:cp932"], '# coding: cp932 +$stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| + assert_equal 1, outs.size + assert_equal 0, errs.size + err = outs.first.force_encoding('utf-8') + assert err.valid_encoding?, 'must be valid encoding' + assert_match /\u3042/, err + end + end + + def test_multibyte_and_newline + bug10727 = '[ruby-core:67473] [Bug #10727]' + assert_in_out_err([], <<-'end;', [], /\u{306b 307b 3093 3054} \(E\)\n\u{6539 884c}/, bug10727, encoding: "UTF-8") + class E < StandardError + def initialize + super("\u{306b 307b 3093 3054}\n\u{6539 884c}") + end + end + raise E + end; + end +end diff --git a/jni/ruby/test/ruby/test_fiber.rb b/jni/ruby/test/ruby/test_fiber.rb new file mode 100644 index 0000000..4684a65 --- /dev/null +++ b/jni/ruby/test/ruby/test_fiber.rb @@ -0,0 +1,347 @@ +require 'test/unit' +require 'fiber' +EnvUtil.suppress_warning {require 'continuation'} +require 'tmpdir' + +class TestFiber < Test::Unit::TestCase + def test_normal + assert_equal(:ok2, + Fiber.new{|e| + assert_equal(:ok1, e) + Fiber.yield :ok2 + }.resume(:ok1) + ) + assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.resume(:a, :b)) + end + + def test_argument + assert_equal(4, Fiber.new {|i=4| i}.resume) + end + + def test_term + assert_equal(:ok, Fiber.new{:ok}.resume) + assert_equal([:a, :b, :c, :d, :e], + Fiber.new{ + Fiber.new{ + Fiber.new{ + Fiber.new{ + [:a] + }.resume + [:b] + }.resume + [:c] + }.resume + [:d] + }.resume + [:e]) + end + + def test_many_fibers + max = 10_000 + assert_equal(max, max.times{ + Fiber.new{} + }) + GC.start # force collect created fibers + assert_equal(max, + max.times{|i| + Fiber.new{ + }.resume + } + ) + GC.start # force collect created fibers + end + + def test_many_fibers_with_threads + assert_normal_exit <<-SRC, timeout: 60 + max = 1000 + @cnt = 0 + (1..100).map{|ti| + Thread.new{ + max.times{|i| + Fiber.new{ + @cnt += 1 + }.resume + } + } + }.each{|t| + t.join + } + SRC + end + + def test_error + assert_raise(ArgumentError){ + Fiber.new # Fiber without block + } + assert_raise(FiberError){ + f = Fiber.new{} + Thread.new{f.resume}.join # Fiber yielding across thread + } + assert_raise(FiberError){ + f = Fiber.new{} + f.resume + f.resume + } + assert_raise(RuntimeError){ + Fiber.new{ + @c = callcc{|c| @c = c} + }.resume + @c.call # cross fiber callcc + } + assert_raise(RuntimeError){ + Fiber.new{ + raise + }.resume + } + assert_raise(FiberError){ + Fiber.yield + } + assert_raise(FiberError){ + fib = Fiber.new{ + fib.resume + } + fib.resume + } + assert_raise(FiberError){ + fib = Fiber.new{ + Fiber.new{ + fib.resume + }.resume + } + fib.resume + } + end + + def test_return + assert_raise(LocalJumpError){ + Fiber.new do + return + end.resume + } + end + + def test_throw + assert_raise(UncaughtThrowError){ + Fiber.new do + throw :a + end.resume + } + end + + def test_transfer + ary = [] + f2 = nil + f1 = Fiber.new{ + ary << f2.transfer(:foo) + :ok + } + f2 = Fiber.new{ + ary << f1.transfer(:baz) + :ng + } + assert_equal(:ok, f1.transfer) + assert_equal([:baz], ary) + end + + def test_tls + # + def tvar(var, val) + old = Thread.current[var] + begin + Thread.current[var] = val + yield + ensure + Thread.current[var] = old + end + end + + fb = Fiber.new { + assert_equal(nil, Thread.current[:v]); tvar(:v, :x) { + assert_equal(:x, Thread.current[:v]); Fiber.yield + assert_equal(:x, Thread.current[:v]); } + assert_equal(nil, Thread.current[:v]); Fiber.yield + raise # unreachable + } + + assert_equal(nil, Thread.current[:v]); tvar(:v,1) { + assert_equal(1, Thread.current[:v]); tvar(:v,3) { + assert_equal(3, Thread.current[:v]); fb.resume + assert_equal(3, Thread.current[:v]); } + assert_equal(1, Thread.current[:v]); } + assert_equal(nil, Thread.current[:v]); fb.resume + assert_equal(nil, Thread.current[:v]); + end + + def test_alive + fib = Fiber.new{Fiber.yield} + assert_equal(true, fib.alive?) + fib.resume + assert_equal(true, fib.alive?) + fib.resume + assert_equal(false, fib.alive?) + end + + def test_resume_self + f = Fiber.new {f.resume} + assert_raise(FiberError, '[ruby-core:23651]') {f.transfer} + end + + def test_fiber_transfer_segv + assert_normal_exit %q{ + require 'fiber' + f2 = nil + f1 = Fiber.new{ f2.resume } + f2 = Fiber.new{ f1.resume } + f1.transfer + }, '[ruby-dev:40833]' + assert_normal_exit %q{ + require 'fiber' + Fiber.new{}.resume + 1.times{Fiber.current.transfer} + } + end + + def test_resume_root_fiber + assert_raise(FiberError) do + Thread.new do + Fiber.current.resume + end.join + end + end + + def test_gc_root_fiber + bug4612 = '[ruby-core:35891]' + + assert_normal_exit %q{ + require 'fiber' + GC.stress = true + Thread.start{ Fiber.current; nil }.join + GC.start + }, bug4612 + end + + def test_no_valid_cfp + bug5083 = '[ruby-dev:44208]' + assert_equal([], Fiber.new(&Module.method(:nesting)).resume, bug5083) + assert_instance_of(Class, Fiber.new(&Class.new.method(:undef_method)).resume(:to_s), bug5083) + end + + def test_prohibit_resume_transfered_fiber + assert_raise(FiberError){ + root_fiber = Fiber.current + f = Fiber.new{ + root_fiber.transfer + } + f.transfer + f.resume + } + assert_raise(FiberError){ + g=nil + f=Fiber.new{ + g.resume + g.resume + } + g=Fiber.new{ + f.resume + f.resume + } + f.transfer + } + end + + def test_fork_from_fiber + begin + pid = Process.fork{} + rescue NotImplementedError + return + else + Process.wait(pid) + end + bug5700 = '[ruby-core:41456]' + assert_nothing_raised(bug5700) do + Fiber.new{ pid = fork {} }.resume + end + pid, status = Process.waitpid2(pid) + assert_equal(0, status.exitstatus, bug5700) + assert_equal(false, status.signaled?, bug5700) + end + + def test_exit_in_fiber + bug5993 = '[ruby-dev:45218]' + assert_nothing_raised(bug5993) do + Thread.new{ Fiber.new{ Thread.exit }.resume; raise "unreachable" }.join + end + end + + def test_fatal_in_fiber + assert_in_out_err(["-r-test-/fatal/rb_fatal", "-e", <<-EOS], "", [], /ok/) + Fiber.new{ + rb_fatal "ok" + }.resume + puts :ng # unreachable. + EOS + end + + def invoke_rec script, vm_stack_size, machine_stack_size, use_length = true + env = {} + env['RUBY_FIBER_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size + env['RUBY_FIBER_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size + out, _ = Dir.mktmpdir("test_fiber") {|tmpdir| + EnvUtil.invoke_ruby([env, '-e', script], '', true, true, chdir: tmpdir) + } + use_length ? out.length : out + end + + def test_stack_size + h_default = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', nil, nil, false)) + h_0 = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 0, 0, false)) + h_large = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 1024 * 1024 * 10, 1024 * 1024 * 10, false)) + + assert_operator(h_default[:fiber_vm_stack_size], :>, h_0[:fiber_vm_stack_size]) + assert_operator(h_default[:fiber_vm_stack_size], :<, h_large[:fiber_vm_stack_size]) + assert_operator(h_default[:fiber_machine_stack_size], :>=, h_0[:fiber_machine_stack_size]) + assert_operator(h_default[:fiber_machine_stack_size], :<=, h_large[:fiber_machine_stack_size]) + + # check VM machine stack size + script = '$stdout.sync=true; def rec; print "."; rec; end; Fiber.new{rec}.resume' + size_default = invoke_rec script, nil, nil + assert_operator(size_default, :>, 0) + size_0 = invoke_rec script, 0, nil + assert_operator(size_default, :>, size_0) + size_large = invoke_rec script, 1024 * 1024 * 10, nil + assert_operator(size_default, :<, size_large) + + return if /mswin|mingw/ =~ RUBY_PLATFORM + + # check machine stack size + # Note that machine stack size may not change size (depend on OSs) + script = '$stdout.sync=true; def rec; print "."; 1.times{1.times{1.times{rec}}}; end; Fiber.new{rec}.resume' + vm_stack_size = 1024 * 1024 + size_default = invoke_rec script, vm_stack_size, nil + size_0 = invoke_rec script, vm_stack_size, 0 + assert_operator(size_default, :>=, size_0) + size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10 + assert_operator(size_default, :<=, size_large) + end + + def test_separate_lastmatch + bug7678 = '[ruby-core:51331]' + /a/ =~ "a" + m1 = $~ + m2 = nil + Fiber.new do + /b/ =~ "b" + m2 = $~ + end.resume + assert_equal("b", m2[0]) + assert_equal(m1, $~, bug7678) + end + + def test_separate_lastline + bug7678 = '[ruby-core:51331]' + $_ = s1 = "outer" + s2 = nil + Fiber.new do + s2 = "inner" + end.resume + assert_equal("inner", s2) + assert_equal(s1, $_, bug7678) + end +end + diff --git a/jni/ruby/test/ruby/test_file.rb b/jni/ruby/test/ruby/test_file.rb new file mode 100644 index 0000000..601d19e --- /dev/null +++ b/jni/ruby/test/ruby/test_file.rb @@ -0,0 +1,423 @@ +require 'test/unit' +require 'tempfile' +require "thread" +require_relative 'ut_eof' + +class TestFile < Test::Unit::TestCase + + # I don't know Ruby's spec about "unlink-before-close" exactly. + # This test asserts current behaviour. + def test_unlink_before_close + Dir.mktmpdir('rubytest-file') {|tmpdir| + filename = tmpdir + '/' + File.basename(__FILE__) + ".#{$$}" + w = File.open(filename, "w") + w << "foo" + w.close + r = File.open(filename, "r") + begin + if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM + assert_raise(Errno::EACCES) {File.unlink(filename)} + else + assert_nothing_raised {File.unlink(filename)} + end + ensure + r.close + File.unlink(filename) if File.exist?(filename) + end + } + end + + include TestEOF + def open_file(content) + Tempfile.create("test-eof") {|f| + f << content + f.rewind + yield f + } + end + alias open_file_rw open_file + + include TestEOF::Seek + + def test_empty_file_bom + bug6487 = '[ruby-core:45203]' + Tempfile.create(__method__.to_s) {|f| + assert_file.exist?(f.path) + assert_nothing_raised(bug6487) {File.read(f.path, mode: 'r:utf-8')} + assert_nothing_raised(bug6487) {File.read(f.path, mode: 'r:bom|utf-8')} + } + end + + def assert_bom(bytes, name) + bug6487 = '[ruby-core:45203]' + + Tempfile.create(name.to_s) {|f| + f.sync = true + expected = "" + result = nil + bytes[0...-1].each do |x| + f.write x + f.write ' ' + f.pos -= 1 + expected << x + assert_nothing_raised(bug6487) {result = File.read(f.path, mode: 'rb:bom|utf-8')} + assert_equal("#{expected} ".force_encoding("utf-8"), result) + end + f.write bytes[-1] + assert_nothing_raised(bug6487) {result = File.read(f.path, mode: 'rb:bom|utf-8')} + assert_equal '', result, "valid bom" + } + end + + def test_bom_8 + assert_bom(["\xEF", "\xBB", "\xBF"], __method__) + end + + def test_bom_16be + assert_bom(["\xFE", "\xFF"], __method__) + end + + def test_bom_16le + assert_bom(["\xFF", "\xFE"], __method__) + end + + def test_bom_32be + assert_bom(["\0", "\0", "\xFE", "\xFF"], __method__) + end + + def test_bom_32le + assert_bom(["\xFF\xFE\0", "\0"], __method__) + end + + def test_truncate_wbuf + Tempfile.create("test-truncate") {|f| + f.print "abc" + f.truncate(0) + f.print "def" + f.flush + assert_equal("\0\0\0def", File.read(f.path), "[ruby-dev:24191]") + } + end + + def test_truncate_rbuf + Tempfile.create("test-truncate") {|f| + f.puts "abc" + f.puts "def" + f.rewind + assert_equal("abc\n", f.gets) + f.truncate(3) + assert_equal(nil, f.gets, "[ruby-dev:24197]") + } + end + + def test_truncate_beyond_eof + Tempfile.create("test-truncate") {|f| + f.print "abc" + f.truncate 10 + assert_equal("\0" * 7, f.read(100), "[ruby-dev:24532]") + } + end + + def test_truncate_size + Tempfile.create("test-truncate") do |f| + q1 = Queue.new + q2 = Queue.new + + th = Thread.new do + data = '' + 64.times do |i| + data << i.to_s + f.rewind + f.print data + f.truncate(data.bytesize) + q1.push data.bytesize + q2.pop + end + q1.push nil + end + + while size = q1.pop + assert_equal size, File.size(f.path) + assert_equal size, f.size + q2.push true + end + th.join + end + end + + def test_read_all_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + assert_equal("a", f.read, "mode = <#{mode}>") + } + end + end + + def test_gets_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + assert_equal("a", f.gets("a"), "mode = <#{mode}>") + } + end + end + + def test_gets_para_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "\na" + f.rewind + assert_equal("a", f.gets(""), "mode = <#{mode}>") + } + end + end + + def test_each_char_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + result = [] + f.each_char {|b| result << b } + assert_equal([?a], result, "mode = <#{mode}>") + } + end + end + + def test_each_byte_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + result = [] + f.each_byte {|b| result << b.chr } + assert_equal([?a], result, "mode = <#{mode}>") + } + end + end + + def test_getc_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + assert_equal(?a, f.getc, "mode = <#{mode}>") + } + end + end + + def test_getbyte_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + Tempfile.create("test-extended-file", mode) {|f| + assert_nil(f.getc) + f.print "a" + f.rewind + assert_equal(?a, f.getbyte.chr, "mode = <#{mode}>") + } + end + end + + def test_s_chown + assert_nothing_raised { File.chown(-1, -1) } + assert_nothing_raised { File.chown nil, nil } + end + + def test_chown + assert_nothing_raised { + File.open(__FILE__) {|f| f.chown(-1, -1) } + } + assert_nothing_raised("[ruby-dev:27140]") { + File.open(__FILE__) {|f| f.chown nil, nil } + } + end + + def test_uninitialized + assert_raise(TypeError) { File::Stat.allocate.readable? } + assert_nothing_raised { File::Stat.allocate.inspect } + end + + def test_realpath + Dir.mktmpdir('rubytest-realpath') {|tmpdir| + realdir = File.realpath(tmpdir) + tst = realdir + (File::SEPARATOR*3 + ".") + assert_equal(realdir, File.realpath(tst)) + assert_equal(realdir, File.realpath(".", tst)) + if File::ALT_SEPARATOR + bug2961 = '[ruby-core:28653]' + assert_equal(realdir, File.realpath(realdir.tr(File::SEPARATOR, File::ALT_SEPARATOR)), bug2961) + end + } + end + + def test_realdirpath + Dir.mktmpdir('rubytest-realdirpath') {|tmpdir| + realdir = File.realpath(tmpdir) + tst = realdir + (File::SEPARATOR*3 + ".") + assert_equal(realdir, File.realdirpath(tst)) + assert_equal(realdir, File.realdirpath(".", tst)) + assert_equal(File.join(realdir, "foo"), File.realdirpath("foo", tst)) + } + begin + result = File.realdirpath("bar", "//:/foo") + rescue SystemCallError + else + if result.start_with?("//") + assert_equal("//:/foo/bar", result) + end + end + end + + def test_utime_with_minus_time_segv + bug5596 = '[ruby-dev:44838]' + assert_in_out_err([], <<-EOS, [bug5596], []) + require "tempfile" + t = Time.at(-1) + begin + Tempfile.create('test_utime_with_minus_time_segv') {|f| + File.utime(t, t, f) + } + rescue + end + puts '#{bug5596}' + EOS + end + + def test_utime + bug6385 = '[ruby-core:44776]' + + mod_time_contents = Time.at 1306527039 + + file = Tempfile.new("utime") + file.close + path = file.path + + File.utime(File.atime(path), mod_time_contents, path) + stats = File.stat(path) + + file.open + file_mtime = file.mtime + file.close(true) + + assert_equal(mod_time_contents, file_mtime, bug6385) + assert_equal(mod_time_contents, stats.mtime, bug6385) + end + + def test_stat + tb = Process.clock_gettime(Process::CLOCK_REALTIME) + Tempfile.create("stat") {|file| + tb = (tb + Process.clock_gettime(Process::CLOCK_REALTIME)) / 2 + file.close + path = file.path + + t0 = Process.clock_gettime(Process::CLOCK_REALTIME) + File.write(path, "foo") + sleep 2 + File.write(path, "bar") + sleep 2 + File.chmod(0644, path) + sleep 2 + File.read(path) + + delta = 1 + stat = File.stat(path) + assert_in_delta tb, stat.birthtime.to_f, delta + assert_in_delta t0+2, stat.mtime.to_f, delta + if stat.birthtime != stat.ctime + assert_in_delta t0+4, stat.ctime.to_f, delta + end + unless /mswin|mingw/ =~ RUBY_PLATFORM + # Windows delays updating atime + assert_in_delta t0+6, stat.atime.to_f, delta + end + } + rescue NotImplementedError + end + + def test_chmod_m17n + bug5671 = '[ruby-dev:44898]' + Dir.mktmpdir('test-file-chmod-m17n-') do |tmpdir| + file = File.join(tmpdir, "\u3042") + File.open(file, 'w'){} + assert_equal(File.chmod(0666, file), 1, bug5671) + end + end + + def test_file_open_permissions + Dir.mktmpdir(__method__.to_s) do |tmpdir| + tmp = File.join(tmpdir, 'x') + File.open(tmp, :mode => IO::RDWR | IO::CREAT | IO::BINARY, + :encoding => Encoding::ASCII_8BIT) do |x| + + assert_predicate(x, :autoclose?) + assert_equal Encoding::ASCII_8BIT, x.external_encoding + x.write 'hello' + + x.seek 0, IO::SEEK_SET + + assert_equal 'hello', x.read + + end + end + end + + def test_file_open_double_mode + assert_raise_with_message(ArgumentError, 'mode specified twice') { + File.open("a", 'w', :mode => 'rw+') + } + end + + def test_conflicting_encodings + Dir.mktmpdir(__method__.to_s) do |tmpdir| + tmp = File.join(tmpdir, 'x') + File.open(tmp, 'wb', :encoding => Encoding::EUC_JP) do |x| + assert_equal Encoding::EUC_JP, x.external_encoding + end + end + end + + def test_untainted_path + bug5374 = '[ruby-core:39745]' + cwd = ("./"*40+".".taint).dup.untaint + in_safe = proc {|safe| $SAFE = safe; File.stat(cwd)} + assert_not_send([cwd, :tainted?]) + (0..1).each do |level| + assert_nothing_raised(SecurityError, bug5374) {in_safe[level]} + end + def (s = Object.new).to_path; "".taint; end + m = "\u{691c 67fb}" + (c = Class.new(File)).singleton_class.class_eval {alias_method m, :stat} + assert_raise_with_message(SecurityError, /#{m}/) { + proc {$SAFE = 3; c.__send__(m, s)}.call + } + end + + if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM + def test_long_unc + feature3399 = '[ruby-core:30623]' + path = File.expand_path(__FILE__) + path.sub!(%r'\A//', 'UNC/') + assert_nothing_raised(Errno::ENOENT, feature3399) do + File.stat("//?/#{path}") + end + end + end + + def test_open_nul + Dir.mktmpdir(__method__.to_s) do |tmpdir| + path = File.join(tmpdir, "foo") + assert_raise(ArgumentError) do + open(path + "\0bar", "w") {} + end + assert_file.not_exist?(path) + end + end +end diff --git a/jni/ruby/test/ruby/test_file_exhaustive.rb b/jni/ruby/test/ruby/test_file_exhaustive.rb new file mode 100644 index 0000000..b347e53 --- /dev/null +++ b/jni/ruby/test/ruby/test_file_exhaustive.rb @@ -0,0 +1,1238 @@ +require "test/unit" +require "fileutils" +require "tmpdir" + +class TestFileExhaustive < Test::Unit::TestCase + DRIVE = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i] + + def assert_incompatible_encoding + d = "\u{3042}\u{3044}".encode("utf-16le") + assert_raise(Encoding::CompatibilityError) {yield d} + m = Class.new {define_method(:to_path) {d}} + assert_raise(Encoding::CompatibilityError) {yield m.new} + end + + def setup + @dir = Dir.mktmpdir("rubytest-file") + @rootdir = "#{DRIVE}/" + File.chown(-1, Process.gid, @dir) + @file = make_tmp_filename("file") + @zerofile = make_tmp_filename("zerofile") + @nofile = make_tmp_filename("nofile") + @symlinkfile = make_tmp_filename("symlinkfile") + @hardlinkfile = make_tmp_filename("hardlinkfile") + make_file("foo", @file) + make_file("", @zerofile) + @time = Time.now + begin + File.symlink(@file, @symlinkfile) + rescue NotImplementedError + @symlinkfile = nil + end + begin + File.link(@file, @hardlinkfile) + rescue NotImplementedError, Errno::EINVAL # EINVAL for Windows Vista + @hardlinkfile = nil + end + end + + def teardown + GC.start + FileUtils.remove_entry_secure @dir + end + + def make_file(content, file = @file) + open(file, "w") {|fh| fh << content } + end + + def make_tmp_filename(prefix) + "#{@dir}/#{prefix}#{File.basename(__FILE__)}.#{$$}.test" + end + + def test_path + file = @file + + assert_equal(file, File.open(file) {|f| f.path}) + assert_equal(file, File.path(file)) + o = Object.new + class << o; self; end.class_eval do + define_method(:to_path) { file } + end + assert_equal(file, File.path(o)) + end + + def assert_integer(n) + assert_kind_of(Integer, n) + end + + def assert_integer_or_nil(n) + msg = ->{"#{n.inspect} is neither Fixnum nor nil."} + if n + assert_kind_of(Integer, n, msg) + else + assert_nil(n, msg) + end + end + + def test_stat + sleep(@time - Time.now + 1.1) + make_file("foo", @file + "2") + fs1, fs2 = File.stat(@file), File.stat(@file + "2") + assert_nothing_raised do + assert_equal(0, fs1 <=> fs1) + assert_equal(-1, fs1 <=> fs2) + assert_equal(1, fs2 <=> fs1) + assert_nil(fs1 <=> nil) + assert_integer(fs1.dev) + assert_integer_or_nil(fs1.rdev) + assert_integer_or_nil(fs1.dev_major) + assert_integer_or_nil(fs1.dev_minor) + assert_integer_or_nil(fs1.rdev_major) + assert_integer_or_nil(fs1.rdev_minor) + assert_integer(fs1.ino) + assert_integer(fs1.mode) + unless /emx|mswin|mingw/ =~ RUBY_PLATFORM + # on Windows, nlink is always 1. but this behavior will be changed + # in the future. + assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink) + end + assert_integer(fs1.uid) + assert_integer(fs1.gid) + assert_equal(3, fs1.size) + assert_integer_or_nil(fs1.blksize) + assert_integer_or_nil(fs1.blocks) + assert_kind_of(Time, fs1.atime) + assert_kind_of(Time, fs1.mtime) + assert_kind_of(Time, fs1.ctime) + assert_kind_of(String, fs1.inspect) + end + assert_raise(Errno::ENOENT) { File.stat(@nofile) } + assert_kind_of(File::Stat, File.open(@file) {|f| f.stat}) + assert_raise(Errno::ENOENT) { File.lstat(@nofile) } + assert_kind_of(File::Stat, File.open(@file) {|f| f.lstat}) + end + + def test_stat_drive_root + assert_nothing_raised { File.stat(DRIVE + "/") } + assert_nothing_raised { File.stat(DRIVE + "/.") } + assert_nothing_raised { File.stat(DRIVE + "/..") } + assert_raise(Errno::ENOENT) { File.stat(DRIVE + "/...") } + # want to test the root of empty drive, but there is no method to test it... + end if DRIVE + + def test_stat_dotted_prefix + Dir.mktmpdir do |dir| + prefix = File.join(dir, "...a") + Dir.mkdir(prefix) + assert_file.exist?(prefix) + + assert_nothing_raised { File.stat(prefix) } + + Dir.chdir(dir) do + assert_nothing_raised { File.stat(File.basename(prefix)) } + end + end + end if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM + + def test_directory_p + assert_file.directory?(@dir) + assert_file.not_directory?(@dir+"/...") + assert_file.not_directory?(@file) + assert_file.not_directory?(@nofile) + end + + def test_pipe_p ## xxx + assert_file.not_pipe?(@dir) + assert_file.not_pipe?(@file) + assert_file.not_pipe?(@nofile) + end + + def test_symlink_p + assert_file.not_symlink?(@dir) + assert_file.not_symlink?(@file) + assert_file.symlink?(@symlinkfile) if @symlinkfile + assert_file.not_symlink?(@hardlinkfile) if @hardlinkfile + assert_file.not_symlink?(@nofile) + end + + def test_socket_p ## xxx + assert_file.not_socket?(@dir) + assert_file.not_socket?(@file) + assert_file.not_socket?(@nofile) + end + + def test_blockdev_p ## xxx + assert_file.not_blockdev?(@dir) + assert_file.not_blockdev?(@file) + assert_file.not_blockdev?(@nofile) + end + + def test_chardev_p ## xxx + assert_file.not_chardev?(@dir) + assert_file.not_chardev?(@file) + assert_file.not_chardev?(@nofile) + end + + def test_exist_p + assert_file.exist?(@dir) + assert_file.exist?(@file) + assert_file.not_exist?(@nofile) + end + + def test_readable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0200, @file) + assert_file.not_readable?(@file) + File.chmod(0600, @file) + assert_file.readable?(@file) + assert_file.not_readable?(@nofile) + end + + def test_readable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0200, @file) + assert_file.not_readable_real?(@file) + File.chmod(0600, @file) + assert_file.readable_real?(@file) + assert_file.not_readable_real?(@nofile) + end + + def test_world_readable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0006, @file) + assert_file.world_readable?(@file) + File.chmod(0060, @file) + assert_file.not_world_readable?(@file) + File.chmod(0600, @file) + assert_file.not_world_readable?(@file) + assert_file.not_world_readable?(@nofile) + end + + def test_writable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0400, @file) + assert_file.not_writable?(@file) + File.chmod(0600, @file) + assert_file.writable?(@file) + assert_file.not_writable?(@nofile) + end + + def test_writable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0400, @file) + assert_file.not_writable_real?(@file) + File.chmod(0600, @file) + assert_file.writable_real?(@file) + assert_file.not_writable_real?(@nofile) + end + + def test_world_writable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0006, @file) + assert_file.world_writable?(@file) + File.chmod(0060, @file) + assert_file.not_world_writable?(@file) + File.chmod(0600, @file) + assert_file.not_world_writable?(@file) + assert_file.not_world_writable?(@nofile) + end + + def test_executable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0100, @file) + assert_file.executable?(@file) + File.chmod(0600, @file) + assert_file.not_executable?(@file) + assert_file.not_executable?(@nofile) + end + + def test_executable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0100, @file) + assert_file.executable_real?(@file) + File.chmod(0600, @file) + assert_file.not_executable_real?(@file) + assert_file.not_executable_real?(@nofile) + end + + def test_file_p + assert_file.not_file?(@dir) + assert_file.file?(@file) + assert_file.not_file?(@nofile) + end + + def test_zero_p + assert_nothing_raised { File.zero?(@dir) } + assert_file.not_zero?(@file) + assert_file.zero?(@zerofile) + assert_file.not_zero?(@nofile) + end + + def test_size_p + assert_nothing_raised { File.size?(@dir) } + assert_equal(3, File.size?(@file)) + assert_file.not_size?(@zerofile) + assert_file.not_size?(@nofile) + end + + def test_owned_p ## xxx + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + assert_file.owned?(@file) + assert_file.grpowned?(@file) + end + + def test_suid_sgid_sticky ## xxx + assert_file.not_setuid?(@file) + assert_file.not_setgid?(@file) + assert_file.not_sticky?(@file) + end + + def test_path_identical_p + assert_file.identical?(@file, @file) + assert_file.not_identical?(@file, @zerofile) + assert_file.not_identical?(@file, @nofile) + assert_file.not_identical?(@nofile, @file) + end + + def test_io_identical_p + open(@file) {|f| + assert_file.identical?(f, f) + assert_file.identical?(@file, f) + assert_file.identical?(f, @file) + } + end + + def test_closed_io_identical_p + io = open(@file) {|f| f} + assert_raise(IOError) { + File.identical?(@file, io) + } + File.unlink(@file) + assert_file.not_exist?(@file) + end + + def test_s_size + assert_integer(File.size(@dir)) + assert_equal(3, File.size(@file)) + assert_equal(0, File.size(@zerofile)) + assert_raise(Errno::ENOENT) { File.size(@nofile) } + end + + def test_ftype + assert_equal("directory", File.ftype(@dir)) + assert_equal("file", File.ftype(@file)) + assert_equal("link", File.ftype(@symlinkfile)) if @symlinkfile + assert_equal("file", File.ftype(@hardlinkfile)) if @hardlinkfile + assert_raise(Errno::ENOENT) { File.ftype(@nofile) } + end + + def test_atime + t1 = File.atime(@file) + t2 = File.open(@file) {|f| f.atime} + assert_kind_of(Time, t1) + assert_kind_of(Time, t2) + assert_equal(t1, t2) + assert_raise(Errno::ENOENT) { File.atime(@nofile) } + end + + def test_mtime + t1 = File.mtime(@file) + t2 = File.open(@file) {|f| f.mtime} + assert_kind_of(Time, t1) + assert_kind_of(Time, t2) + assert_equal(t1, t2) + assert_raise(Errno::ENOENT) { File.mtime(@nofile) } + end + + def test_ctime + t1 = File.ctime(@file) + t2 = File.open(@file) {|f| f.ctime} + assert_kind_of(Time, t1) + assert_kind_of(Time, t2) + assert_equal(t1, t2) + assert_raise(Errno::ENOENT) { File.ctime(@nofile) } + end + + def test_chmod + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + assert_equal(1, File.chmod(0444, @file)) + assert_equal(0444, File.stat(@file).mode % 01000) + assert_equal(0, File.open(@file) {|f| f.chmod(0222)}) + assert_equal(0222, File.stat(@file).mode % 01000) + File.chmod(0600, @file) + assert_raise(Errno::ENOENT) { File.chmod(0600, @nofile) } + end + + def test_lchmod + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + assert_equal(1, File.lchmod(0444, @file)) + assert_equal(0444, File.stat(@file).mode % 01000) + File.lchmod(0600, @file) + assert_raise(Errno::ENOENT) { File.lchmod(0600, @nofile) } + rescue NotImplementedError + end + + def test_chown ## xxx + end + + def test_lchown ## xxx + end + + def test_symlink + return unless @symlinkfile + assert_equal("link", File.ftype(@symlinkfile)) + assert_raise(Errno::EEXIST) { File.symlink(@file, @file) } + end + + def test_utime + t = Time.local(2000) + File.utime(t + 1, t + 2, @zerofile) + assert_equal(t + 1, File.atime(@zerofile)) + assert_equal(t + 2, File.mtime(@zerofile)) + end + + def test_hardlink + return unless @hardlinkfile + assert_equal("file", File.ftype(@hardlinkfile)) + assert_raise(Errno::EEXIST) { File.link(@file, @file) } + end + + def test_readlink + return unless @symlinkfile + assert_equal(@file, File.readlink(@symlinkfile)) + assert_raise(Errno::EINVAL) { File.readlink(@file) } + assert_raise(Errno::ENOENT) { File.readlink(@nofile) } + if fs = Encoding.find("filesystem") + assert_equal(fs, File.readlink(@symlinkfile).encoding) + end + rescue NotImplementedError + end + + def test_readlink_long_path + return unless @symlinkfile + bug9157 = '[ruby-core:58592] [Bug #9157]' + assert_separately(["-", @symlinkfile, bug9157], <<-"end;") + symlinkfile, bug9157 = *ARGV + 100.step(1000, 100) do |n| + File.unlink(symlinkfile) + link = "foo"*n + begin + File.symlink(link, symlinkfile) + rescue Errno::ENAMETOOLONG + break + end + assert_equal(link, File.readlink(symlinkfile), bug9157) + end + end; + end + + def test_unlink + assert_equal(1, File.unlink(@file)) + make_file("foo", @file) + assert_raise(Errno::ENOENT) { File.unlink(@nofile) } + end + + def test_rename + assert_equal(0, File.rename(@file, @nofile)) + assert_file.not_exist?(@file) + assert_file.exist?(@nofile) + assert_equal(0, File.rename(@nofile, @file)) + assert_raise(Errno::ENOENT) { File.rename(@nofile, @file) } + end + + def test_umask + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + prev = File.umask(0777) + assert_equal(0777, File.umask) + open(@nofile, "w") { } + assert_equal(0, File.stat(@nofile).mode % 01000) + File.unlink(@nofile) + assert_equal(0777, File.umask(prev)) + assert_raise(ArgumentError) { File.umask(0, 1, 2) } + end + + def test_expand_path + assert_equal(@file, File.expand_path(File.basename(@file), File.dirname(@file))) + case RUBY_PLATFORM + when /cygwin|mingw|mswin|bccwin/ + assert_equal(@file, File.expand_path(@file + " ")) + assert_equal(@file, File.expand_path(@file + ".")) + assert_equal(@file, File.expand_path(@file + "::$DATA")) + assert_match(/\Ac:\//i, File.expand_path('c:'), '[ruby-core:31591]') + assert_match(/\Ac:\//i, File.expand_path('c:foo', 'd:/bar')) + assert_match(/\Ae:\//i, File.expand_path('e:foo', 'd:/bar')) + assert_match(%r'\Ac:/bar/foo\z'i, File.expand_path('c:foo', 'c:/bar')) + when /darwin/ + ["\u{feff}", *"\u{2000}"..."\u{2100}"].each do |c| + file = @file + c + begin + open(file) {} + rescue + assert_equal(file, File.expand_path(file), c.dump) + else + assert_equal(@file, File.expand_path(file), c.dump) + end + end + end + if DRIVE + assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar")) + assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar")) + assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo')) + else + assert_equal("/foo", File.expand_path('/foo')) + end + end + + def test_expand_path_memsize + 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) + path = File.expand_path("/a"*25) + assert_equal(path.bytesize+1 + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], ObjectSpace.memsize_of(path), bug9934) + end + + def test_expand_path_encoding + drive = (DRIVE ? 'C:' : '') + if Encoding.find("filesystem") == Encoding::CP1251 + a = "#{drive}/\u3042\u3044\u3046\u3048\u304a".encode("cp932") + else + a = "#{drive}/\u043f\u0440\u0438\u0432\u0435\u0442".encode("cp1251") + end + assert_equal(a, File.expand_path(a)) + a = "#{drive}/\225\\\\" + if File::ALT_SEPARATOR == '\\' + [%W"cp437 #{drive}/\225", %W"cp932 #{drive}/\225\\"] + else + [["cp437", a], ["cp932", a]] + end.each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.expand_path(a.dup.force_encoding(cp)), cp) + end + + path = "\u3042\u3044\u3046\u3048\u304a".encode("EUC-JP") + assert_equal("#{Dir.pwd}/#{path}".encode("CP932"), File.expand_path(path).encode("CP932")) + + path = "\u3042\u3044\u3046\u3048\u304a".encode("CP51932") + assert_equal("#{Dir.pwd}/#{path}", File.expand_path(path)) + + assert_incompatible_encoding {|d| File.expand_path(d)} + end + + def test_expand_path_encoding_filesystem + home = ENV["HOME"] + ENV["HOME"] = "#{DRIVE}/UserHome" + + path = "~".encode("US-ASCII") + dir = "C:/".encode("IBM437") + fs = Encoding.find("filesystem") + + assert_equal fs, File.expand_path(path).encoding + assert_equal fs, File.expand_path(path, dir).encoding + ensure + ENV["HOME"] = home + end + + UnknownUserHome = "~foo_bar_baz_unknown_user_wahaha".freeze + + def test_expand_path_home + assert_kind_of(String, File.expand_path("~")) if ENV["HOME"] + assert_raise(ArgumentError) { File.expand_path(UnknownUserHome) } + assert_raise(ArgumentError) { File.expand_path(UnknownUserHome, "/") } + begin + bug3630 = '[ruby-core:31537]' + home = ENV["HOME"] + home_drive = ENV["HOMEDRIVE"] + home_path = ENV["HOMEPATH"] + user_profile = ENV["USERPROFILE"] + ENV["HOME"] = nil + ENV["HOMEDRIVE"] = nil + ENV["HOMEPATH"] = nil + ENV["USERPROFILE"] = nil + assert_raise(ArgumentError) { File.expand_path("~") } + ENV["HOME"] = "~" + assert_raise(ArgumentError, bug3630) { File.expand_path("~") } + ENV["HOME"] = "." + assert_raise(ArgumentError, bug3630) { File.expand_path("~") } + ensure + ENV["HOME"] = home + ENV["HOMEDRIVE"] = home_drive + ENV["HOMEPATH"] = home_path + ENV["USERPROFILE"] = user_profile + end + end + + def test_expand_path_home_dir_string + home = ENV["HOME"] + new_home = "#{DRIVE}/UserHome" + ENV["HOME"] = new_home + bug8034 = "[ruby-core:53168]" + + assert_equal File.join(new_home, "foo"), File.expand_path("foo", "~"), bug8034 + assert_equal File.join(new_home, "bar", "foo"), File.expand_path("foo", "~/bar"), bug8034 + + assert_raise(ArgumentError) { File.expand_path(".", UnknownUserHome) } + assert_nothing_raised(ArgumentError) { File.expand_path("#{DRIVE}/", UnknownUserHome) } + ensure + ENV["HOME"] = home + end + + if /mswin|mingw/ =~ RUBY_PLATFORM + def test_expand_path_home_memory_leak_in_path + assert_no_memory_leak_at_expand_path_home('', 'in path') + end + + def test_expand_path_home_memory_leak_in_base + assert_no_memory_leak_at_expand_path_home('".",', 'in base') + end + + def assert_no_memory_leak_at_expand_path_home(arg, message) + prep = 'ENV["HOME"] = "foo"*100' + assert_no_memory_leak([], prep, <<-TRY, "memory leaked at non-absolute home #{message}") + 10000.times do + begin + File.expand_path(#{arg}"~/a") + rescue ArgumentError => e + next + ensure + abort("ArgumentError (non-absolute home) expected") unless e + end + end + GC.start + TRY + end + end + + + def test_expand_path_remove_trailing_alternative_data + assert_equal File.join(@rootdir, "aaa"), File.expand_path("#{@rootdir}/aaa::$DATA") + assert_equal File.join(@rootdir, "aa:a"), File.expand_path("#{@rootdir}/aa:a:$DATA") + assert_equal File.join(@rootdir, "aaa:$DATA"), File.expand_path("#{@rootdir}/aaa:$DATA") + end if DRIVE + + def test_expand_path_resolve_empty_string_current_directory + assert_equal(Dir.pwd, File.expand_path("")) + end + + def test_expand_path_resolve_dot_current_directory + assert_equal(Dir.pwd, File.expand_path(".")) + end + + def test_expand_path_resolve_file_name_relative_current_directory + assert_equal(File.join(Dir.pwd, "foo"), File.expand_path("foo")) + end + + def test_ignore_nil_dir_string + assert_equal(File.join(Dir.pwd, "foo"), File.expand_path("foo", nil)) + end + + def test_expand_path_resolve_file_name_and_dir_string_relative + assert_equal(File.join(Dir.pwd, "bar", "foo"), + File.expand_path("foo", "bar")) + end + + def test_expand_path_cleanup_dots_file_name + bug = "[ruby-talk:18512]" + + assert_equal(File.join(Dir.pwd, ".a"), File.expand_path(".a"), bug) + assert_equal(File.join(Dir.pwd, "..a"), File.expand_path("..a"), bug) + + if DRIVE + # cleanup dots only on Windows + assert_equal(File.join(Dir.pwd, "a"), File.expand_path("a."), bug) + assert_equal(File.join(Dir.pwd, "a"), File.expand_path("a.."), bug) + else + assert_equal(File.join(Dir.pwd, "a."), File.expand_path("a."), bug) + assert_equal(File.join(Dir.pwd, "a.."), File.expand_path("a.."), bug) + end + end + + def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_a_complete_path + assert_equal(@dir, File.expand_path("", "#{@dir}")) + assert_equal(File.join(@dir, "a"), File.expand_path("a", "#{@dir}")) + assert_equal(File.join(@dir, "a"), File.expand_path("../a", "#{@dir}/xxx")) + assert_equal(@rootdir, File.expand_path(".", "#{@rootdir}")) + end + + def test_expand_path_ignores_supplied_dir_if_path_contains_a_drive_letter + assert_equal(@rootdir, File.expand_path(@rootdir, "D:/")) + end if DRIVE + + def test_expand_path_removes_trailing_slashes_from_absolute_path + assert_equal(File.join(@rootdir, "foo"), File.expand_path("#{@rootdir}foo/")) + assert_equal(File.join(@rootdir, "foo.rb"), File.expand_path("#{@rootdir}foo.rb/")) + end + + def test_expand_path_removes_trailing_spaces_from_absolute_path + assert_equal(File.join(@rootdir, "a"), File.expand_path("#{@rootdir}a ")) + end if DRIVE + + def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_dir_s_drive + assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar")) + end if DRIVE + + def test_expand_path_converts_a_pathname_which_starts_with_a_slash_and_unc_pathname + assert_equal("//foo", File.expand_path('//foo', "//bar")) + assert_equal("//bar/foo", File.expand_path('/foo', "//bar")) + assert_equal("//foo", File.expand_path('//foo', "/bar")) + end if DRIVE + + def test_expand_path_converts_a_dot_with_unc_dir + assert_equal("//", File.expand_path('.', "//")) + end + + def test_expand_path_preserves_unc_path_root + assert_equal("//", File.expand_path("//")) + assert_equal("//", File.expand_path("//.")) + assert_equal("//", File.expand_path("//..")) + end + + def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_host_share + assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar")) + end if DRIVE + + def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_a_current_drive + assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo')) + end + + def test_expand_path_returns_tainted_strings_or_not + assert_equal(true, File.expand_path('foo').tainted?) + assert_equal(true, File.expand_path('foo'.taint).tainted?) + assert_equal(true, File.expand_path('/foo'.taint).tainted?) + assert_equal(true, File.expand_path('foo', 'bar').tainted?) + assert_equal(true, File.expand_path('foo', '/bar'.taint).tainted?) + assert_equal(true, File.expand_path('foo'.taint, '/bar').tainted?) + assert_equal(true, File.expand_path('~').tainted?) if ENV["HOME"] + + if DRIVE + assert_equal(true, File.expand_path('/foo').tainted?) + assert_equal(false, File.expand_path('//foo').tainted?) + assert_equal(true, File.expand_path('C:/foo'.taint).tainted?) + assert_equal(false, File.expand_path('C:/foo').tainted?) + assert_equal(true, File.expand_path('foo', '/bar').tainted?) + assert_equal(true, File.expand_path('foo', 'C:/bar'.taint).tainted?) + assert_equal(true, File.expand_path('foo'.taint, 'C:/bar').tainted?) + assert_equal(false, File.expand_path('foo', 'C:/bar').tainted?) + assert_equal(false, File.expand_path('C:/foo/../bar').tainted?) + assert_equal(false, File.expand_path('foo', '//bar').tainted?) + else + assert_equal(false, File.expand_path('/foo').tainted?) + assert_equal(false, File.expand_path('foo', '/bar').tainted?) + end + end + + def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_home_as_base + old_home = ENV["HOME"] + home = ENV["HOME"] = "#{DRIVE}/UserHome" + assert_equal(home, File.expand_path("~")) + assert_equal(home, File.expand_path("~", "C:/FooBar")) + assert_equal(File.join(home, "a"), File.expand_path("~/a", "C:/FooBar")) + ensure + ENV["HOME"] = old_home + end + + def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_unc_home + old_home = ENV["HOME"] + unc_home = ENV["HOME"] = "//UserHome" + assert_equal(unc_home, File.expand_path("~")) + ensure + ENV["HOME"] = old_home + end if DRIVE + + def test_expand_path_does_not_modify_a_home_string_argument + old_home = ENV["HOME"] + home = ENV["HOME"] = "#{DRIVE}/UserHome" + str = "~/a" + assert_equal("#{home}/a", File.expand_path(str)) + assert_equal("~/a", str) + ensure + ENV["HOME"] = old_home + end + + def test_expand_path_raises_argument_error_for_any_supplied_username + bug = '[ruby-core:39597]' + assert_raise(ArgumentError, bug) { File.expand_path("~anything") } + end if DRIVE + + def test_expand_path_for_existent_username + user = ENV['USER'] + skip "ENV['USER'] is not set" unless user + assert_equal(ENV['HOME'], File.expand_path("~#{user}")) + end unless DRIVE + + def test_expand_path_error_for_nonexistent_username + user = "\u{3086 3046 3066 3044}:\u{307F 3084 304A 3046}" + assert_raise_with_message(ArgumentError, /#{user}/) {File.expand_path("~#{user}")} + end unless DRIVE + + def test_expand_path_error_for_non_absolute_home + old_home = ENV["HOME"] + ENV["HOME"] = "./UserHome" + assert_raise_with_message(ArgumentError, /non-absolute home/) {File.expand_path("~")} + ensure + ENV["HOME"] = old_home + end + + def test_expand_path_raises_a_type_error_if_not_passed_a_string_type + assert_raise(TypeError) { File.expand_path(1) } + assert_raise(TypeError) { File.expand_path(nil) } + assert_raise(TypeError) { File.expand_path(true) } + end + + def test_expand_path_expands_dot_dir + assert_equal("#{DRIVE}/dir", File.expand_path("#{DRIVE}/./dir")) + end + + def test_expand_path_does_not_expand_wildcards + assert_equal("#{DRIVE}/*", File.expand_path("./*", "#{DRIVE}/")) + assert_equal("#{Dir.pwd}/*", File.expand_path("./*", Dir.pwd)) + assert_equal("#{DRIVE}/?", File.expand_path("./?", "#{DRIVE}/")) + assert_equal("#{Dir.pwd}/?", File.expand_path("./?", Dir.pwd)) + end if DRIVE + + def test_expand_path_does_not_modify_the_string_argument + str = "./a/b/../c" + assert_equal("#{Dir.pwd}/a/c", File.expand_path(str, Dir.pwd)) + assert_equal("./a/b/../c", str) + end + + def test_expand_path_returns_a_string_when_passed_a_string_subclass + sub = Class.new(String) + str = sub.new "./a/b/../c" + path = File.expand_path(str, Dir.pwd) + assert_equal("#{Dir.pwd}/a/c", path) + assert_instance_of(String, path) + end + + def test_expand_path_accepts_objects_that_have_a_to_path_method + klass = Class.new { def to_path; "a/b/c"; end } + obj = klass.new + assert_equal("#{Dir.pwd}/a/b/c", File.expand_path(obj)) + end + + def test_expand_path_with_drive_letter + bug10858 = '[ruby-core:68130] [Bug #10858]' + assert_match(%r'/bar/foo\z'i, File.expand_path('z:foo', 'bar'), bug10858) + assert_equal('z:/bar/foo', File.expand_path('z:foo', '/bar'), bug10858) + end if DRIVE + + def test_basename + assert_equal(File.basename(@file).sub(/\.test$/, ""), File.basename(@file, ".test")) + assert_equal("", s = File.basename("")) + assert(!s.frozen?, '[ruby-core:24199]') + assert_equal("foo", s = File.basename("foo")) + assert(!s.frozen?, '[ruby-core:24199]') + assert_equal("foo", File.basename("foo", ".ext")) + assert_equal("foo", File.basename("foo.ext", ".ext")) + assert_equal("foo", File.basename("foo.ext", ".*")) + if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM + basename = File.basename(@file) + assert_equal(basename, File.basename(@file + " ")) + assert_equal(basename, File.basename(@file + ".")) + assert_equal(basename, File.basename(@file + "::$DATA")) + basename.chomp!(".test") + assert_equal(basename, File.basename(@file + " ", ".test")) + assert_equal(basename, File.basename(@file + ".", ".test")) + assert_equal(basename, File.basename(@file + "::$DATA", ".test")) + assert_equal(basename, File.basename(@file + " ", ".*")) + assert_equal(basename, File.basename(@file + ".", ".*")) + assert_equal(basename, File.basename(@file + "::$DATA", ".*")) + end + if File::ALT_SEPARATOR == '\\' + a = "foo/\225\\\\" + [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.basename(a.dup.force_encoding(cp)), cp) + end + end + + assert_incompatible_encoding {|d| File.basename(d)} + assert_incompatible_encoding {|d| File.basename(d, ".*")} + assert_raise(Encoding::CompatibilityError) {File.basename("foo.ext", ".*".encode("utf-16le"))} + + s = "foo\x93_a".force_encoding("cp932") + assert_equal(s, File.basename(s, "_a")) + + s = "\u4032.\u3024" + assert_equal(s, File.basename(s, ".\x95\\".force_encoding("cp932"))) + end + + def test_dirname + assert(@file.start_with?(File.dirname(@file))) + assert_equal(".", File.dirname("")) + assert_incompatible_encoding {|d| File.dirname(d)} + if File::ALT_SEPARATOR == '\\' + a = "\225\\\\foo" + [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.dirname(a.dup.force_encoding(cp)), cp) + end + end + end + + def test_extname + assert_equal(".test", File.extname(@file)) + prefixes = ["", "/", ".", "/.", "bar/.", "/bar/."] + infixes = ["", " ", "."] + infixes2 = infixes + [".ext "] + appendixes = [""] + if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM + appendixes << " " << "." << "::$DATA" << "::$DATA.bar" + end + prefixes.each do |prefix| + appendixes.each do |appendix| + infixes.each do |infix| + path = "#{prefix}foo#{infix}#{appendix}" + assert_equal("", File.extname(path), "File.extname(#{path.inspect})") + end + infixes2.each do |infix| + path = "#{prefix}foo#{infix}.ext#{appendix}" + assert_equal(".ext", File.extname(path), "File.extname(#{path.inspect})") + end + end + end + bug3175 = '[ruby-core:29627]' + assert_equal(".rb", File.extname("/tmp//bla.rb"), bug3175) + + assert_incompatible_encoding {|d| File.extname(d)} + end + + def test_split + d, b = File.split(@file) + assert_equal(File.dirname(@file), d) + assert_equal(File.basename(@file), b) + end + + def test_join + s = "foo" + File::SEPARATOR + "bar" + File::SEPARATOR + "baz" + assert_equal(s, File.join("foo", "bar", "baz")) + assert_equal(s, File.join(["foo", "bar", "baz"])) + + o = Object.new + def o.to_path; "foo"; end + assert_equal(s, File.join(o, "bar", "baz")) + assert_equal(s, File.join("foo" + File::SEPARATOR, "bar", File::SEPARATOR + "baz")) + end + + def test_join_alt_separator + if File::ALT_SEPARATOR == '\\' + a = "\225\\" + b = "foo" + [%W"cp437 \225\\foo", %W"cp932 \225\\/foo"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.join(a.dup.force_encoding(cp), b.dup.force_encoding(cp)), cp) + end + end + end + + def test_join_ascii_incompatible + bug7168 = '[ruby-core:48012]' + names = %w"a b".map {|s| s.encode(Encoding::UTF_16LE)} + assert_raise(Encoding::CompatibilityError, bug7168) {File.join(*names)} + assert_raise(Encoding::CompatibilityError, bug7168) {File.join(names)} + + a = Object.new + b = names[1] + names = [a, "b"] + a.singleton_class.class_eval do + define_method(:to_path) do + names[1] = b + "a" + end + end + assert_raise(Encoding::CompatibilityError, bug7168) {File.join(names)} + end + + def test_truncate + assert_equal(0, File.truncate(@file, 1)) + assert_file.exist?(@file) + assert_equal(1, File.size(@file)) + assert_equal(0, File.truncate(@file, 0)) + assert_file.exist?(@file) + assert_file.zero?(@file) + make_file("foo", @file) + assert_raise(Errno::ENOENT) { File.truncate(@nofile, 0) } + + f = File.new(@file, "w") + assert_equal(0, f.truncate(2)) + assert_file.exist?(@file) + assert_equal(2, File.size(@file)) + assert_equal(0, f.truncate(0)) + assert_file.exist?(@file) + assert_file.zero?(@file) + f.close + make_file("foo", @file) + + assert_raise(IOError) { File.open(@file) {|ff| ff.truncate(0)} } + rescue NotImplementedError + end + + def test_flock ## xxx + f = File.new(@file, "r+") + f.flock(File::LOCK_EX) + f.flock(File::LOCK_SH) + f.flock(File::LOCK_UN) + f.close + rescue NotImplementedError + end + + def test_test + sleep(@time - Time.now + 1.1) + make_file("foo", @file + "2") + [@dir, @file, @zerofile, @symlinkfile, @hardlinkfile].compact.each do |f| + assert_equal(File.atime(f), test(?A, f)) + assert_equal(File.ctime(f), test(?C, f)) + assert_equal(File.mtime(f), test(?M, f)) + assert_equal(File.blockdev?(f), test(?b, f)) + assert_equal(File.chardev?(f), test(?c, f)) + assert_equal(File.directory?(f), test(?d, f)) + assert_equal(File.exist?(f), test(?e, f)) + assert_equal(File.file?(f), test(?f, f)) + assert_equal(File.setgid?(f), test(?g, f)) + assert_equal(File.grpowned?(f), test(?G, f)) + assert_equal(File.sticky?(f), test(?k, f)) + assert_equal(File.symlink?(f), test(?l, f)) + assert_equal(File.owned?(f), test(?o, f)) + assert_nothing_raised { test(?O, f) } + assert_equal(File.pipe?(f), test(?p, f)) + assert_equal(File.readable?(f), test(?r, f)) + assert_equal(File.readable_real?(f), test(?R, f)) + assert_equal(File.size?(f), test(?s, f)) + assert_equal(File.socket?(f), test(?S, f)) + assert_equal(File.setuid?(f), test(?u, f)) + assert_equal(File.writable?(f), test(?w, f)) + assert_equal(File.writable_real?(f), test(?W, f)) + assert_equal(File.executable?(f), test(?x, f)) + assert_equal(File.executable_real?(f), test(?X, f)) + assert_equal(File.zero?(f), test(?z, f)) + end + assert_equal(false, test(?-, @dir, @file)) + assert_equal(true, test(?-, @file, @file)) + assert_equal(true, test(?=, @file, @file)) + assert_equal(false, test(?>, @file, @file)) + assert_equal(false, test(?<, @file, @file)) + unless /cygwin/ =~ RUBY_PLATFORM + assert_equal(false, test(?=, @file, @file + "2")) + assert_equal(false, test(?>, @file, @file + "2")) + assert_equal(true, test(?>, @file + "2", @file)) + assert_equal(true, test(?<, @file, @file + "2")) + assert_equal(false, test(?<, @file + "2", @file)) + end + assert_raise(ArgumentError) { test } + assert_raise(Errno::ENOENT) { test(?A, @nofile) } + assert_raise(ArgumentError) { test(?a) } + assert_raise(ArgumentError) { test("\0".ord) } + end + + def test_stat_init + sleep(@time - Time.now + 1.1) + make_file("foo", @file + "2") + fs1, fs2 = File::Stat.new(@file), File::Stat.new(@file + "2") + assert_nothing_raised do + assert_equal(0, fs1 <=> fs1) + assert_equal(-1, fs1 <=> fs2) + assert_equal(1, fs2 <=> fs1) + assert_nil(fs1 <=> nil) + assert_integer(fs1.dev) + assert_integer_or_nil(fs1.rdev) + assert_integer_or_nil(fs1.dev_major) + assert_integer_or_nil(fs1.dev_minor) + assert_integer_or_nil(fs1.rdev_major) + assert_integer_or_nil(fs1.rdev_minor) + assert_integer(fs1.ino) + assert_integer(fs1.mode) + unless /emx|mswin|mingw/ =~ RUBY_PLATFORM + # on Windows, nlink is always 1. but this behavior will be changed + # in the future. + assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink) + end + assert_integer(fs1.uid) + assert_integer(fs1.gid) + assert_equal(3, fs1.size) + assert_integer_or_nil(fs1.blksize) + assert_integer_or_nil(fs1.blocks) + assert_kind_of(Time, fs1.atime) + assert_kind_of(Time, fs1.mtime) + assert_kind_of(Time, fs1.ctime) + assert_kind_of(String, fs1.inspect) + end + assert_raise(Errno::ENOENT) { File::Stat.new(@nofile) } + assert_kind_of(File::Stat, File::Stat.new(@file).dup) + assert_raise(TypeError) do + File::Stat.new(@file).instance_eval { initialize_copy(0) } + end + end + + def test_stat_ftype + assert_equal("directory", File::Stat.new(@dir).ftype) + assert_equal("file", File::Stat.new(@file).ftype) + # File::Stat uses stat + assert_equal("file", File::Stat.new(@symlinkfile).ftype) if @symlinkfile + assert_equal("file", File::Stat.new(@hardlinkfile).ftype) if @hardlinkfile + end + + def test_stat_directory_p + assert(File::Stat.new(@dir).directory?) + assert(!(File::Stat.new(@file).directory?)) + end + + def test_stat_pipe_p ## xxx + assert(!(File::Stat.new(@dir).pipe?)) + assert(!(File::Stat.new(@file).pipe?)) + end + + def test_stat_symlink_p + assert(!(File::Stat.new(@dir).symlink?)) + assert(!(File::Stat.new(@file).symlink?)) + # File::Stat uses stat + assert(!(File::Stat.new(@symlinkfile).symlink?)) if @symlinkfile + assert(!(File::Stat.new(@hardlinkfile).symlink?)) if @hardlinkfile + end + + def test_stat_socket_p ## xxx + assert(!(File::Stat.new(@dir).socket?)) + assert(!(File::Stat.new(@file).socket?)) + end + + def test_stat_blockdev_p ## xxx + assert(!(File::Stat.new(@dir).blockdev?)) + assert(!(File::Stat.new(@file).blockdev?)) + end + + def test_stat_chardev_p ## xxx + assert(!(File::Stat.new(@dir).chardev?)) + assert(!(File::Stat.new(@file).chardev?)) + end + + def test_stat_readable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0200, @file) + assert(!(File::Stat.new(@file).readable?)) + File.chmod(0600, @file) + assert(File::Stat.new(@file).readable?) + end + + def test_stat_readable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0200, @file) + assert(!(File::Stat.new(@file).readable_real?)) + File.chmod(0600, @file) + assert(File::Stat.new(@file).readable_real?) + end + + def test_stat_world_readable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0006, @file) + assert(File::Stat.new(@file).world_readable?) + File.chmod(0060, @file) + assert(!(File::Stat.new(@file).world_readable?)) + File.chmod(0600, @file) + assert(!(File::Stat.new(@file).world_readable?)) + end + + def test_stat_writable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0400, @file) + assert(!(File::Stat.new(@file).writable?)) + File.chmod(0600, @file) + assert(File::Stat.new(@file).writable?) + end + + def test_stat_writable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + return if Process.euid == 0 + File.chmod(0400, @file) + assert(!(File::Stat.new(@file).writable_real?)) + File.chmod(0600, @file) + assert(File::Stat.new(@file).writable_real?) + end + + def test_stat_world_writable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0006, @file) + assert(File::Stat.new(@file).world_writable?) + File.chmod(0060, @file) + assert(!(File::Stat.new(@file).world_writable?)) + File.chmod(0600, @file) + assert(!(File::Stat.new(@file).world_writable?)) + end + + def test_stat_executable_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0100, @file) + assert(File::Stat.new(@file).executable?) + File.chmod(0600, @file) + assert(!(File::Stat.new(@file).executable?)) + end + + def test_stat_executable_real_p + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + File.chmod(0100, @file) + assert(File::Stat.new(@file).executable_real?) + File.chmod(0600, @file) + assert(!(File::Stat.new(@file).executable_real?)) + end + + def test_stat_file_p + assert(!(File::Stat.new(@dir).file?)) + assert(File::Stat.new(@file).file?) + end + + def test_stat_zero_p + assert_nothing_raised { File::Stat.new(@dir).zero? } + assert(!(File::Stat.new(@file).zero?)) + assert(File::Stat.new(@zerofile).zero?) + end + + def test_stat_size_p + assert_nothing_raised { File::Stat.new(@dir).size? } + assert_equal(3, File::Stat.new(@file).size?) + assert(!(File::Stat.new(@zerofile).size?)) + end + + def test_stat_owned_p ## xxx + return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM + assert(File::Stat.new(@file).owned?) + assert(File::Stat.new(@file).grpowned?) + end + + def test_stat_suid_sgid_sticky ## xxx + assert(!(File::Stat.new(@file).setuid?)) + assert(!(File::Stat.new(@file).setgid?)) + assert(!(File::Stat.new(@file).sticky?)) + end + + def test_stat_size + assert_integer(File::Stat.new(@dir).size) + assert_equal(3, File::Stat.new(@file).size) + assert_equal(0, File::Stat.new(@zerofile).size) + end + + def test_stat_special_file + # test for special files such as pagefile.sys on Windows + assert_nothing_raised do + Dir::glob("C:/*.sys") {|f| File::Stat.new(f) } + end + end if DRIVE + + def test_path_check + assert_nothing_raised { ENV["PATH"] } + end + + def test_size + assert_equal(3, File.open(@file) {|f| f.size }) + File.open(@file, "a") do |f| + f.write("bar") + assert_equal(6, f.size) + end + end + + def test_absolute_path + assert_equal(File.join(Dir.pwd, "~foo"), File.absolute_path("~foo")) + dir = File.expand_path("/bar") + assert_equal(File.join(dir, "~foo"), File.absolute_path("~foo", dir)) + end +end diff --git a/jni/ruby/test/ruby/test_fixnum.rb b/jni/ruby/test/ruby/test_fixnum.rb new file mode 100644 index 0000000..8b2cf2e --- /dev/null +++ b/jni/ruby/test/ruby/test_fixnum.rb @@ -0,0 +1,315 @@ +require 'test/unit' + +class TestFixnum < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_pow + [1, 2, 2**64, 2**63*3, 2**64*3].each do |y| + [-1, 0, 1].each do |x| + z1 = x**y + z2 = (-x)**y + if y % 2 == 1 + assert_equal(z2, -z1) + else + assert_equal(z2, z1) + end + end + end + end + + def test_succ + assert_equal(0x40000000, 0x3fffffff.succ, "[ruby-dev:31189]") + assert_equal(0x4000000000000000, 0x3fffffffffffffff.succ, "[ruby-dev:31190]") + end + + def test_pred + assert_equal(-0x40000001, (-0x40000000).pred) + assert_equal(-0x4000000000000001, (-0x4000000000000000).pred) + end + + def test_plus + assert_equal(0x40000000, 0x3fffffff+1) + assert_equal(0x4000000000000000, 0x3fffffffffffffff+1) + assert_equal(-0x40000001, (-0x40000000)+(-1)) + assert_equal(-0x4000000000000001, (-0x4000000000000000)+(-1)) + assert_equal(-0x80000000, (-0x40000000)+(-0x40000000)) + end + + def test_sub + assert_equal(0x40000000, 0x3fffffff-(-1)) + assert_equal(0x4000000000000000, 0x3fffffffffffffff-(-1)) + assert_equal(-0x40000001, (-0x40000000)-1) + assert_equal(-0x4000000000000001, (-0x4000000000000000)-1) + assert_equal(-0x80000000, (-0x40000000)-0x40000000) + end + + def test_mult + assert_equal(0x40000000, 0x20000000*2) + assert_equal(0x4000000000000000, 0x2000000000000000*2) + assert_equal(-0x40000001, 33025*(-32513)) + assert_equal(-0x4000000000000001, 1380655685*(-3340214413)) + assert_equal(0x40000000, (-0x40000000)*(-1)) + end + + def test_div + assert_equal(2, 5/2) + assert_equal(0, 1/2) + assert_equal(-1, -1/2) + assert_equal(0, -(1/2)) + assert_equal(-1, (-1)/2) + assert_equal(0, (-1)/(-2)) + assert_equal(-1, 1/(-2)) + assert_equal(1, -(1/(-2))) + assert_equal(0x3fffffff, 0xbffffffd/3) + assert_equal(0x40000000, 0xc0000000/3) + assert_equal(0x4000000000000000, 0xc000000000000000/3) + assert_equal(-0x40000001, 0xc0000003/(-3)) + assert_equal(-0x4000000000000001, 0xc000000000000003/(-3)) + assert_equal(0x40000000, (-0x40000000)/(-1), "[ruby-dev:31210]") + assert_equal(0x4000000000000000, (-0x4000000000000000)/(-1)) + assert_raise(FloatDomainError) { 2.div(Float::NAN).nan? } + end + + def test_mod + assert_equal(2, (-0x40000000) % 3) + assert_equal(0, (-0x40000000) % (-1)) + end + + def test_divmod + (-5).upto(5) {|a| + (-5).upto(5) {|b| + next if b == 0 + q, r = a.divmod(b) + assert_equal(a, b*q+r) + assert_operator(r.abs, :<, b.abs) + if 0 < b + assert_operator(r, :>=, 0) + assert_operator(r, :<, b) + else + assert_operator(r, :>, b) + assert_operator(r, :<=, 0) + end + assert_equal(q, a/b) + assert_equal(q, a.div(b)) + assert_equal(r, a%b) + assert_equal(r, a.modulo(b)) + } + } + assert_raise(FloatDomainError) { 2.divmod(Float::NAN) } + end + + def test_not + assert_equal(-0x40000000, ~0x3fffffff) + assert_equal(0x3fffffff, ~-0x40000000) + end + + def test_lshift + assert_equal(0x40000000, 0x20000000 << 1) + assert_equal(-0x40000000, (-0x20000000) << 1) + assert_equal(-0x80000000, (-0x40000000) << 1) + end + + def test_rshift + assert_equal(0x20000000, 0x40000000 >> 1) + assert_equal(-0x20000000, (-0x40000000) >> 1) + assert_equal(-0x40000000, (-0x80000000) >> 1) + end + + def test_abs + assert_equal(0x40000000, (-0x40000000).abs) + assert_equal(0x4000000000000000, (-0x4000000000000000).abs) + end + + def test_to_s + assert_equal("1010", 10.to_s(2)) + assert_equal("a", 10.to_s(36)) + assert_raise(ArgumentError) { 10.to_s(1) } + end + + def test_plus2 + assert_equal(2, 1 + 1) + assert_equal(4294967297, 1 + 2**32) + assert_equal(2.0, 1 + 1.0) + assert_raise(TypeError) { 1 + nil } + end + + def test_minus + assert_equal(0, 1 - 1) + assert_equal(-4294967295, 1 - 2**32) + assert_equal(0.0, 1 - 1.0) + assert_raise(TypeError) { 1 - nil } + end + + def test_mul + assert_equal(6, 2.send(:*, 3)) + a = 2**30-1 + assert_equal(1152921502459363329, a.send(:*, a)) + + assert_equal(6.0, 2 * 3.0) + assert_raise(TypeError) { 2 * nil } + end + + def test_divide + assert_equal(2.0, 4.quo(2)) + assert_equal(2.0, 4 / 2) + assert_equal(2.0, 4.div(2)) + + assert_equal(0.5**32, 1.quo(2**32)) + assert_equal(0, 1 / (2**32)) + assert_equal(0, 1.div(2**32)) + + assert_kind_of(Float, 1.quo(2.0)) + assert_equal(0.5, 1.quo(2.0)) + assert_equal(0.5, 1 / 2.0) + assert_equal(0, 1.div(2.0)) + + ### rational changes the behavior of Fixnum#quo + #assert_raise(TypeError) { 2.quo(nil) } + assert_raise(TypeError, NoMethodError) { 2.quo(nil) } + assert_raise(TypeError) { 2 / nil } + assert_raise(TypeError) { 2.div(nil) } + + assert_equal(0, 4.modulo(2)) + assert_equal(1, 1.modulo(2**32)) + assert_equal(1, 1.modulo(2.0)) + assert_raise(TypeError) { 2.modulo(nil) } + + assert_equal([2, 0], 4.divmod(2)) + assert_equal([0, 1], 1.divmod(2**32)) + assert_equal([0, 1], 1.divmod(2.0)) + assert_raise(TypeError) { 2.divmod(nil) } + end + + def test_pow2 + assert_equal(65536, 2**16) + assert_equal(4294967296, 2**32) + assert_equal(0.5**16, 2**-16) + assert_equal(1, (-1)**4294967296) + assert_equal(-1, (-1)**4294967295) + assert_equal(4, 2**((2**32).coerce(2).first)) + assert_equal(2, 4**0.5) + assert_equal(0, 0**0.5) + assert_equal(1, (0**-1.0).infinite?) + ### rational changes the behavior of Fixnum#** + #assert_raise(TypeError) { 1 ** nil } + assert_raise(TypeError, NoMethodError) { 1 ** nil } + end + + def test_cmp + assert_operator(1, :!=, nil) + + assert_equal(0, 1 <=> 1) + assert_equal(-1, 1 <=> 4294967296) + assert_equal(0, 1 <=> 1.0) + assert_nil(1 <=> nil) + + assert_operator(1, :>, 0) + assert_not_operator(1, :>, 1) + assert_not_operator(1, :>, 2) + assert_not_operator(1, :>, 4294967296) + assert_operator(1, :>, 0.0) + assert_raise(ArgumentError) { 1 > nil } + + assert_operator(1, :>=, 0) + assert_operator(1, :>=, 1) + assert_not_operator(1, :>=, 2) + assert_not_operator(1, :>=, 4294967296) + assert_operator(1, :>=, 0.0) + assert_raise(ArgumentError) { 1 >= nil } + + assert_not_operator(1, :<, 0) + assert_not_operator(1, :<, 1) + assert_operator(1, :<, 2) + assert_operator(1, :<, 4294967296) + assert_not_operator(1, :<, 0.0) + assert_raise(ArgumentError) { 1 < nil } + + assert_not_operator(1, :<=, 0) + assert_operator(1, :<=, 1) + assert_operator(1, :<=, 2) + assert_operator(1, :<=, 4294967296) + assert_not_operator(1, :<=, 0.0) + assert_raise(ArgumentError) { 1 <= nil } + end + + class DummyNumeric < Numeric + def to_int + 1 + end + end + + def test_and_with_float + assert_raise(TypeError) { 1 & 1.5 } + end + + def test_and_with_rational + assert_raise(TypeError, "#1792") { 1 & Rational(3, 2) } + end + + def test_and_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { 1 & DummyNumeric.new } + end + + def test_or_with_float + assert_raise(TypeError) { 1 | 1.5 } + end + + def test_or_with_rational + assert_raise(TypeError, "#1792") { 1 | Rational(3, 2) } + end + + def test_or_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { 1 | DummyNumeric.new } + end + + def test_xor_with_float + assert_raise(TypeError) { 1 ^ 1.5 } + end + + def test_xor_with_rational + assert_raise(TypeError, "#1792") { 1 ^ Rational(3, 2) } + end + + def test_xor_with_nonintegral_numeric + assert_raise(TypeError, "#1792") { 1 ^ DummyNumeric.new } + end + + def test_singleton_method + assert_raise(TypeError) { a = 1; def a.foo; end } + end + + def test_frozen + assert_equal(true, 1.frozen?) + end + + def assert_eql(a, b, mess) + assert a.eql?(b), "expected #{a} & #{b} to be eql? #{mess}" + end + + def test_power_of_1_and_minus_1 + bug5715 = '[ruby-core:41498]' + big = 1 << 66 + assert_eql 1, 1 ** -big , bug5715 + assert_eql 1, (-1) ** -big , bug5715 + assert_eql -1, (-1) ** -(big+1) , bug5715 + end + + def test_power_of_0 + bug5713 = '[ruby-core:41494]' + big = 1 << 66 + assert_raise(ZeroDivisionError, bug5713) { 0 ** -big } + assert_raise(ZeroDivisionError, bug5713) { 0 ** Rational(-2,3) } + end + + def test_remainder + assert_equal(1, 5.remainder(4)) + assert_predicate(4.remainder(Float::NAN), :nan?) + end +end diff --git a/jni/ruby/test/ruby/test_flip.rb b/jni/ruby/test/ruby/test_flip.rb new file mode 100644 index 0000000..84f7bf0 --- /dev/null +++ b/jni/ruby/test/ruby/test_flip.rb @@ -0,0 +1,41 @@ +require 'test/unit' + +class TestFlip < Test::Unit::TestCase + def test_hidden_key + bug6899 = '[ruby-core:47253]' + foo = "foor" + bar = "bar" + assert_nothing_raised(NotImplementedError, bug6899) do + 2000.times {eval %[(foo..bar) ? 1 : 2]} + end + end + + def test_shared_eval + bug7671 = '[ruby-core:51296]' + vs = (1..9).to_a + vs.select {|n| if n==2..n==16 then 1 end} + v = eval("vs.select {|n| if n==3..n==6 then 1 end}") + assert_equal([*3..6], v, bug7671) + end + + def test_shared_thread + ff = proc {|n| true if n==3..n==5} + v = 1..9 + a = true + th = Thread.new { + v.select {|i| + Thread.pass while a + ff[i].tap {a = true} + } + } + v1 = v.select {|i| + Thread.pass until a + ff[i].tap {a = false} + } + v2 = th.value + expected = [3, 4, 5] + mesg = 'flip-flop should be separated per threads' + assert_equal(expected, v1, mesg) + assert_equal(expected, v2, mesg) + end +end diff --git a/jni/ruby/test/ruby/test_float.rb b/jni/ruby/test/ruby/test_float.rb new file mode 100644 index 0000000..eab4d12 --- /dev/null +++ b/jni/ruby/test/ruby/test_float.rb @@ -0,0 +1,683 @@ +require 'test/unit' + +class TestFloat < Test::Unit::TestCase + include EnvUtil + + def test_float + assert_equal(2, 2.6.floor) + assert_equal(-3, (-2.6).floor) + assert_equal(3, 2.6.ceil) + assert_equal(-2, (-2.6).ceil) + assert_equal(2, 2.6.truncate) + assert_equal(-2, (-2.6).truncate) + assert_equal(3, 2.6.round) + assert_equal(-2, (-2.4).truncate) + assert_in_delta(13.4 % 1, 0.4, 0.0001) + assert_equal(36893488147419111424, + 36893488147419107329.0.to_i) + end + + def nan_test(x,y) + extend Test::Unit::Assertions + assert_operator(x, :!=, y) + assert_not_operator(x, :<, y) + assert_not_operator(x, :>, y) + assert_not_operator(x, :<=, y) + assert_not_operator(x, :>=, y) + end + def test_nan + nan = Float::NAN + nan_test(nan, nan) + nan_test(nan, 0) + nan_test(nan, 1) + nan_test(nan, -1) + nan_test(nan, 1000) + nan_test(nan, -1000) + nan_test(nan, 1_000_000_000_000) + nan_test(nan, -1_000_000_000_000) + nan_test(nan, 100.0); + nan_test(nan, -100.0); + nan_test(nan, 0.001); + nan_test(nan, -0.001); + nan_test(nan, 1.0/0); + nan_test(nan, -1.0/0); + end + + def test_precision + u = 3.7517675036461267e+17 + v = sprintf("%.16e", u).to_f + assert_in_delta(u, v, u.abs * Float::EPSILON) + assert_in_delta(u, v, v.abs * Float::EPSILON) + end + + def test_symmetry_bignum # [ruby-bugs-ja:118] + a = 100000000000000000000000 + b = 100000000000000000000000.0 + assert_equal(a == b, b == a) + end + + def test_cmp_int + 100.times {|i| + int0 = 1 << i + [int0, -int0].each {|int| + flt = int.to_f + bigger = int + 1 + smaller = int - 1 + assert_operator(flt, :==, int) + assert_operator(flt, :>, smaller) + assert_operator(flt, :>=, smaller) + assert_operator(flt, :<, bigger) + assert_operator(flt, :<=, bigger) + assert_equal(0, flt <=> int) + assert_equal(-1, flt <=> bigger) + assert_equal(1, flt <=> smaller) + assert_operator(int, :==, flt) + assert_operator(bigger, :>, flt) + assert_operator(bigger, :>=, flt) + assert_operator(smaller, :<, flt) + assert_operator(smaller, :<=, flt) + assert_equal(0, int <=> flt) + assert_equal(-1, smaller <=> flt) + assert_equal(1, bigger <=> flt) + [ + [int, flt + 0.5, bigger], + [smaller, flt - 0.5, int] + ].each {|smaller2, flt2, bigger2| + next if flt2 == flt2.round + assert_operator(flt2, :!=, smaller2) + assert_operator(flt2, :!=, bigger2) + assert_operator(flt2, :>, smaller2) + assert_operator(flt2, :>=, smaller2) + assert_operator(flt2, :<, bigger2) + assert_operator(flt2, :<=, bigger2) + assert_equal(-1, flt2 <=> bigger2) + assert_equal(1, flt2 <=> smaller2) + assert_operator(smaller2, :!=, flt2) + assert_operator(bigger2, :!=, flt2) + assert_operator(bigger2, :>, flt2) + assert_operator(bigger2, :>=, flt2) + assert_operator(smaller2, :<, flt2) + assert_operator(smaller2, :<=, flt2) + assert_equal(-1, smaller2 <=> flt2) + assert_equal(1, bigger2 <=> flt2) + } + } + } + end + + def test_strtod + a = Float("0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("0.0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("+0.0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("-0.0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("0.0000000000000000001") + assert_not_equal(0.0, a) + a = Float("+0.0000000000000000001") + assert_not_equal(0.0, a) + a = Float("-0.0000000000000000001") + assert_not_equal(0.0, a) + a = Float(".0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("+.0") + assert_in_delta(a, 0, Float::EPSILON) + a = Float("-.0") + assert_in_delta(a, 0, Float::EPSILON) + assert_raise(ArgumentError){Float("0.")} + assert_raise(ArgumentError){Float("+0.")} + assert_raise(ArgumentError){Float("-0.")} + assert_raise(ArgumentError){Float(".")} + assert_raise(ArgumentError){Float("+")} + assert_raise(ArgumentError){Float("+.")} + assert_raise(ArgumentError){Float("-")} + assert_raise(ArgumentError){Float("-.")} + assert_raise(ArgumentError){Float("1e")} + assert_raise(ArgumentError){Float("1__1")} + assert_raise(ArgumentError){Float("1.")} + assert_raise(ArgumentError){Float("1.e+00")} + assert_raise(ArgumentError){Float("0x1.p+0")} + # add expected behaviour here. + assert_equal(10, Float("1_0")) + + assert_equal([ 0.0].pack('G'), [Float(" 0x0p+0").to_f].pack('G')) + assert_equal([-0.0].pack('G'), [Float("-0x0p+0").to_f].pack('G')) + assert_equal(255.0, Float("0Xff")) + assert_equal(1024.0, Float("0x1p10")) + assert_equal(1024.0, Float("0x1p+10")) + assert_equal(0.0009765625, Float("0x1p-10")) + assert_equal(2.6881171418161356e+43, Float("0x1.3494a9b171bf5p+144")) + assert_equal(-3.720075976020836e-44, Float("-0x1.a8c1f14e2af5dp-145")) + assert_equal(31.0*2**1019, Float("0x0."+("0"*268)+"1fp2099")) + assert_equal(31.0*2**1019, Float("0x0."+("0"*600)+"1fp3427")) + assert_equal(-31.0*2**1019, Float("-0x0."+("0"*268)+"1fp2099")) + assert_equal(-31.0*2**1019, Float("-0x0."+("0"*600)+"1fp3427")) + suppress_warning do + assert_equal(31.0*2**-1027, Float("0x1f"+("0"*268)+".0p-2099")) + assert_equal(31.0*2**-1027, Float("0x1f"+("0"*600)+".0p-3427")) + assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*268)+".0p-2099")) + assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*600)+".0p-3427")) + end + end + + def test_divmod + assert_equal([2, 3.5], 11.5.divmod(4)) + assert_equal([-3, -0.5], 11.5.divmod(-4)) + assert_equal([-3, 0.5], (-11.5).divmod(4)) + assert_equal([2, -3.5], (-11.5).divmod(-4)) + assert_raise(FloatDomainError) { Float::NAN.divmod(2) } + assert_raise(FloatDomainError) { Float::INFINITY.divmod(2) } + end + + def test_div + assert_equal(2, 11.5.div(4)) + assert_equal(-3, 11.5.div(-4)) + assert_equal(-3, (-11.5).div(4)) + assert_equal(2, (-11.5).div(-4)) + assert_raise(FloatDomainError) { 11.5.div(Float::NAN).nan? } + assert_raise(FloatDomainError) { Float::NAN.div(2).nan? } + assert_raise(FloatDomainError) { Float::NAN.div(11.5).nan? } + end + + def test_modulo + assert_equal(3.5, 11.5.modulo(4)) + assert_equal(-0.5, 11.5.modulo(-4)) + assert_equal(0.5, (-11.5).modulo(4)) + assert_equal(-3.5, (-11.5).modulo(-4)) + end + + def test_remainder + assert_equal(3.5, 11.5.remainder(4)) + assert_equal(3.5, 11.5.remainder(-4)) + assert_equal(-3.5, (-11.5).remainder(4)) + assert_equal(-3.5, (-11.5).remainder(-4)) + assert_predicate(Float::NAN.remainder(4), :nan?) + assert_predicate(4.remainder(Float::NAN), :nan?) + end + + def test_to_s + inf = Float::INFINITY + assert_equal("Infinity", inf.to_s) + assert_equal("-Infinity", (-inf).to_s) + assert_equal("NaN", (inf / inf).to_s) + + assert_equal("1.0e+18", 1000_00000_00000_00000.0.to_s) + + bug3273 = '[ruby-core:30145]' + [0.21611564636388508, 0.56].each do |f| + s = f.to_s + assert_equal(f, s.to_f, bug3273) + assert_not_equal(f, s.chop.to_f, bug3273) + end + end + + def test_coerce + assert_equal(Float, 1.0.coerce(1).first.class) + end + + def test_plus + assert_equal(4.0, 2.0.send(:+, 2)) + assert_equal(4.0, 2.0.send(:+, (2**32).coerce(2).first)) + assert_equal(4.0, 2.0.send(:+, 2.0)) + assert_equal(Float::INFINITY, 2.0.send(:+, Float::INFINITY)) + assert_predicate(2.0.send(:+, Float::NAN), :nan?) + assert_raise(TypeError) { 2.0.send(:+, nil) } + end + + def test_minus + assert_equal(0.0, 2.0.send(:-, 2)) + assert_equal(0.0, 2.0.send(:-, (2**32).coerce(2).first)) + assert_equal(0.0, 2.0.send(:-, 2.0)) + assert_equal(-Float::INFINITY, 2.0.send(:-, Float::INFINITY)) + assert_predicate(2.0.send(:-, Float::NAN), :nan?) + assert_raise(TypeError) { 2.0.send(:-, nil) } + end + + def test_mul + assert_equal(4.0, 2.0.send(:*, 2)) + assert_equal(4.0, 2.0.send(:*, (2**32).coerce(2).first)) + assert_equal(4.0, 2.0.send(:*, 2.0)) + assert_equal(Float::INFINITY, 2.0.send(:*, Float::INFINITY)) + assert_raise(TypeError) { 2.0.send(:*, nil) } + end + + def test_div2 + assert_equal(1.0, 2.0.send(:/, 2)) + assert_equal(1.0, 2.0.send(:/, (2**32).coerce(2).first)) + assert_equal(1.0, 2.0.send(:/, 2.0)) + assert_equal(0.0, 2.0.send(:/, Float::INFINITY)) + assert_raise(TypeError) { 2.0.send(:/, nil) } + end + + def test_modulo2 + assert_equal(0.0, 2.0.send(:%, 2)) + assert_equal(0.0, 2.0.send(:%, (2**32).coerce(2).first)) + assert_equal(0.0, 2.0.send(:%, 2.0)) + assert_raise(TypeError) { 2.0.send(:%, nil) } + end + + def test_modulo3 + bug6048 = '[ruby-core:42726]' + assert_equal(4.2, 4.2.send(:%, Float::INFINITY), bug6048) + assert_equal(4.2, 4.2 % Float::INFINITY, bug6048) + assert_is_minus_zero(-0.0 % 4.2) + assert_is_minus_zero(-0.0.send :%, 4.2) + assert_raise(ZeroDivisionError, bug6048) { 4.2.send(:%, 0.0) } + assert_raise(ZeroDivisionError, bug6048) { 4.2 % 0.0 } + assert_raise(ZeroDivisionError, bug6048) { 42.send(:%, 0) } + assert_raise(ZeroDivisionError, bug6048) { 42 % 0 } + end + + def test_modulo4 + assert_predicate((0.0).modulo(Float::NAN), :nan?) + assert_predicate((1.0).modulo(Float::NAN), :nan?) + assert_predicate(Float::INFINITY.modulo(1), :nan?) + end + + def test_divmod2 + assert_equal([1.0, 0.0], 2.0.divmod(2)) + assert_equal([1.0, 0.0], 2.0.divmod((2**32).coerce(2).first)) + assert_equal([1.0, 0.0], 2.0.divmod(2.0)) + assert_raise(TypeError) { 2.0.divmod(nil) } + + inf = Float::INFINITY + assert_raise(ZeroDivisionError) {inf.divmod(0)} + + a, b = (2.0**32).divmod(1.0) + assert_equal(2**32, a) + assert_equal(0, b) + end + + def test_pow + assert_equal(1.0, 1.0 ** (2**32)) + assert_equal(1.0, 1.0 ** 1.0) + assert_raise(TypeError) { 1.0 ** nil } + end + + def test_eql + inf = Float::INFINITY + nan = Float::NAN + assert_operator(1.0, :eql?, 1.0) + assert_operator(inf, :eql?, inf) + assert_not_operator(nan, :eql?, nan) + assert_not_operator(1.0, :eql?, nil) + + assert_equal(1.0, 1) + assert_not_equal(1.0, 2**32) + assert_not_equal(1.0, nan) + assert_not_equal(1.0, nil) + end + + def test_cmp + inf = Float::INFINITY + nan = Float::NAN + assert_equal(0, 1.0 <=> 1.0) + assert_equal(1, 1.0 <=> 0.0) + assert_equal(-1, 1.0 <=> 2.0) + assert_nil(1.0 <=> nil) + assert_nil(1.0 <=> nan) + assert_nil(nan <=> 1.0) + + assert_equal(0, 1.0 <=> 1) + assert_equal(1, 1.0 <=> 0) + assert_equal(-1, 1.0 <=> 2) + + assert_equal(-1, 1.0 <=> 2**32) + + assert_equal(1, inf <=> (Float::MAX.to_i*2)) + assert_equal(-1, -inf <=> (-Float::MAX.to_i*2)) + assert_equal(-1, (Float::MAX.to_i*2) <=> inf) + assert_equal(1, (-Float::MAX.to_i*2) <=> -inf) + + bug3609 = '[ruby-core:31470]' + def (pinf = Object.new).infinite?; +1 end + def (ninf = Object.new).infinite?; -1 end + def (fin = Object.new).infinite?; nil end + nonum = Object.new + assert_equal(0, inf <=> pinf, bug3609) + assert_equal(1, inf <=> fin, bug3609) + assert_equal(1, inf <=> ninf, bug3609) + assert_nil(inf <=> nonum, bug3609) + assert_equal(-1, -inf <=> pinf, bug3609) + assert_equal(-1, -inf <=> fin, bug3609) + assert_equal(0, -inf <=> ninf, bug3609) + assert_nil(-inf <=> nonum, bug3609) + + assert_raise(ArgumentError) { 1.0 > nil } + assert_raise(ArgumentError) { 1.0 >= nil } + assert_raise(ArgumentError) { 1.0 < nil } + assert_raise(ArgumentError) { 1.0 <= nil } + end + + def test_zero_p + assert_predicate(0.0, :zero?) + assert_not_predicate(1.0, :zero?) + end + + def test_infinite_p + inf = Float::INFINITY + assert_equal(1, inf.infinite?) + assert_equal(-1, (-inf).infinite?) + assert_nil(1.0.infinite?) + end + + def test_finite_p + inf = Float::INFINITY + assert_not_predicate(inf, :finite?) + assert_not_predicate(-inf, :finite?) + assert_predicate(1.0, :finite?) + end + + def test_floor_ceil_round_truncate + assert_equal(1, 1.5.floor) + assert_equal(2, 1.5.ceil) + assert_equal(2, 1.5.round) + assert_equal(1, 1.5.truncate) + + assert_equal(2, 2.0.floor) + assert_equal(2, 2.0.ceil) + assert_equal(2, 2.0.round) + assert_equal(2, 2.0.truncate) + + assert_equal(-2, (-1.5).floor) + assert_equal(-1, (-1.5).ceil) + assert_equal(-2, (-1.5).round) + assert_equal(-1, (-1.5).truncate) + + assert_equal(-2, (-2.0).floor) + assert_equal(-2, (-2.0).ceil) + assert_equal(-2, (-2.0).round) + assert_equal(-2, (-2.0).truncate) + + inf = Float::INFINITY + assert_raise(FloatDomainError) { inf.floor } + assert_raise(FloatDomainError) { inf.ceil } + assert_raise(FloatDomainError) { inf.round } + assert_raise(FloatDomainError) { inf.truncate } + end + + def test_round_with_precision + assert_equal(1.100, 1.111.round(1)) + assert_equal(1.110, 1.111.round(2)) + assert_equal(11110.0, 11111.1.round(-1)) + assert_equal(11100.0, 11111.1.round(-2)) + + assert_equal(10**300, 1.1e300.round(-300)) + assert_equal(-10**300, -1.1e300.round(-300)) + assert_equal(1.0e-300, 1.1e-300.round(300)) + assert_equal(-1.0e-300, -1.1e-300.round(300)) + + bug5227 = '[ruby-core:39093]' + assert_equal(42.0, 42.0.round(308), bug5227) + assert_equal(1.0e307, 1.0e307.round(2), bug5227) + + assert_raise(TypeError) {1.0.round("4")} + assert_raise(TypeError) {1.0.round(nil)} + def (prec = Object.new).to_int; 2; end + assert_equal(1.0, 0.998.round(prec)) + end + + VS = [ + 18446744073709551617.0, + 18446744073709551616.0, + 18446744073709551615.8, + 18446744073709551615.5, + 18446744073709551615.2, + 18446744073709551615.0, + 18446744073709551614.0, + + 4611686018427387905.0, + 4611686018427387904.0, + 4611686018427387903.8, + 4611686018427387903.5, + 4611686018427387903.2, + 4611686018427387903.0, + 4611686018427387902.0, + + 4294967297.0, + 4294967296.0, + 4294967295.8, + 4294967295.5, + 4294967295.2, + 4294967295.0, + 4294967294.0, + + 1073741825.0, + 1073741824.0, + 1073741823.8, + 1073741823.5, + 1073741823.2, + 1073741823.0, + 1073741822.0, + + -1073741823.0, + -1073741824.0, + -1073741824.2, + -1073741824.5, + -1073741824.8, + -1073741825.0, + -1073741826.0, + + -4294967295.0, + -4294967296.0, + -4294967296.2, + -4294967296.5, + -4294967296.8, + -4294967297.0, + -4294967298.0, + + -4611686018427387903.0, + -4611686018427387904.0, + -4611686018427387904.2, + -4611686018427387904.5, + -4611686018427387904.8, + -4611686018427387905.0, + -4611686018427387906.0, + + -18446744073709551615.0, + -18446744073709551616.0, + -18446744073709551616.2, + -18446744073709551616.5, + -18446744073709551616.8, + -18446744073709551617.0, + -18446744073709551618.0, + ] + + def test_truncate + VS.each {|f| + i = f.truncate + assert_equal(i, f.to_i) + if f < 0 + assert_operator(i, :<, 0) + else + assert_operator(i, :>, 0) + end + assert_operator(i.abs, :<=, f.abs) + d = f.abs - i.abs + assert_operator(0, :<=, d) + assert_operator(d, :<, 1) + } + end + + def test_ceil + VS.each {|f| + i = f.ceil + if f < 0 + assert_operator(i, :<, 0) + else + assert_operator(i, :>, 0) + end + assert_operator(i, :>=, f) + d = f - i + assert_operator(-1, :<, d) + assert_operator(d, :<=, 0) + } + end + + def test_floor + VS.each {|f| + i = f.floor + if f < 0 + assert_operator(i, :<, 0) + else + assert_operator(i, :>, 0) + end + assert_operator(i, :<=, f) + d = f - i + assert_operator(0, :<=, d) + assert_operator(d, :<, 1) + } + end + + def test_round + VS.each {|f| + msg = "round(#{f})" + i = f.round + if f < 0 + assert_operator(i, :<, 0, msg) + else + assert_operator(i, :>, 0, msg) + end + d = f - i + assert_operator(-0.5, :<=, d, msg) + assert_operator(d, :<=, 0.5, msg) + } + end + + def test_Float + assert_in_delta(0.125, Float("0.1_2_5"), 0.00001) + assert_in_delta(0.125, "0.1_2_5__".to_f, 0.00001) + assert_equal(1, suppress_warning {Float(([1] * 10000).join)}.infinite?) + assert_not_predicate(Float(([1] * 10000).join("_")), :infinite?) # is it really OK? + assert_raise(ArgumentError) { Float("1.0\x001") } + assert_equal(15.9375, Float('0xf.fp0')) + assert_raise(ArgumentError) { Float('0x') } + assert_equal(15, Float('0xf')) + assert_equal(15, Float('0xfp0')) + assert_raise(ArgumentError) { Float('0xfp') } + assert_raise(ArgumentError) { Float('0xf.') } + assert_raise(ArgumentError) { Float('0xf.p') } + assert_raise(ArgumentError) { Float('0xf.p0') } + assert_raise(ArgumentError) { Float('0xf.f') } + assert_raise(ArgumentError) { Float('0xf.fp') } + assert_equal(Float::INFINITY, Float('0xf.fp1000000000000000')) + assert_equal(1, suppress_warning {Float("1e10_00")}.infinite?) + assert_raise(TypeError) { Float(nil) } + o = Object.new + def o.to_f; inf = Float::INFINITY; inf/inf; end + assert_predicate(Float(o), :nan?) + end + + def test_invalid_str + bug4310 = '[ruby-core:34820]' + assert_raise(ArgumentError, bug4310) {under_gc_stress {Float('a'*10000)}} + end + + def test_num2dbl + assert_raise(ArgumentError) do + 1.0.step(2.0, "0.5") {} + end + assert_raise(TypeError) do + 1.0.step(2.0, nil) {} + end + end + + def test_sleep_with_Float + assert_nothing_raised("[ruby-core:23282]") do + sleep(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1) + end + end + + def test_step + 1000.times do + a = rand + b = a+rand*1000 + s = (b - a) / 10 + assert_equal(11, (a..b).step(s).to_a.length) + end + + (1.0..12.7).step(1.3).each do |n| + assert_operator(n, :<=, 12.7) + end + + assert_equal([5.0, 4.0, 3.0, 2.0], 5.0.step(1.5, -1).to_a) + end + + def test_step2 + assert_equal([0.0], 0.0.step(1.0, Float::INFINITY).to_a) + end + + def test_step_excl + 1000.times do + a = rand + b = a+rand*1000 + s = (b - a) / 10 + assert_equal(10, (a...b).step(s).to_a.length) + end + + assert_equal([1.0, 2.9, 4.8, 6.699999999999999], (1.0...6.8).step(1.9).to_a) + + e = 1+1E-12 + (1.0 ... e).step(1E-16) do |n| + assert_operator(n, :<=, e) + end + end + + def test_singleton_method + # flonum on 64bit platform + assert_raise(TypeError) { a = 1.0; def a.foo; end } + # always not flonum + assert_raise(TypeError) { a = Float::INFINITY; def a.foo; end } + end + + def test_long_string + assert_separately([], <<-'end;') + assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9) + end; + end + + def test_next_float + smallest = 0.0.next_float + assert_equal(-Float::MAX, (-Float::INFINITY).next_float) + assert_operator(-Float::MAX, :<, (-Float::MAX).next_float) + assert_equal(Float::EPSILON/2, (-1.0).next_float + 1.0) + assert_operator(0.0, :<, smallest) + assert_operator([0.0, smallest], :include?, smallest/2) + assert_equal(Float::EPSILON, 1.0.next_float - 1.0) + assert_equal(Float::INFINITY, Float::MAX.next_float) + assert_equal(Float::INFINITY, Float::INFINITY.next_float) + assert_predicate(Float::NAN.next_float, :nan?) + end + + def test_prev_float + smallest = 0.0.next_float + assert_equal(-Float::INFINITY, (-Float::INFINITY).prev_float) + assert_equal(-Float::INFINITY, (-Float::MAX).prev_float) + assert_equal(-Float::EPSILON, (-1.0).prev_float + 1.0) + assert_equal(-smallest, 0.0.prev_float) + assert_operator([0.0, 0.0.prev_float], :include?, 0.0.prev_float/2) + assert_equal(-Float::EPSILON/2, 1.0.prev_float - 1.0) + assert_operator(Float::MAX, :>, Float::MAX.prev_float) + assert_equal(Float::MAX, Float::INFINITY.prev_float) + assert_predicate(Float::NAN.prev_float, :nan?) + end + + def test_next_prev_float_zero + z = 0.0.next_float.prev_float + assert_equal(0.0, z) + assert_equal(Float::INFINITY, 1.0/z) + z = 0.0.prev_float.next_float + assert_equal(0.0, z) + assert_equal(-Float::INFINITY, 1.0/z) + end + + def test_hash_0 + bug10979 = '[ruby-core:68541] [Bug #10979]' + assert_equal(+0.0.hash, -0.0.hash) + assert_operator(+0.0, :eql?, -0.0) + h = {0.0 => bug10979} + assert_equal(bug10979, h[-0.0]) + end +end diff --git a/jni/ruby/test/ruby/test_fnmatch.rb b/jni/ruby/test/ruby/test_fnmatch.rb new file mode 100644 index 0000000..a0eab54 --- /dev/null +++ b/jni/ruby/test/ruby/test_fnmatch.rb @@ -0,0 +1,131 @@ +require 'test/unit' + +class TestFnmatch < Test::Unit::TestCase + + def bracket_test(s, t) # `s' should start with neither '!' nor '^' + 0x21.upto(0x7E) do |i| + assert_equal(t.include?(i.chr), File.fnmatch("[#{s}]", i.chr, File::FNM_DOTMATCH)) + assert_equal(t.include?(i.chr), !File.fnmatch("[^#{s}]", i.chr, File::FNM_DOTMATCH)) + assert_equal(t.include?(i.chr), !File.fnmatch("[!#{s}]", i.chr, File::FNM_DOTMATCH)) + end + end + def test_fnmatch + assert_file.for("[ruby-dev:22819]").fnmatch('\[1\]' , '[1]') + assert_file.for("[ruby-dev:22815]").fnmatch('*?', 'a') + assert_file.fnmatch('*/', 'a/') + assert_file.fnmatch('\[1\]' , '[1]', File::FNM_PATHNAME) + assert_file.fnmatch('*?', 'a', File::FNM_PATHNAME) + assert_file.fnmatch('*/', 'a/', File::FNM_PATHNAME) + # text + assert_file.fnmatch('cat', 'cat') + assert_file.not_fnmatch('cat', 'category') + assert_file.not_fnmatch('cat', 'wildcat') + # '?' matches any one character + assert_file.fnmatch('?at', 'cat') + assert_file.fnmatch('c?t', 'cat') + assert_file.fnmatch('ca?', 'cat') + assert_file.fnmatch('?a?', 'cat') + assert_file.not_fnmatch('c??t', 'cat') + assert_file.not_fnmatch('??at', 'cat') + assert_file.not_fnmatch('ca??', 'cat') + # '*' matches any number (including 0) of any characters + assert_file.fnmatch('c*', 'cats') + assert_file.fnmatch('c*ts', 'cats') + assert_file.fnmatch('*ts', 'cats') + assert_file.fnmatch('*c*a*t*s*', 'cats') + assert_file.not_fnmatch('c*t', 'cats') + assert_file.not_fnmatch('*abc', 'abcabz') + assert_file.fnmatch('*abz', 'abcabz') + assert_file.not_fnmatch('a*abc', 'abc') + assert_file.fnmatch('a*bc', 'abc') + assert_file.not_fnmatch('a*bc', 'abcd') + # [seq] : matches any character listed between bracket + # [!seq] or [^seq] : matches any character except those listed between bracket + bracket_test("bd-gikl-mosv-x", "bdefgiklmosvwx") + # escaping character + assert_file.fnmatch('\?', '?') + assert_file.not_fnmatch('\?', '\?') + assert_file.not_fnmatch('\?', 'a') + assert_file.not_fnmatch('\?', '\a') + assert_file.fnmatch('\*', '*') + assert_file.not_fnmatch('\*', '\*') + assert_file.not_fnmatch('\*', 'cats') + assert_file.not_fnmatch('\*', '\cats') + assert_file.fnmatch('\a', 'a') + assert_file.not_fnmatch('\a', '\a') + assert_file.fnmatch('[a\-c]', 'a') + assert_file.fnmatch('[a\-c]', '-') + assert_file.fnmatch('[a\-c]', 'c') + assert_file.not_fnmatch('[a\-c]', 'b') + assert_file.not_fnmatch('[a\-c]', '\\') + # escaping character loses its meaning if FNM_NOESCAPE is set + assert_file.not_fnmatch('\?', '?', File::FNM_NOESCAPE) + assert_file.fnmatch('\?', '\?', File::FNM_NOESCAPE) + assert_file.not_fnmatch('\?', 'a', File::FNM_NOESCAPE) + assert_file.fnmatch('\?', '\a', File::FNM_NOESCAPE) + assert_file.not_fnmatch('\*', '*', File::FNM_NOESCAPE) + assert_file.fnmatch('\*', '\*', File::FNM_NOESCAPE) + assert_file.not_fnmatch('\*', 'cats', File::FNM_NOESCAPE) + assert_file.fnmatch('\*', '\cats', File::FNM_NOESCAPE) + assert_file.not_fnmatch('\a', 'a', File::FNM_NOESCAPE) + assert_file.fnmatch('\a', '\a', File::FNM_NOESCAPE) + assert_file.fnmatch('[a\-c]', 'a', File::FNM_NOESCAPE) + assert_file.not_fnmatch('[a\-c]', '-', File::FNM_NOESCAPE) + assert_file.fnmatch('[a\-c]', 'c', File::FNM_NOESCAPE) + assert_file.fnmatch('[a\-c]', 'b', File::FNM_NOESCAPE) # '\\' < 'b' < 'c' + assert_file.fnmatch('[a\-c]', '\\', File::FNM_NOESCAPE) + # case is ignored if FNM_CASEFOLD is set + assert_file.not_fnmatch('cat', 'CAT') + assert_file.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) + assert_file.not_fnmatch('[a-z]', 'D') + assert_file.fnmatch('[a-z]', 'D', File::FNM_CASEFOLD) + assert_file.not_fnmatch('[abc]', 'B') + assert_file.fnmatch('[abc]', 'B', File::FNM_CASEFOLD) + # wildcard doesn't match '/' if FNM_PATHNAME is set + assert_file.fnmatch('foo?boo', 'foo/boo') + assert_file.fnmatch('foo*', 'foo/boo') + assert_file.not_fnmatch('foo?boo', 'foo/boo', File::FNM_PATHNAME) + assert_file.not_fnmatch('foo*', 'foo/boo', File::FNM_PATHNAME) + # wildcard matches leading period if FNM_DOTMATCH is set + assert_file.not_fnmatch('*', '.profile') + assert_file.fnmatch('*', '.profile', File::FNM_DOTMATCH) + assert_file.fnmatch('.*', '.profile') + assert_file.fnmatch('*', 'dave/.profile') + assert_file.fnmatch('*/*', 'dave/.profile') + assert_file.not_fnmatch('*/*', 'dave/.profile', File::FNM_PATHNAME) + assert_file.fnmatch('*/*', 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) + # recursive matching + assert_file.fnmatch('**/foo', 'a/b/c/foo', File::FNM_PATHNAME) + assert_file.fnmatch('**/foo', '/foo', File::FNM_PATHNAME) + assert_file.not_fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME) + assert_file.fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) + assert_file.fnmatch('**/foo', '/root/foo', File::FNM_PATHNAME) + assert_file.fnmatch('**/foo', 'c:/root/foo', File::FNM_PATHNAME) + end + + def test_extglob + feature5422 = '[ruby-core:40037]' + assert_file.for(feature5422).not_fnmatch?( "{.g,t}*", ".gem") + assert_file.for(feature5422).fnmatch?("{.g,t}*", ".gem", File::FNM_EXTGLOB) + end + + def test_unmatched_encoding + bug7911 = '[ruby-dev:47069] [Bug #7911]' + path = "\u{3042}" + pattern_ascii = 'a'.encode('US-ASCII') + pattern_eucjp = path.encode('EUC-JP') + assert_nothing_raised(ArgumentError, bug7911) do + assert_file.not_fnmatch(pattern_ascii, path) + assert_file.not_fnmatch(pattern_eucjp, path) + assert_file.not_fnmatch(pattern_ascii, path, File::FNM_CASEFOLD) + assert_file.not_fnmatch(pattern_eucjp, path, File::FNM_CASEFOLD) + assert_file.fnmatch("{*,#{pattern_ascii}}", path, File::FNM_EXTGLOB) + assert_file.fnmatch("{*,#{pattern_eucjp}}", path, File::FNM_EXTGLOB) + end + end + + def test_unicode + assert_file.fnmatch("[a-\u3042]*", "\u3042") + assert_file.not_fnmatch("[a-\u3042]*", "\u3043") + end +end diff --git a/jni/ruby/test/ruby/test_gc.rb b/jni/ruby/test/ruby/test_gc.rb new file mode 100644 index 0000000..e9e4bdc --- /dev/null +++ b/jni/ruby/test/ruby/test_gc.rb @@ -0,0 +1,379 @@ +require 'test/unit' + +class TestGc < Test::Unit::TestCase + class S + def initialize(a) + @a = a + end + end + + def test_gc + prev_stress = GC.stress + GC.stress = false + + assert_nothing_raised do + 1.upto(10000) { + tmp = [0,1,2,3,4,5,6,7,8,9] + } + tmp = nil + end + l=nil + 100000.times { + l = S.new(l) + } + GC.start + assert true # reach here or dumps core + l = [] + 100000.times { + l.push([l]) + } + GC.start + assert true # reach here or dumps core + + GC.stress = prev_stress + end + + def use_rgengc? + GC::OPTS.include? 'USE_RGENGC'.freeze + end + + def test_enable_disable + GC.enable + assert_equal(false, GC.enable) + assert_equal(false, GC.disable) + assert_equal(true, GC.disable) + assert_equal(true, GC.disable) + assert_nil(GC.start) + assert_equal(true, GC.enable) + assert_equal(false, GC.enable) + ensure + GC.enable + end + + def test_start_full_mark + return unless use_rgengc? + + GC.start(full_mark: false) + assert_nil GC.latest_gc_info(:major_by) + + GC.start(full_mark: true) + assert_not_nil GC.latest_gc_info(:major_by) + end + + def test_start_immediate_sweep + GC.start(immediate_sweep: false) + assert_equal false, GC.latest_gc_info(:immediate_sweep) + + GC.start(immediate_sweep: true) + assert_equal true, GC.latest_gc_info(:immediate_sweep) + end + + def test_count + c = GC.count + GC.start + assert_operator(c, :<, GC.count) + end + + def test_stat + res = GC.stat + assert_equal(false, res.empty?) + assert_kind_of(Integer, res[:count]) + + arg = Hash.new + res = GC.stat(arg) + assert_equal(arg, res) + assert_equal(false, res.empty?) + assert_kind_of(Integer, res[:count]) + + stat, count = {}, {} + GC.start + GC.stat(stat) + ObjectSpace.count_objects(count) + assert_equal(count[:TOTAL]-count[:FREE], stat[:heap_live_slots]) + assert_equal(count[:FREE], stat[:heap_free_slots]) + + # measure again without GC.start + 1000.times{ "a" + "b" } + GC.stat(stat) + ObjectSpace.count_objects(count) + assert_equal(count[:FREE], stat[:heap_free_slots]) + end + + def test_stat_argument + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {GC.stat(:"\u{30eb 30d3 30fc}")} + end + + def test_stat_single + stat = GC.stat + assert_equal stat[:count], GC.stat(:count) + assert_raise(ArgumentError){ GC.stat(:invalid) } + end + + def test_stat_constraints + stat = GC.stat + assert_equal stat[:total_allocated_pages], stat[:heap_allocated_pages] + stat[:total_freed_pages] + assert_operator stat[:heap_sorted_length], :>=, stat[:heap_eden_pages] + stat[:heap_allocatable_pages], "stat is: " + stat.inspect + assert_equal stat[:heap_available_slots], stat[:heap_live_slots] + stat[:heap_free_slots] + stat[:heap_final_slots] + assert_equal stat[:heap_live_slots], stat[:total_allocated_objects] - stat[:total_freed_objects] - stat[:heap_final_slots] + assert_equal stat[:heap_allocated_pages], stat[:heap_eden_pages] + stat[:heap_tomb_pages] + + if use_rgengc? + assert_equal stat[:count], stat[:major_gc_count] + stat[:minor_gc_count] + end + end + + def test_latest_gc_info + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' + GC.start + count = GC.stat(:heap_free_slots) + GC.stat(:heap_allocatable_pages) * GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT] + count.times{ "a" + "b" } + assert_equal :newobj, GC.latest_gc_info[:gc_by] + eom + + GC.start + assert_equal :force, GC.latest_gc_info[:major_by] if use_rgengc? + assert_equal :method, GC.latest_gc_info[:gc_by] + assert_equal true, GC.latest_gc_info[:immediate_sweep] + + GC.stress = true + assert_equal :force, GC.latest_gc_info[:major_by] + ensure + GC.stress = false + end + + def test_latest_gc_info_argument + info = {} + GC.latest_gc_info(info) + + assert_not_empty info + assert_equal info[:gc_by], GC.latest_gc_info(:gc_by) + assert_raises(ArgumentError){ GC.latest_gc_info(:invalid) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {GC.latest_gc_info(:"\u{30eb 30d3 30fc}")} + end + + def test_singleton_method + assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:42832]") + GC.stress = true + 10.times do + obj = Object.new + def obj.foo() end + def obj.bar() raise "obj.foo is called, but this is obj.bar" end + obj.foo + end + EOS + end + + def test_singleton_method_added + assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:44436]") + class BasicObject + undef singleton_method_added + def singleton_method_added(mid) + raise + end + end + b = proc {} + class << b; end + b.clone rescue nil + GC.start + EOS + end + + def test_gc_parameter + env = { + "RUBY_GC_MALLOC_LIMIT" => "60000000", + "RUBY_GC_HEAP_INIT_SLOTS" => "100000" + } + assert_normal_exit("exit", "[ruby-core:39777]", :child_env => env) + + env = { + "RUBYOPT" => "", + "RUBY_GC_HEAP_INIT_SLOTS" => "100000" + } + assert_in_out_err([env, "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-W0", "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-W1", "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_INIT_SLOTS=100000/, "[ruby-core:39795]") + + env = { + "RUBY_GC_HEAP_GROWTH_FACTOR" => "2.0", + "RUBY_GC_HEAP_GROWTH_MAX_SLOTS" => "10000" + } + assert_normal_exit("exit", "", :child_env => env) + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_FACTOR=2.0/, "") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_MAX_SLOTS=10000/, "[ruby-core:57928]") + + env = { + "RUBY_GC_HEAP_INIT_SLOTS" => "100000", + "RUBY_GC_HEAP_FREE_SLOTS" => "10000", + "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" => "0.9", + } + assert_normal_exit("exit", "", :child_env => env) + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=0\.9/, "") + + # always full GC when RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR < 1.0 + assert_in_out_err([env, "-e", "1000_000.times{Object.new}; p(GC.stat[:minor_gc_count] < GC.stat[:major_gc_count])"], "", ['true'], //, "") if use_rgengc? + + # check obsolete + assert_in_out_err([{'RUBY_FREE_MIN' => '100'}, '-w', '-eexit'], '', [], + /RUBY_FREE_MIN is obsolete. Use RUBY_GC_HEAP_FREE_SLOTS instead/) + assert_in_out_err([{'RUBY_HEAP_MIN_SLOTS' => '100'}, '-w', '-eexit'], '', [], + /RUBY_HEAP_MIN_SLOTS is obsolete. Use RUBY_GC_HEAP_INIT_SLOTS instead/) + + env = { + "RUBY_GC_MALLOC_LIMIT" => "60000000", + "RUBY_GC_MALLOC_LIMIT_MAX" => "160000000", + "RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR" => "2.0" + } + assert_normal_exit("exit", "", :child_env => env) + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT=6000000/, "") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT_MAX=16000000/, "") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=2.0/, "") + + if use_rgengc? + env = { + "RUBY_GC_OLDMALLOC_LIMIT" => "60000000", + "RUBY_GC_OLDMALLOC_LIMIT_MAX" => "160000000", + "RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR" => "2.0" + } + assert_normal_exit("exit", "", :child_env => env) + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT=6000000/, "") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_MAX=16000000/, "") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=2.0/, "") + end + end + + def test_profiler_enabled + GC::Profiler.enable + assert_equal(true, GC::Profiler.enabled?) + GC::Profiler.disable + assert_equal(false, GC::Profiler.enabled?) + ensure + GC::Profiler.disable + end + + def test_profiler_clear + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' + GC::Profiler.enable + + GC.start + assert_equal(1, GC::Profiler.raw_data.size) + GC::Profiler.clear + assert_equal(0, GC::Profiler.raw_data.size) + + 200.times{ GC.start } + assert_equal(200, GC::Profiler.raw_data.size) + GC::Profiler.clear + assert_equal(0, GC::Profiler.raw_data.size) + eom + end + + def test_profiler_total_time + GC::Profiler.enable + GC::Profiler.clear + + GC.start + assert_operator(GC::Profiler.total_time, :>=, 0) + ensure + GC::Profiler.disable + end + + def test_finalizing_main_thread + assert_in_out_err(%w[--disable-gems], <<-EOS, ["\"finalize\""], [], "[ruby-dev:46647]") + ObjectSpace.define_finalizer(Thread.main) { p 'finalize' } + EOS + end + + def test_expand_heap + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' + GC.start + base_length = GC.stat[:heap_eden_pages] + (base_length * 500).times{ 'a' } + GC.start + assert_in_delta base_length, (v = GC.stat[:heap_eden_pages]), 1, + "invalid heap expanding (base_length: #{base_length}, GC.stat[:heap_eden_pages]: #{v})" + + a = [] + (base_length * 500).times{ a << 'a'; nil } + GC.start + assert_operator base_length, :<, GC.stat[:heap_eden_pages] + 1 + eom + end + + def test_gc_internals + assert_not_nil GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT] + assert_not_nil GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] + end + + def test_sweep_in_finalizer + bug9205 = '[ruby-core:58833] [Bug #9205]' + 2.times do + assert_ruby_status([], <<-'end;', bug9205, timeout: 60) + raise_proc = proc do |id| + GC.start + end + 1000.times do + ObjectSpace.define_finalizer(Object.new, raise_proc) + end + end; + end + end + + def test_exception_in_finalizer + bug9168 = '[ruby-core:58652] [Bug #9168]' + assert_normal_exit(<<-'end;', bug9168) + raise_proc = proc {raise} + 10000.times do + ObjectSpace.define_finalizer(Object.new, raise_proc) + Thread.handle_interrupt(RuntimeError => :immediate) {break} + Thread.handle_interrupt(RuntimeError => :on_blocking) {break} + Thread.handle_interrupt(RuntimeError => :never) {break} + end + end; + end + + def test_interrupt_in_finalizer + bug10595 = '[ruby-core:66825] [Bug #10595]' + src = <<-'end;' + pid = $$ + Thread.start do + 10.times { + sleep 0.1 + Process.kill("INT", pid) rescue break + } + sleep 5 + Process.kill("SEGV", pid) rescue nil + Process.kill("KILL", pid) rescue nil + end + f = proc {1000.times {}} + loop do + ObjectSpace.define_finalizer(Object.new, f) + end + end; + status = assert_in_out_err(["-e", src], "", [], /Interrupt/, bug10595) + unless /mswin|mingw/ =~ RUBY_PLATFORM + assert_equal("INT", Signal.signame(status.termsig)) + end + end + + def test_verify_internal_consistency + assert_nil(GC.verify_internal_consistency) + end + + def test_gc_stress_on_realloc + assert_normal_exit(<<-'end;', '[Bug #9859]') + class C + def initialize + @a = nil + @b = nil + @c = nil + @d = nil + @e = nil + @f = nil + end + end + + GC.stress = true + C.new + end; + end +end diff --git a/jni/ruby/test/ruby/test_hash.rb b/jni/ruby/test/ruby/test_hash.rb new file mode 100644 index 0000000..1bb32f6 --- /dev/null +++ b/jni/ruby/test/ruby/test_hash.rb @@ -0,0 +1,1300 @@ +# -*- coding: us-ascii -*- +require 'test/unit' +EnvUtil.suppress_warning {require 'continuation'} + +class TestHash < Test::Unit::TestCase + + def test_hash + x = @cls[1=>2, 2=>4, 3=>6] + y = @cls[1=>2, 2=>4, 3=>6] # y = {1, 2, 2, 4, 3, 6} # 1.9 doesn't support + + assert_equal(2, x[1]) + + assert(begin + for k,v in y + raise if k*2 != v + end + true + rescue + false + end) + + assert_equal(3, x.length) + assert_send([x, :has_key?, 1]) + assert_send([x, :has_value?, 4]) + assert_equal([4,6], x.values_at(2,3)) + assert_equal({1=>2, 2=>4, 3=>6}, x) + + z = y.keys.join(":") + assert_equal("1:2:3", z) + + z = y.values.join(":") + assert_equal("2:4:6", z) + assert_equal(x, y) + + y.shift + assert_equal(2, y.length) + + z = [1,2] + y[z] = 256 + assert_equal(256, y[z]) + + x = Hash.new(0) + x[1] = 1 + assert_equal(1, x[1]) + assert_equal(0, x[2]) + + x = Hash.new([]) + assert_equal([], x[22]) + assert_same(x[22], x[22]) + + x = Hash.new{[]} + assert_equal([], x[22]) + assert_not_same(x[22], x[22]) + + x = Hash.new{|h,kk| z = kk; h[kk] = kk*2} + z = 0 + assert_equal(44, x[22]) + assert_equal(22, z) + z = 0 + assert_equal(44, x[22]) + assert_equal(0, z) + x.default = 5 + assert_equal(5, x[23]) + + x = Hash.new + def x.default(k) + $z = k + self[k] = k*2 + end + $z = 0 + assert_equal(44, x[22]) + assert_equal(22, $z) + $z = 0 + assert_equal(44, x[22]) + assert_equal(0, $z) + end + + # From rubicon + + def setup + @cls ||= Hash + @h = @cls[ + 1 => 'one', 2 => 'two', 3 => 'three', + self => 'self', true => 'true', nil => 'nil', + 'nil' => nil + ] + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_bad_initialize_copy + h = Class.new(Hash) { + def initialize_copy(h) + super(Object.new) + end + }.new + assert_raise(TypeError) { h.dup } + end + + def test_clear_initialize_copy + h = @cls[1=>2] + h.instance_eval {initialize_copy({})} + assert_empty(h) + end + + def test_self_initialize_copy + h = @cls[1=>2] + h.instance_eval {initialize_copy(h)} + assert_equal(2, h[1]) + end + + def test_dup_will_rehash + set1 = @cls[] + set2 = @cls[set1 => true] + + set1[set1] = true + + assert_equal set2, set2.dup + end + + def test_s_AREF + h = @cls["a" => 100, "b" => 200] + assert_equal(100, h['a']) + assert_equal(200, h['b']) + assert_nil(h['c']) + + h = @cls.[]("a" => 100, "b" => 200) + assert_equal(100, h['a']) + assert_equal(200, h['b']) + assert_nil(h['c']) + end + + def test_s_new + h = @cls.new + assert_instance_of(@cls, h) + assert_nil(h.default) + assert_nil(h['spurious']) + + h = @cls.new('default') + assert_instance_of(@cls, h) + assert_equal('default', h.default) + assert_equal('default', h['spurious']) + + end + + def test_AREF # '[]' + t = Time.now + h = @cls[ + 1 => 'one', 2 => 'two', 3 => 'three', + self => 'self', t => 'time', nil => 'nil', + 'nil' => nil + ] + + assert_equal('one', h[1]) + assert_equal('two', h[2]) + assert_equal('three', h[3]) + assert_equal('self', h[self]) + assert_equal('time', h[t]) + assert_equal('nil', h[nil]) + assert_equal(nil, h['nil']) + assert_equal(nil, h['koala']) + + h1 = h.dup + h1.default = :default + + assert_equal('one', h1[1]) + assert_equal('two', h1[2]) + assert_equal('three', h1[3]) + assert_equal('self', h1[self]) + assert_equal('time', h1[t]) + assert_equal('nil', h1[nil]) + assert_equal(nil, h1['nil']) + assert_equal(:default, h1['koala']) + + + end + + def test_ASET # '[]=' + t = Time.now + h = @cls.new + h[1] = 'one' + h[2] = 'two' + h[3] = 'three' + h[self] = 'self' + h[t] = 'time' + h[nil] = 'nil' + h['nil'] = nil + assert_equal('one', h[1]) + assert_equal('two', h[2]) + assert_equal('three', h[3]) + assert_equal('self', h[self]) + assert_equal('time', h[t]) + assert_equal('nil', h[nil]) + assert_equal(nil, h['nil']) + assert_equal(nil, h['koala']) + + h[1] = 1 + h[nil] = 99 + h['nil'] = nil + z = [1,2] + h[z] = 256 + assert_equal(1, h[1]) + assert_equal('two', h[2]) + assert_equal('three', h[3]) + assert_equal('self', h[self]) + assert_equal('time', h[t]) + assert_equal(99, h[nil]) + assert_equal(nil, h['nil']) + assert_equal(nil, h['koala']) + assert_equal(256, h[z]) + end + + def test_AREF_fstring_key + h = {"abc" => 1} + before = GC.stat(:total_allocated_objects) + 5.times{ h["abc"] } + assert_equal before, GC.stat(:total_allocated_objects) + end + + def test_ASET_fstring_key + a, b = {}, {} + assert_equal 1, a["abc"] = 1 + assert_equal 1, b["abc"] = 1 + assert_same a.keys[0], b.keys[0] + end + + def test_NEWHASH_fstring_key + a = {"ABC" => :t} + b = {"ABC" => :t} + assert_same a.keys[0], b.keys[0] + assert_same "ABC".freeze, a.keys[0] + end + + def test_EQUAL # '==' + h1 = @cls[ "a" => 1, "c" => 2 ] + h2 = @cls[ "a" => 1, "c" => 2, 7 => 35 ] + h3 = @cls[ "a" => 1, "c" => 2, 7 => 35 ] + h4 = @cls[ ] + assert_equal(h1, h1) + assert_equal(h2, h2) + assert_equal(h3, h3) + assert_equal(h4, h4) + assert_not_equal(h1, h2) + assert_equal(h2, h3) + assert_not_equal(h3, h4) + end + + def test_clear + assert_operator(@h.size, :>, 0) + @h.clear + assert_equal(0, @h.size) + assert_nil(@h[1]) + end + + def test_clone + for taint in [ false, true ] + for frozen in [ false, true ] + a = @h.clone + a.taint if taint + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert_not_same(a, b) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + end + + def test_default + assert_nil(@h.default) + h = @cls.new(:xyzzy) + assert_equal(:xyzzy, h.default) + end + + def test_default= + assert_nil(@h.default) + @h.default = :xyzzy + assert_equal(:xyzzy, @h.default) + end + + def test_delete + h1 = @cls[ 1 => 'one', 2 => 'two', true => 'true' ] + h2 = @cls[ 1 => 'one', 2 => 'two' ] + h3 = @cls[ 2 => 'two' ] + + assert_equal('true', h1.delete(true)) + assert_equal(h2, h1) + + assert_equal('one', h1.delete(1)) + assert_equal(h3, h1) + + assert_equal('two', h1.delete(2)) + assert_equal(@cls[], h1) + + assert_nil(h1.delete(99)) + assert_equal(@cls[], h1) + + assert_equal('default 99', h1.delete(99) {|i| "default #{i}" }) + end + + def test_delete_if + base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] + h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] + h2 = @cls[ 2 => false, 'cat' => 99 ] + h3 = @cls[ 2 => false ] + + h = base.dup + assert_equal(h, h.delete_if { false }) + assert_equal(@cls[], h.delete_if { true }) + + h = base.dup + assert_equal(h1, h.delete_if {|k,v| k.instance_of?(String) }) + assert_equal(h1, h) + + h = base.dup + assert_equal(h2, h.delete_if {|k,v| v.instance_of?(String) }) + assert_equal(h2, h) + + h = base.dup + assert_equal(h3, h.delete_if {|k,v| v }) + assert_equal(h3, h) + + h = base.dup + n = 0 + h.delete_if {|*a| + n += 1 + assert_equal(2, a.size) + assert_equal(base[a[0]], a[1]) + h.shift + true + } + assert_equal(base.size, n) + end + + def test_keep_if + h = @cls[1=>2,3=>4,5=>6] + assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 }) + h = @cls[1=>2,3=>4,5=>6] + assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true}) + end + + def test_dup + for taint in [ false, true ] + for frozen in [ false, true ] + a = @h.dup + a.taint if taint + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert_not_same(a, b) + assert_equal(false, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + end + + def test_dup_equality + h = @cls['k' => 'v'] + assert_equal(h, h.dup) + h1 = @cls[h => 1] + assert_equal(h1, h1.dup) + h[1] = 2 + assert_equal(h1, h1.dup) + end + + def test_each + count = 0 + @cls[].each { |k, v| count + 1 } + assert_equal(0, count) + + h = @h + h.each do |k, v| + assert_equal(v, h.delete(k)) + end + assert_equal(@cls[], h) + + h = @cls[] + h[1] = 1 + h[2] = 2 + assert_equal([[1,1],[2,2]], h.each.to_a) + end + + def test_each_key + count = 0 + @cls[].each_key { |k| count + 1 } + assert_equal(0, count) + + h = @h + h.each_key do |k| + h.delete(k) + end + assert_equal(@cls[], h) + end + + def test_each_pair + count = 0 + @cls[].each_pair { |k, v| count + 1 } + assert_equal(0, count) + + h = @h + h.each_pair do |k, v| + assert_equal(v, h.delete(k)) + end + assert_equal(@cls[], h) + end + + def test_each_value + res = [] + @cls[].each_value { |v| res << v } + assert_equal(0, [].length) + + @h.each_value { |v| res << v } + assert_equal(0, [].length) + + expected = [] + @h.each { |k, v| expected << v } + + assert_equal([], expected - res) + assert_equal([], res - expected) + end + + def test_empty? + assert_empty(@cls[]) + assert_not_empty(@h) + end + + def test_fetch + assert_equal('gumbygumby', @h.fetch('gumby') {|k| k * 2 }) + assert_equal('pokey', @h.fetch('gumby', 'pokey')) + + assert_equal('one', @h.fetch(1)) + assert_equal(nil, @h.fetch('nil')) + assert_equal('nil', @h.fetch(nil)) + end + + def test_fetch_error + assert_raise(KeyError) { @cls[].fetch(1) } + assert_raise(KeyError) { @h.fetch('gumby') } + e = assert_raise(KeyError) { @h.fetch('gumby'*20) } + assert_match(/key not found: "gumbygumby/, e.message) + assert_match(/\.\.\.\z/, e.message) + end + + def test_key2? + assert_not_send([@cls[], :key?, 1]) + assert_not_send([@cls[], :key?, nil]) + assert_send([@h, :key?, nil]) + assert_send([@h, :key?, 1]) + assert_not_send([@h, :key?, 'gumby']) + end + + def test_value? + assert_not_send([@cls[], :value?, 1]) + assert_not_send([@cls[], :value?, nil]) + assert_send([@h, :value?, 'one']) + assert_send([@h, :value?, nil]) + assert_not_send([@h, :value?, 'gumby']) + end + + def test_include? + assert_not_send([@cls[], :include?, 1]) + assert_not_send([@cls[], :include?, nil]) + assert_send([@h, :include?, nil]) + assert_send([@h, :include?, 1]) + assert_not_send([@h, :include?, 'gumby']) + end + + def test_key + assert_equal(1, @h.key('one')) + assert_equal(nil, @h.key('nil')) + assert_equal('nil', @h.key(nil)) + + assert_equal(nil, @h.key('gumby')) + assert_equal(nil, @cls[].key('gumby')) + end + + def test_values_at + res = @h.values_at('dog', 'cat', 'horse') + assert_equal(3, res.length) + assert_equal([nil, nil, nil], res) + + res = @h.values_at + assert_equal(0, res.length) + + res = @h.values_at(3, 2, 1, nil) + assert_equal 4, res.length + assert_equal %w( three two one nil ), res + + res = @h.values_at(3, 99, 1, nil) + assert_equal 4, res.length + assert_equal ['three', nil, 'one', 'nil'], res + end + + + def test_invert + h = @h.invert + assert_equal(1, h['one']) + assert_equal(true, h['true']) + assert_equal(nil, h['nil']) + + h.each do |k, v| + assert_send([@h, :key?, v]) # not true in general, but works here + end + + h = @cls[ 'a' => 1, 'b' => 2, 'c' => 1].invert + assert_equal(2, h.length) + assert_include(%w[a c], h[1]) + assert_equal('b', h[2]) + end + + def test_key? + assert_not_send([@cls[], :key?, 1]) + assert_not_send([@cls[], :key?, nil]) + assert_send([@h, :key?, nil]) + assert_send([@h, :key?, 1]) + assert_not_send([@h, :key?, 'gumby']) + end + + def test_keys + assert_equal([], @cls[].keys) + + keys = @h.keys + expected = [] + @h.each { |k, v| expected << k } + assert_equal([], keys - expected) + assert_equal([], expected - keys) + end + + def test_length + assert_equal(0, @cls[].length) + assert_equal(7, @h.length) + end + + def test_member? + assert_not_send([@cls[], :member?, 1]) + assert_not_send([@cls[], :member?, nil]) + assert_send([@h, :member?, nil]) + assert_send([@h, :member?, 1]) + assert_not_send([@h, :member?, 'gumby']) + end + + def test_rehash + a = [ "a", "b" ] + c = [ "c", "d" ] + h = @cls[ a => 100, c => 300 ] + assert_equal(100, h[a]) + a[0] = "z" + assert_nil(h[a]) + h.rehash + assert_equal(100, h[a]) + end + + def test_reject + assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].reject {|k, v| k + v < 7 }) + + base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] + h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] + h2 = @cls[ 2 => false, 'cat' => 99 ] + h3 = @cls[ 2 => false ] + + h = base.dup + assert_equal(h, h.reject { false }) + assert_equal(@cls[], h.reject { true }) + + h = base.dup + assert_equal(h1, h.reject {|k,v| k.instance_of?(String) }) + + assert_equal(h2, h.reject {|k,v| v.instance_of?(String) }) + + assert_equal(h3, h.reject {|k,v| v }) + assert_equal(base, h) + + h.instance_variable_set(:@foo, :foo) + h.default = 42 + h.taint + h = EnvUtil.suppress_warning {h.reject {false}} + assert_instance_of(Hash, h) + assert_not_predicate(h, :tainted?) + assert_nil(h.default) + assert_not_send([h, :instance_variable_defined?, :@foo]) + end + + def test_reject! + base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] + h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] + h2 = @cls[ 2 => false, 'cat' => 99 ] + h3 = @cls[ 2 => false ] + + h = base.dup + assert_equal(nil, h.reject! { false }) + assert_equal(@cls[], h.reject! { true }) + + h = base.dup + assert_equal(h1, h.reject! {|k,v| k.instance_of?(String) }) + assert_equal(h1, h) + + h = base.dup + assert_equal(h2, h.reject! {|k,v| v.instance_of?(String) }) + assert_equal(h2, h) + + h = base.dup + assert_equal(h3, h.reject! {|k,v| v }) + assert_equal(h3, h) + end + + def test_replace + h = @cls[ 1 => 2, 3 => 4 ] + h1 = h.replace(@cls[ 9 => 8, 7 => 6 ]) + assert_equal(h, h1) + assert_equal(8, h[9]) + assert_equal(6, h[7]) + assert_nil(h[1]) + assert_nil(h[2]) + end + + def test_replace_bug9230 + h = @cls[] + h.replace(@cls[]) + assert_empty h + + h = @cls[] + h.replace(@cls[].compare_by_identity) + assert_predicate(h, :compare_by_identity?) + end + + def test_shift + h = @h.dup + + @h.length.times { + k, v = h.shift + assert_send([@h, :key?, k]) + assert_equal(@h[k], v) + } + + assert_equal(0, h.length) + end + + def test_size + assert_equal(0, @cls[].length) + assert_equal(7, @h.length) + end + + def test_sort + h = @cls[].sort + assert_equal([], h) + + h = @cls[ 1 => 1, 2 => 1 ].sort + assert_equal([[1,1], [2,1]], h) + + h = @cls[ 'cat' => 'feline', 'ass' => 'asinine', 'bee' => 'beeline' ] + h1 = h.sort + assert_equal([ %w(ass asinine), %w(bee beeline), %w(cat feline)], h1) + end + + def test_store + t = Time.now + h = @cls.new + h.store(1, 'one') + h.store(2, 'two') + h.store(3, 'three') + h.store(self, 'self') + h.store(t, 'time') + h.store(nil, 'nil') + h.store('nil', nil) + assert_equal('one', h[1]) + assert_equal('two', h[2]) + assert_equal('three', h[3]) + assert_equal('self', h[self]) + assert_equal('time', h[t]) + assert_equal('nil', h[nil]) + assert_equal(nil, h['nil']) + assert_equal(nil, h['koala']) + + h.store(1, 1) + h.store(nil, 99) + h.store('nil', nil) + assert_equal(1, h[1]) + assert_equal('two', h[2]) + assert_equal('three', h[3]) + assert_equal('self', h[self]) + assert_equal('time', h[t]) + assert_equal(99, h[nil]) + assert_equal(nil, h['nil']) + assert_equal(nil, h['koala']) + end + + def test_to_a + assert_equal([], @cls[].to_a) + assert_equal([[1,2]], @cls[ 1=>2 ].to_a) + a = @cls[ 1=>2, 3=>4, 5=>6 ].to_a + assert_equal([1,2], a.delete([1,2])) + assert_equal([3,4], a.delete([3,4])) + assert_equal([5,6], a.delete([5,6])) + assert_equal(0, a.length) + + h = @cls[ 1=>2, 3=>4, 5=>6 ] + h.taint + a = h.to_a + assert_equal(true, a.tainted?) + end + + def test_to_hash + h = @h.to_hash + assert_equal(@h, h) + assert_instance_of(@cls, h) + end + + def test_to_h + h = @h.to_h + assert_equal(@h, h) + assert_instance_of(Hash, h) + end + + def test_nil_to_h + h = nil.to_h + assert_equal({}, h) + assert_nil(h.default) + assert_nil(h.default_proc) + end + + def test_to_s + h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ] + assert_equal(h.inspect, h.to_s) + $, = ":" + assert_equal(h.inspect, h.to_s) + h = @cls[] + assert_equal(h.inspect, h.to_s) + ensure + $, = nil + end + + def test_update + h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ] + h2 = @cls[ 2 => 'two', 4 => 'four' ] + + ha = @cls[ 1 => 2, 2 => 'two', 3 => 4, 4 => 'four' ] + hb = @cls[ 1 => 2, 2 => 3, 3 => 4, 4 => 'four' ] + + assert_equal(ha, h1.update(h2)) + assert_equal(ha, h1) + + h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ] + h2 = @cls[ 2 => 'two', 4 => 'four' ] + + assert_equal(hb, h2.update(h1)) + assert_equal(hb, h2) + end + + def test_value2? + assert_not_send([@cls[], :value?, 1]) + assert_not_send([@cls[], :value?, nil]) + assert_send([@h, :value?, nil]) + assert_send([@h, :value?, 'one']) + assert_not_send([@h, :value?, 'gumby']) + end + + def test_values + assert_equal([], @cls[].values) + + vals = @h.values + expected = [] + @h.each { |k, v| expected << v } + assert_equal([], vals - expected) + assert_equal([], expected - vals) + end + + def test_intialize_wrong_arguments + assert_raise(ArgumentError) do + Hash.new(0) { } + end + end + + def test_create + assert_equal({1=>2, 3=>4}, @cls[[[1,2],[3,4]]]) + assert_raise(ArgumentError) { Hash[0, 1, 2] } + assert_warning(/wrong element type Fixnum at 1 /) {@cls[[[1, 2], 3]]} + bug5406 = '[ruby-core:39945]' + assert_raise(ArgumentError, bug5406) { @cls[[[1, 2], [3, 4, 5]]] } + assert_equal({1=>2, 3=>4}, @cls[1,2,3,4]) + o = Object.new + def o.to_hash() {1=>2} end + assert_equal({1=>2}, @cls[o], "[ruby-dev:34555]") + end + + def test_rehash2 + h = @cls[1 => 2, 3 => 4] + assert_equal(h.dup, h.rehash) + assert_raise(RuntimeError) { h.each { h.rehash } } + assert_equal({}, @cls[].rehash) + end + + def test_fetch2 + assert_equal(:bar, @h.fetch(0, :foo) { :bar }) + end + + def test_default_proc + h = @cls.new {|hh, k| hh + k + "baz" } + assert_equal("foobarbaz", h.default_proc.call("foo", "bar")) + assert_nil(h.default_proc = nil) + assert_nil(h.default_proc) + h.default_proc = ->(_,_){ true } + assert_equal(true, h[:nope]) + h = @cls[] + assert_nil(h.default_proc) + end + + def test_shift2 + 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) + + h = @cls.new(:foo) + h[1] = 2 + assert_equal([1, 2], h.shift) + assert_equal(:foo, h.shift) + assert_equal(:foo, h.shift) + + h =@cls[1=>2] + h.each { assert_equal([1, 2], h.shift) } + end + + def test_shift_none + h = @cls.new {|hh, k| "foo"} + def h.default(k = nil) + super.upcase + end + assert_equal("FOO", h.shift) + end + + def test_reject_bang2 + assert_equal({1=>2}, @cls[1=>2,3=>4].reject! {|k, v| k + v == 7 }) + assert_nil(@cls[1=>2,3=>4].reject! {|k, v| k == 5 }) + assert_nil(@cls[].reject! { }) + end + + def test_select + assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].select {|k, v| k + v >= 7 }) + + base = @cls[ 1 => 'one', '2' => false, true => 'true', 'cat' => 99 ] + h1 = @cls[ '2' => false, 'cat' => 99 ] + h2 = @cls[ 1 => 'one', true => 'true' ] + h3 = @cls[ 1 => 'one', true => 'true', 'cat' => 99 ] + + h = base.dup + assert_equal(h, h.select { true }) + assert_equal(@cls[], h.select { false }) + + h = base.dup + assert_equal(h1, h.select {|k,v| k.instance_of?(String) }) + + assert_equal(h2, h.select {|k,v| v.instance_of?(String) }) + + assert_equal(h3, h.select {|k,v| v }) + assert_equal(base, h) + + h.instance_variable_set(:@foo, :foo) + h.default = 42 + h.taint + h = h.select {true} + assert_instance_of(Hash, h) + assert_not_predicate(h, :tainted?) + assert_nil(h.default) + assert_not_send([h, :instance_variable_defined?, :@foo]) + end + + def test_select! + h = @cls[1=>2,3=>4,5=>6] + assert_equal(h, h.select! {|k, v| k + v >= 7 }) + assert_equal({3=>4,5=>6}, h) + h = @cls[1=>2,3=>4,5=>6] + assert_equal(nil, h.select!{true}) + end + + def test_clear2 + assert_equal({}, @cls[1=>2,3=>4,5=>6].clear) + h = @cls[1=>2,3=>4,5=>6] + h.each { h.clear } + assert_equal({}, h) + end + + def test_replace2 + h1 = @cls.new { :foo } + h2 = @cls.new + h2.replace h1 + assert_equal(:foo, h2[0]) + + assert_raise(ArgumentError) { h2.replace() } + assert_raise(TypeError) { h2.replace(1) } + h2.freeze + assert_raise(ArgumentError) { h2.replace() } + assert_raise(RuntimeError) { h2.replace(h1) } + assert_raise(RuntimeError) { h2.replace(42) } + end + + def test_size2 + assert_equal(0, @cls[].size) + end + + def test_equal2 + assert_not_equal(0, @cls[]) + o = Object.new + o.instance_variable_set(:@cls, @cls) + def o.to_hash; @cls[]; end + def o.==(x); true; end + assert_equal({}, o) + def o.==(x); false; end + assert_not_equal({}, o) + + h1 = @cls[1=>2]; h2 = @cls[3=>4] + assert_not_equal(h1, h2) + h1 = @cls[1=>2]; h2 = @cls[1=>4] + assert_not_equal(h1, h2) + end + + def test_eql + assert_not_send([@cls[], :eql?, 0]) + o = Object.new + o.instance_variable_set(:@cls, @cls) + def o.to_hash; @cls[]; end + def o.eql?(x); true; end + assert_send([@cls[], :eql?, o]) + def o.eql?(x); false; end + assert_not_send([@cls[], :eql?, o]) + end + + def test_hash2 + assert_kind_of(Integer, @cls[].hash) + h = @cls[1=>2] + h.shift + assert_equal({}.hash, h.hash, '[ruby-core:38650]') + bug9231 = '[ruby-core:58993] [Bug #9231]' + assert_not_equal(0, @cls[].hash, bug9231) + end + + def test_update2 + h1 = @cls[1=>2, 3=>4] + h2 = {1=>3, 5=>7} + h1.update(h2) {|k, v1, v2| k + v1 + v2 } + assert_equal({1=>6, 3=>4, 5=>7}, h1) + end + + def test_merge + h1 = @cls[1=>2, 3=>4] + h2 = {1=>3, 5=>7} + assert_equal({1=>3, 3=>4, 5=>7}, h1.merge(h2)) + assert_equal({1=>6, 3=>4, 5=>7}, h1.merge(h2) {|k, v1, v2| k + v1 + v2 }) + end + + def test_assoc + assert_equal([3,4], @cls[1=>2, 3=>4, 5=>6].assoc(3)) + assert_nil(@cls[1=>2, 3=>4, 5=>6].assoc(4)) + assert_equal([1.0,1], @cls[1.0=>1].assoc(1)) + end + + def test_assoc_compare_by_identity + h = @cls[] + h.compare_by_identity + h["a"] = 1 + h["a".dup] = 2 + assert_equal(["a",1], h.assoc("a")) + end + + def test_rassoc + assert_equal([3,4], @cls[1=>2, 3=>4, 5=>6].rassoc(4)) + assert_nil({1=>2, 3=>4, 5=>6}.rassoc(3)) + end + + def test_flatten + assert_equal([[1], [2]], @cls[[1] => [2]].flatten) + + a = @cls[1=> "one", 2 => [2,"two"], 3 => [3, ["three"]]] + assert_equal([1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten) + assert_equal([[1, "one"], [2, [2, "two"]], [3, [3, ["three"]]]], a.flatten(0)) + assert_equal([1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten(1)) + assert_equal([1, "one", 2, 2, "two", 3, 3, ["three"]], a.flatten(2)) + assert_equal([1, "one", 2, 2, "two", 3, 3, "three"], a.flatten(3)) + assert_equal([1, "one", 2, 2, "two", 3, 3, "three"], a.flatten(-1)) + assert_raise(TypeError){ a.flatten(Object) } + end + + def test_callcc + h = @cls[1=>2] + c = nil + f = false + h.each { callcc {|c2| c = c2 } } + unless f + f = true + c.call + end + assert_raise(RuntimeError) { h.each { h.rehash } } + + h = @cls[1=>2] + c = nil + assert_raise(RuntimeError) do + h.each { callcc {|c2| c = c2 } } + h.clear + c.call + end + end + + def test_callcc_iter_level + bug9105 = '[ruby-dev:47803] [Bug #9105]' + h = @cls[1=>2, 3=>4] + c = nil + f = false + h.each {callcc {|c2| c = c2}} + unless f + f = true + c.call + end + assert_nothing_raised(RuntimeError, bug9105) do + h.each {|i, j| + h.delete(i); + assert_not_equal(false, i, bug9105) + } + end + end + + def test_callcc_escape + bug9105 = '[ruby-dev:47803] [Bug #9105]' + assert_nothing_raised(RuntimeError, bug9105) do + h=@cls[] + cnt=0 + c = callcc {|cc|cc} + h[cnt] = true + h.each{|i| + cnt+=1 + c.call if cnt == 1 + } + end + end + + def test_callcc_reenter + bug9105 = '[ruby-dev:47803] [Bug #9105]' + assert_nothing_raised(RuntimeError, bug9105) do + h = @cls[1=>2,3=>4] + c = nil + f = false + h.each { |i| + callcc {|c2| c = c2 } unless c + h.delete(1) if f + } + unless f + f = true + c.call + end + end + end + + def test_threaded_iter_level + bug9105 = '[ruby-dev:47807] [Bug #9105]' + h = @cls[1=>2] + 2.times.map { + f = false + th = Thread.start {h.each {f = true; sleep}} + Thread.pass until f + Thread.pass until th.stop? + th + }.each {|th| th.run; th.join} + assert_nothing_raised(RuntimeError, bug9105) do + h[5] = 6 + end + assert_equal(6, h[5], bug9105) + end + + def test_compare_by_identity + a = "foo" + assert_not_predicate(@cls[], :compare_by_identity?) + h = @cls[a => "bar"] + assert_not_predicate(h, :compare_by_identity?) + h.compare_by_identity + assert_predicate(h, :compare_by_identity?) + #assert_equal("bar", h[a]) + assert_nil(h["foo"]) + + bug8703 = '[ruby-core:56256] [Bug #8703] copied identhash' + h.clear + assert_predicate(h.dup, :compare_by_identity?, bug8703) + end + + def test_same_key + bug9646 = '[ruby-dev:48047] [Bug #9646] Infinite loop at Hash#each' + h = @cls[a=[], 1] + a << 1 + h[[]] = 2 + a.clear + cnt = 0 + r = h.each{ break nil if (cnt+=1) > 100 } + assert_not_nil(r,bug9646) + end + + class ObjWithHash + def initialize(value, hash) + @value = value + @hash = hash + end + attr_reader :value, :hash + + def eql?(other) + @value == other.value + end + end + + def test_hash_hash + assert_equal({0=>2,11=>1}.hash, @cls[11=>1,0=>2].hash) + o1 = ObjWithHash.new(0,1) + o2 = ObjWithHash.new(11,1) + assert_equal({o1=>1,o2=>2}.hash, @cls[o2=>2,o1=>1].hash) + end + + def test_hash_bignum_hash + x = 2<<(32-3)-1 + assert_equal({x=>1}.hash, @cls[x=>1].hash) + x = 2<<(64-3)-1 + assert_equal({x=>1}.hash, @cls[x=>1].hash) + + o = Object.new + def o.hash; 2 << 100; end + assert_equal({o=>1}.hash, @cls[o=>1].hash) + end + + def test_hash_poped + assert_nothing_raised { eval("a = 1; @cls[a => a]; a") } + end + + def test_recursive_key + h = @cls[] + assert_nothing_raised { h[h] = :foo } + h.rehash + assert_equal(:foo, h[h]) + end + + def test_inverse_hash + feature4262 = '[ruby-core:34334]' + [@cls[1=>2], @cls[123=>"abc"]].each do |h| + assert_not_equal(h.hash, h.invert.hash, feature4262) + end + end + + def test_recursive_hash_value_struct + bug9151 = '[ruby-core:58567] [Bug #9151]' + + s = Struct.new(:x) {def hash; [x,""].hash; end} + a = s.new + b = s.new + a.x = b + b.x = a + assert_nothing_raised(SystemStackError, bug9151) {a.hash} + assert_nothing_raised(SystemStackError, bug9151) {b.hash} + + h = @cls[] + h[[a,"hello"]] = 1 + assert_equal(1, h.size) + h[[b,"world"]] = 2 + assert_equal(2, h.size) + + obj = Object.new + h = @cls[a => obj] + assert_same(obj, h[b]) + end + + def test_recursive_hash_value_array + h = @cls[] + h[[[1]]] = 1 + assert_equal(1, h.size) + h[[[2]]] = 1 + assert_equal(2, h.size) + + a = [] + a << a + + h = @cls[] + h[[a, 1]] = 1 + assert_equal(1, h.size) + h[[a, 2]] = 2 + assert_equal(2, h.size) + h[[a, a]] = 3 + assert_equal(3, h.size) + + obj = Object.new + h = @cls[a => obj] + assert_same(obj, h[[[a]]]) + end + + def test_recursive_hash_value_array_hash + h = @cls[] + rec = [h] + h[:x] = rec + + obj = Object.new + h2 = {rec => obj} + [h, {x: rec}].each do |k| + k = [k] + assert_same(obj, h2[k], ->{k.inspect}) + end + end + + def test_recursive_hash_value_hash_array + h = @cls[] + rec = [h] + h[:x] = rec + + obj = Object.new + h2 = {h => obj} + [rec, [h]].each do |k| + k = {x: k} + assert_same(obj, h2[k], ->{k.inspect}) + end + end + + def test_exception_in_rehash + return unless @cls == Hash + + bug9187 = '[ruby-core:58728] [Bug #9187]' + + prepare = <<-EOS + class Foo + def initialize + @raise = false + end + + def hash + raise if @raise + @raise = true + return 0 + end + end + h = {Foo.new => true} + EOS + + code = <<-EOS + 10_0000.times do + h.rehash rescue nil + end + GC.start + EOS + + assert_no_memory_leak([], prepare, code, bug9187) + end + + def test_wrapper_of_special_const + bug9381 = '[ruby-core:59638] [Bug #9381]' + + wrapper = Class.new do + def initialize(obj) + @obj = obj + end + + def hash + @obj.hash + end + + def eql?(other) + @obj.eql?(other) + end + end + + bad = [ + 5, true, false, nil, + 0.0, 1.72723e-77, + ].select do |x| + hash = {x => bug9381} + hash[wrapper.new(x)] != bug9381 + end + assert_empty(bad, bug9381) + end + + def test_label_syntax + return unless @cls == Hash + + feature4935 = '[ruby-core:37553] [Feature #4935]' + x = 'world' + hash = assert_nothing_raised(SyntaxError) do + break eval(%q({foo: 1, "foo-bar": 2, "hello-#{x}": 3, 'hello-#{x}': 4, 'bar': {}})) + end + assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4, :bar => {}}, hash) + end + + class TestSubHash < TestHash + class SubHash < Hash + def reject(*) + super + end + end + + def setup + @cls = SubHash + super + end + end +end diff --git a/jni/ruby/test/ruby/test_ifunless.rb b/jni/ruby/test/ruby/test_ifunless.rb new file mode 100644 index 0000000..e144ff8 --- /dev/null +++ b/jni/ruby/test/ruby/test_ifunless.rb @@ -0,0 +1,14 @@ +require 'test/unit' + +class TestIfunless < Test::Unit::TestCase + def test_if_unless + x = 'test'; + assert(if x == x then true else false end) + bad = false + unless x == x + bad = true + end + assert(!bad) + assert(unless x != x then true else false end) + end +end diff --git a/jni/ruby/test/ruby/test_integer.rb b/jni/ruby/test/ruby/test_integer.rb new file mode 100644 index 0000000..3dbf365 --- /dev/null +++ b/jni/ruby/test/ruby/test_integer.rb @@ -0,0 +1,280 @@ +require 'test/unit' + +class TestInteger < Test::Unit::TestCase + BDSIZE = 0x4000000000000000.coerce(0)[0].size + def self.bdsize(x) + ((x + 1) / 8 + BDSIZE) / BDSIZE * BDSIZE + end + def bdsize(x) + self.class.bdsize(x) + end + + def test_aref + # assert_equal(1, (1 << 0x40000000)[0x40000000], "[ruby-dev:31271]") + # assert_equal(0, (-1 << 0x40000001)[0x40000000], "[ruby-dev:31271]") + big_zero = 0x40000000.coerce(0)[0] + assert_equal(0, (-0x40000002)[big_zero], "[ruby-dev:31271]") + assert_equal(1, 0x400000001[big_zero], "[ruby-dev:31271]") + end + + def test_pow + assert_not_equal(0, begin + 0**-1 + rescue + nil + end, "[ruby-dev:32084] [ruby-dev:34547]") + end + + def test_lshift + assert_equal(0, 1 << -0x40000000) + assert_equal(0, 1 << -0x40000001) + assert_equal(0, 1 << -0x80000000) + assert_equal(0, 1 << -0x80000001) + # assert_equal(bdsize(0x80000000), (1 << 0x80000000).size) + end + + def test_rshift + # assert_equal(bdsize(0x40000001), (1 >> -0x40000001).size) + assert_predicate((1 >> 0x80000000), :zero?) + assert_predicate((1 >> 0xffffffff), :zero?) + assert_predicate((1 >> 0x100000000), :zero?) + # assert_equal((1 << 0x40000000), (1 >> -0x40000000)) + # assert_equal((1 << 0x40000001), (1 >> -0x40000001)) + end + + def test_Integer + assert_raise(ArgumentError) {Integer("0x-1")} + assert_raise(ArgumentError) {Integer("-0x-1")} + assert_raise(ArgumentError) {Integer("0x 123")} + assert_raise(ArgumentError) {Integer("0x 123")} + assert_raise(ArgumentError) {Integer("0x0x5")} + assert_raise(ArgumentError) {Integer("0x0x000000005")} + assert_nothing_raised(ArgumentError) { + assert_equal(1540841, "0x0x5".to_i(36)) + } + assert_raise(ArgumentError) { Integer("--0") } + assert_raise(ArgumentError) { Integer("-+0") } + assert_raise(ArgumentError) { Integer("++1") } + assert_raise(ArgumentError) { Integer("") } + assert_raise(ArgumentError) { Integer("10 x") } + assert_raise(ArgumentError) { Integer("1__2") } + assert_raise(ArgumentError) { Integer("1z") } + assert_raise(ArgumentError) { Integer("46116860184273__87904") } + assert_raise(ArgumentError) { Integer("4611686018427387904_") } + assert_raise(ArgumentError) { Integer("4611686018427387904 :") } + assert_equal(0x4000000000000000, Integer("46_11_686_0184273_87904")) + assert_raise(ArgumentError) { Integer("\0") } + assert_nothing_raised(ArgumentError, "[ruby-core:13873]") { + assert_equal(0, Integer("0 ")) + } + assert_nothing_raised(ArgumentError, "[ruby-core:14139]") { + assert_equal(0377, Integer("0_3_7_7")) + } + assert_raise(ArgumentError, "[ruby-core:14139]") {Integer("0__3_7_7")} + assert_equal(1234, Integer(1234)) + assert_equal(1, Integer(1.234)) + + # base argument + assert_equal(1234, Integer("1234", 10)) + assert_equal(668, Integer("1234", 8)) + assert_equal(4660, Integer("1234", 16)) + assert_equal(49360, Integer("1234", 36)) + # decimal, not octal + assert_equal(1234, Integer("01234", 10)) + assert_raise(ArgumentError) { Integer("0x123", 10) } + assert_raise(ArgumentError) { Integer(1234, 10) } + assert_raise(ArgumentError) { Integer(12.34, 10) } + assert_raise(ArgumentError) { Integer(Object.new, 1) } + + assert_raise(ArgumentError) { Integer(1, 1, 1) } + + assert_equal(2 ** 50, Integer(2.0 ** 50)) + assert_raise(TypeError) { Integer(nil) } + + bug6192 = '[ruby-core:43566]' + assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16be"))} + assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16le"))} + assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32be"))} + assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32le"))} + assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("iso-2022-jp"))} + end + + def test_int_p + assert_not_predicate(1.0, :integer?) + assert_predicate(1, :integer?) + end + + def test_odd_p_even_p + Fixnum.class_eval do + alias odd_bak odd? + alias even_bak even? + remove_method :odd?, :even? + end + + assert_predicate(1, :odd?) + assert_not_predicate(2, :odd?) + assert_not_predicate(1, :even?) + assert_predicate(2, :even?) + + ensure + Fixnum.class_eval do + alias odd? odd_bak + alias even? even_bak + remove_method :odd_bak, :even_bak + end + end + + def test_succ + assert_equal(2, 1.send(:succ)) + + Fixnum.class_eval do + alias succ_bak succ + remove_method :succ + end + + assert_equal(2, 1.succ) + assert_equal(4294967297, 4294967296.succ) + + ensure + Fixnum.class_eval do + alias succ succ_bak + remove_method :succ_bak + end + end + + def test_chr + assert_equal("a", "a".ord.chr) + assert_raise(RangeError) { (-1).chr } + assert_raise(RangeError) { 0x100.chr } + end + + def test_upto + a = [] + 1.upto(3) {|x| a << x } + assert_equal([1, 2, 3], a) + + a = [] + 1.upto(0) {|x| a << x } + assert_equal([], a) + + y = 2**30 - 1 + a = [] + y.upto(y+2) {|x| a << x } + assert_equal([y, y+1, y+2], a) + end + + def test_downto + a = [] + -1.downto(-3) {|x| a << x } + assert_equal([-1, -2, -3], a) + + a = [] + 1.downto(2) {|x| a << x } + assert_equal([], a) + + y = -(2**30) + a = [] + y.downto(y-2) {|x| a << x } + assert_equal([y, y-1, y-2], a) + end + + def test_times + (2**32).times do |i| + break if i == 2 + end + end + + def test_round + assert_equal(11111, 11111.round) + assert_equal(Fixnum, 11111.round.class) + assert_equal(11111, 11111.round(0)) + assert_equal(Fixnum, 11111.round(0).class) + + assert_equal(11111.0, 11111.round(1)) + assert_equal(Float, 11111.round(1).class) + assert_equal(11111.0, 11111.round(2)) + assert_equal(Float, 11111.round(2).class) + + assert_equal(11110, 11111.round(-1)) + assert_equal(Fixnum, 11111.round(-1).class) + assert_equal(11100, 11111.round(-2)) + assert_equal(Fixnum, 11111.round(-2).class) + + assert_equal(1111_1111_1111_1111_1111_1111_1111_1110, 1111_1111_1111_1111_1111_1111_1111_1111.round(-1)) + assert_equal(Bignum, 1111_1111_1111_1111_1111_1111_1111_1111.round(-1).class) + assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1)) + assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class) + end + + def test_bitwise_and_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 & obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 & 10, 3 & obj) + end + + def test_bitwise_or_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 | obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 | 10, 3 | obj) + end + + def test_bitwise_xor_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 ^ obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 ^ 10, 3 ^ obj) + end + + def test_bit_length + assert_equal(13, (-2**12-1).bit_length) + assert_equal(12, (-2**12).bit_length) + assert_equal(12, (-2**12+1).bit_length) + assert_equal(9, -0x101.bit_length) + assert_equal(8, -0x100.bit_length) + assert_equal(8, -0xff.bit_length) + assert_equal(1, -2.bit_length) + assert_equal(0, -1.bit_length) + assert_equal(0, 0.bit_length) + assert_equal(1, 1.bit_length) + assert_equal(8, 0xff.bit_length) + assert_equal(9, 0x100.bit_length) + assert_equal(9, 0x101.bit_length) + assert_equal(12, (2**12-1).bit_length) + assert_equal(13, (2**12).bit_length) + assert_equal(13, (2**12+1).bit_length) + + assert_equal(10001, (-2**10000-1).bit_length) + assert_equal(10000, (-2**10000).bit_length) + assert_equal(10000, (-2**10000+1).bit_length) + assert_equal(10000, (2**10000-1).bit_length) + assert_equal(10001, (2**10000).bit_length) + assert_equal(10001, (2**10000+1).bit_length) + + 2.upto(1000) {|i| + n = 2**i + assert_equal(i+1, (-n-1).bit_length, "(#{-n-1}).bit_length") + assert_equal(i, (-n).bit_length, "(#{-n}).bit_length") + assert_equal(i, (-n+1).bit_length, "(#{-n+1}).bit_length") + assert_equal(i, (n-1).bit_length, "#{n-1}.bit_length") + assert_equal(i+1, (n).bit_length, "#{n}.bit_length") + assert_equal(i+1, (n+1).bit_length, "#{n+1}.bit_length") + } + end +end diff --git a/jni/ruby/test/ruby/test_integer_comb.rb b/jni/ruby/test/ruby/test_integer_comb.rb new file mode 100644 index 0000000..e00e758 --- /dev/null +++ b/jni/ruby/test/ruby/test_integer_comb.rb @@ -0,0 +1,631 @@ +require 'test/unit' + +class TestIntegerComb < Test::Unit::TestCase + VS = [ + -0x1000000000000000000000000000000000000000000000002, + -0x1000000000000000000000000000000000000000000000001, + -0x1000000000000000000000000000000000000000000000000, + -0xffffffffffffffffffffffffffffffffffffffffffffffff, + -0x1000000000000000000000002, + -0x1000000000000000000000001, + -0x1000000000000000000000000, + -0xffffffffffffffffffffffff, + -0x10000000000000002, + -0x10000000000000001, + -0x10000000000000000, + -0xffffffffffffffff, + -0x4000000000000002, + -0x4000000000000001, + -0x4000000000000000, + -0x3fffffffffffffff, + -0x100000002, + -0x100000001, + -0x100000000, + -0xffffffff, + -0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001 + -0x80000002, + -0x80000001, + -0x80000000, + -0x7fffffff, + -0x524b2245, + -0x40000002, + -0x40000001, + -0x40000000, + -0x3fffffff, + -0x10002, + -0x10001, + -0x10000, + -0xffff, + -0x8101, # 0x8101 * 0x7f01 = 0x40000001 + -0x8002, + -0x8001, + -0x8000, + -0x7fff, + -0x7f01, + -65, + -64, + -63, + -62, + -33, + -32, + -31, + -30, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 30, + 31, + 32, + 33, + 62, + 63, + 64, + 65, + 0x7f01, + 0x7ffe, + 0x7fff, + 0x8000, + 0x8001, + 0x8101, + 0xfffe, + 0xffff, + 0x10000, + 0x10001, + 0x3ffffffe, + 0x3fffffff, + 0x40000000, + 0x40000001, + 0x524b2245, + 0x7ffffffe, + 0x7fffffff, + 0x80000000, + 0x80000001, + 0xc717a08d, + 0xfffffffe, + 0xffffffff, + 0x100000000, + 0x100000001, + 0x3ffffffffffffffe, + 0x3fffffffffffffff, + 0x4000000000000000, + 0x4000000000000001, + 0xfffffffffffffffe, + 0xffffffffffffffff, + 0x10000000000000000, + 0x10000000000000001, + 0xffffffffffffffffffffffff, + 0x1000000000000000000000000, + 0x1000000000000000000000001, + 0xffffffffffffffffffffffffffffffffffffffffffffffff, + 0x1000000000000000000000000000000000000000000000000, + 0x1000000000000000000000000000000000000000000000001 + ] + + #VS.map! {|v| 0x4000000000000000.coerce(v)[0] } + #VS.concat VS.find_all {|v| Fixnum === v }.map {|v| 0x4000000000000000.coerce(v)[0] } + #VS.sort! {|a, b| a.abs <=> b.abs } + + min = -1 + min *= 2 while min.class == Fixnum + FIXNUM_MIN = min/2 + max = 1 + max *= 2 while (max-1).class == Fixnum + FIXNUM_MAX = max/2-1 + + def test_fixnum_range + assert_instance_of(Bignum, FIXNUM_MIN-1) + assert_instance_of(Fixnum, FIXNUM_MIN) + assert_instance_of(Fixnum, FIXNUM_MAX) + assert_instance_of(Bignum, FIXNUM_MAX+1) + end + + def check_class(n) + if FIXNUM_MIN <= n && n <= FIXNUM_MAX + assert_instance_of(Fixnum, n) + else + assert_instance_of(Bignum, n) + end + end + + def test_aref + VS.each {|a| + 100.times {|i| + assert_equal((a >> i).odd? ? 1 : 0, a[i], "(#{a})[#{i}]") + } + } + VS.each {|a| + VS.each {|b| + c = nil + assert_nothing_raised("(#{a})[#{b}]") { c = a[b] } + check_class(c) + if b < 0 + assert_equal(0, c, "(#{a})[#{b}]") + else + assert_equal((a >> b).odd? ? 1 : 0, c, "(#{a})[#{b}]") + end + } + } + end + + def test_plus + VS.each {|a| + VS.each {|b| + c = a + b + check_class(c) + assert_equal(b + a, c, "#{a} + #{b}") + assert_equal(a, c - b, "(#{a} + #{b}) - #{b}") + assert_equal(a-~b-1, c, "#{a} + #{b}") # Hacker's Delight + assert_equal((a^b)+2*(a&b), c, "#{a} + #{b}") # Hacker's Delight + assert_equal((a|b)+(a&b), c, "#{a} + #{b}") # Hacker's Delight + assert_equal(2*(a|b)-(a^b), c, "#{a} + #{b}") # Hacker's Delight + } + } + end + + def test_minus + VS.each {|a| + VS.each {|b| + c = a - b + check_class(c) + assert_equal(a, c + b, "(#{a} - #{b}) + #{b}") + assert_equal(-b, c - a, "(#{a} - #{b}) - #{a}") + assert_equal(a+~b+1, c, "#{a} - #{b}") # Hacker's Delight + assert_equal((a^b)-2*(b&~a), c, "#{a} - #{b}") # Hacker's Delight + assert_equal((a&~b)-(b&~a), c, "#{a} - #{b}") # Hacker's Delight + assert_equal(2*(a&~b)-(a^b), c, "#{a} - #{b}") # Hacker's Delight + } + } + end + + def test_mult + VS.each {|a| + VS.each {|b| + c = a * b + check_class(c) + assert_equal(b * a, c, "#{a} * #{b}") + assert_equal(b.send(:*, a), c, "#{a} * #{b}") + assert_equal(b, c / a, "(#{a} * #{b}) / #{a}") if a != 0 + assert_equal(a.abs * b.abs, (a * b).abs, "(#{a} * #{b}).abs") + assert_equal((a-100)*(b-100)+(a-100)*100+(b-100)*100+10000, c, "#{a} * #{b}") + assert_equal((a+100)*(b+100)-(a+100)*100-(b+100)*100+10000, c, "#{a} * #{b}") + } + } + end + + def test_divmod + VS.each {|a| + VS.each {|b| + if b == 0 + assert_raise(ZeroDivisionError) { a.divmod(b) } + else + q, r = a.divmod(b) + check_class(q) + check_class(r) + assert_equal(a, b*q+r) + assert_operator(r.abs, :<, b.abs) + if 0 < b + assert_operator(r, :>=, 0) + assert_operator(r, :<, b) + else + assert_operator(r, :>, b) + assert_operator(r, :<=, 0) + end + assert_equal(q, a/b) + assert_equal(q, a.div(b)) + assert_equal(r, a%b) + assert_equal(r, a.modulo(b)) + end + } + } + end + + def test_pow + small_values = VS.find_all {|v| 0 <= v && v < 1000 } + VS.each {|a| + small_values.each {|b| + c = a ** b + check_class(c) + d = 1 + b.times { d *= a } + assert_equal(d, c, "(#{a}) ** #{b}") + if a != 0 + d = c + b.times { d /= a } + assert_equal(1, d, "((#{a}) ** #{b}) / #{a} / ...(#{b} times)...") + end + } + } + end + + def test_not + VS.each {|a| + b = ~a + check_class(b) + assert_equal(-1 ^ a, b, "~#{a}") + assert_equal(-a-1, b, "~#{a}") # Hacker's Delight + assert_equal(0, a & b, "#{a} & ~#{a}") + assert_equal(-1, a | b, "#{a} | ~#{a}") + } + end + + def test_or + VS.each {|a| + VS.each {|b| + c = a | b + check_class(c) + assert_equal(b | a, c, "#{a} | #{b}") + assert_equal(a + b - (a&b), c, "#{a} | #{b}") + assert_equal((a & ~b) + b, c, "#{a} | #{b}") # Hacker's Delight + assert_equal(-1, c | ~a, "(#{a} | #{b}) | ~#{a})") + } + } + end + + def test_and + VS.each {|a| + VS.each {|b| + c = a & b + check_class(c) + assert_equal(b & a, c, "#{a} & #{b}") + assert_equal(a + b - (a|b), c, "#{a} & #{b}") + assert_equal((~a | b) - ~a, c, "#{a} & #{b}") # Hacker's Delight + assert_equal(0, c & ~a, "(#{a} & #{b}) & ~#{a}") + } + } + end + + def test_xor + VS.each {|a| + VS.each {|b| + c = a ^ b + check_class(c) + assert_equal(b ^ a, c, "#{a} ^ #{b}") + assert_equal((a|b)-(a&b), c, "#{a} ^ #{b}") # Hacker's Delight + assert_equal(b, c ^ a, "(#{a} ^ #{b}) ^ #{a}") + } + } + end + + def test_lshift + small_values = VS.find_all {|v| v < 8000 } + VS.each {|a| + small_values.each {|b| + c = a << b + check_class(c) + if 0 <= b + assert_equal(a, c >> b, "(#{a} << #{b}) >> #{b}") + assert_equal(a * 2**b, c, "#{a} << #{b}") + end + 0.upto(c.size*8+10) {|nth| + assert_equal(a[nth-b], c[nth], "(#{a} << #{b})[#{nth}]") + } + } + } + end + + def test_rshift + small_values = VS.find_all {|v| -8000 < v } + VS.each {|a| + small_values.each {|b| + c = a >> b + check_class(c) + if b <= 0 + assert_equal(a, c << b, "(#{a} >> #{b}) << #{b}") + assert_equal(a * 2**(-b), c, "#{a} >> #{b}") + end + 0.upto(c.size*8+10) {|nth| + assert_equal(a[nth+b], c[nth], "(#{a} >> #{b})[#{nth}]") + } + } + } + end + + def test_succ + VS.each {|a| + b = a.succ + check_class(b) + assert_equal(a+1, b, "(#{a}).succ") + assert_equal(a, b.pred, "(#{a}).succ.pred") + assert_equal(a, b-1, "(#{a}).succ - 1") + } + end + + def test_pred + VS.each {|a| + b = a.pred + check_class(b) + assert_equal(a-1, b, "(#{a}).pred") + assert_equal(a, b.succ, "(#{a}).pred.succ") + assert_equal(a, b + 1, "(#{a}).pred + 1") + } + end + + def test_unary_plus + VS.each {|a| + b = +a + check_class(b) + assert_equal(a, b, "+(#{a})") + } + end + + def test_unary_minus + VS.each {|a| + b = -a + check_class(b) + assert_equal(0-a, b, "-(#{a})") + assert_equal(~a+1, b, "-(#{a})") + assert_equal(0, a+b, "#{a}+(-(#{a}))") + } + end + + def test_cmp + VS.each_with_index {|a, i| + VS.each_with_index {|b, j| + assert_equal(i <=> j, a <=> b, "#{a} <=> #{b}") + assert_equal(i < j, a < b, "#{a} < #{b}") + assert_equal(i <= j, a <= b, "#{a} <= #{b}") + assert_equal(i > j, a > b, "#{a} > #{b}") + assert_equal(i >= j, a >= b, "#{a} >= #{b}") + } + } + end + + def test_eq + VS.each_with_index {|a, i| + VS.each_with_index {|b, j| + c = a == b + assert_equal(b == a, c, "#{a} == #{b}") + assert_equal(i == j, c, "#{a} == #{b}") + } + } + end + + def test_abs + VS.each {|a| + b = a.abs + check_class(b) + if a < 0 + assert_equal(-a, b, "(#{a}).abs") + else + assert_equal(a, b, "(#{a}).abs") + end + } + end + + def test_ceil + VS.each {|a| + b = a.ceil + check_class(b) + assert_equal(a, b, "(#{a}).ceil") + } + end + + def test_floor + VS.each {|a| + b = a.floor + check_class(b) + assert_equal(a, b, "(#{a}).floor") + } + end + + def test_round + VS.each {|a| + b = a.round + check_class(b) + assert_equal(a, b, "(#{a}).round") + } + end + + def test_truncate + VS.each {|a| + b = a.truncate + check_class(b) + assert_equal(a, b, "(#{a}).truncate") + } + end + + def test_remainder + VS.each {|a| + VS.each {|b| + if b == 0 + assert_raise(ZeroDivisionError) { a.divmod(b) } + else + r = a.remainder(b) + check_class(r) + if a < 0 + assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})") + assert_operator(0, :>=, r, "#{a}.remainder(#{b})") + elsif 0 < a + assert_operator(0, :<=, r, "#{a}.remainder(#{b})") + assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})") + else + assert_equal(0, r, "#{a}.remainder(#{b})") + end + end + } + } + end + + def test_zero_nonzero + VS.each {|a| + z = a.zero? + n = a.nonzero? + if a == 0 + assert_equal(true, z, "(#{a}).zero?") + assert_equal(nil, n, "(#{a}).nonzero?") + else + assert_equal(false, z, "(#{a}).zero?") + assert_equal(a, n, "(#{a}).nonzero?") + check_class(n) + end + assert(z ^ n, "(#{a}).zero? ^ (#{a}).nonzero?") + } + end + + def test_even_odd + VS.each {|a| + e = a.even? + o = a.odd? + assert_equal((a % 2) == 0, e, "(#{a}).even?") + assert_equal((a % 2) == 1, o, "(#{a}).odd") + assert_equal((a & 1) == 0, e, "(#{a}).even?") + assert_equal((a & 1) == 1, o, "(#{a}).odd") + assert(e ^ o, "(#{a}).even? ^ (#{a}).odd?") + } + end + + def test_to_s + 2.upto(36) {|radix| + VS.each {|a| + s = a.to_s(radix) + b = s.to_i(radix) + assert_equal(a, b, "(#{a}).to_s(#{radix}).to_i(#{radix})") + } + } + end + + def test_printf_x + VS.reverse_each {|a| + s = sprintf("%x", a) + if /\A\.\./ =~ s + b = -($'.tr('0123456789abcdef', 'fedcba9876543210').to_i(16) + 1) + else + b = s.to_i(16) + end + assert_equal(a, b, "sprintf('%x', #{a}) = #{s.inspect}") + } + end + + def test_printf_x_sign + VS.reverse_each {|a| + s = sprintf("%+x", a) + b = s.to_i(16) + assert_equal(a, b, "sprintf('%+x', #{a}) = #{s.inspect}") + s = sprintf("% x", a) + b = s.to_i(16) + assert_equal(a, b, "sprintf('% x', #{a}) = #{s.inspect}") + } + end + + def test_printf_o + VS.reverse_each {|a| + s = sprintf("%o", a) + if /\A\.\./ =~ s + b = -($'.tr('01234567', '76543210').to_i(8) + 1) + else + b = s.to_i(8) + end + assert_equal(a, b, "sprintf('%o', #{a}) = #{s.inspect}") + } + end + + def test_printf_o_sign + VS.reverse_each {|a| + s = sprintf("%+o", a) + b = s.to_i(8) + assert_equal(a, b, "sprintf('%+o', #{a}) = #{s.inspect}") + s = sprintf("% o", a) + b = s.to_i(8) + assert_equal(a, b, "sprintf('% o', #{a}) = #{s.inspect}") + } + end + + def test_printf_b + VS.reverse_each {|a| + s = sprintf("%b", a) + if /\A\.\./ =~ s + b = -($'.tr('01', '10').to_i(2) + 1) + else + b = s.to_i(2) + end + assert_equal(a, b, "sprintf('%b', #{a}) = #{s.inspect}") + } + end + + def test_printf_b_sign + VS.reverse_each {|a| + s = sprintf("%+b", a) + b = s.to_i(2) + assert_equal(a, b, "sprintf('%+b', #{a}) = #{s.inspect}") + s = sprintf("% b", a) + b = s.to_i(2) + assert_equal(a, b, "sprintf('% b', #{a}) = #{s.inspect}") + } + end + + def test_printf_diu + VS.reverse_each {|a| + s = sprintf("%d", a) + b = s.to_i + assert_equal(a, b, "sprintf('%d', #{a}) = #{s.inspect}") + s = sprintf("%i", a) + b = s.to_i + assert_equal(a, b, "sprintf('%i', #{a}) = #{s.inspect}") + s = sprintf("%u", a) + b = s.to_i + assert_equal(a, b, "sprintf('%u', #{a}) = #{s.inspect}") + } + end + + def test_marshal + VS.reverse_each {|a| + s = Marshal.dump(a) + b = Marshal.load(s) + assert_equal(a, b, "Marshal.load(Marshal.dump(#{a}))") + } + end + + def test_pack + %w[c C s S s! S! i I i! I! l L l! L! q Q n N v V].each {|template| + size = [0].pack(template).size + mask = (1 << (size * 8)) - 1 + if /[A-Znv]/ =~ template + min = 0 + max = (1 << (size * 8))-1 + else + min = -(1 << (size * 8 - 1)) + max = (1 << (size * 8 - 1)) - 1 + end + VS.reverse_each {|a| + s = [a].pack(template) + b = s.unpack(template)[0] + if min <= a && a <= max + assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})[0]") + end + assert_operator(min, :<=, b) + assert_operator(b, :<=, max) + assert_equal(a & mask, b & mask, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})[0] & #{mask}") + } + } + end + + def test_pack_ber + template = "w" + VS.reverse_each {|a| + if a < 0 + assert_raise(ArgumentError) { [a].pack(template) } + else + s = [a].pack(template) + b = s.unpack(template)[0] + assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})") + end + } + end + + def test_pack_utf8 + template = "U" + VS.reverse_each {|a| + if a < 0 || 0x7fffffff < a + assert_raise(RangeError) { [a].pack(template) } + else + s = [a].pack(template) + b = s.unpack(template)[0] + assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})") + end + } + end +end diff --git a/jni/ruby/test/ruby/test_io.rb b/jni/ruby/test/ruby/test_io.rb new file mode 100644 index 0000000..d0ca5e6 --- /dev/null +++ b/jni/ruby/test/ruby/test_io.rb @@ -0,0 +1,3171 @@ +# coding: US-ASCII +require 'test/unit' +require 'tmpdir' +require "fcntl" +require 'io/nonblock' +require 'socket' +require 'stringio' +require 'timeout' +require 'tempfile' +require 'weakref' + +class TestIO < Test::Unit::TestCase + module Feature + def have_close_on_exec? + $stdin.close_on_exec? + true + rescue NotImplementedError + false + end + + def have_nonblock? + IO.method_defined?("nonblock=") + end + end + + include Feature + extend Feature + + def pipe(wp, rp) + re, we = nil, nil + r, w = IO.pipe + rt = Thread.new do + begin + rp.call(r) + rescue Exception + r.close + re = $! + end + end + wt = Thread.new do + begin + wp.call(w) + rescue Exception + w.close + we = $! + end + end + flunk("timeout") unless wt.join(10) && rt.join(10) + ensure + w.close unless !w || w.closed? + r.close unless !r || r.closed? + (wt.kill; wt.join) if wt + (rt.kill; rt.join) if rt + raise we if we + raise re if re + end + + def with_pipe + r, w = IO.pipe + begin + yield r, w + ensure + r.close unless r.closed? + w.close unless w.closed? + end + end + + def with_read_pipe(content) + pipe(proc do |w| + w << content + w.close + end, proc do |r| + yield r + end) + end + + def mkcdtmpdir + Dir.mktmpdir {|d| + Dir.chdir(d) { + yield + } + } + end + + def trapping_usr1 + @usr1_rcvd = 0 + trap(:USR1) { @usr1_rcvd += 1 } + yield + ensure + trap(:USR1, "DEFAULT") + end + + def test_pipe + r, w = IO.pipe + assert_instance_of(IO, r) + assert_instance_of(IO, w) + [ + Thread.start{ + w.print "abc" + w.close + }, + Thread.start{ + assert_equal("abc", r.read) + r.close + } + ].each{|thr| thr.join} + end + + def test_pipe_block + x = nil + ret = IO.pipe {|r, w| + x = [r,w] + assert_instance_of(IO, r) + assert_instance_of(IO, w) + [ + Thread.start do + w.print "abc" + w.close + end, + Thread.start do + assert_equal("abc", r.read) + end + ].each{|thr| thr.join} + assert_not_predicate(r, :closed?) + assert_predicate(w, :closed?) + :foooo + } + assert_equal(:foooo, ret) + assert_predicate(x[0], :closed?) + assert_predicate(x[1], :closed?) + end + + def test_pipe_block_close + 4.times {|i| + x = nil + IO.pipe {|r, w| + x = [r,w] + r.close if (i&1) == 0 + w.close if (i&2) == 0 + } + assert_predicate(x[0], :closed?) + assert_predicate(x[1], :closed?) + } + end + + def test_gets_rs + # default_rs + pipe(proc do |w| + w.print "aaa\nbbb\n" + w.close + end, proc do |r| + assert_equal "aaa\n", r.gets + assert_equal "bbb\n", r.gets + assert_nil r.gets + r.close + end) + + # nil + pipe(proc do |w| + w.print "a\n\nb\n\n" + w.close + end, proc do |r| + assert_equal "a\n\nb\n\n", r.gets(nil) + assert_nil r.gets("") + r.close + end) + + # "\377" + pipe(proc do |w| + w.print "\377xyz" + w.close + end, proc do |r| + r.binmode + assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]") + r.close + end) + + # "" + pipe(proc do |w| + w.print "a\n\nb\n\n" + w.close + end, proc do |r| + assert_equal "a\n\n", r.gets(""), "[ruby-core:03771]" + assert_equal "b\n\n", r.gets("") + assert_nil r.gets("") + r.close + end) + end + + def test_gets_limit_extra_arg + pipe(proc do |w| + w << "0123456789\n0123456789" + w.close + end, proc do |r| + assert_equal("0123456789\n0", r.gets(nil, 12)) + assert_raise(TypeError) { r.gets(3,nil) } + end) + end + + # This test cause SEGV. + def test_ungetc + pipe(proc do |w| + w.close + end, proc do |r| + s = "a" * 1000 + assert_raise(IOError, "[ruby-dev:31650]") { 200.times { r.ungetc s } } + end) + end + + def test_ungetbyte + make_tempfile {|t| + t.open + t.binmode + t.ungetbyte(0x41) + assert_equal(-1, t.pos) + assert_equal(0x41, t.getbyte) + t.rewind + assert_equal(0, t.pos) + t.ungetbyte("qux") + assert_equal(-3, t.pos) + assert_equal("quxfoo\n", t.gets) + assert_equal(4, t.pos) + t.set_encoding("utf-8") + t.ungetbyte(0x89) + t.ungetbyte(0x8e) + t.ungetbyte("\xe7") + t.ungetbyte("\xe7\xb4\x85") + assert_equal(-2, t.pos) + assert_equal("\u7d05\u7389bar\n", t.gets) + } + end + + def test_each_byte + pipe(proc do |w| + w << "abc def" + w.close + end, proc do |r| + r.each_byte {|byte| break if byte == 32 } + assert_equal("def", r.read, "[ruby-dev:31659]") + end) + end + + def test_each_byte_with_seek + make_tempfile {|t| + bug5119 = '[ruby-core:38609]' + i = 0 + open(t.path) do |f| + f.each_byte {i = f.pos} + end + assert_equal(12, i, bug5119) + } + end + + def test_each_codepoint + make_tempfile {|t| + bug2959 = '[ruby-core:28650]' + a = "" + File.open(t, 'rt') {|f| + f.each_codepoint {|c| a << c} + } + assert_equal("foo\nbar\nbaz\n", a, bug2959) + } + end + + def test_codepoints + make_tempfile {|t| + bug2959 = '[ruby-core:28650]' + a = "" + File.open(t, 'rt') {|f| + assert_warn(/deprecated/) { + f.codepoints {|c| a << c} + } + } + assert_equal("foo\nbar\nbaz\n", a, bug2959) + } + end + + def test_rubydev33072 + t = make_tempfile + path = t.path + t.close! + assert_raise(Errno::ENOENT, "[ruby-dev:33072]") do + File.read(path, nil, nil, {}) + end + end + + def with_srccontent(content = "baz") + src = "src" + mkcdtmpdir { + File.open(src, "w") {|f| f << content } + yield src, content + } + end + + def test_copy_stream_small + with_srccontent("foobar") {|src, content| + ret = IO.copy_stream(src, "dst") + assert_equal(content.bytesize, ret) + assert_equal(content, File.read("dst")) + } + end + + def test_copy_stream_smaller + with_srccontent {|src, content| + + # overwrite by smaller file. + dst = "dst" + File.open(dst, "w") {|f| f << "foobar"} + + ret = IO.copy_stream(src, dst) + assert_equal(content.bytesize, ret) + assert_equal(content, File.read(dst)) + + ret = IO.copy_stream(src, dst, 2) + assert_equal(2, ret) + assert_equal(content[0,2], File.read(dst)) + + ret = IO.copy_stream(src, dst, 0) + assert_equal(0, ret) + assert_equal("", File.read(dst)) + + ret = IO.copy_stream(src, dst, nil, 1) + assert_equal(content.bytesize-1, ret) + assert_equal(content[1..-1], File.read(dst)) + } + end + + def test_copy_stream_noent + with_srccontent {|src, content| + assert_raise(Errno::ENOENT) { + IO.copy_stream("nodir/foo", "dst") + } + + assert_raise(Errno::ENOENT) { + IO.copy_stream(src, "nodir/bar") + } + } + end + + def test_copy_stream_pipe + with_srccontent {|src, content| + pipe(proc do |w| + ret = IO.copy_stream(src, w) + assert_equal(content.bytesize, ret) + w.close + end, proc do |r| + assert_equal(content, r.read) + end) + } + end + + def test_copy_stream_write_pipe + with_srccontent {|src, content| + with_pipe {|r, w| + w.close + assert_raise(IOError) { IO.copy_stream(src, w) } + } + } + end + + def with_pipecontent + mkcdtmpdir { + yield "abc" + } + end + + def test_copy_stream_pipe_to_file + with_pipecontent {|pipe_content| + dst = "dst" + with_read_pipe(pipe_content) {|r| + ret = IO.copy_stream(r, dst) + assert_equal(pipe_content.bytesize, ret) + assert_equal(pipe_content, File.read(dst)) + } + } + end + + def test_copy_stream_read_pipe + with_pipecontent {|pipe_content| + with_read_pipe(pipe_content) {|r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + w2.sync = false + w2 << "def" + ret = IO.copy_stream(r1, w2) + assert_equal(2, ret) + w2.close + end, proc do |r2| + assert_equal("defbc", r2.read) + end) + } + + with_read_pipe(pipe_content) {|r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + w2.sync = false + w2 << "def" + ret = IO.copy_stream(r1, w2, 1) + assert_equal(1, ret) + w2.close + end, proc do |r2| + assert_equal("defb", r2.read) + end) + } + + with_read_pipe(pipe_content) {|r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + ret = IO.copy_stream(r1, w2) + assert_equal(2, ret) + w2.close + end, proc do |r2| + assert_equal("bc", r2.read) + end) + } + + with_read_pipe(pipe_content) {|r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + ret = IO.copy_stream(r1, w2, 1) + assert_equal(1, ret) + w2.close + end, proc do |r2| + assert_equal("b", r2.read) + end) + } + + with_read_pipe(pipe_content) {|r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + ret = IO.copy_stream(r1, w2, 0) + assert_equal(0, ret) + w2.close + end, proc do |r2| + assert_equal("", r2.read) + end) + } + + pipe(proc do |w1| + w1 << "abc" + w1 << "def" + w1.close + end, proc do |r1| + assert_equal("a", r1.getc) + pipe(proc do |w2| + ret = IO.copy_stream(r1, w2) + assert_equal(5, ret) + w2.close + end, proc do |r2| + assert_equal("bcdef", r2.read) + end) + end) + } + end + + def test_copy_stream_file_to_pipe + with_srccontent {|src, content| + pipe(proc do |w| + ret = IO.copy_stream(src, w, 1, 1) + assert_equal(1, ret) + w.close + end, proc do |r| + assert_equal(content[1,1], r.read) + end) + } + end + + if have_nonblock? + def test_copy_stream_pipe_nonblock + mkcdtmpdir { + with_read_pipe("abc") {|r1| + assert_equal("a", r1.getc) + with_pipe {|r2, w2| + begin + w2.nonblock = true + rescue Errno::EBADF + skip "nonblocking IO for pipe is not implemented" + break + end + s = w2.syswrite("a" * 100000) + t = Thread.new { sleep 0.1; r2.read } + ret = IO.copy_stream(r1, w2) + w2.close + assert_equal(2, ret) + assert_equal("a" * s + "bc", t.value) + } + } + } + end + end + + def with_bigcontent + yield "abc" * 123456 + end + + def with_bigsrc + mkcdtmpdir { + with_bigcontent {|bigcontent| + bigsrc = "bigsrc" + File.open("bigsrc", "w") {|f| f << bigcontent } + yield bigsrc, bigcontent + } + } + end + + def test_copy_stream_bigcontent + with_bigsrc {|bigsrc, bigcontent| + ret = IO.copy_stream(bigsrc, "bigdst") + assert_equal(bigcontent.bytesize, ret) + assert_equal(bigcontent, File.read("bigdst")) + } + end + + def test_copy_stream_bigcontent_chop + with_bigsrc {|bigsrc, bigcontent| + ret = IO.copy_stream(bigsrc, "bigdst", nil, 100) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(bigcontent[100..-1], File.read("bigdst")) + } + end + + def test_copy_stream_bigcontent_mid + with_bigsrc {|bigsrc, bigcontent| + ret = IO.copy_stream(bigsrc, "bigdst", 30000, 100) + assert_equal(30000, ret) + assert_equal(bigcontent[100, 30000], File.read("bigdst")) + } + end + + def test_copy_stream_bigcontent_fpos + with_bigsrc {|bigsrc, bigcontent| + File.open(bigsrc) {|f| + begin + assert_equal(0, f.pos) + ret = IO.copy_stream(f, "bigdst", nil, 10) + assert_equal(bigcontent.bytesize-10, ret) + assert_equal(bigcontent[10..-1], File.read("bigdst")) + assert_equal(0, f.pos) + ret = IO.copy_stream(f, "bigdst", 40, 30) + assert_equal(40, ret) + assert_equal(bigcontent[30, 40], File.read("bigdst")) + assert_equal(0, f.pos) + rescue NotImplementedError + #skip "pread(2) is not implemtented." + end + } + } + end + + def test_copy_stream_closed_pipe + with_srccontent {|src,| + with_pipe {|r, w| + w.close + assert_raise(IOError) { IO.copy_stream(src, w) } + } + } + end + + def with_megacontent + yield "abc" * 1234567 + end + + def with_megasrc + mkcdtmpdir { + with_megacontent {|megacontent| + megasrc = "megasrc" + File.open(megasrc, "w") {|f| f << megacontent } + yield megasrc, megacontent + } + } + end + + if have_nonblock? + def test_copy_stream_megacontent_nonblock + with_megacontent {|megacontent| + with_pipe {|r1, w1| + with_pipe {|r2, w2| + begin + r1.nonblock = true + w2.nonblock = true + rescue Errno::EBADF + skip "nonblocking IO for pipe is not implemented" + end + t1 = Thread.new { w1 << megacontent; w1.close } + t2 = Thread.new { r2.read } + t3 = Thread.new { + ret = IO.copy_stream(r1, w2) + assert_equal(megacontent.bytesize, ret) + w2.close + } + _, t2_value, _ = assert_join_threads([t1, t2, t3]) + assert_equal(megacontent, t2_value) + } + } + } + end + end + + def test_copy_stream_megacontent_pipe_to_file + with_megasrc {|megasrc, megacontent| + with_pipe {|r1, w1| + with_pipe {|r2, w2| + t1 = Thread.new { w1 << megacontent; w1.close } + t2 = Thread.new { r2.read } + t3 = Thread.new { + ret = IO.copy_stream(r1, w2) + assert_equal(megacontent.bytesize, ret) + w2.close + } + _, t2_value, _ = assert_join_threads([t1, t2, t3]) + assert_equal(megacontent, t2_value) + } + } + } + end + + def test_copy_stream_megacontent_file_to_pipe + with_megasrc {|megasrc, megacontent| + with_pipe {|r, w| + t1 = Thread.new { r.read } + t2 = Thread.new { + ret = IO.copy_stream(megasrc, w) + assert_equal(megacontent.bytesize, ret) + w.close + } + t1_value, _ = assert_join_threads([t1, t2]) + assert_equal(megacontent, t1_value) + } + } + end + + def test_copy_stream_rbuf + mkcdtmpdir { + begin + pipe(proc do |w| + File.open("foo", "w") {|f| f << "abcd" } + File.open("foo") {|f| + f.read(1) + assert_equal(3, IO.copy_stream(f, w, 10, 1)) + } + w.close + end, proc do |r| + assert_equal("bcd", r.read) + end) + rescue NotImplementedError + skip "pread(2) is not implemtented." + end + } + end + + def with_socketpair + s1, s2 = UNIXSocket.pair + begin + yield s1, s2 + ensure + s1.close unless s1.closed? + s2.close unless s2.closed? + end + end + + def test_copy_stream_socket1 + with_srccontent("foobar") {|src, content| + with_socketpair {|s1, s2| + ret = IO.copy_stream(src, s1) + assert_equal(content.bytesize, ret) + s1.close + assert_equal(content, s2.read) + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket2 + with_bigsrc {|bigsrc, bigcontent| + with_socketpair {|s1, s2| + t1 = Thread.new { s2.read } + t2 = Thread.new { + ret = IO.copy_stream(bigsrc, s1) + assert_equal(bigcontent.bytesize, ret) + s1.close + } + result, _ = assert_join_threads([t1, t2]) + assert_equal(bigcontent, result) + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket3 + with_bigsrc {|bigsrc, bigcontent| + with_socketpair {|s1, s2| + t1 = Thread.new { s2.read } + t2 = Thread.new { + ret = IO.copy_stream(bigsrc, s1, 10000) + assert_equal(10000, ret) + s1.close + } + result, _ = assert_join_threads([t1, t2]) + assert_equal(bigcontent[0,10000], result) + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket4 + with_bigsrc {|bigsrc, bigcontent| + File.open(bigsrc) {|f| + assert_equal(0, f.pos) + with_socketpair {|s1, s2| + t1 = Thread.new { s2.read } + t2 = Thread.new { + ret = IO.copy_stream(f, s1, nil, 100) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(0, f.pos) + s1.close + } + result, _ = assert_join_threads([t1, t2]) + assert_equal(bigcontent[100..-1], result) + } + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket5 + with_bigsrc {|bigsrc, bigcontent| + File.open(bigsrc) {|f| + assert_equal(bigcontent[0,100], f.read(100)) + assert_equal(100, f.pos) + with_socketpair {|s1, s2| + t1 = Thread.new { s2.read } + t2 = Thread.new { + ret = IO.copy_stream(f, s1) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(bigcontent.length, f.pos) + s1.close + } + result, _ = assert_join_threads([t1, t2]) + assert_equal(bigcontent[100..-1], result) + } + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket6 + mkcdtmpdir { + megacontent = "abc" * 1234567 + File.open("megasrc", "w") {|f| f << megacontent } + + with_socketpair {|s1, s2| + begin + s1.nonblock = true + rescue Errno::EBADF + skip "nonblocking IO for pipe is not implemented" + end + t1 = Thread.new { s2.read } + t2 = Thread.new { + ret = IO.copy_stream("megasrc", s1) + assert_equal(megacontent.bytesize, ret) + s1.close + } + result, _ = assert_join_threads([t1, t2]) + assert_equal(megacontent, result) + } + } + end if defined? UNIXSocket + + def test_copy_stream_socket7 + GC.start + mkcdtmpdir { + megacontent = "abc" * 1234567 + File.open("megasrc", "w") {|f| f << megacontent } + + with_socketpair {|s1, s2| + begin + s1.nonblock = true + rescue Errno::EBADF + skip "nonblocking IO for pipe is not implemented" + end + trapping_usr1 do + nr = 30 + begin + pid = fork do + s1.close + IO.select([s2]) + Process.kill(:USR1, Process.ppid) + s2.read + end + s2.close + nr.times do + assert_equal megacontent.bytesize, IO.copy_stream("megasrc", s1) + end + assert_equal(1, @usr1_rcvd) + ensure + s1.close + _, status = Process.waitpid2(pid) if pid + end + assert_predicate(status, :success?) + end + } + } + end if defined? UNIXSocket and IO.method_defined?("nonblock=") + + def test_copy_stream_strio + src = StringIO.new("abcd") + dst = StringIO.new + ret = IO.copy_stream(src, dst) + assert_equal(4, ret) + assert_equal("abcd", dst.string) + assert_equal(4, src.pos) + end + + def test_copy_stream_strio_len + src = StringIO.new("abcd") + dst = StringIO.new + ret = IO.copy_stream(src, dst, 3) + assert_equal(3, ret) + assert_equal("abc", dst.string) + assert_equal(3, src.pos) + end + + def test_copy_stream_strio_off + src = StringIO.new("abcd") + with_pipe {|r, w| + assert_raise(ArgumentError) { + IO.copy_stream(src, w, 3, 1) + } + } + end + + def test_copy_stream_fname_to_strio + mkcdtmpdir { + File.open("foo", "w") {|f| f << "abcd" } + src = "foo" + dst = StringIO.new + ret = IO.copy_stream(src, dst, 3) + assert_equal(3, ret) + assert_equal("abc", dst.string) + } + end + + def test_copy_stream_strio_to_fname + mkcdtmpdir { + # StringIO to filename + src = StringIO.new("abcd") + ret = IO.copy_stream(src, "fooo", 3) + assert_equal(3, ret) + assert_equal("abc", File.read("fooo")) + assert_equal(3, src.pos) + } + end + + def test_copy_stream_io_to_strio + mkcdtmpdir { + # IO to StringIO + File.open("bar", "w") {|f| f << "abcd" } + File.open("bar") {|src| + dst = StringIO.new + ret = IO.copy_stream(src, dst, 3) + assert_equal(3, ret) + assert_equal("abc", dst.string) + assert_equal(3, src.pos) + } + } + end + + def test_copy_stream_strio_to_io + mkcdtmpdir { + # StringIO to IO + src = StringIO.new("abcd") + ret = File.open("baz", "w") {|dst| + IO.copy_stream(src, dst, 3) + } + assert_equal(3, ret) + assert_equal("abc", File.read("baz")) + assert_equal(3, src.pos) + } + end + + def test_copy_stream_write_in_binmode + bug8767 = '[ruby-core:56518] [Bug #8767]' + mkcdtmpdir { + EnvUtil.with_default_internal(Encoding::UTF_8) do + # StringIO to object with to_path + bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT) + src = StringIO.new(bytes) + dst = Object.new + def dst.to_path + "qux" + end + assert_nothing_raised(bug8767) { + IO.copy_stream(src, dst) + } + assert_equal(bytes, File.binread("qux"), bug8767) + assert_equal(4, src.pos, bug8767) + end + } + end + + def test_copy_stream_read_in_binmode + bug8767 = '[ruby-core:56518] [Bug #8767]' + mkcdtmpdir { + EnvUtil.with_default_internal(Encoding::UTF_8) do + # StringIO to object with to_path + bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT) + File.binwrite("qux", bytes) + dst = StringIO.new + src = Object.new + def src.to_path + "qux" + end + assert_nothing_raised(bug8767) { + IO.copy_stream(src, dst) + } + assert_equal(bytes, dst.string.b, bug8767) + assert_equal(4, dst.pos, bug8767) + end + } + end + + class Rot13IO + def initialize(io) + @io = io + end + + def readpartial(*args) + ret = @io.readpartial(*args) + ret.tr!('a-zA-Z', 'n-za-mN-ZA-M') + ret + end + + def write(str) + @io.write(str.tr('a-zA-Z', 'n-za-mN-ZA-M')) + end + + def to_io + @io + end + end + + def test_copy_stream_io_to_rot13 + mkcdtmpdir { + File.open("bar", "w") {|f| f << "vex" } + File.open("bar") {|src| + File.open("baz", "w") {|dst0| + dst = Rot13IO.new(dst0) + ret = IO.copy_stream(src, dst, 3) + assert_equal(3, ret) + } + assert_equal("irk", File.read("baz")) + } + } + end + + def test_copy_stream_rot13_to_io + mkcdtmpdir { + File.open("bar", "w") {|f| f << "flap" } + File.open("bar") {|src0| + src = Rot13IO.new(src0) + File.open("baz", "w") {|dst| + ret = IO.copy_stream(src, dst, 4) + assert_equal(4, ret) + } + } + assert_equal("sync", File.read("baz")) + } + end + + def test_copy_stream_rot13_to_rot13 + mkcdtmpdir { + File.open("bar", "w") {|f| f << "bin" } + File.open("bar") {|src0| + src = Rot13IO.new(src0) + File.open("baz", "w") {|dst0| + dst = Rot13IO.new(dst0) + ret = IO.copy_stream(src, dst, 3) + assert_equal(3, ret) + } + } + assert_equal("bin", File.read("baz")) + } + end + + def test_copy_stream_strio_flush + with_pipe {|r, w| + w.sync = false + w.write "zz" + src = StringIO.new("abcd") + IO.copy_stream(src, w) + t1 = Thread.new { + w.close + } + t2 = Thread.new { r.read } + _, result = assert_join_threads([t1, t2]) + assert_equal("zzabcd", result) + } + end + + def test_copy_stream_strio_rbuf + pipe(proc do |w| + w << "abcd" + w.close + end, proc do |r| + assert_equal("a", r.read(1)) + sio = StringIO.new + IO.copy_stream(r, sio) + assert_equal("bcd", sio.string) + end) + end + + def test_copy_stream_src_wbuf + mkcdtmpdir { + pipe(proc do |w| + File.open("foe", "w+") {|f| + f.write "abcd\n" + f.rewind + f.write "xy" + IO.copy_stream(f, w) + } + assert_equal("xycd\n", File.read("foe")) + w.close + end, proc do |r| + assert_equal("cd\n", r.read) + r.close + end) + } + end + + class Bug5237 + attr_reader :count + def initialize + @count = 0 + end + + def read(bytes, buffer) + @count += 1 + buffer.replace "this is a test" + nil + end + end + + def test_copy_stream_broken_src_read_eof + src = Bug5237.new + dst = StringIO.new + assert_equal 0, src.count + th = Thread.new { IO.copy_stream(src, dst) } + flunk("timeout") unless th.join(10) + assert_equal 1, src.count + end + + def test_copy_stream_dst_rbuf + mkcdtmpdir { + pipe(proc do |w| + w << "xyz" + w.close + end, proc do |r| + File.open("fom", "w+b") {|f| + f.write "abcd\n" + f.rewind + assert_equal("abc", f.read(3)) + f.ungetc "c" + IO.copy_stream(r, f) + } + assert_equal("abxyz", File.read("fom")) + end) + } + end + + def ruby(*args) + args = ['-e', '$>.write($<.read)'] if args.empty? + ruby = EnvUtil.rubybin + f = IO.popen([ruby] + args, 'r+') + pid = f.pid + yield(f) + ensure + f.close unless !f || f.closed? + begin + Process.wait(pid) + rescue Errno::ECHILD, Errno::ESRCH + end + end + + def test_try_convert + assert_equal(STDOUT, IO.try_convert(STDOUT)) + assert_equal(nil, IO.try_convert("STDOUT")) + end + + def test_ungetc2 + f = false + pipe(proc do |w| + Thread.pass until f + w.write("1" * 10000) + w.close + end, proc do |r| + r.ungetc("0" * 10000) + f = true + assert_equal("0" * 10000 + "1" * 10000, r.read) + end) + end + + def test_write_non_writable + with_pipe do |r, w| + assert_raise(IOError) do + r.write "foobarbaz" + end + end + end + + def test_dup + ruby do |f| + begin + f2 = f.dup + f.puts "foo" + f2.puts "bar" + f.close_write + f2.close_write + assert_equal("foo\nbar\n", f.read) + assert_equal("", f2.read) + ensure + f2.close + end + end + end + + def test_dup_many + ruby('-e', <<-'End') {|f| + ok = 0 + a = [] + begin + loop {a << IO.pipe} + rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM + ok += 1 + end + print "no" if ok != 1 + begin + loop {a << [a[-1][0].dup, a[-1][1].dup]} + rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM + ok += 1 + end + print "no" if ok != 2 + print "ok" + End + assert_equal("ok", f.read) + } + end + + def test_inspect + with_pipe do |r, w| + assert_match(/^#<IO:fd \d+>$/, r.inspect) + r.freeze + assert_match(/^#<IO:fd \d+>$/, r.inspect) + end + end + + def test_readpartial + pipe(proc do |w| + w.write "foobarbaz" + w.close + end, proc do |r| + assert_raise(ArgumentError) { r.readpartial(-1) } + assert_equal("fooba", r.readpartial(5)) + r.readpartial(5, s = "") + assert_equal("rbaz", s) + end) + end + + def test_readpartial_lock + with_pipe do |r, w| + s = "" + t = Thread.new { r.readpartial(5, s) } + Thread.pass until t.stop? + assert_raise(RuntimeError) { s.clear } + w.write "foobarbaz" + w.close + assert_equal("fooba", t.value) + end + end + + def test_readpartial_pos + mkcdtmpdir { + open("foo", "w") {|f| f << "abc" } + open("foo") {|f| + f.seek(0) + assert_equal("ab", f.readpartial(2)) + assert_equal(2, f.pos) + } + } + end + + def test_readpartial_with_not_empty_buffer + pipe(proc do |w| + w.write "foob" + w.close + end, proc do |r| + r.readpartial(5, s = "01234567") + assert_equal("foob", s) + end) + end + + def test_readpartial_buffer_error + with_pipe do |r, w| + s = "" + t = Thread.new { r.readpartial(5, s) } + Thread.pass until t.stop? + t.kill + t.value + assert_equal("", s) + end + end + + def test_read + pipe(proc do |w| + w.write "foobarbaz" + w.close + end, proc do |r| + assert_raise(ArgumentError) { r.read(-1) } + assert_equal("fooba", r.read(5)) + r.read(nil, s = "") + assert_equal("rbaz", s) + end) + end + + def test_read_lock + with_pipe do |r, w| + s = "" + t = Thread.new { r.read(5, s) } + Thread.pass until t.stop? + assert_raise(RuntimeError) { s.clear } + w.write "foobarbaz" + w.close + assert_equal("fooba", t.value) + end + end + + def test_read_with_not_empty_buffer + pipe(proc do |w| + w.write "foob" + w.close + end, proc do |r| + r.read(nil, s = "01234567") + assert_equal("foob", s) + end) + end + + def test_read_buffer_error + with_pipe do |r, w| + s = "" + t = Thread.new { r.read(5, s) } + Thread.pass until t.stop? + t.kill + t.value + assert_equal("", s) + end + with_pipe do |r, w| + s = "xxx" + t = Thread.new {r.read(2, s)} + Thread.pass until t.stop? + t.kill + t.value + assert_equal("xxx", s) + end + end + + def test_write_nonblock + pipe(proc do |w| + w.write_nonblock(1) + w.close + end, proc do |r| + assert_equal("1", r.read) + end) + end + + def test_read_nonblock_with_not_empty_buffer + with_pipe {|r, w| + w.write "foob" + w.close + r.read_nonblock(5, s = "01234567") + assert_equal("foob", s) + } + end + + def test_write_nonblock_simple_no_exceptions + pipe(proc do |w| + w.write_nonblock('1', exception: false) + w.close + end, proc do |r| + assert_equal("1", r.read) + end) + end + + def test_read_nonblock_error + return if !have_nonblock? + with_pipe {|r, w| + begin + r.read_nonblock 4096 + rescue Errno::EWOULDBLOCK + assert_kind_of(IO::WaitReadable, $!) + end + } + + with_pipe {|r, w| + begin + r.read_nonblock 4096, "" + rescue Errno::EWOULDBLOCK + assert_kind_of(IO::WaitReadable, $!) + end + } + end + + def test_read_nonblock_no_exceptions + return if !have_nonblock? + with_pipe {|r, w| + assert_equal :wait_readable, r.read_nonblock(4096, exception: false) + w.puts "HI!" + assert_equal "HI!\n", r.read_nonblock(4096, exception: false) + w.close + assert_equal nil, r.read_nonblock(4096, exception: false) + } + end + + def test_read_nonblock_with_buffer_no_exceptions + return if !have_nonblock? + with_pipe {|r, w| + assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false) + w.puts "HI!" + buf = "buf" + value = r.read_nonblock(4096, buf, exception: false) + assert_equal value, "HI!\n" + assert_same(buf, value) + w.close + assert_equal nil, r.read_nonblock(4096, "", exception: false) + } + end + + def test_write_nonblock_error + return if !have_nonblock? + with_pipe {|r, w| + begin + loop { + w.write_nonblock "a"*100000 + } + rescue Errno::EWOULDBLOCK + assert_kind_of(IO::WaitWritable, $!) + end + } + end + + def test_write_nonblock_no_exceptions + return if !have_nonblock? + with_pipe {|r, w| + loop { + ret = w.write_nonblock("a"*100000, exception: false) + if ret.is_a?(Symbol) + assert_equal :wait_writable, ret + break + end + } + } + end + + def test_gets + pipe(proc do |w| + w.write "foobarbaz" + w.close + end, proc do |r| + assert_equal("", r.gets(0)) + assert_equal("foobarbaz", r.gets(9)) + end) + end + + def test_close_read + ruby do |f| + f.close_read + f.write "foobarbaz" + assert_raise(IOError) { f.read } + end + end + + def test_close_read_pipe + with_pipe do |r, w| + r.close_read + assert_raise(Errno::EPIPE) { w.write "foobarbaz" } + end + end + + def test_write_epipe_nosync + assert_separately([], <<-"end;") + r, w = IO.pipe + r.close + w.sync = false + assert_raise(Errno::EPIPE) { + loop { w.write "a" } + } + end; + end + + def test_close_read_non_readable + with_pipe do |r, w| + assert_raise(IOError) do + w.close_read + end + end + end + + def test_close_write + ruby do |f| + f.write "foobarbaz" + f.close_write + assert_equal("foobarbaz", f.read) + end + end + + def test_close_write_non_readable + with_pipe do |r, w| + assert_raise(IOError) do + r.close_write + end + end + end + + def test_close_read_write_separately + bug = '[ruby-list:49598]' + (1..10).each do |i| + assert_nothing_raised(IOError, "#{bug} trying ##{i}") do + IO.popen(EnvUtil.rubybin, "r+") {|f| + th = Thread.new {f.close_write} + f.close_read + th.join + } + end + end + end + + def test_pid + IO.pipe {|r, w| + assert_equal(nil, r.pid) + assert_equal(nil, w.pid) + } + + begin + pipe = IO.popen(EnvUtil.rubybin, "r+") + pid1 = pipe.pid + pipe.puts "p $$" + pipe.close_write + pid2 = pipe.read.chomp.to_i + assert_equal(pid2, pid1) + assert_equal(pid2, pipe.pid) + ensure + pipe.close + end + assert_raise(IOError) { pipe.pid } + end + + def test_pid_after_close_read + pid1 = pid2 = nil + IO.popen("exit ;", "r+") do |io| + pid1 = io.pid + io.close_read + pid2 = io.pid + end + assert_not_nil(pid1) + assert_equal(pid1, pid2) + end + + def make_tempfile + t = Tempfile.new("test_io") + t.binmode + t.puts "foo" + t.puts "bar" + t.puts "baz" + t.close + if block_given? + begin + yield t + ensure + t.close(true) + end + else + t + end + end + + def test_set_lineno + make_tempfile {|t| + ruby("-e", <<-SRC, t.path) do |f| + open(ARGV[0]) do |f| + p $. + f.gets; p $. + f.gets; p $. + f.lineno = 1000; p $. + f.gets; p $. + f.gets; p $. + f.rewind; p $. + f.gets; p $. + f.gets; p $. + f.gets; p $. + f.gets; p $. + end + SRC + assert_equal("0,1,2,2,1001,1001,1001,1,2,3,3", f.read.chomp.gsub("\n", ",")) + end + + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + r.gets; assert_equal(1, $.) + r.gets; assert_equal(2, $.) + r.lineno = 1000; assert_equal(2, $.) + r.gets; assert_equal(1001, $.) + r.gets; assert_equal(1001, $.) + end) + } + end + + def test_readline + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + r.readline; assert_equal(1, $.) + r.readline; assert_equal(2, $.) + r.lineno = 1000; assert_equal(2, $.) + r.readline; assert_equal(1001, $.) + assert_raise(EOFError) { r.readline } + end) + end + + def test_each_char + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + a = [] + r.each_char {|c| a << c } + assert_equal(%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"], a) + end) + end + + def test_lines + verbose, $VERBOSE = $VERBOSE, nil + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + e = nil + assert_warn(/deprecated/) { + e = r.lines + } + assert_equal("foo\n", e.next) + assert_equal("bar\n", e.next) + assert_equal("baz\n", e.next) + assert_raise(StopIteration) { e.next } + end) + ensure + $VERBOSE = verbose + end + + def test_bytes + verbose, $VERBOSE = $VERBOSE, nil + pipe(proc do |w| + w.binmode + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + e = nil + assert_warn(/deprecated/) { + e = r.bytes + } + (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| + assert_equal(c.ord, e.next) + end + assert_raise(StopIteration) { e.next } + end) + ensure + $VERBOSE = verbose + end + + def test_chars + verbose, $VERBOSE = $VERBOSE, nil + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + e = nil + assert_warn(/deprecated/) { + e = r.chars + } + (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| + assert_equal(c, e.next) + end + assert_raise(StopIteration) { e.next } + end) + ensure + $VERBOSE = verbose + end + + def test_readbyte + pipe(proc do |w| + w.binmode + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + r.binmode + (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| + assert_equal(c.ord, r.readbyte) + end + assert_raise(EOFError) { r.readbyte } + end) + end + + def test_readchar + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| + assert_equal(c, r.readchar) + end + assert_raise(EOFError) { r.readchar } + end) + end + + def test_close_on_exec + skip "IO\#close_on_exec is not implemented." unless have_close_on_exec? + ruby do |f| + assert_equal(true, f.close_on_exec?) + f.close_on_exec = false + assert_equal(false, f.close_on_exec?) + f.close_on_exec = true + assert_equal(true, f.close_on_exec?) + f.close_on_exec = false + assert_equal(false, f.close_on_exec?) + end + + with_pipe do |r, w| + assert_equal(true, r.close_on_exec?) + r.close_on_exec = false + assert_equal(false, r.close_on_exec?) + r.close_on_exec = true + assert_equal(true, r.close_on_exec?) + r.close_on_exec = false + assert_equal(false, r.close_on_exec?) + + assert_equal(true, w.close_on_exec?) + w.close_on_exec = false + assert_equal(false, w.close_on_exec?) + w.close_on_exec = true + assert_equal(true, w.close_on_exec?) + w.close_on_exec = false + assert_equal(false, w.close_on_exec?) + end + end + + def test_pos + make_tempfile {|t| + + open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f| + f.write "Hello" + assert_equal(5, f.pos) + end + open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f| + f.sync = true + f.read + f.write "Hello" + assert_equal(5, f.pos) + end + } + end + + def test_pos_with_getc + _bug6179 = '[ruby-core:43497]' + make_tempfile {|t| + ["", "t", "b"].each do |mode| + open(t.path, "w#{mode}") do |f| + f.write "0123456789\n" + end + + open(t.path, "r#{mode}") do |f| + assert_equal 0, f.pos, "mode=r#{mode}" + assert_equal '0', f.getc, "mode=r#{mode}" + assert_equal 1, f.pos, "mode=r#{mode}" + assert_equal '1', f.getc, "mode=r#{mode}" + assert_equal 2, f.pos, "mode=r#{mode}" + assert_equal '2', f.getc, "mode=r#{mode}" + assert_equal 3, f.pos, "mode=r#{mode}" + assert_equal '3', f.getc, "mode=r#{mode}" + assert_equal 4, f.pos, "mode=r#{mode}" + assert_equal '4', f.getc, "mode=r#{mode}" + end + end + } + end + + def can_seek_data(f) + if /linux/ =~ RUBY_PLATFORM + require "-test-/file" + # lseek(2) + case Bug::File::Fs.fsname(f.path) + when "btrfs" + return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,1]) >= 0 + when "ocfs" + return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,2]) >= 0 + when "xfs" + return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,5]) >= 0 + when "ext4" + return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0 + when "tmpfs" + return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0 + end + end + false + end + + def test_seek + make_tempfile {|t| + open(t.path) { |f| + f.seek(9) + assert_equal("az\n", f.read) + } + + open(t.path) { |f| + f.seek(9, IO::SEEK_SET) + assert_equal("az\n", f.read) + } + + open(t.path) { |f| + f.seek(-4, IO::SEEK_END) + assert_equal("baz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, IO::SEEK_CUR) + assert_equal("r\nbaz\n", f.read) + } + + if defined?(IO::SEEK_DATA) + open(t.path) { |f| + break unless can_seek_data(f) + assert_equal("foo\n", f.gets) + f.seek(0, IO::SEEK_DATA) + assert_equal("foo\nbar\nbaz\n", f.read) + } + open(t.path, 'r+') { |f| + break unless can_seek_data(f) + f.seek(100*1024, IO::SEEK_SET) + f.print("zot\n") + f.seek(50*1024, IO::SEEK_DATA) + assert_operator(f.pos, :>=, 50*1024) + assert_match(/\A\0*zot\n\z/, f.read) + } + end + + if defined?(IO::SEEK_HOLE) + open(t.path) { |f| + break unless can_seek_data(f) + assert_equal("foo\n", f.gets) + f.seek(0, IO::SEEK_HOLE) + assert_operator(f.pos, :>, 20) + f.seek(100*1024, IO::SEEK_HOLE) + assert_equal("", f.read) + } + end + } + end + + def test_seek_symwhence + make_tempfile {|t| + open(t.path) { |f| + f.seek(9, :SET) + assert_equal("az\n", f.read) + } + + open(t.path) { |f| + f.seek(-4, :END) + assert_equal("baz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, :CUR) + assert_equal("r\nbaz\n", f.read) + } + + if defined?(IO::SEEK_DATA) + open(t.path) { |f| + break unless can_seek_data(f) + assert_equal("foo\n", f.gets) + f.seek(0, :DATA) + assert_equal("foo\nbar\nbaz\n", f.read) + } + open(t.path, 'r+') { |f| + break unless can_seek_data(f) + f.seek(100*1024, :SET) + f.print("zot\n") + f.seek(50*1024, :DATA) + assert_operator(f.pos, :>=, 50*1024) + assert_match(/\A\0*zot\n\z/, f.read) + } + end + + if defined?(IO::SEEK_HOLE) + open(t.path) { |f| + break unless can_seek_data(f) + assert_equal("foo\n", f.gets) + f.seek(0, :HOLE) + assert_operator(f.pos, :>, 20) + f.seek(100*1024, :HOLE) + assert_equal("", f.read) + } + end + } + end + + def test_sysseek + make_tempfile {|t| + open(t.path) do |f| + f.sysseek(-4, IO::SEEK_END) + assert_equal("baz\n", f.read) + end + + open(t.path) do |f| + a = [f.getc, f.getc, f.getc] + a.reverse_each {|c| f.ungetc c } + assert_raise(IOError) { f.sysseek(1) } + end + } + end + + def test_syswrite + make_tempfile {|t| + open(t.path, "w") do |f| + o = Object.new + def o.to_s; "FOO\n"; end + f.syswrite(o) + end + assert_equal("FOO\n", File.read(t.path)) + } + end + + def test_sysread + make_tempfile {|t| + open(t.path) do |f| + a = [f.getc, f.getc, f.getc] + a.reverse_each {|c| f.ungetc c } + assert_raise(IOError) { f.sysread(1) } + end + } + end + + def test_sysread_with_not_empty_buffer + pipe(proc do |w| + w.write "foob" + w.close + end, proc do |r| + r.sysread( 5, s = "01234567" ) + assert_equal( "foob", s ) + end) + end + + def test_flag + make_tempfile {|t| + assert_raise(ArgumentError) do + open(t.path, "z") { } + end + + assert_raise(ArgumentError) do + open(t.path, "rr") { } + end + } + end + + def test_sysopen + make_tempfile {|t| + fd = IO.sysopen(t.path) + assert_kind_of(Integer, fd) + f = IO.for_fd(fd) + assert_equal("foo\nbar\nbaz\n", f.read) + f.close + + fd = IO.sysopen(t.path, "w", 0666) + assert_kind_of(Integer, fd) + if defined?(Fcntl::F_GETFL) + f = IO.for_fd(fd) + else + f = IO.for_fd(fd, 0666) + end + f.write("FOO\n") + f.close + + fd = IO.sysopen(t.path, "r") + assert_kind_of(Integer, fd) + f = IO.for_fd(fd) + assert_equal("FOO\n", f.read) + f.close + } + end + + def try_fdopen(fd, autoclose = true, level = 50) + if level > 0 + begin + 1.times {return try_fdopen(fd, autoclose, level - 1)} + ensure + GC.start + end + else + WeakRef.new(IO.for_fd(fd, autoclose: autoclose)) + end + end + + def test_autoclose + feature2250 = '[ruby-core:26222]' + pre = 'ft2250' + + Dir.mktmpdir {|d| + t = open("#{d}/#{pre}", "w") + f = IO.for_fd(t.fileno) + assert_equal(true, f.autoclose?) + f.autoclose = false + assert_equal(false, f.autoclose?) + f.close + assert_nothing_raised(Errno::EBADF, feature2250) {t.close} + + t = open("#{d}/#{pre}", "w") + f = IO.for_fd(t.fileno, autoclose: false) + assert_equal(false, f.autoclose?) + f.autoclose = true + assert_equal(true, f.autoclose?) + f.close + assert_raise(Errno::EBADF, feature2250) {t.close} + } + end + + def test_autoclose_true_closed_by_finalizer + feature2250 = '[ruby-core:26222]' + pre = 'ft2250' + t = Tempfile.new(pre) + w = try_fdopen(t.fileno) + begin + w.close + begin + t.close + rescue Errno::EBADF + end + skip "expect IO object was GC'ed but not recycled yet" + rescue WeakRef::RefError + assert_raise(Errno::EBADF, feature2250) {t.close} + end + ensure + t.close! + end + + def test_autoclose_false_closed_by_finalizer + feature2250 = '[ruby-core:26222]' + pre = 'ft2250' + t = Tempfile.new(pre) + w = try_fdopen(t.fileno, false) + begin + w.close + t.close + skip "expect IO object was GC'ed but not recycled yet" + rescue WeakRef::RefError + assert_nothing_raised(Errno::EBADF, feature2250) {t.close} + end + ensure + t.close! + end + + def test_open_redirect + o = Object.new + def o.to_open; self; end + assert_equal(o, open(o)) + o2 = nil + open(o) do |f| + o2 = f + end + assert_equal(o, o2) + end + + def test_open_pipe + open("|" + EnvUtil.rubybin, "r+") do |f| + f.puts "puts 'foo'" + f.close_write + assert_equal("foo\n", f.read) + end + end + + def test_reopen + make_tempfile {|t| + open(__FILE__) do |f| + f.gets + assert_nothing_raised { + f.reopen(t.path) + assert_equal("foo\n", f.gets) + } + end + + open(__FILE__) do |f| + f.gets + f2 = open(t.path) + begin + f2.gets + assert_nothing_raised { + f.reopen(f2) + assert_equal("bar\n", f.gets, '[ruby-core:24240]') + } + ensure + f2.close + end + end + + open(__FILE__) do |f| + f2 = open(t.path) + begin + f.reopen(f2) + assert_equal("foo\n", f.gets) + assert_equal("bar\n", f.gets) + f.reopen(f2) + assert_equal("baz\n", f.gets, '[ruby-dev:39479]') + ensure + f2.close + end + end + } + end + + def test_reopen_inherit + mkcdtmpdir { + system(EnvUtil.rubybin, '-e', <<"End") + f = open("out", "w") + STDOUT.reopen(f) + STDERR.reopen(f) + system(#{EnvUtil.rubybin.dump}, '-e', 'STDOUT.print "out"') + system(#{EnvUtil.rubybin.dump}, '-e', 'STDERR.print "err"') +End + assert_equal("outerr", File.read("out")) + } + end + + def test_reopen_stdio + mkcdtmpdir { + fname = 'bug11319' + File.write(fname, 'hello') + system(EnvUtil.rubybin, '-e', "STDOUT.reopen('#{fname}', 'w+')") + assert_equal('', File.read(fname)) + } + end + + def test_reopen_mode + feature7067 = '[ruby-core:47694]' + make_tempfile {|t| + open(__FILE__) do |f| + assert_nothing_raised { + f.reopen(t.path, "r") + assert_equal("foo\n", f.gets) + } + end + + open(__FILE__) do |f| + assert_nothing_raised(feature7067) { + f.reopen(t.path, File::RDONLY) + assert_equal("foo\n", f.gets) + } + end + } + end + + def test_reopen_opt + feature7103 = '[ruby-core:47806]' + make_tempfile {|t| + open(__FILE__) do |f| + assert_nothing_raised(feature7103) { + f.reopen(t.path, "r", binmode: true) + } + assert_equal("foo\n", f.gets) + end + + open(__FILE__) do |f| + assert_nothing_raised(feature7103) { + f.reopen(t.path, autoclose: false) + } + assert_equal("foo\n", f.gets) + end + } + end + + def make_tempfile_for_encoding + t = make_tempfile + open(t.path, "rb+:utf-8") {|f| f.puts "\u7d05\u7389bar\n"} + if block_given? + yield t + else + t + end + ensure + t.close(true) if t and block_given? + end + + def test_reopen_encoding + make_tempfile_for_encoding {|t| + open(__FILE__) {|f| + f.reopen(t.path, "r:utf-8") + s = f.gets + assert_equal(Encoding::UTF_8, s.encoding) + assert_equal("\u7d05\u7389bar\n", s) + } + + open(__FILE__) {|f| + f.reopen(t.path, "r:UTF-8:EUC-JP") + s = f.gets + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s) + } + } + end + + def test_reopen_opt_encoding + feature7103 = '[ruby-core:47806]' + make_tempfile_for_encoding {|t| + open(__FILE__) {|f| + assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "ASCII-8BIT")} + s = f.gets + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xe7\xb4\x85\xe7\x8e\x89bar\n", s) + } + + open(__FILE__) {|f| + assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "UTF-8:EUC-JP")} + s = f.gets + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s) + } + } + end + + def test_foreach + a = [] + IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x } + assert_equal(["foo\n", "bar\n", "baz\n"], a) + + make_tempfile {|t| + a = [] + IO.foreach(t.path) {|x| a << x } + assert_equal(["foo\n", "bar\n", "baz\n"], a) + + a = [] + IO.foreach(t.path, {:mode => "r" }) {|x| a << x } + assert_equal(["foo\n", "bar\n", "baz\n"], a) + + a = [] + IO.foreach(t.path, {:open_args => [] }) {|x| a << x } + assert_equal(["foo\n", "bar\n", "baz\n"], a) + + a = [] + IO.foreach(t.path, {:open_args => ["r"] }) {|x| a << x } + assert_equal(["foo\n", "bar\n", "baz\n"], a) + + a = [] + IO.foreach(t.path, "b") {|x| a << x } + assert_equal(["foo\nb", "ar\nb", "az\n"], a) + + a = [] + IO.foreach(t.path, 3) {|x| a << x } + assert_equal(["foo", "\n", "bar", "\n", "baz", "\n"], a) + + a = [] + IO.foreach(t.path, "b", 3) {|x| a << x } + assert_equal(["foo", "\nb", "ar\n", "b", "az\n"], a) + + bug = '[ruby-dev:31525]' + assert_raise(ArgumentError, bug) {IO.foreach} + + a = nil + assert_nothing_raised(ArgumentError, bug) {a = IO.foreach(t.path).to_a} + assert_equal(["foo\n", "bar\n", "baz\n"], a, bug) + + bug6054 = '[ruby-dev:45267]' + assert_raise_with_message(IOError, /not opened for reading/, bug6054) do + IO.foreach(t.path, mode:"w").next + end + } + end + + def test_s_readlines + make_tempfile {|t| + assert_equal(["foo\n", "bar\n", "baz\n"], IO.readlines(t.path)) + assert_equal(["foo\nb", "ar\nb", "az\n"], IO.readlines(t.path, "b")) + assert_equal(["fo", "o\n", "ba", "r\n", "ba", "z\n"], IO.readlines(t.path, 2)) + assert_equal(["fo", "o\n", "b", "ar", "\nb", "az", "\n"], IO.readlines(t.path, "b", 2)) + } + end + + def test_printf + pipe(proc do |w| + printf(w, "foo %s baz\n", "bar") + w.close_write + end, proc do |r| + assert_equal("foo bar baz\n", r.read) + end) + end + + def test_print + make_tempfile {|t| + assert_in_out_err(["-", t.path], + "print while $<.gets", + %w(foo bar baz), []) + } + end + + def test_print_separators + $, = ':' + $\ = "\n" + pipe(proc do |w| + w.print('a') + w.print('a','b','c') + w.close + end, proc do |r| + assert_equal("a\n", r.gets) + assert_equal("a:b:c\n", r.gets) + assert_nil r.gets + r.close + end) + ensure + $, = nil + $\ = nil + end + + def test_putc + pipe(proc do |w| + w.putc "A" + w.putc "BC" + w.putc 68 + w.close_write + end, proc do |r| + assert_equal("ABD", r.read) + end) + + assert_in_out_err([], "putc 65", %w(A), []) + end + + def test_puts_recursive_array + a = ["foo"] + a << a + pipe(proc do |w| + w.puts a + w.close + end, proc do |r| + assert_equal("foo\n[...]\n", r.read) + end) + end + + def test_display + pipe(proc do |w| + "foo".display(w) + w.close + end, proc do |r| + assert_equal("foo", r.read) + end) + + assert_in_out_err([], "'foo'.display", %w(foo), []) + end + + def test_set_stdout + assert_raise(TypeError) { $> = Object.new } + + assert_in_out_err([], "$> = $stderr\nputs 'foo'", [], %w(foo)) + + assert_separately(%w[-Eutf-8], <<-"end;") # do + alias $\u{6a19 6e96 51fa 529b} $stdout + x = eval("class X\u{307b 3052}; self; end".encode("euc-jp")) + assert_raise_with_message(TypeError, /\\$\u{6a19 6e96 51fa 529b} must.*, X\u{307b 3052} given/) do + $\u{6a19 6e96 51fa 529b} = x.new + end + end; + end + + def test_initialize + return unless defined?(Fcntl::F_GETFL) + + make_tempfile {|t| + + fd = IO.sysopen(t.path, "w") + assert_kind_of(Integer, fd) + %w[r r+ w+ a+].each do |mode| + assert_raise(Errno::EINVAL, "#{mode} [ruby-dev:38571]") {IO.new(fd, mode)} + end + f = IO.new(fd, "w") + f.write("FOO\n") + f.close + + assert_equal("FOO\n", File.read(t.path)) + } + end + + def test_reinitialize + make_tempfile {|t| + f = open(t.path) + begin + assert_raise(RuntimeError) do + f.instance_eval { initialize } + end + ensure + f.close + end + } + end + + def test_new_with_block + assert_in_out_err([], "r, w = IO.pipe; r.autoclose=false; IO.new(r.fileno) {}.close", [], /^.+$/) + n = "IO\u{5165 51fa 529b}" + c = eval("class #{n} < IO; self; end") + IO.pipe do |r, w| + assert_warning(/#{n}/) { + r.autoclose=false + io = c.new(r.fileno) {} + io.close + } + end + end + + def test_readline2 + assert_in_out_err(["-e", <<-SRC], "foo\nbar\nbaz\n", %w(foo bar baz end), []) + puts readline + puts readline + puts readline + begin + puts readline + rescue EOFError + puts "end" + end + SRC + end + + def test_readlines + assert_in_out_err(["-e", "p readlines"], "foo\nbar\nbaz\n", + ["[\"foo\\n\", \"bar\\n\", \"baz\\n\"]"], []) + end + + def test_s_read + make_tempfile {|t| + assert_equal("foo\nbar\nbaz\n", File.read(t.path)) + assert_equal("foo\nba", File.read(t.path, 6)) + assert_equal("bar\n", File.read(t.path, 4, 4)) + } + end + + def test_uninitialized + assert_raise(IOError) { IO.allocate.print "" } + end + + def test_nofollow + # O_NOFOLLOW is not standard. + return if /freebsd|linux/ !~ RUBY_PLATFORM + return unless defined? File::NOFOLLOW + mkcdtmpdir { + open("file", "w") {|f| f << "content" } + begin + File.symlink("file", "slnk") + rescue NotImplementedError + return + end + assert_raise(Errno::EMLINK, Errno::ELOOP) { + open("slnk", File::RDONLY|File::NOFOLLOW) {} + } + assert_raise(Errno::EMLINK, Errno::ELOOP) { + File.foreach("slnk", :open_args=>[File::RDONLY|File::NOFOLLOW]) {} + } + } + end + + def test_tainted + make_tempfile {|t| + assert_predicate(File.read(t.path, 4), :tainted?, '[ruby-dev:38826]') + assert_predicate(File.open(t.path) {|f| f.read(4)}, :tainted?, '[ruby-dev:38826]') + } + end + + def test_binmode_after_closed + make_tempfile {|t| + assert_raise(IOError) {t.binmode} + } + end + + def test_threaded_flush + bug3585 = '[ruby-core:31348]' + src = %q{\ + t = Thread.new { sleep 3 } + Thread.new {sleep 1; t.kill; p 'hi!'} + t.join + }.gsub(/^\s+/, '') + 10.times.map do + Thread.start do + assert_in_out_err([], src) {|stdout, stderr| + assert_no_match(/hi.*hi/, stderr.join, bug3585) + } + end + end.each {|th| th.join} + end + + def test_flush_in_finalizer1 + require 'tempfile' + bug3910 = '[ruby-dev:42341]' + t = Tempfile.open("bug3910") {|t| + path = t.path + t.close + fds = [] + assert_nothing_raised(TypeError, bug3910) do + 500.times { + f = File.open(path, "w") + f.instance_variable_set(:@test_flush_in_finalizer1, true) + fds << f.fileno + f.print "hoge" + } + end + t + } + ensure + ObjectSpace.each_object(File) {|f| + if f.instance_variables.include?(:@test_flush_in_finalizer1) + f.close + end + } + t.close! + end + + def test_flush_in_finalizer2 + require 'tempfile' + bug3910 = '[ruby-dev:42341]' + Tempfile.open("bug3910") {|t| + path = t.path + t.close + begin + 1.times do + io = open(path,"w") + io.instance_variable_set(:@test_flush_in_finalizer2, true) + io.print "hoge" + end + assert_nothing_raised(TypeError, bug3910) do + GC.start + end + ensure + ObjectSpace.each_object(File) {|f| + if f.instance_variables.include?(:@test_flush_in_finalizer2) + f.close + end + } + end + t.close! + } + end + + def test_readlines_limit_0 + bug4024 = '[ruby-dev:42538]' + make_tempfile {|t| + open(t.path, "r") do |io| + assert_raise(ArgumentError, bug4024) do + io.readlines(0) + end + end + } + end + + def test_each_line_limit_0 + bug4024 = '[ruby-dev:42538]' + make_tempfile {|t| + open(t.path, "r") do |io| + assert_raise(ArgumentError, bug4024) do + io.each_line(0).next + end + end + } + end + + def os_and_fs(path) + uname = Etc.uname + os = "#{uname[:sysname]} #{uname[:release]}" + + fs = nil + if uname[:sysname] == 'Linux' + # [ruby-dev:45703] Old Linux's fadvice() doesn't work on tmpfs. + mount = `mount` + mountpoints = [] + mount.scan(/ on (\S+) type (\S+) /) { + mountpoints << [$1, $2] + } + mountpoints.sort_by {|mountpoint, fstype| mountpoint.length }.reverse_each {|mountpoint, fstype| + if path == mountpoint + fs = fstype + break + end + mountpoint += "/" if %r{/\z} !~ mountpoint + if path.start_with?(mountpoint) + fs = fstype + break + end + } + end + + if fs + "#{fs} on #{os}" + else + os + end + end + + def test_advise + make_tempfile {|tf| + assert_raise(ArgumentError, "no arguments") { tf.advise } + %w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv| + [[0,0], [0, 20], [400, 2]].each do |offset, len| + open(tf.path) do |t| + ret = assert_nothing_raised(lambda { os_and_fs(tf.path) }) { + begin + t.advise(adv, offset, len) + rescue Errno::EINVAL => e + if /linux/ =~ RUBY_PLATFORM && (Etc.uname[:release].split('.').map(&:to_i) <=> [3,6]) < 0 + next # [ruby-core:65355] tmpfs is not supported + else + raise e + end + end + } + assert_nil(ret) + assert_raise(ArgumentError, "superfluous arguments") do + t.advise(adv, offset, len, offset) + end + assert_raise(TypeError, "wrong type for first argument") do + t.advise(adv.to_s, offset, len) + end + assert_raise(TypeError, "wrong type for last argument") do + t.advise(adv, offset, Array(len)) + end + assert_raise(RangeError, "last argument too big") do + t.advise(adv, offset, 9999e99) + end + end + assert_raise(IOError, "closed file") do + make_tempfile {|tf2| + tf2.advise(adv.to_sym, offset, len) + } + end + end + end + } + end + + def test_invalid_advise + feature4204 = '[ruby-dev:42887]' + make_tempfile {|tf| + %W{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv| + [[0,0], [0, 20], [400, 2]].each do |offset, len| + open(tf.path) do |t| + assert_raise_with_message(NotImplementedError, /#{Regexp.quote(adv.inspect)}/, feature4204) { t.advise(adv, offset, len) } + end + end + end + } + end + + def test_fcntl_lock_linux + return if /x86_64-linux/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform + return if [nil].pack("p").bytesize != 8 # Return if x32 platform. + + pad=0 + Tempfile.create(self.class.name) do |f| + r, w = IO.pipe + pid = fork do + r.close + lock = [Fcntl::F_WRLCK, IO::SEEK_SET, pad, 12, 34, 0].pack("s!s!i!L!L!i!") + f.fcntl Fcntl::F_SETLKW, lock + w.syswrite "." + sleep + end + w.close + assert_equal ".", r.read(1) + r.close + pad = 0 + getlock = [Fcntl::F_WRLCK, 0, pad, 0, 0, 0].pack("s!s!i!L!L!i!") + f.fcntl Fcntl::F_GETLK, getlock + + ptype, whence, pad, start, len, lockpid = getlock.unpack("s!s!i!L!L!i!") + + assert_equal(ptype, Fcntl::F_WRLCK) + assert_equal(whence, IO::SEEK_SET) + assert_equal(start, 12) + assert_equal(len, 34) + assert_equal(pid, lockpid) + + Process.kill :TERM, pid + Process.waitpid2(pid) + end + end + + def test_fcntl_lock_freebsd + return if /freebsd/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform + + start = 12 + len = 34 + sysid = 0 + Tempfile.create(self.class.name) do |f| + r, w = IO.pipe + pid = fork do + r.close + lock = [start, len, 0, Fcntl::F_WRLCK, IO::SEEK_SET, sysid].pack("qqis!s!i!") + f.fcntl Fcntl::F_SETLKW, lock + w.syswrite "." + sleep + end + w.close + assert_equal ".", r.read(1) + r.close + + getlock = [0, 0, 0, Fcntl::F_WRLCK, 0, 0].pack("qqis!s!i!") + f.fcntl Fcntl::F_GETLK, getlock + + start, len, lockpid, ptype, whence, sysid = getlock.unpack("qqis!s!i!") + + assert_equal(ptype, Fcntl::F_WRLCK) + assert_equal(whence, IO::SEEK_SET) + assert_equal(start, 12) + assert_equal(len, 34) + assert_equal(pid, lockpid) + + Process.kill :TERM, pid + Process.waitpid2(pid) + end + end + + def test_fcntl_dupfd + Tempfile.create(self.class.name) do |f| + fd = f.fcntl(Fcntl::F_DUPFD, 63) + begin + assert_operator(fd, :>=, 63) + ensure + IO.for_fd(fd).close + end + end + end + + def test_cross_thread_close_fd + with_pipe do |r,w| + read_thread = Thread.new do + begin + r.read(1) + rescue => e + e + end + end + + sleep(0.1) until read_thread.stop? + r.close + read_thread.join + assert_kind_of(IOError, read_thread.value) + end + end + + def test_cross_thread_close_stdio + assert_separately([], <<-'end;') + IO.pipe do |r,w| + $stdin.reopen(r) + r.close + read_thread = Thread.new do + $stdin.read(1) + end + sleep(0.1) until read_thread.stop? + $stdin.close + assert_raise(IOError) {read_thread.join} + end + end; + end + + def test_open_mode + feature4742 = "[ruby-core:36338]" + bug6055 = '[ruby-dev:45268]' + + mkcdtmpdir do + assert_not_nil(f = File.open('symbolic', 'w')) + f.close + assert_not_nil(f = File.open('numeric', File::WRONLY|File::TRUNC|File::CREAT)) + f.close + assert_not_nil(f = File.open('hash-symbolic', :mode => 'w')) + f.close + assert_not_nil(f = File.open('hash-numeric', :mode => File::WRONLY|File::TRUNC|File::CREAT), feature4742) + f.close + assert_nothing_raised(bug6055) {f = File.open('hash-symbolic', binmode: true)} + f.close + end + end + + def test_s_write + mkcdtmpdir do + path = "test_s_write" + File.write(path, "foo\nbar\nbaz") + assert_equal("foo\nbar\nbaz", File.read(path)) + File.write(path, "FOO", 0) + assert_equal("FOO\nbar\nbaz", File.read(path)) + File.write(path, "BAR") + assert_equal("BAR", File.read(path)) + File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP") + assert_equal("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP")) + File.delete path + assert_equal(6, File.write(path, 'string', 2)) + File.delete path + assert_raise(Errno::EINVAL) { File.write('nonexisting','string', -2) } + assert_equal(6, File.write(path, 'string')) + assert_equal(3, File.write(path, 'sub', 1)) + assert_equal("ssubng", File.read(path)) + File.delete path + assert_equal(3, File.write(path, "foo", encoding: "UTF-8")) + File.delete path + assert_equal(3, File.write(path, "foo", 0, encoding: "UTF-8")) + assert_equal("foo", File.read(path)) + assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8")) + assert_equal("ffo", File.read(path)) + File.delete path + assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8")) + assert_equal("\00f", File.read(path)) + assert_equal(1, File.write(path, "f", 0, encoding: "UTF-8")) + assert_equal("ff", File.read(path)) + assert_raise(TypeError) { + File.write(path, "foo", Object.new => Object.new) + } + end + end + + def test_s_binwrite + mkcdtmpdir do + path = "test_s_binwrite" + File.binwrite(path, "foo\nbar\nbaz") + assert_equal("foo\nbar\nbaz", File.read(path)) + File.binwrite(path, "FOO", 0) + assert_equal("FOO\nbar\nbaz", File.read(path)) + File.binwrite(path, "BAR") + assert_equal("BAR", File.read(path)) + File.binwrite(path, "\u{3042}") + assert_equal("\u{3042}".force_encoding("ASCII-8BIT"), File.binread(path)) + File.delete path + assert_equal(6, File.binwrite(path, 'string', 2)) + File.delete path + assert_equal(6, File.binwrite(path, 'string')) + assert_equal(3, File.binwrite(path, 'sub', 1)) + assert_equal("ssubng", File.binread(path)) + assert_equal(6, File.size(path)) + assert_raise(Errno::EINVAL) { File.binwrite('nonexisting', 'string', -2) } + assert_nothing_raised(TypeError) { File.binwrite(path, "string", mode: "w", encoding: "EUC-JP") } + end + end + + def test_race_between_read + Tempfile.create("test") {|file| + begin + path = file.path + file.close + write_file = File.open(path, "wt") + read_file = File.open(path, "rt") + + threads = [] + 10.times do |i| + threads << Thread.new {write_file.print(i)} + threads << Thread.new {read_file.read} + end + assert_join_threads(threads) + assert(true, "[ruby-core:37197]") + ensure + read_file.close + write_file.close + end + } + end + + def test_warn + assert_warning "warning\n" do + warn "warning" + end + + assert_warning '' do + warn + end + + assert_warning "[Feature #5029]\n[ruby-core:38070]\n" do + warn "[Feature #5029]", "[ruby-core:38070]" + end + end + + def test_cloexec + return unless defined? Fcntl::FD_CLOEXEC + open(__FILE__) {|f| + assert_predicate(f, :close_on_exec?) + g = f.dup + begin + assert_predicate(g, :close_on_exec?) + f.reopen(g) + assert_predicate(f, :close_on_exec?) + ensure + g.close + end + g = IO.new(f.fcntl(Fcntl::F_DUPFD)) + begin + assert_predicate(g, :close_on_exec?) + ensure + g.close + end + } + IO.pipe {|r,w| + assert_predicate(r, :close_on_exec?) + assert_predicate(w, :close_on_exec?) + } + end + + def test_ioctl_linux + return if /linux/ !~ RUBY_PLATFORM + # Alpha, mips, sparc and ppc have an another ioctl request number scheme. + # So, hardcoded 0x80045200 may fail. + return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM + + assert_nothing_raised do + File.open('/dev/urandom'){|f1| + entropy_count = "" + # RNDGETENTCNT(0x80045200) mean "get entropy count". + f1.ioctl(0x80045200, entropy_count) + } + end + + buf = '' + assert_nothing_raised do + fionread = 0x541B + File.open(__FILE__){|f1| + f1.ioctl(fionread, buf) + } + end + assert_equal(File.size(__FILE__), buf.unpack('i!')[0]) + end + + def test_ioctl_linux2 + return if /linux/ !~ RUBY_PLATFORM + return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM + + return unless system('tty', '-s') # stdin is not a terminal + File.open('/dev/tty') { |f| + tiocgwinsz=0x5413 + winsize="" + assert_nothing_raised { + f.ioctl(tiocgwinsz, winsize) + } + } + end + + def test_setpos + mkcdtmpdir { + File.open("tmp.txt", "wb") {|f| + f.puts "a" + f.puts "bc" + f.puts "def" + } + pos1 = pos2 = pos3 = nil + File.open("tmp.txt", "rb") {|f| + assert_equal("a\n", f.gets) + pos1 = f.pos + assert_equal("bc\n", f.gets) + pos2 = f.pos + assert_equal("def\n", f.gets) + pos3 = f.pos + assert_equal(nil, f.gets) + } + File.open("tmp.txt", "rb") {|f| + f.pos = pos1 + assert_equal("bc\n", f.gets) + assert_equal("def\n", f.gets) + assert_equal(nil, f.gets) + } + File.open("tmp.txt", "rb") {|f| + f.pos = pos2 + assert_equal("def\n", f.gets) + assert_equal(nil, f.gets) + } + File.open("tmp.txt", "rb") {|f| + f.pos = pos3 + assert_equal(nil, f.gets) + } + File.open("tmp.txt", "rb") {|f| + f.pos = File.size("tmp.txt") + s = "not empty string " + assert_equal("", f.read(0,s)) + } + } + end + + def test_std_fileno + assert_equal(0, STDIN.fileno) + assert_equal(1, STDOUT.fileno) + assert_equal(2, STDERR.fileno) + assert_equal(0, $stdin.fileno) + assert_equal(1, $stdout.fileno) + assert_equal(2, $stderr.fileno) + end + + def test_frozen_fileno + bug9865 = '[ruby-dev:48241] [Bug #9865]' + with_pipe do |r,w| + fd = r.fileno + assert_equal(fd, r.freeze.fileno, bug9865) + end + end + + def test_frozen_autoclose + with_pipe do |r,w| + fd = r.fileno + assert_equal(true, r.freeze.autoclose?) + end + end + + def test_sysread_locktmp + bug6099 = '[ruby-dev:45297]' + buf = " " * 100 + data = "a" * 100 + with_pipe do |r,w| + th = Thread.new {r.sysread(100, buf)} + Thread.pass until th.stop? + buf.replace("") + assert_empty(buf, bug6099) + w.write(data) + Thread.pass while th.alive? + th.join + end + assert_equal(data, buf, bug6099) + end + + def test_readpartial_locktmp + bug6099 = '[ruby-dev:45297]' + buf = " " * 100 + data = "a" * 100 + th = nil + with_pipe do |r,w| + r.nonblock = true + th = Thread.new {r.readpartial(100, buf)} + + Thread.pass until th.stop? + + assert_equal 100, buf.bytesize + + begin + buf.replace("") + rescue RuntimeError => e + assert_match(/can't modify string; temporarily locked/, e.message) + Thread.pass + end until buf.empty? + + assert_empty(buf, bug6099) + assert_predicate(th, :alive?) + w.write(data) + Thread.pass while th.alive? + th.join + end + assert_equal(data, buf, bug6099) + end + + def test_advise_pipe + # we don't know if other platforms have a real posix_fadvise() + return if /linux/ !~ RUBY_PLATFORM + 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) } + assert_raise(Errno::ESPIPE, Errno::EINVAL) { w.advise(:willneed) } + end + end + + def assert_buffer_not_raise_shared_string_error + bug6764 = '[ruby-core:46586]' + bug9847 = '[ruby-core:62643] [Bug #9847]' + size = 28 + data = [*"a".."z", *"A".."Z"].shuffle.join("") + t = Tempfile.new("test_io") + t.write(data) + t.close + w = [] + assert_nothing_raised(RuntimeError, bug6764) do + buf = '' + File.open(t.path, "r") do |r| + while yield(r, size, buf) + w << buf.dup + end + end + end + assert_equal(data, w.join(""), bug9847) + ensure + t.close! + end + + def test_read_buffer_not_raise_shared_string_error + assert_buffer_not_raise_shared_string_error do |r, size, buf| + r.read(size, buf) + end + end + + def test_sysread_buffer_not_raise_shared_string_error + assert_buffer_not_raise_shared_string_error do |r, size, buf| + begin + r.sysread(size, buf) + rescue EOFError + nil + end + end + end + + def test_readpartial_buffer_not_raise_shared_string_error + assert_buffer_not_raise_shared_string_error do |r, size, buf| + begin + r.readpartial(size, buf) + rescue EOFError + nil + end + end + end + + def test_puts_recursive_ary + bug5986 = '[ruby-core:42444]' + c = Class.new { + def to_ary + [self] + end + } + s = StringIO.new + s.puts(c.new) + assert_equal("[...]\n", s.string, bug5986) + end + + def test_io_select_with_many_files + bug8080 = '[ruby-core:53349]' + + assert_normal_exit %q{ + require "tempfile" + + # try to raise RLIM_NOFILE to >FD_SETSIZE + # Unfortunately, ruby export FD_SETSIZE. then we assume it's 1024. + fd_setsize = 1024 + + begin + Process.setrlimit(Process::RLIMIT_NOFILE, fd_setsize+10) + rescue =>e + # Process::RLIMIT_NOFILE couldn't be raised. skip the test + exit 0 + end + + tempfiles = [] + (0..fd_setsize+1).map {|i| + tempfiles << Tempfile.open("test_io_select_with_many_files") + } + + IO.select(tempfiles) + }, bug8080, timeout: 30 + end + + def test_read_32bit_boundary + bug8431 = '[ruby-core:55098] [Bug #8431]' + make_tempfile {|t| + assert_separately(["-", bug8431, t.path], <<-"end;") + msg = ARGV.shift + f = open(ARGV[0], "rb") + f.seek(0xffff_ffff) + assert_nil(f.read(1), msg) + end; + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_write_32bit_boundary + bug8431 = '[ruby-core:55098] [Bug #8431]' + make_tempfile {|t| + def t.close(unlink_now = false) + # TODO: Tempfile should deal with this delay on Windows? + # NOTE: re-opening with O_TEMPORARY does not work. + path = self.path + ret = super + if unlink_now + begin + File.unlink(path) + rescue Errno::ENOENT + rescue Errno::EACCES + sleep(2) + retry + end + end + ret + end + + begin + assert_separately(["-", bug8431, t.path], <<-"end;", timeout: 30) + msg = ARGV.shift + f = open(ARGV[0], "wb") + f.seek(0xffff_ffff) + begin + # this will consume very long time or fail by ENOSPC on a + # filesystem which sparse file is not supported + f.write('1') + pos = f.tell + rescue Errno::ENOSPC + skip "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" + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + IO.pipe {|r,| + t = Thread.new { r.read(nil, str) } + sleep 0.1 until t.stop? + t.raise + sleep 0.1 while t.alive? + assert_nothing_raised(RuntimeError, bug8669) { str.clear } + assert_raise(RuntimeError) { t.join } + } + end + + def test_readpartial_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + IO.pipe {|r, w| + t = Thread.new { r.readpartial(4096, str) } + sleep 0.1 until t.stop? + t.raise + sleep 0.1 while t.alive? + assert_nothing_raised(RuntimeError, bug8669) { str.clear } + assert_raise(RuntimeError) { t.join } + } + end + + def test_sysread_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + IO.pipe {|r, w| + t = Thread.new { r.sysread(4096, str) } + sleep 0.1 until t.stop? + t.raise + sleep 0.1 while t.alive? + assert_nothing_raised(RuntimeError, bug8669) { str.clear } + assert_raise(RuntimeError) { t.join } + } + end + + def test_exception_at_close + bug10153 = '[ruby-core:64463] [Bug #10153] exception in close at the end of block' + assert_raise(Errno::EBADF, bug10153) do + IO.pipe do |r, w| + assert_nothing_raised {IO.open(w.fileno) {}} + end + end + end +end diff --git a/jni/ruby/test/ruby/test_io_m17n.rb b/jni/ruby/test/ruby/test_io_m17n.rb new file mode 100644 index 0000000..734b017 --- /dev/null +++ b/jni/ruby/test/ruby/test_io_m17n.rb @@ -0,0 +1,2566 @@ +# coding: US-ASCII +require 'test/unit' +require 'tmpdir' +require 'timeout' + +class TestIO_M17N < Test::Unit::TestCase + ENCS = [ + Encoding::ASCII_8BIT, + Encoding::EUC_JP, + Encoding::Shift_JIS, + Encoding::UTF_8 + ] + + def with_tmpdir + Dir.mktmpdir {|dir| + Dir.chdir(dir) { + yield dir + } + } + end + + def pipe(*args, wp, rp) + re, we = nil, nil + r, w = IO.pipe(*args) + rt = Thread.new do + begin + rp.call(r) + rescue Exception + r.close + re = $! + end + end + wt = Thread.new do + begin + wp.call(w) + rescue Exception + w.close + we = $! + end + end + flunk("timeout") unless wt.join(10) && rt.join(10) + ensure + w.close unless !w || w.closed? + r.close unless !r || r.closed? + (wt.kill; wt.join) if wt + (rt.kill; rt.join) if rt + raise we if we + raise re if re + end + + def with_pipe(*args) + r, w = IO.pipe(*args) + begin + yield r, w + ensure + r.close if !r.closed? + w.close if !w.closed? + end + end + + def generate_file(path, content) + open(path, "wb") {|f| f.write content } + end + + def encdump(str) + "#{str.dump}.force_encoding(#{str.encoding.name.dump})" + end + + def assert_str_equal(expected, actual, message=nil) + full_message = build_message(message, <<EOT) +#{encdump expected} expected but not equal to +#{encdump actual}. +EOT + assert_equal(expected, actual, full_message) + end + + def test_open_r + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r") {|f| + assert_equal(Encoding.default_external, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_rb + with_tmpdir { + generate_file('tmp', "") + open("tmp", "rb") {|f| + assert_equal(Encoding.find("ASCII-8BIT"), f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_enc + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r:euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_ascii8bit + with_tmpdir { + generate_file('tmp', "") + EnvUtil.with_default_external(Encoding::ASCII_8BIT) do + EnvUtil.with_default_internal(Encoding::UTF_8) do + open("tmp", "r") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + open("tmp", "r:ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + open("tmp", "r:ascii-8bit:utf-16") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + end + EnvUtil.with_default_internal(nil) do + open("tmp", "r") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + open("tmp", "r:ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + open("tmp", "r:ascii-8bit:utf-16") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + end + end + } + end + + def test_open_r_enc_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", encoding: "euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_encname_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", encoding: Encoding::EUC_JP) {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_ext_enc_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", external_encoding: Encoding::EUC_JP) {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_ext_encname_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", external_encoding: "euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_r_enc_enc + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", external_encoding: Encoding::EUC_JP, internal_encoding: Encoding::UTF_8) {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_r_encname_encname + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r:euc-jp:utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_r_encname_encname_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", encoding: "euc-jp:utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_r_enc_enc_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", external_encoding: Encoding::EUC_JP, internal_encoding: Encoding::UTF_8) {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_r_externalencname_internalencname_in_opt + with_tmpdir { + generate_file('tmp', "") + open("tmp", "r", external_encoding: "euc-jp", internal_encoding: "utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_w + with_tmpdir { + open("tmp", "w") {|f| + assert_equal(nil, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_wb + with_tmpdir { + open("tmp", "wb") {|f| + assert_equal(Encoding.find("ASCII-8BIT"), f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_w_enc + with_tmpdir { + open("tmp", "w:euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_w_enc_in_opt + with_tmpdir { + open("tmp", "w", encoding: "euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_w_enc_in_opt2 + with_tmpdir { + open("tmp", "w", external_encoding: "euc-jp") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + } + } + end + + def test_open_w_enc_enc + with_tmpdir { + open("tmp", "w:euc-jp:utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_w_enc_enc_in_opt + with_tmpdir { + open("tmp", "w", encoding: "euc-jp:utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_w_enc_enc_in_opt2 + with_tmpdir { + open("tmp", "w", external_encoding: "euc-jp", internal_encoding: "utf-8") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_open_w_enc_enc_perm + with_tmpdir { + open("tmp", "w:euc-jp:utf-8", 0600) {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + } + } + end + + def test_ignored_encoding_option + enc = "\u{30a8 30f3 30b3 30fc 30c7 30a3 30f3 30b0}" + pattern = /#{enc}/ + assert_warning(pattern) { + open(IO::NULL, external_encoding: "us-ascii", encoding: enc) {} + } + assert_warning(pattern) { + open(IO::NULL, internal_encoding: "us-ascii", encoding: enc) {} + } + end + + def test_io_new_enc + with_tmpdir { + generate_file("tmp", "\xa1") + fd = IO.sysopen("tmp") + f = IO.new(fd, "r:sjis") + begin + assert_equal(Encoding::Windows_31J, f.read.encoding) + ensure + f.close + end + } + end + + def test_s_pipe_invalid + pipe("utf-8", "euc-jp", { :invalid=>:replace }, + proc do |w| + w << "\x80" + w.close + end, + proc do |r| + assert_equal("?", r.read) + end) + end + + def test_s_pipe_undef + pipe("utf-8:euc-jp", { :undef=>:replace }, + proc do |w| + w << "\ufffd" + w.close + end, + proc do |r| + assert_equal("?", r.read) + end) + end + + def test_s_pipe_undef_replace_string + pipe("utf-8:euc-jp", { :undef=>:replace, :replace=>"X" }, + proc do |w| + w << "\ufffd" + w.close + end, + proc do |r| + assert_equal("X", r.read) + end) + end + + def test_dup + pipe("utf-8:euc-jp", + proc do |w| + w << "\u3042" + w.close + end, + proc do |r| + r2 = r.dup + begin + assert_equal("\xA4\xA2".force_encoding("euc-jp"), r2.read) + ensure + r2.close + end + end) + end + + def test_dup_undef + pipe("utf-8:euc-jp", { :undef=>:replace }, + proc do |w| + w << "\uFFFD" + w.close + end, + proc do |r| + r2 = r.dup + begin + assert_equal("?", r2.read) + ensure + r2.close + end + end) + end + + def test_stdin + assert_equal(Encoding.default_external, STDIN.external_encoding) + assert_equal(nil, STDIN.internal_encoding) + end + + def test_stdout + assert_equal(nil, STDOUT.external_encoding) + assert_equal(nil, STDOUT.internal_encoding) + end + + def test_stderr + assert_equal(nil, STDERR.external_encoding) + assert_equal(nil, STDERR.internal_encoding) + end + + def test_terminator_conversion + with_tmpdir { + generate_file('tmp', "before \u00FF after") + s = open("tmp", "r:utf-8:iso-8859-1") {|f| + f.gets("\xFF".force_encoding("iso-8859-1")) + } + assert_equal(Encoding.find("iso-8859-1"), s.encoding) + assert_str_equal("before \xFF".force_encoding("iso-8859-1"), s, '[ruby-core:14288]') + } + end + + def test_terminator_conversion2 + with_tmpdir { + generate_file('tmp', "before \xA1\xA2\xA2\xA3 after") + s = open("tmp", "r:euc-jp:utf-8") {|f| + f.gets("\xA2\xA2".force_encoding("euc-jp").encode("utf-8")) + } + assert_equal(Encoding.find("utf-8"), s.encoding) + assert_str_equal("before \xA1\xA2\xA2\xA3 after".force_encoding("euc-jp").encode("utf-8"), s, '[ruby-core:14319]') + } + end + + def test_terminator_stateful_conversion + with_tmpdir { + src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp") + generate_file('tmp', src) + s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| + f.gets("0".force_encoding("euc-jp")) + } + assert_equal(Encoding.find("euc-jp"), s.encoding) + assert_str_equal(src.encode("euc-jp"), s) + } + end + + def test_nonascii_terminator + with_tmpdir { + generate_file('tmp', "before \xA2\xA2 after") + open("tmp", "r:euc-jp") {|f| + assert_raise(ArgumentError) { + f.gets("\xA2\xA2".force_encoding("utf-8")) + } + } + } + end + + def test_pipe_terminator_conversion + rs = "\xA2\xA2".encode("utf-8", "euc-jp") + pipe("euc-jp:utf-8", + proc do |w| + w.write "before \xa2\xa2 after" + w.close + end, + proc do |r| + timeout(1) { + assert_equal("before \xa2\xa2".encode("utf-8", "euc-jp"), + r.gets(rs)) + } + end) + end + + def test_pipe_conversion + pipe("euc-jp:utf-8", + proc do |w| + w.write "\xa1\xa1" + end, + proc do |r| + assert_equal("\xa1\xa1".encode("utf-8", "euc-jp"), r.getc) + end) + end + + def test_pipe_convert_partial_read + pipe("euc-jp:utf-8", + proc do |w| + w.write "\xa1" + sleep 0.1 + w.write "\xa1" + end, + proc do |r| + assert_equal("\xa1\xa1".encode("utf-8", "euc-jp"), r.getc) + end) + end + + def test_getc_invalid + pipe("euc-jp:utf-8", + proc do |w| + w << "\xa1xyz" + w.close + end, + proc do |r| + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } + assert_equal("\xA1".force_encoding("ascii-8bit"), err.error_bytes) + assert_equal("xyz", r.read(10)) + end) + end + + def test_getc_stateful_conversion + with_tmpdir { + src = "\e$B\x23\x30\x23\x31\e(B".force_encoding("iso-2022-jp") + generate_file('tmp', src) + open("tmp", "r:iso-2022-jp:euc-jp") {|f| + assert_equal("\xa3\xb0".force_encoding("euc-jp"), f.getc) + assert_equal("\xa3\xb1".force_encoding("euc-jp"), f.getc) + } + } + end + + def test_getc_newlineconv + with_tmpdir { + src = "\u3042" + generate_file('tmp', src) + EnvUtil.with_default_external(Encoding::UTF_8) do + open("tmp", "rt") {|f| + s = f.getc + assert_equal(true, s.valid_encoding?) + assert_equal("\u3042", s) + } + end + } + end + + def test_getc_newlineconv_invalid + with_tmpdir { + src = "\xE3\x81" + generate_file('tmp', src) + EnvUtil.with_default_external(Encoding::UTF_8) do + open("tmp", "rt") {|f| + s = f.getc + assert_equal(false, s.valid_encoding?) + assert_equal("\xE3".force_encoding("UTF-8"), s) + s = f.getc + assert_equal(false, s.valid_encoding?) + assert_equal("\x81".force_encoding("UTF-8"), s) + } + end + } + end + + def test_ungetc_int + with_tmpdir { + generate_file('tmp', "A") + s = open("tmp", "r:GB18030") {|f| + f.ungetc(0x8431A439) + f.read + } + assert_equal(Encoding::GB18030, s.encoding) + assert_str_equal(0x8431A439.chr("GB18030")+"A", s) + } + end + + def test_ungetc_str + with_tmpdir { + generate_file('tmp', "A") + s = open("tmp", "r:GB18030") {|f| + f.ungetc(0x8431A439.chr("GB18030")) + f.read + } + assert_equal(Encoding::GB18030, s.encoding) + assert_str_equal(0x8431A439.chr("GB18030")+"A", s) + } + end + + def test_ungetc_stateful_conversion + with_tmpdir { + src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp") + generate_file('tmp', src) + s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| + f.ungetc("0".force_encoding("euc-jp")) + f.read + } + assert_equal(Encoding.find("euc-jp"), s.encoding) + assert_str_equal("0" + src.encode("euc-jp"), s) + } + end + + def test_ungetc_stateful_conversion2 + with_tmpdir { + src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp") + former = "before \e$B\x23\x30\e(B".force_encoding("iso-2022-jp") + rs = "\e$B\x23\x30\e(B".force_encoding("iso-2022-jp") + latter = "\e$B\x23\x31\e(B after".force_encoding("iso-2022-jp") + generate_file('tmp', src) + s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| + assert_equal(former.encode("euc-jp", "iso-2022-jp"), + f.gets(rs.encode("euc-jp", "iso-2022-jp"))) + f.ungetc("0") + f.read + } + assert_equal(Encoding.find("euc-jp"), s.encoding) + assert_str_equal("0" + latter.encode("euc-jp"), s) + } + end + + def test_open_ascii + with_tmpdir { + src = "abc\n" + generate_file('tmp', "abc\n") + ENCS.each {|enc| + s = open('tmp', "r:#{enc}") {|f| f.gets } + assert_equal(enc, s.encoding) + assert_str_equal(src, s) + } + } + end + + def test_open_nonascii + with_tmpdir { + src = "\xc2\xa1\n" + generate_file('tmp', src) + ENCS.each {|enc| + content = src.dup.force_encoding(enc) + s = open('tmp', "r:#{enc}") {|f| f.gets } + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + } + end + + def test_read_encoding + with_tmpdir { + src = "\xc2\xa1\n".force_encoding("ASCII-8BIT") + generate_file('tmp', "\xc2\xa1\n") + ENCS.each {|enc| + content = src.dup.force_encoding(enc) + open('tmp', "r:#{enc}") {|f| + s = f.getc + assert_equal(enc, s.encoding) + assert_str_equal(content[0], s) + } + open('tmp', "r:#{enc}") {|f| + s = f.readchar + assert_equal(enc, s.encoding) + assert_str_equal(content[0], s) + } + open('tmp', "r:#{enc}") {|f| + s = f.gets + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + open('tmp', "r:#{enc}") {|f| + s = f.readline + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + open('tmp', "r:#{enc}") {|f| + lines = f.readlines + assert_equal(1, lines.length) + s = lines[0] + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + open('tmp', "r:#{enc}") {|f| + f.each_line {|s| + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + } + open('tmp', "r:#{enc}") {|f| + s = f.read + assert_equal(enc, s.encoding) + assert_str_equal(content, s) + } + open('tmp', "r:#{enc}") {|f| + s = f.read(1) + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_str_equal(src[0], s) + } + open('tmp', "r:#{enc}") {|f| + s = f.readpartial(1) + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_str_equal(src[0], s) + } + open('tmp', "r:#{enc}") {|f| + s = f.sysread(1) + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_str_equal(src[0], s) + } + } + } + end + + def test_write_noenc + src = "\xc2\xa1\n".force_encoding("ascii-8bit") + with_tmpdir { + open('tmp', "w") {|f| + ENCS.each {|enc| + f.write src.dup.force_encoding(enc) + } + } + open('tmp', 'r:ascii-8bit') {|f| + assert_equal(src*ENCS.length, f.read) + } + } + end + + def test_write_conversion + utf8 = "\u6666" + eucjp = "\xb3\xa2".force_encoding("EUC-JP") + with_tmpdir { + open('tmp', "w:EUC-JP") {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(nil, f.internal_encoding) + f.print utf8 + } + assert_equal(eucjp, File.read('tmp').force_encoding("EUC-JP")) + open('tmp', 'r:EUC-JP:UTF-8') {|f| + assert_equal(Encoding::EUC_JP, f.external_encoding) + assert_equal(Encoding::UTF_8, f.internal_encoding) + assert_equal(utf8, f.read) + } + } + end + + def test_pipe + utf8 = "\u6666" + eucjp = "\xb3\xa2".force_encoding("EUC-JP") + + pipe(proc do |w| + w << utf8 + w.close + end, proc do |r| + assert_equal(Encoding.default_external, r.external_encoding) + assert_equal(nil, r.internal_encoding) + s = r.read + assert_equal(Encoding.default_external, s.encoding) + assert_str_equal(utf8.dup.force_encoding(Encoding.default_external), s) + end) + + pipe("EUC-JP", + proc do |w| + w << eucjp + w.close + end, + proc do |r| + assert_equal(Encoding::EUC_JP, r.external_encoding) + assert_equal(nil, r.internal_encoding) + assert_equal(eucjp, r.read) + end) + + pipe("UTF-8", + proc do |w| + w << "a" * 1023 + "\u3042" + "a" * 1022 + w.close + end, + proc do |r| + assert_equal(true, r.read.valid_encoding?) + end) + + pipe("UTF-8:EUC-JP", + proc do |w| + w << utf8 + w.close + end, + proc do |r| + assert_equal(Encoding::UTF_8, r.external_encoding) + assert_equal(Encoding::EUC_JP, r.internal_encoding) + assert_equal(eucjp, r.read) + end) + + assert_raise_with_message(ArgumentError, /invalid name encoding/) do + with_pipe("UTF-8", "UTF-8".encode("UTF-32BE")) {} + end + assert_raise_with_message(ArgumentError, /invalid name encoding/) do + with_pipe("UTF-8".encode("UTF-32BE")) {} + end + + ENCS.each {|enc| + pipe(enc, + proc do |w| + w << "\xc2\xa1" + w.close + end, + proc do |r| + s = r.getc + assert_equal(enc, s.encoding) + end) + } + + ENCS.each {|enc| + next if enc == Encoding::ASCII_8BIT + next if enc == Encoding::UTF_8 + pipe("#{enc}:UTF-8", + proc do |w| + w << "\xc2\xa1" + w.close + end, + proc do |r| + s = r.read + assert_equal(Encoding::UTF_8, s.encoding) + assert_equal(s.encode("UTF-8"), s) + end) + } + + end + + def test_marshal + data = 56225 + pipe("EUC-JP", + proc do |w| + Marshal.dump(data, w) + w.close + end, + proc do |r| + result = nil + assert_nothing_raised("[ruby-dev:33264]") { result = Marshal.load(r) } + assert_equal(data, result) + end) + end + + def test_gets_nil + pipe("UTF-8:EUC-JP", + proc do |w| + w << "\u{3042}" + w.close + end, + proc do |r| + result = r.gets(nil) + assert_equal("\u{3042}".encode("euc-jp"), result) + end) + end + + def test_gets_limit + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.gets(1)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.gets(2)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4".force_encoding("euc-jp"), r.gets(3)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4".force_encoding("euc-jp"), r.gets(4)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6".force_encoding("euc-jp"), r.gets(5)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6".force_encoding("euc-jp"), r.gets(6)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(7)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(8)) }) + pipe("euc-jp", + proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close }, + proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(9)) }) + end + + def test_gets_invalid + before = "\u{3042}\u{3044}" + invalid = "\x80".force_encoding("utf-8") + after = "\u{3046}\u{3048}" + pipe("utf-8:euc-jp", + proc do |w| + w << before + invalid + after + w.close + end, + proc do |r| + err = assert_raise(Encoding::InvalidByteSequenceError) { r.gets } + assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) + assert_equal(after.encode("euc-jp"), r.gets) + end) + end + + def test_getc_invalid2 + before1 = "\u{3042}" + before2 = "\u{3044}" + invalid = "\x80".force_encoding("utf-8") + after1 = "\u{3046}" + after2 = "\u{3048}" + pipe("utf-8:euc-jp", + proc do |w| + w << before1 + before2 + invalid + after1 + after2 + w.close + end, + proc do |r| + assert_equal(before1.encode("euc-jp"), r.getc) + assert_equal(before2.encode("euc-jp"), r.getc) + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } + assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) + assert_equal(after1.encode("euc-jp"), r.getc) + assert_equal(after2.encode("euc-jp"), r.getc) + end) + end + + def test_getc_invalid3 + before1 = "\x42\x30".force_encoding("utf-16le") + before2 = "\x44\x30".force_encoding("utf-16le") + invalid = "\x00\xd8".force_encoding("utf-16le") + after1 = "\x46\x30".force_encoding("utf-16le") + after2 = "\x48\x30".force_encoding("utf-16le") + pipe("utf-16le:euc-jp", { :binmode => true }, + proc do |w| + w << before1 + before2 + invalid + after1 + after2 + w.close + end, + proc do |r| + assert_equal(before1.encode("euc-jp"), r.getc) + assert_equal(before2.encode("euc-jp"), r.getc) + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } + assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) + assert_equal(after1.encode("euc-jp"), r.getc) + assert_equal(after2.encode("euc-jp"), r.getc) + end) + end + + def test_read_all + str = "\u3042\u3044" + pipe("utf-8:euc-jp", + proc do |w| + w << str + w.close + end, + proc do |r| + assert_equal(str.encode("euc-jp"), r.read) + end) + end + + def test_read_all_invalid + before = "\u{3042}\u{3044}" + invalid = "\x80".force_encoding("utf-8") + after = "\u{3046}\u{3048}" + pipe("utf-8:euc-jp", + proc do |w| + w << before + invalid + after + w.close + end, + proc do |r| + err = assert_raise(Encoding::InvalidByteSequenceError) { r.read } + assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) + assert_equal(after.encode("euc-jp"), r.read) + end) + end + + def test_file_foreach + with_tmpdir { + generate_file('tst', 'a' * 8191 + "\xa1\xa1") + assert_nothing_raised { + File.foreach('tst', :encoding=>"euc-jp") {|line| line.inspect } + } + } + end + + def test_set_encoding + pipe("utf-8:euc-jp", + proc do |w| + s = "\u3042".force_encoding("ascii-8bit") + s << "\x82\xa0".force_encoding("ascii-8bit") + w << s + w.close + end, + proc do |r| + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + r.set_encoding("shift_jis:euc-jp") + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + end) + end + + def test_set_encoding2 + pipe("utf-8:euc-jp", + proc do |w| + s = "\u3042".force_encoding("ascii-8bit") + s << "\x82\xa0".force_encoding("ascii-8bit") + w << s + w.close + end, + proc do |r| + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + r.set_encoding("shift_jis", "euc-jp") + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + end) + end + + def test_set_encoding_nil + pipe("utf-8:euc-jp", + proc do |w| + s = "\u3042".force_encoding("ascii-8bit") + s << "\x82\xa0".force_encoding("ascii-8bit") + w << s + w.close + end, + proc do |r| + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + r.set_encoding(nil) + assert_equal("\x82\xa0".force_encoding(Encoding.default_external), r.read) + end) + end + + def test_set_encoding_enc + pipe("utf-8:euc-jp", + proc do |w| + s = "\u3042".force_encoding("ascii-8bit") + s << "\x82\xa0".force_encoding("ascii-8bit") + w << s + w.close + end, + proc do |r| + assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc) + r.set_encoding(Encoding::Shift_JIS) + assert_equal("\x82\xa0".force_encoding(Encoding::Shift_JIS), r.getc) + end) + end + + def test_set_encoding_invalid + pipe(proc do |w| + w << "\x80" + w.close + end, + proc do |r| + r.set_encoding("utf-8:euc-jp", :invalid=>:replace) + assert_equal("?", r.read) + end) + end + + def test_set_encoding_identical + #bug5568 = '[ruby-core:40727]' + bug6324 = '[ruby-core:44455]' + open(__FILE__, "r") do |f| + assert_warning('', bug6324) { + f.set_encoding("eucjp:euc-jp") + } + assert_warning('', bug6324) { + f.set_encoding("eucjp", "euc-jp") + } + assert_warning('', bug6324) { + f.set_encoding(Encoding::EUC_JP, "euc-jp") + } + assert_warning('', bug6324) { + f.set_encoding("eucjp", Encoding::EUC_JP) + } + assert_warning('', bug6324) { + f.set_encoding(Encoding::EUC_JP, Encoding::EUC_JP) + } + nonstr = Object.new + def nonstr.to_str; "eucjp"; end + assert_warning('', bug6324) { + f.set_encoding(nonstr, nonstr) + } + end + end + + def test_set_encoding_undef + pipe(proc do |w| + w << "\ufffd" + w.close + end, + proc do |r| + r.set_encoding("utf-8", "euc-jp", :undef=>:replace) + assert_equal("?", r.read) + end) + end + + def test_set_encoding_undef_replace + pipe(proc do |w| + w << "\ufffd" + w.close + end, + proc do |r| + r.set_encoding("utf-8", "euc-jp", :undef=>:replace, :replace=>"ZZZ") + assert_equal("ZZZ", r.read) + end) + pipe(proc do |w| + w << "\ufffd" + w.close + end, + proc do |r| + r.set_encoding("utf-8:euc-jp", :undef=>:replace, :replace=>"ZZZ") + assert_equal("ZZZ", r.read) + end) + end + + def test_set_encoding_binmode + assert_raise(ArgumentError) { + open(__FILE__, "rt") {|f| + f.set_encoding("iso-2022-jp") + } + } + assert_raise(ArgumentError) { + open(__FILE__, "r") {|f| + f.set_encoding("iso-2022-jp") + } + } + assert_nothing_raised { + open(__FILE__, "rb") {|f| + f.set_encoding("iso-2022-jp") + } + } + assert_nothing_raised { + open(__FILE__, "r") {|f| + f.binmode + f.set_encoding("iso-2022-jp") + } + } + assert_nothing_raised { + open(__FILE__, "rt") {|f| + f.binmode + f.set_encoding("iso-2022-jp") + } + } + assert_nothing_raised { + open(__FILE__, "r", binmode: true) {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + f.set_encoding("iso-2022-jp") + } + } + assert_raise(ArgumentError) { + open(__FILE__, "rb", binmode: true) {|f| + f.set_encoding("iso-2022-jp") + } + } + assert_raise(ArgumentError) { + open(__FILE__, "rb", binmode: false) {|f| + f.set_encoding("iso-2022-jp") + } + } + end + + def test_set_encoding_unsupported + bug5567 = '[ruby-core:40726]' + IO.pipe do |r, w| + assert_nothing_raised(bug5567) do + assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx")} + assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx", "us-ascii")} + assert_warning(/Unsupported/, bug5567) {r.set_encoding("us-ascii", "fffffffffffxx")} + end + end + end + + def test_textmode_twice + assert_raise(ArgumentError) { + open(__FILE__, "rt", textmode: true) {|f| + f.set_encoding("iso-2022-jp") + } + } + assert_raise(ArgumentError) { + open(__FILE__, "rt", textmode: false) {|f| + f.set_encoding("iso-2022-jp") + } + } + end + + def test_write_conversion_fixenc + pipe(proc do |w| + w.set_encoding("iso-2022-jp:utf-8") + w << "\u3042" + w << "\u3044" + w.close + end, + proc do |r| + assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"), + r.read.force_encoding("ascii-8bit")) + end) + end + + def test_write_conversion_anyenc_stateful + pipe(proc do |w| + w.set_encoding("iso-2022-jp") + w << "\u3042" + w << "\x82\xa2".force_encoding("sjis") + w.close + end, + proc do |r| + assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"), + r.read.force_encoding("ascii-8bit")) + end) + end + + def test_write_conversion_anyenc_stateless + pipe(proc do |w| + w.set_encoding("euc-jp") + w << "\u3042" + w << "\x82\xa2".force_encoding("sjis") + w.close + end, + proc do |r| + assert_equal("\xa4\xa2\xa4\xa4".force_encoding("ascii-8bit"), + r.read.force_encoding("ascii-8bit")) + end) + end + + def test_write_conversion_anyenc_stateful_nosync + pipe(proc do |w| + w.sync = false + w.set_encoding("iso-2022-jp") + w << "\u3042" + w << "\x82\xa2".force_encoding("sjis") + w.close + end, + proc do |r| + assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"), + r.read.force_encoding("ascii-8bit")) + end) + end + + def test_read_stateful + pipe("euc-jp:iso-2022-jp", + proc do |w| + w << "\xA4\xA2" + w.close + end, + proc do |r| + assert_equal("\e$B$\"\e(B".force_encoding("iso-2022-jp"), r.read) + end) + end + + def test_stdin_external_encoding_with_reopen + skip "passing non-stdio fds is not supported" if /mswin|mingw/ =~ RUBY_PLATFORM + with_tmpdir { + open("tst", "w+") {|f| + pid = spawn(EnvUtil.rubybin, '-e', <<-'End', 10=>f) + io = IO.new(10, "r+") + STDIN.reopen(io) + STDIN.external_encoding + STDIN.write "\u3042" + STDIN.flush + End + Process.wait pid + f.rewind + result = f.read.force_encoding("ascii-8bit") + assert_equal("\u3042".force_encoding("ascii-8bit"), result) + } + } + end + + def test_popen_r_enc + IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + end + + def test_popen_r_enc_in_opt + IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r", encoding: "ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + end + + def test_popen_r_enc_in_opt2 + IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r", external_encoding: "ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + end + + def test_popen_r_enc_enc + IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r:shift_jis:euc-jp") {|f| + assert_equal(Encoding::Shift_JIS, f.external_encoding) + assert_equal(Encoding::EUC_JP, f.internal_encoding) + s = f.read + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\x8e\xa1".force_encoding("euc-jp"), s) + } + end + + def test_popen_r_enc_enc_in_opt + IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r", encoding: "shift_jis:euc-jp") {|f| + assert_equal(Encoding::Shift_JIS, f.external_encoding) + assert_equal(Encoding::EUC_JP, f.internal_encoding) + s = f.read + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\x8e\xa1".force_encoding("euc-jp"), s) + } + end + + def test_popen_r_enc_enc_in_opt2 + IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r", external_encoding: "shift_jis", internal_encoding: "euc-jp") {|f| + assert_equal(Encoding::Shift_JIS, f.external_encoding) + assert_equal(Encoding::EUC_JP, f.internal_encoding) + s = f.read + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\x8e\xa1".force_encoding("euc-jp"), s) + } + end + + def test_popenv_r_enc_enc_in_opt2 + IO.popen([EnvUtil.rubybin, "-e", "putc 0xa1"], "r", external_encoding: "shift_jis", internal_encoding: "euc-jp") {|f| + assert_equal(Encoding::Shift_JIS, f.external_encoding) + assert_equal(Encoding::EUC_JP, f.internal_encoding) + s = f.read + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\x8e\xa1".force_encoding("euc-jp"), s) + } + end + + def test_open_pipe_r_enc + open("|#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + end + + def test_open_pipe_r_enc2 + open("|#{EnvUtil.rubybin} -e 'putc \"\\u3042\"'", "r:UTF-8") {|f| + assert_equal(Encoding::UTF_8, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::UTF_8, s.encoding) + assert_equal("\u3042", s) + } + end + + def test_s_foreach_enc + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :mode => "r:ascii-8bit") {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_enc_in_opt + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :encoding => "ascii-8bit") {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_enc_in_opt2 + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :external_encoding => "ascii-8bit") {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_enc_enc + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :mode => "r:utf-8:euc-jp") {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_s_foreach_enc_enc_in_opt + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :mode => "r", :encoding => "utf-8:euc-jp") {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_s_foreach_enc_enc_in_opt2 + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :mode => "r", :external_encoding => "utf-8", :internal_encoding => "euc-jp") {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_s_foreach_open_args_enc + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :open_args => ["r:ascii-8bit"]) {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_open_args_enc_in_opt + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :open_args => ["r", encoding: "ascii-8bit"]) {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_open_args_enc_in_opt2 + with_tmpdir { + generate_file("t", "\xff") + IO.foreach("t", :open_args => ["r", external_encoding: "ascii-8bit"]) {|s| + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } + } + end + + def test_s_foreach_open_args_enc_enc + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :open_args => ["r:utf-8:euc-jp"]) {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_s_foreach_open_args_enc_enc_in_opt + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :open_args => ["r", encoding: "utf-8:euc-jp"]) {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_s_foreach_open_args_enc_enc_in_opt2 + with_tmpdir { + generate_file("t", "\u3042") + IO.foreach("t", :open_args => ["r", external_encoding: "utf-8", internal_encoding: "euc-jp"]) {|s| + assert_equal(Encoding::EUC_JP, s.encoding) + assert_equal("\xa4\xa2".force_encoding("euc-jp"), s) + } + } + end + + def test_both_textmode_binmode + bug5918 = '[ruby-core:42199]' + assert_raise(ArgumentError, bug5918) { open("not-exist", "r", :textmode=>true, :binmode=>true) } + assert_raise(ArgumentError, bug5918) { open("not-exist", "rt", :binmode=>true) } + assert_raise(ArgumentError, bug5918) { open("not-exist", "rt", :binmode=>false) } + assert_raise(ArgumentError, bug5918) { open("not-exist", "rb", :textmode=>true) } + assert_raise(ArgumentError, bug5918) { open("not-exist", "rb", :textmode=>false) } + end + + def test_textmode_decode_universal_newline_read + with_tmpdir { + generate_file("t.crlf", "a\r\nb\r\nc\r\n") + assert_equal("a\nb\nc\n", File.read("t.crlf", mode:"rt:euc-jp:utf-8")) + assert_equal("a\nb\nc\n", File.read("t.crlf", mode:"rt")) + open("t.crlf", "rt:euc-jp:utf-8") {|f| assert_equal("a\nb\nc\n", f.read) } + open("t.crlf", "rt") {|f| assert_equal("a\nb\nc\n", f.read) } + open("t.crlf", "r", :textmode=>true) {|f| assert_equal("a\nb\nc\n", f.read) } + open("t.crlf", "r", textmode: true, universal_newline: false) {|f| + assert_equal("a\r\nb\r\nc\r\n", f.read) + } + + generate_file("t.cr", "a\rb\rc\r") + assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt:euc-jp:utf-8")) + assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt")) + + generate_file("t.lf", "a\nb\nc\n") + assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt:euc-jp:utf-8")) + assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt")) + } + end + + def test_textmode_decode_universal_newline_getc + with_tmpdir { + generate_file("t.crlf", "a\r\nb\r\nc\r\n") + open("t.crlf", "rt") {|f| + assert_equal("a", f.getc) + assert_equal("\n", f.getc) + assert_equal("b", f.getc) + assert_equal("\n", f.getc) + assert_equal("c", f.getc) + assert_equal("\n", f.getc) + assert_equal(nil, f.getc) + } + + generate_file("t.cr", "a\rb\rc\r") + open("t.cr", "rt") {|f| + assert_equal("a", f.getc) + assert_equal("\n", f.getc) + assert_equal("b", f.getc) + assert_equal("\n", f.getc) + assert_equal("c", f.getc) + assert_equal("\n", f.getc) + assert_equal(nil, f.getc) + } + + generate_file("t.lf", "a\nb\nc\n") + open("t.lf", "rt") {|f| + assert_equal("a", f.getc) + assert_equal("\n", f.getc) + assert_equal("b", f.getc) + assert_equal("\n", f.getc) + assert_equal("c", f.getc) + assert_equal("\n", f.getc) + assert_equal(nil, f.getc) + } + } + end + + def test_textmode_decode_universal_newline_gets + with_tmpdir { + generate_file("t.crlf", "a\r\nb\r\nc\r\n") + open("t.crlf", "rt") {|f| + assert_equal("a\n", f.gets) + assert_equal("b\n", f.gets) + assert_equal("c\n", f.gets) + assert_equal(nil, f.gets) + } + + generate_file("t.cr", "a\rb\rc\r") + open("t.cr", "rt") {|f| + assert_equal("a\n", f.gets) + assert_equal("b\n", f.gets) + assert_equal("c\n", f.gets) + assert_equal(nil, f.gets) + } + + generate_file("t.lf", "a\nb\nc\n") + open("t.lf", "rt") {|f| + assert_equal("a\n", f.gets) + assert_equal("b\n", f.gets) + assert_equal("c\n", f.gets) + assert_equal(nil, f.gets) + } + } + end + + def test_textmode_decode_universal_newline_utf16 + with_tmpdir { + generate_file("t.utf16be.crlf", "\0a\0\r\0\n\0b\0\r\0\n\0c\0\r\0\n") + assert_equal("a\nb\nc\n", File.read("t.utf16be.crlf", mode:"rt:utf-16be:utf-8")) + + generate_file("t.utf16le.crlf", "a\0\r\0\n\0b\0\r\0\n\0c\0\r\0\n\0") + assert_equal("a\nb\nc\n", File.read("t.utf16le.crlf", mode:"rt:utf-16le:utf-8")) + + generate_file("t.utf16be.cr", "\0a\0\r\0b\0\r\0c\0\r") + assert_equal("a\nb\nc\n", File.read("t.utf16be.cr", mode:"rt:utf-16be:utf-8")) + + generate_file("t.utf16le.cr", "a\0\r\0b\0\r\0c\0\r\0") + assert_equal("a\nb\nc\n", File.read("t.utf16le.cr", mode:"rt:utf-16le:utf-8")) + + generate_file("t.utf16be.lf", "\0a\0\n\0b\0\n\0c\0\n") + assert_equal("a\nb\nc\n", File.read("t.utf16be.lf", mode:"rt:utf-16be:utf-8")) + + generate_file("t.utf16le.lf", "a\0\n\0b\0\n\0c\0\n\0") + assert_equal("a\nb\nc\n", File.read("t.utf16le.lf", mode:"rt:utf-16le:utf-8")) + } + end + + SYSTEM_NEWLINE = [] + def system_newline + return SYSTEM_NEWLINE.first if !SYSTEM_NEWLINE.empty? + with_tmpdir { + open("newline", "wt") {|f| + f.print "\n" + } + open("newline", "rb") {|f| + SYSTEM_NEWLINE << f.read + } + } + SYSTEM_NEWLINE.first + end + + def test_textmode_encode_newline + with_tmpdir { + open("t.txt", "wt") {|f| + f.puts "abc" + f.puts "def" + } + content = File.read("t.txt", :mode=>"rb") + nl = system_newline + assert_equal("abc#{nl}def#{nl}", content) + } + end + + def test_textmode_encode_newline_enc + with_tmpdir { + open("t.txt", "wt:euc-jp") {|f| + f.puts "abc\u3042" + f.puts "def\u3044" + } + content = File.read("t.txt", :mode=>"rb:ascii-8bit") + nl = system_newline + assert_equal("abc\xA4\xA2#{nl}def\xA4\xA4#{nl}", content) + } + end + + def test_read_newline_conversion_with_encoding_conversion + with_tmpdir { + generate_file("t.utf8.crlf", "a\r\nb\r\n") + open("t.utf8.crlf", "rb:utf-8:utf-16be") {|f| + content = f.read + assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"), content) + } + open("t.utf8.crlf", "rt:utf-8:utf-16be") {|f| + content = f.read + assert_equal("\0a\0\n\0b\0\n".force_encoding("UTF-16BE"), content) + } + open("t.utf8.crlf", "r:utf-8:utf-16be") {|f| + content = f.read + if system_newline == "\n" + assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"), content) + else + assert_equal("\0a\0\n\0b\0\n".force_encoding("UTF-16BE"), content) + end + } + } + end + + def test_read_newline_conversion_without_encoding_conversion + with_tmpdir { + generate_file("t.utf16.crlf", "\0a\0\r\0\n\0b\0\r\0\n") + open("t.utf16.crlf", "rb:utf-16be") {|f| + content = f.read + assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"), + content) + } + } + end + + def test_read_newline_conversion_error + with_tmpdir { + generate_file("empty.txt", "") + # ascii incompatible encoding without conversion needs binmode. + assert_raise(ArgumentError) { + open("empty.txt", "rt:utf-16be") {|f| } + } + assert_raise(ArgumentError) { + open("empty.txt", "r:utf-16be") {|f| } + } + } + end + + def test_read_mode + with_tmpdir { + generate_file("t", "a\rb\r\nc\n\xc2\xa2") + generate_file("ie", "a\rb\r\nc\n\e$B\x42\x22\e(B") + generate_file("iu", "a\rb\r\nc\n\e$B\x21\x71\e(B") + generate_file("be", "\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35") + generate_file("bu", "\0a\0\r\0b\0\r\0\n\0c\0\n\0\xa2") + # "\xc2\xa2" is valid as EUC-JP and UTF-8 + # EUC-JP UTF-8 Unicode + # 0xC2A2 0xE894B5 U+8535 + # 0xA1F1 0xC2A2 U+00A2 + + open("t","rt") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding(Encoding.default_external), f.read) } + open("t","rb") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding(Encoding::ASCII_8BIT), f.read) } + + open("t","rt:euc-jp") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) } + open("t","rb:euc-jp") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) } + open("t","rt:utf-8") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) } + open("t","rb:utf-8") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) } + assert_raise(ArgumentError) { open("t", "rt:iso-2022-jp") {|f| } } + open("t","rb:iso-2022-jp") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("ISO-2022-JP"), f.read) } + + open("t","rt:euc-jp:utf-8") {|f| assert_equal("a\nb\nc\n\u8535", f.read) } + open("t","rt:utf-8:euc-jp") {|f| assert_equal("a\nb\nc\n\xa1\xf1".force_encoding("EUC-JP"), f.read) } + open("t","rb:euc-jp:utf-8") {|f| assert_equal("a\rb\r\nc\n\u8535", f.read) } + open("t","rb:utf-8:euc-jp") {|f| assert_equal("a\rb\r\nc\n\xa1\xf1".force_encoding("EUC-JP"), f.read) } + + open("t","rt:euc-jp:iso-2022-jp"){|f| assert_equal("a\nb\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"), f.read) } + open("t","rt:utf-8:iso-2022-jp"){|f| assert_equal("a\nb\nc\n\e$B\x21\x71\e(B".force_encoding("ISO-2022-JP"), f.read) } + open("t","rt:euc-jp:utf-16be"){|f| assert_equal("\0a\0\n\0b\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"), f.read) } + open("t","rt:utf-8:utf-16be"){|f| assert_equal("\0a\0\n\0b\0\n\0c\0\n\0\xa2".force_encoding("UTF-16BE"), f.read) } + open("t","rb:euc-jp:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)} + open("t","rb:utf-8:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x21\x71\e(B".force_encoding("ISO-2022-JP"),f.read)} + open("t","rb:euc-jp:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)} + open("t","rb:utf-8:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\0\xa2".force_encoding("UTF-16BE"),f.read)} + + open("ie","rt:iso-2022-jp:euc-jp"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) } + open("iu","rt:iso-2022-jp:utf-8"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) } + open("be","rt:utf-16be:euc-jp"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) } + open("bu","rt:utf-16be:utf-8"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) } + open("ie","rb:iso-2022-jp:euc-jp"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"),f.read)} + open("iu","rb:iso-2022-jp:utf-8"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"),f.read)} + open("be","rb:utf-16be:euc-jp"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"),f.read)} + open("bu","rb:utf-16be:utf-8"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"),f.read)} + + open("ie","rt:iso-2022-jp:utf-16be"){|f|assert_equal("\0a\0\n\0b\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)} + open("be","rt:utf-16be:iso-2022-jp"){|f|assert_equal("a\nb\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)} + open("ie","rb:iso-2022-jp:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)} + open("be","rb:utf-16be:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)} + } + end + + def assert_write(expected, mode, *args) + with_tmpdir { + open("t", mode) {|f| + args.each {|arg| f.print arg } + } + content = File.read("t", :mode=>"rb:ascii-8bit") + assert_equal(expected.dup.force_encoding("ascii-8bit"), + content.force_encoding("ascii-8bit")) + } + end + + def test_write_mode + # "\xc2\xa2" is valid as EUC-JP and UTF-8 + # EUC-JP UTF-8 Unicode + # 0xC2A2 0xE894B5 U+8535 + # 0xA1F1 0xC2A2 U+00A2 + a = "a\rb\r\nc\n" + e = "\xc2\xa2".force_encoding("euc-jp") + u8 = "\xc2\xa2".force_encoding("utf-8") + u16 = "\x85\x35\0\r\x00\xa2\0\r\0\n\0\n".force_encoding("utf-16be") + i = "\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n".force_encoding("iso-2022-jp") + n = system_newline + n.encode("utf-16be").force_encoding("ascii-8bit") + + assert_write("a\rb\r#{n}c#{n}", "wt", a) + assert_write("\xc2\xa2", "wt", e) + assert_write("\xc2\xa2", "wt", u8) + + assert_write("a\rb\r\nc\n", "wb", a) + assert_write("\xc2\xa2", "wb", e) + assert_write("\xc2\xa2", "wb", u8) + + #assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wt", u16) should raise + #assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wt", i) should raise + assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb", u16) + assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb", i) + + t_write_mode_enc + t_write_mode_enc(":utf-8") + end + + def t_write_mode_enc(enc="") + # "\xc2\xa2" is valid as EUC-JP and UTF-8 + # EUC-JP UTF-8 Unicode + # 0xC2A2 0xE894B5 U+8535 + # 0xA1F1 0xC2A2 U+00A2 + a = "a\rb\r\nc\n" + e = "\xc2\xa2".force_encoding("euc-jp") + u8 = "\xc2\xa2".force_encoding("utf-8") + u16 = "\x85\x35\0\r\x00\xa2\0\r\0\n\0\n".force_encoding("utf-16be") + i = "\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n".force_encoding("iso-2022-jp") + n = system_newline + un = n.encode("utf-16be").force_encoding("ascii-8bit") + + assert_write("a\rb\r#{n}c#{n}", "wt:euc-jp#{enc}", a) + assert_write("\xc2\xa2", "wt:euc-jp#{enc}", e) + assert_write("\xa1\xf1", "wt:euc-jp#{enc}", u8) + + assert_write("a\rb\r\nc\n", "wb:euc-jp#{enc}", a) + assert_write("\xc2\xa2", "wb:euc-jp#{enc}", e) + assert_write("\xa1\xf1", "wb:euc-jp#{enc}", u8) + + assert_write("\xc2\xa2\r\xa1\xf1\r#{n}#{n}", "wt:euc-jp#{enc}", u16) + assert_write("\xc2\xa2\r\xa1\xf1\r#{n}#{n}", "wt:euc-jp#{enc}", i) + assert_write("\xc2\xa2\r\xa1\xf1\r\n\n", "wb:euc-jp#{enc}", u16) + assert_write("\xc2\xa2\r\xa1\xf1\r\n\n", "wb:euc-jp#{enc}", i) + + assert_write("\0a\0\r\0b\0\r#{un}\0c#{un}", "wt:utf-16be#{enc}", a) + assert_write("\x85\x35", "wt:utf-16be#{enc}", e) + assert_write("\x00\xa2", "wt:utf-16be#{enc}", u8) + assert_write("a\rb\r#{n}c#{n}", "wt:iso-2022-jp#{enc}", a) + assert_write("\e$B\x42\x22\e(B", "wt:iso-2022-jp#{enc}", e) + assert_write("\e$B\x21\x71\e(B", "wt:iso-2022-jp#{enc}", u8) + + assert_write("\0a\0\r\0b\0\r\0\n\0c\0\n", "wb:utf-16be#{enc}", a) + assert_write("\x85\x35", "wb:utf-16be#{enc}", e) + assert_write("\x00\xa2", "wb:utf-16be#{enc}", u8) + assert_write("a\rb\r\nc\n", "wb:iso-2022-jp#{enc}", a) + assert_write("\e$B\x42\x22\e(B", "wb:iso-2022-jp#{enc}", e) + assert_write("\e$B\x21\x71\e(B", "wb:iso-2022-jp#{enc}", u8) + + assert_write("\x85\x35\0\r\x00\xa2\0\r#{un}#{un}", "wt:utf-16be#{enc}", u16) + assert_write("\x85\x35\0\r\x00\xa2\0\r#{un}#{un}", "wt:utf-16be#{enc}", i) + assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb:utf-16be#{enc}", u16) + assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb:utf-16be#{enc}", i) + assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r#{n}#{n}", "wt:iso-2022-jp#{enc}", u16) + assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r#{n}#{n}", "wt:iso-2022-jp#{enc}", i) + assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb:iso-2022-jp#{enc}", u16) + assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb:iso-2022-jp#{enc}", i) + end + + def test_write_mode_fail + return if system_newline == "\n" + with_tmpdir { + open("t", "wt") {|f| + assert_raise(ArgumentError) { f.print "\0\r\0\r\0\n\0\n".force_encoding("utf-16be") } + } + } + end + + def test_write_ascii_incompat + with_tmpdir { + open("t.utf8", "wb:utf-8:utf-16be") {|f| } + open("t.utf8", "wt:utf-8:utf-16be") {|f| } + open("t.utf8", "w:utf-8:utf-16be") {|f| } + open("t.utf16", "wb:utf-16be") {|f| } + open("t.utf16", "wt:utf-16be") {|f| } + open("t.utf16", "w:utf-16be") {|f| } + } + end + + def test_binmode_write_ascii_incompat_internal + with_tmpdir { + open("t.utf8.lf", "wb:utf-8:utf-16be") {|f| + f.print "\0a\0\n\0b\0\n".force_encoding("UTF-16BE") + } + content = File.read("t.utf8.lf", :mode=>"rb:ascii-8bit") + assert_equal("a\nb\n", content) + + open("t.utf8.lf", "wb:utf-16be") {|f| + f.print "\0a\0\n\0b\0\n".force_encoding("UTF-16BE") + } + content = File.read("t.utf8.lf", :mode=>"rb:ascii-8bit") + assert_equal("\0a\0\n\0b\0\n", content) + } + end + + def test_binary + with_tmpdir { + src = "a\nb\rc\r\nd\n" + generate_file("t.txt", src) + open("t.txt", "rb") {|f| + assert_equal(src, f.read) + } + open("t.txt", "r", :binmode=>true) {|f| + assert_equal(src, f.read) + } + if system_newline == "\n" + open("t.txt", "r") {|f| + assert_equal(src, f.read) + } + end + } + end + + def test_binmode + with_tmpdir { + src = "a\r\nb\r\nc\r\n" + generate_file("t.txt", src) + open("t.txt", "rt") {|f| + assert_equal("a", f.getc) + assert_equal("\n", f.getc) + f.binmode + assert_equal("b", f.getc) + assert_equal("\r", f.getc) + assert_equal("\n", f.getc) + assert_equal("c", f.getc) + assert_equal("\r", f.getc) + assert_equal("\n", f.getc) + assert_equal(nil, f.getc) + } + } + end + + def test_binmode2 + with_tmpdir { + src = "a\r\nb\r\nc\r\n" + generate_file("t.txt", src) + open("t.txt", "rt:euc-jp:utf-8") {|f| + assert_equal("a", f.getc) + assert_equal("\n", f.getc) + f.binmode + assert_equal("b", f.getc) + assert_equal("\r", f.getc) + assert_equal("\n", f.getc) + assert_equal("c", f.getc) + assert_equal("\r", f.getc) + assert_equal("\n", f.getc) + assert_equal(nil, f.getc) + } + } + end + + def test_binmode3 + with_tmpdir { + src = "\u3042\r\n" + generate_file("t.txt", src) + srcbin = src.dup.force_encoding("ascii-8bit") + open("t.txt", "rt:utf-8:euc-jp") {|f| + f.binmode + result = f.read + assert_str_equal(srcbin, result) + assert_equal(Encoding::ASCII_8BIT, result.encoding) + } + } + end + + def test_invalid_r + with_tmpdir { + generate_file("t.txt", "a\x80b") + open("t.txt", "r:utf-8:euc-jp", :invalid => :replace) {|f| + assert_equal("a?b", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :invalid => :replace, :replace => "") {|f| + assert_equal("ab", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :undef => :replace) {|f| + assert_raise(Encoding::InvalidByteSequenceError) { f.read } + assert_equal("b", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :undef => :replace, :replace => "") {|f| + assert_raise(Encoding::InvalidByteSequenceError) { f.read } + assert_equal("b", f.read) + } + } + end + + def test_undef_r + with_tmpdir { + generate_file("t.txt", "a\uFFFDb") + open("t.txt", "r:utf-8:euc-jp", :undef => :replace) {|f| + assert_equal("a?b", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :undef => :replace, :replace => "") {|f| + assert_equal("ab", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :invalid => :replace) {|f| + assert_raise(Encoding::UndefinedConversionError) { f.read } + assert_equal("b", f.read) + } + open("t.txt", "r:utf-8:euc-jp", :invalid => :replace, :replace => "") {|f| + assert_raise(Encoding::UndefinedConversionError) { f.read } + assert_equal("b", f.read) + } + } + end + + def test_invalid_w + with_tmpdir { + invalid_utf8 = "a\x80b".force_encoding("utf-8") + open("t.txt", "w:euc-jp", :invalid => :replace) {|f| + assert_nothing_raised { f.write invalid_utf8 } + } + assert_equal("a?b", File.read("t.txt")) + + open("t.txt", "w:euc-jp", :invalid => :replace, :replace => "") {|f| + assert_nothing_raised { f.write invalid_utf8 } + } + assert_equal("ab", File.read("t.txt")) + + open("t.txt", "w:euc-jp", :undef => :replace) {|f| + assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 } + } + open("t.txt", "w:euc-jp", :undef => :replace, :replace => "") {|f| + assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 } + } + } + end + + def test_undef_w_stateless + with_tmpdir { + generate_file("t.txt", "a\uFFFDb") + open("t.txt", "w:euc-jp:utf-8", :undef => :replace) {|f| + assert_nothing_raised { f.write "a\uFFFDb" } + } + assert_equal("a?b", File.read("t.txt")) + open("t.txt", "w:euc-jp:utf-8", :undef => :replace, :replace => "") {|f| + assert_nothing_raised { f.write "a\uFFFDb" } + } + assert_equal("ab", File.read("t.txt")) + open("t.txt", "w:euc-jp:utf-8", :invalid => :replace) {|f| + assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" } + } + open("t.txt", "w:euc-jp:utf-8", :invalid => :replace, :replace => "") {|f| + assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" } + } + } + end + + def test_undef_w_stateful + with_tmpdir { + generate_file("t.txt", "a\uFFFDb") + open("t.txt", "w:iso-2022-jp:utf-8", :undef => :replace) {|f| + assert_nothing_raised { f.write "a\uFFFDb" } + } + assert_equal("a?b", File.read("t.txt")) + open("t.txt", "w:iso-2022-jp:utf-8", :undef => :replace, :replace => "") {|f| + assert_nothing_raised { f.write "a\uFFFDb" } + } + assert_equal("ab", File.read("t.txt")) + open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace) {|f| + assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" } + } + open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace, :replace => "") {|f| + assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" } + } + } + end + + def test_w_xml_attr + with_tmpdir { + open("raw.txt", "wb", xml: :attr) {|f| f.print '&<>"\''; f.puts "\u4E02\u3042" } + content = File.read("raw.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"&<>"'\u4E02\u3042\n\"".force_encoding("ascii-8bit"), content) + + open("ascii.txt", "wb:us-ascii", xml: :attr) {|f| f.print '&<>"\''; f.puts "\u4E02\u3042" } + content = File.read("ascii.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"&<>"'丂あ\n\"".force_encoding("ascii-8bit"), content) + + open("iso-2022-jp.txt", "wb:iso-2022-jp", xml: :attr) {|f| f.print '&<>"\''; f.puts "\u4E02\u3042" } + content = File.read("iso-2022-jp.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"&<>"'丂\e$B$\"\e(B\n\"".force_encoding("ascii-8bit"), content) + + open("utf-16be.txt", "wb:utf-16be", xml: :attr) {|f| f.print '&<>"\''; f.puts "\u4E02\u3042" } + content = File.read("utf-16be.txt", :mode=>"rb:ascii-8bit") + assert_equal("\0\"\0&\0a\0m\0p\0;\0&\0l\0t\0;\0&\0g\0t\0;\0&\0q\0u\0o\0t\0;\0'\x4E\x02\x30\x42\0\n\0\"".force_encoding("ascii-8bit"), content) + + open("eucjp.txt", "w:euc-jp:utf-8", xml: :attr) {|f| + f.print "\u4E02" # U+4E02 is 0x3021 in JIS X 0212 + } + content = File.read("eucjp.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"\x8F\xB0\xA1\"".force_encoding("ascii-8bit"), content) + + open("sjis.txt", "w:sjis:utf-8", xml: :attr) {|f| + f.print "\u4E02" # U+4E02 is 0x3021 in JIS X 0212 + } + content = File.read("sjis.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"丂\"".force_encoding("ascii-8bit"), content) + + open("iso-2022-jp.txt", "w:iso-2022-jp:utf-8", xml: :attr) {|f| + f.print "\u4E02" # U+4E02 is 0x3021 in JIS X 0212 + } + content = File.read("iso-2022-jp.txt", :mode=>"rb:ascii-8bit") + assert_equal("\"丂\"".force_encoding("ascii-8bit"), content) + } + end + + def test_strip_bom + with_tmpdir { + text = "\uFEFFa" + stripped = "a" + %w/UTF-8 UTF-16BE UTF-16LE UTF-32BE UTF-32LE/.each do |name| + path = '%s-bom.txt' % name + content = text.encode(name) + generate_file(path, content) + result = File.read(path, mode: 'rb:BOM|UTF-8') + assert_equal(content[1].force_encoding("ascii-8bit"), + result.force_encoding("ascii-8bit")) + result = File.read(path, mode: 'rb:BOM|UTF-8:UTF-8') + assert_equal(Encoding::UTF_8, result.encoding) + assert_equal(stripped, result) + end + + bug3407 = '[ruby-core:30641]' + path = 'UTF-8-bom.txt' + result = File.read(path, encoding: 'BOM|UTF-8') + assert_equal("a", result.force_encoding("ascii-8bit"), bug3407) + + bug8323 = '[ruby-core:54563] [Bug #8323]' + expected = "a\xff".force_encoding("utf-8") + open(path, 'ab') {|f| f.write("\xff")} + result = File.read(path, encoding: 'BOM|UTF-8') + assert_not_predicate(result, :valid_encoding?, bug8323) + assert_equal(expected, result, bug8323) + result = File.read(path, encoding: 'BOM|UTF-8:UTF-8') + assert_not_predicate(result, :valid_encoding?, bug8323) + assert_equal(expected, result, bug8323) + + path = 'ascii.txt' + generate_file(path, stripped) + result = File.read(path, encoding: 'BOM|UTF-8') + assert_equal(stripped, result, bug8323) + result = File.read(path, encoding: 'BOM|UTF-8:UTF-8') + assert_equal(stripped, result, bug8323) + } + end + + def test_cbuf + with_tmpdir { + fn = "tst" + open(fn, "w") {|f| f.print "foo" } + open(fn, "r+t") {|f| + f.ungetc(f.getc) + assert_raise(IOError, "[ruby-dev:40493]") { f.readpartial(2) } + assert_raise(IOError) { f.read(2) } + assert_raise(IOError) { f.each_byte {|c| } } + assert_raise(IOError) { f.getbyte } + assert_raise(IOError) { f.ungetbyte(0) } + assert_raise(IOError) { f.sysread(2) } + assert_raise(IOError) { IO.copy_stream(f, "tmpout") } + assert_raise(IOError) { f.sysseek(2) } + } + open(fn, "r+t") {|f| + f.ungetc(f.getc) + assert_equal("foo", f.read) + } + } + end + + def test_text_mode_ungetc_eof + with_tmpdir { + open("ff", "w") {|f| } + open("ff", "rt") {|f| + f.ungetc "a" + assert_not_predicate(f, :eof?, "[ruby-dev:40506] (3)") + } + } + end + + def test_cbuf_select + pipe("US-ASCII:UTF-8", { :universal_newline => true }, + proc do |w| + w << "\r\n" + end, + proc do |r| + r.ungetc(r.getc) + assert_equal([[r],[],[]], IO.select([r], nil, nil, 1)) + end) + end + + def test_textmode_paragraphmode + pipe("US-ASCII:UTF-8", { :universal_newline => true }, + proc do |w| + w << "a\n\n\nc".gsub(/\n/, "\r\n") + w.close + end, + proc do |r| + assert_equal("a\n\n", r.gets("")) + assert_equal("c", r.gets(""), "[ruby-core:23723] (18)") + end) + end + + def test_textmode_paragraph_binaryread + pipe("US-ASCII:UTF-8", { :universal_newline => true }, + proc do |w| + w << "a\n\n\ncdefgh".gsub(/\n/, "\r\n") + w.close + end, + proc do |r| + assert_equal("a\n\n", r.gets("")) + assert_equal("c", r.getc) + assert_equal("defgh", r.readpartial(10)) + end) + end + + def test_textmode_paragraph_nonasciicompat + bug3534 = ['[ruby-dev:41803]', '[Bug #3534]'] + IO.pipe {|r, w| + [Encoding::UTF_32BE, Encoding::UTF_32LE, + Encoding::UTF_16BE, Encoding::UTF_16LE, + Encoding::UTF_8].each do |e| + r.set_encoding(Encoding::US_ASCII, e) + wthr = Thread.new{ w.print(bug3534[0], "\n\n\n\n", bug3534[1], "\n") } + assert_equal((bug3534[0]+"\n\n").encode(e), r.gets(""), bug3534[0]) + assert_equal((bug3534[1]+"\n").encode(e), r.gets(), bug3534[1]) + wthr.join + end + } + end + + def test_binmode_paragraph_nonasciicompat + bug3534 = ['[ruby-dev:41803]', '[Bug #3534]'] + IO.pipe {|r, w| + r.binmode + w.binmode + [Encoding::UTF_32BE, Encoding::UTF_32LE, + Encoding::UTF_16BE, Encoding::UTF_16LE, + Encoding::UTF_8].each do |e| + r.set_encoding(Encoding::US_ASCII, e) + wthr = Thread.new{ w.print(bug3534[0], "\n\n\n\n", bug3534[1], "\n") } + assert_equal((bug3534[0]+"\n\n").encode(e), r.gets(""), bug3534[0]) + assert_equal((bug3534[1]+"\n").encode(e), r.gets(), bug3534[1]) + wthr.join + end + } + end + + def test_puts_widechar + bug = '[ruby-dev:42212]' + pipe(Encoding::ASCII_8BIT, + proc do |w| + w.binmode + w.puts(0x010a.chr(Encoding::UTF_32BE)) + w.puts(0x010a.chr(Encoding::UTF_16BE)) + w.puts(0x0a010000.chr(Encoding::UTF_32LE)) + w.puts(0x0a01.chr(Encoding::UTF_16LE)) + w.close + end, + proc do |r| + r.binmode + assert_equal("\x00\x00\x01\x0a\n", r.read(5), bug) + assert_equal("\x01\x0a\n", r.read(3), bug) + assert_equal("\x00\x00\x01\x0a\n", r.read(5), bug) + assert_equal("\x01\x0a\n", r.read(3), bug) + assert_equal("", r.read, bug) + r.close + end) + end + + def test_getc_ascii_only + bug4557 = '[ruby-core:35630]' + c = with_tmpdir { + open("a", "wb") {|f| f.puts "a"} + open("a", "rt") {|f| f.getc} + } + assert_predicate(c, :ascii_only?, bug4557) + end + + def test_getc_conversion + bug8516 = '[ruby-core:55444] [Bug #8516]' + c = with_tmpdir { + open("a", "wb") {|f| f.putc "\xe1"} + open("a", "r:iso-8859-1:utf-8") {|f| f.getc} + } + assert_not_predicate(c, :ascii_only?, bug8516) + assert_equal(1, c.size, bug8516) + end + + def test_default_mode_on_dosish + with_tmpdir { + open("a", "w") {|f| f.write "\n"} + assert_equal("\r\n", IO.binread("a")) + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_default_mode_on_unix + with_tmpdir { + open("a", "w") {|f| f.write "\n"} + assert_equal("\n", IO.binread("a")) + } + end unless /mswin|mingw/ =~ RUBY_PLATFORM + + def test_text_mode + with_tmpdir { + open("a", "wb") {|f| f.write "\r\n"} + assert_equal("\n", open("a", "rt"){|f| f.read}) + } + end + + def test_binary_mode + with_tmpdir { + open("a", "wb") {|f| f.write "\r\n"} + assert_equal("\r\n", open("a", "rb"){|f| f.read}) + } + end + + def test_default_stdout_stderr_mode + with_pipe do |in_r, in_w| + with_pipe do |out_r, out_w| + pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w, err: out_w) + in_r.close + out_w.close + in_w.write <<-EOS + STDOUT.puts "abc" + STDOUT.flush + STDERR.puts "def" + STDERR.flush + EOS + in_w.close + Process.wait pid + assert_equal "abc\r\ndef\r\n", out_r.binmode.read + out_r.close + end + end + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_cr_decorator_on_stdout + with_pipe do |in_r, in_w| + with_pipe do |out_r, out_w| + pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w) + in_r.close + out_w.close + in_w.write <<-EOS + STDOUT.set_encoding('locale', nil, newline: :cr) + STDOUT.puts "abc" + STDOUT.flush + EOS + in_w.close + Process.wait pid + assert_equal "abc\r", out_r.binmode.read + out_r.close + end + end + end + + def test_lf_decorator_on_stdout + with_pipe do |in_r, in_w| + with_pipe do |out_r, out_w| + pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w) + in_r.close + out_w.close + in_w.write <<-EOS + STDOUT.set_encoding('locale', nil, newline: :lf) + STDOUT.puts "abc" + STDOUT.flush + EOS + in_w.close + Process.wait pid + assert_equal "abc\n", out_r.binmode.read + out_r.close + end + end + end + + def test_crlf_decorator_on_stdout + with_pipe do |in_r, in_w| + with_pipe do |out_r, out_w| + pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w) + in_r.close + out_w.close + in_w.write <<-EOS + STDOUT.set_encoding('locale', nil, newline: :crlf) + STDOUT.puts "abc" + STDOUT.flush + EOS + in_w.close + Process.wait pid + assert_equal "abc\r\n", out_r.binmode.read + out_r.close + end + end + end + + def test_binmode_with_pipe + with_pipe do |r, w| + src = "a\r\nb\r\nc\r\n" + w.binmode.write src + w.close + + assert_equal("a", r.getc) + assert_equal("\n", r.getc) + r.binmode + assert_equal("b", r.getc) + assert_equal("\r", r.getc) + assert_equal("\n", r.getc) + assert_equal("c", r.getc) + assert_equal("\r", r.getc) + assert_equal("\n", r.getc) + assert_equal(nil, r.getc) + r.close + end + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_stdin_binmode + with_pipe do |in_r, in_w| + with_pipe do |out_r, out_w| + pid = Process.spawn({}, EnvUtil.rubybin, '-e', <<-'End', in: in_r, out: out_w) + STDOUT.binmode + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDIN.binmode + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + STDOUT.write STDIN.getc + End + in_r.close + out_w.close + src = "a\r\nb\r\nc\r\n" + in_w.binmode.write src + in_w.close + Process.wait pid + assert_equal "a\nb\r\nc\r\n", out_r.binmode.read + out_r.close + end + end + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_length + with_tmpdir { + str = "a\nb" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal(str, f.read(3)) + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_length_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + # read with length should be binary mode + assert_equal("a\r\n", f.read(3)) # binary + assert_equal("b\nc\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_gets_and_read_with_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a\n", f.gets) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\r\n", f.read(3)) # binary + assert_equal("\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_getc_and_read_with_binmode + with_tmpdir { + str = "a\r\nb\r\nc\n\n\r\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\n\n\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_binmode_and_gets + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + open("tmp", "wb") { |f| f.write str } + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\n", f.gets) # text + assert_equal("\n", f.gets) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_binmode_and_getc + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + open("tmp", "wb") { |f| f.write str } + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("\n", f.getc) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_write_with_binmode + with_tmpdir { + str = "a\r\n" + generate_file("tmp", str) + open("tmp", "r+") do |f| + assert_equal("a\r\n", f.read(3)) # binary + f.write("b\n\n"); # text + f.rewind + assert_equal("a\nb\n\n", f.read) # text + f.rewind + assert_equal("a\r\nb\r\n\r\n", f.binmode.read) # binary + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_seek_with_setting_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n\n\n\n\n\n\n\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a\n", f.gets) # text + assert_equal("b\r\n", f.read(3)) # binary + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_error_nonascii + bug6071 = '[ruby-dev:45279]' + paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")] + encs = with_tmpdir { + paths.map {|path| + open(path) rescue $!.message.encoding + } + } + assert_equal(paths.map(&:encoding), encs, bug6071) + end + + def test_inspect_nonascii + bug6072 = '[ruby-dev:45280]' + paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")] + encs = with_tmpdir { + paths.map {|path| + open(path, "wb") {|f| f.inspect.encoding} + } + } + assert_equal(paths.map(&:encoding), encs, bug6072) + end + + def test_pos_dont_move_cursor_position + bug6179 = '[ruby-core:43497]' + with_tmpdir { + str = "line one\r\nline two\r\nline three\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("line one\n", f.readline) + assert_equal(10, f.pos, bug6179) + assert_equal("line two\n", f.readline, bug6179) + assert_equal(20, f.pos, bug6179) + assert_equal("line three\n", f.readline, bug6179) + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_pos_with_buffer_end_cr + bug6401 = '[ruby-core:44874]' + with_tmpdir { + # Read buffer size is 8191. This generates '\r' at 8191. + lines = ["X" * 8187, "X"] + generate_file("tmp", lines.join("\r\n") + "\r\n") + + open("tmp", "r") do |f| + lines.each do |line| + f.pos + assert_equal(line, f.readline.chomp, bug6401) + end + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_crlf_and_eof + bug6271 = '[ruby-core:44189]' + with_tmpdir { + str = "a\r\nb\r\nc\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + i = 0 + until f.eof? + assert_equal(str[i], f.read(1), bug6271) + i += 1 + end + assert_equal(str.size, i, bug6271) + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_buf_broken_ascii_only + a, b = IO.pipe + a.binmode + b.binmode + b.write("\xE2\x9C\x93") + b.close + + buf = "".force_encoding("binary") + assert buf.ascii_only?, "should have been ascii_only?" + a.read(1, buf) + assert !buf.ascii_only?, "should not have been ascii_only?" + ensure + a.close rescue nil + b.close rescue nil + end +end diff --git a/jni/ruby/test/ruby/test_iseq.rb b/jni/ruby/test/ruby/test_iseq.rb new file mode 100644 index 0000000..686646d --- /dev/null +++ b/jni/ruby/test/ruby/test_iseq.rb @@ -0,0 +1,144 @@ +require 'test/unit' + +class TestISeq < Test::Unit::TestCase + ISeq = RubyVM::InstructionSequence + + def test_no_linenum + bug5894 = '[ruby-dev:45130]' + assert_normal_exit('p RubyVM::InstructionSequence.compile("1", "mac", "", 0).to_a', bug5894) + end + + def lines src + body = RubyVM::InstructionSequence.new(src).to_a[13] + body.find_all{|e| e.kind_of? Fixnum} + end + + def test_to_a_lines + src = <<-EOS + p __LINE__ # 1 + p __LINE__ # 2 + # 3 + p __LINE__ # 4 + EOS + assert_equal [1, 2, 4], lines(src) + + src = <<-EOS + # 1 + p __LINE__ # 2 + # 3 + p __LINE__ # 4 + # 5 + EOS + assert_equal [2, 4], lines(src) + + src = <<-EOS + 1 # should be optimized out + 2 # should be optimized out + p __LINE__ # 3 + p __LINE__ # 4 + 5 # should be optimized out + 6 # should be optimized out + p __LINE__ # 7 + 8 # should be optimized out + 9 + EOS + assert_equal [3, 4, 7, 9], lines(src) + end + + def test_unsupport_type + ary = RubyVM::InstructionSequence.compile("p").to_a + ary[9] = :foobar + assert_raise_with_message(TypeError, /:foobar/) {RubyVM::InstructionSequence.load(ary)} + end if defined?(RubyVM::InstructionSequence.load) + + def test_disasm_encoding + src = "\u{3042} = 1; \u{3042}; \u{3043}" + asm = RubyVM::InstructionSequence.compile(src).disasm + assert_equal(src.encoding, asm.encoding) + assert_predicate(asm, :valid_encoding?) + src.encode!(Encoding::Shift_JIS) + asm = RubyVM::InstructionSequence.compile(src).disasm + assert_equal(src.encoding, asm.encoding) + assert_predicate(asm, :valid_encoding?) + end + + LINE_BEFORE_METHOD = __LINE__ + def method_test_line_trace + + a = 1 + + b = 2 + + end + + def test_line_trace + iseq = ISeq.compile \ + %q{ a = 1 + b = 2 + c = 3 + # d = 4 + e = 5 + # f = 6 + g = 7 + + } + assert_equal([1, 2, 3, 5, 7], iseq.line_trace_all) + iseq.line_trace_specify(1, true) # line 2 + iseq.line_trace_specify(3, true) # line 5 + + result = [] + TracePoint.new(:specified_line){|tp| + result << tp.lineno + }.enable{ + iseq.eval + } + assert_equal([2, 5], result) + + iseq = ISeq.of(self.class.instance_method(:method_test_line_trace)) + assert_equal([LINE_BEFORE_METHOD + 3, LINE_BEFORE_METHOD + 5], iseq.line_trace_all) + end if false # TODO: now, it is only for C APIs. + + LINE_OF_HERE = __LINE__ + def test_location + iseq = ISeq.of(method(:test_location)) + + assert_equal(__FILE__, iseq.path) + assert_match(/#{__FILE__}/, iseq.absolute_path) + assert_equal("test_location", iseq.label) + assert_equal("test_location", iseq.base_label) + assert_equal(LINE_OF_HERE+1, iseq.first_lineno) + + line = __LINE__ + iseq = ISeq.of(Proc.new{}) + assert_equal(__FILE__, iseq.path) + assert_match(/#{__FILE__}/, iseq.absolute_path) + assert_equal("test_location", iseq.base_label) + assert_equal("block in test_location", iseq.label) + assert_equal(line+1, iseq.first_lineno) + end + + def test_label_fstring + c = Class.new{ def foobar() end } + + a, b = eval("# encoding: us-ascii\n'foobar'.freeze"), + ISeq.of(c.instance_method(:foobar)).label + assert_same a, b + end + + def test_disable_opt + src = "a['foo'] = a['bar']; 'a'.freeze" + _,_,_,_,_,_,_,_,_,_,_,_,_,body= RubyVM::InstructionSequence.compile(src, __FILE__, __FILE__, __LINE__, false).to_a + body.each{|insn| + next if Integer === insn + op = insn.first + assert(!op.to_s.match(/^opt_/), "#{op}") + } + end + + def test_invalid_source + bug11159 = '[ruby-core:69219] [Bug #11159]' + assert_raise(TypeError, bug11159) {ISeq.compile(nil)} + assert_raise(TypeError, bug11159) {ISeq.compile(:foo)} + assert_raise(TypeError, bug11159) {ISeq.compile(1)} + end +end diff --git a/jni/ruby/test/ruby/test_iterator.rb b/jni/ruby/test/ruby/test_iterator.rb new file mode 100644 index 0000000..34652db --- /dev/null +++ b/jni/ruby/test/ruby/test_iterator.rb @@ -0,0 +1,497 @@ +require 'test/unit' + +class Array + def iter_test1 + collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]} + end + def iter_test2 + ary = collect{|e| [e, yield(e)]} + ary.sort{|a,b|a[1]<=>b[1]} + end +end + +class TestIterator < Test::Unit::TestCase + def ttt + assert(iterator?) + end + + def test_iterator + assert(!iterator?) + + ttt{} + + # yield at top level !! here's not toplevel + assert(!defined?(yield)) + end + + def test_array + x = [1, 2, 3, 4] + y = [] + + # iterator over array + for i in x + y.push i + end + assert_equal(x, y) + end + + def tt + 1.upto(10) {|i| + yield i + } + end + + def tt2(dummy) + yield 1 + end + + def tt3(&block) + tt2(raise(ArgumentError,""),&block) + end + + def test_nested_iterator + i = 0 + tt{|j| break if j == 5} + assert_equal(0, i) + + assert_raise(ArgumentError) do + tt3{} + end + end + + def tt4 &block + tt2(raise(ArgumentError,""),&block) + end + + def test_block_argument_without_paren + assert_raise(ArgumentError) do + tt4{} + end + end + + # iterator break/redo/next + def test_break + done = true + loop{ + break + done = false # should not reach here + } + assert(done) + + done = false + bad = false + loop { + break if done + done = true + next + bad = true # should not reach here + } + assert(!bad) + + done = false + bad = false + loop { + break if done + done = true + redo + bad = true # should not reach here + } + assert(!bad) + + x = [] + for i in 1 .. 7 + x.push i + end + assert_equal(7, x.size) + assert_equal([1, 2, 3, 4, 5, 6, 7], x) + end + + def test_append_method_to_built_in_class + x = [[1,2],[3,4],[5,6]] + assert_equal(x.iter_test1{|x|x}, x.iter_test2{|x|x}) + end + + class IterTest + def initialize(e); @body = e; end + + def each0(&block); @body.each(&block); end + def each1(&block); @body.each {|*x| block.call(*x) } end + def each2(&block); @body.each {|*x| block.call(x) } end + def each3(&block); @body.each {|x| block.call(*x) } end + def each4(&block); @body.each {|x| block.call(x) } end + def each5; @body.each {|*x| yield(*x) } end + def each6; @body.each {|*x| yield(x) } end + def each7; @body.each {|x| yield(*x) } end + def each8; @body.each {|x| yield(x) } end + + def f(a) + a + end + end + + def test_itertest + assert_equal([1], IterTest.new(nil).method(:f).to_proc.call([1])) + m = /\w+/.match("abc") + assert_equal([m], IterTest.new(nil).method(:f).to_proc.call([m])) + + IterTest.new([0]).each0 {|x| assert_equal(0, x)} + IterTest.new([1]).each1 {|x| assert_equal(1, x)} + IterTest.new([2]).each2 {|x| assert_equal([2], x)} + IterTest.new([4]).each4 {|x| assert_equal(4, x)} + IterTest.new([5]).each5 {|x| assert_equal(5, x)} + IterTest.new([6]).each6 {|x| assert_equal([6], x)} + IterTest.new([8]).each8 {|x| assert_equal(8, x)} + + IterTest.new([[0]]).each0 {|x| assert_equal([0], x)} + IterTest.new([[1]]).each1 {|x| assert_equal([1], x)} + IterTest.new([[2]]).each2 {|x| assert_equal([[2]], x)} + IterTest.new([[3]]).each3 {|x| assert_equal(3, x)} + IterTest.new([[4]]).each4 {|x| assert_equal([4], x)} + IterTest.new([[5]]).each5 {|x| assert_equal([5], x)} + IterTest.new([[6]]).each6 {|x| assert_equal([[6]], x)} + IterTest.new([[7]]).each7 {|x| assert_equal(7, x)} + IterTest.new([[8]]).each8 {|x| assert_equal([8], x)} + + IterTest.new([[0,0]]).each0 {|*x| assert_equal([[0,0]], x)} + IterTest.new([[8,8]]).each8 {|*x| assert_equal([[8,8]], x)} + end + + def m(var) + var + end + + def m1 + m(block_given?) + end + + def m2 + m(block_given?,&proc{}) + end + + def test_block_given + assert(m1{p 'test'}) + assert(m2{p 'test'}) + assert(!m1()) + assert(!m2()) + end + + def m3(var, &block) + m(yield(var), &block) + end + + def m4(&block) + m(m1(), &block) + end + + def test_block_passing + assert(!m4()) + assert(!m4 {}) + assert_equal(100, m3(10) {|x|x*x}) + end + + class C + include Enumerable + def initialize + @a = [1,2,3] + end + def each(&block) + @a.each(&block) + end + end + + def test_collect + assert_equal([1,2,3], C.new.collect{|n| n}) + end + + def test_proc + assert_instance_of(Proc, lambda{}) + assert_instance_of(Proc, Proc.new{}) + lambda{|a|assert_equal(a, 1)}.call(1) + end + + def test_block + assert_instance_of(NilClass, get_block) + assert_instance_of(Proc, get_block{}) + end + + def test_argument + assert_nothing_raised {lambda{||}.call} + assert_raise(ArgumentError) {lambda{||}.call(1)} + assert_nothing_raised {lambda{|a,|}.call(1)} + assert_raise(ArgumentError) {lambda{|a,|}.call()} + assert_raise(ArgumentError) {lambda{|a,|}.call(1,2)} + end + + def get_block(&block) + block + end + + def test_get_block + assert_instance_of(Proc, get_block{}) + assert_nothing_raised {get_block{||}.call()} + assert_nothing_raised {get_block{||}.call(1)} + assert_nothing_raised {get_block{|a,|}.call(1)} + assert_nothing_raised {get_block{|a,|}.call()} + assert_nothing_raised {get_block{|a,|}.call(1,2)} + + assert_nothing_raised {get_block(&lambda{||}).call()} + assert_raise(ArgumentError) {get_block(&lambda{||}).call(1)} + assert_nothing_raised {get_block(&lambda{|a,|}).call(1)} + assert_raise(ArgumentError) {get_block(&lambda{|a,|}).call(1,2)} + + block = get_block{11} + assert_instance_of(Proc, block) + assert_instance_of(Proc, block.to_proc) + assert_equal(block.clone.call, 11) + assert_instance_of(Proc, get_block(&block)) + + lmd = lambda{44} + assert_instance_of(Proc, lmd) + assert_instance_of(Proc, lmd.to_proc) + assert_equal(lmd.clone.call, 44) + assert_instance_of(Proc, get_block(&lmd)) + + assert_equal(1, Proc.new{|a,| a}.call(1,2,3)) + assert_nothing_raised {Proc.new{|a,|}.call(1,2)} + end + + def return1_test + Proc.new { + return 55 + }.call + 5 + end + + def test_return1 + assert_equal(55, return1_test()) + end + + def return2_test + lambda { + return 55 + }.call + 5 + end + + def test_return2 + assert_equal(60, return2_test()) + end + + def proc_call(&b) + b.call + end + def proc_yield() + yield + end + def proc_return1 + proc_call{return 42}+1 + end + + def test_proc_return1 + assert_equal(42, proc_return1()) + end + + def proc_return2 + proc_yield{return 42}+1 + end + + def test_proc_return2 + assert_equal(42, proc_return2()) + end + + def test_ljump + assert_raise(LocalJumpError) {get_block{break}.call} + + # cannot use assert_nothing_raised due to passing block. + begin + val = lambda{break 11}.call + rescue LocalJumpError + assert(false, "LocalJumpError occurred from break in lambda") + else + assert_equal(11, val) + end + + block = get_block{11} + lmd = lambda{44} + assert_equal(0, block.arity) + assert_equal(0, lmd.arity) + assert_equal(0, lambda{||}.arity) + assert_equal(1, lambda{|a|}.arity) + assert_equal(1, lambda{|a,|}.arity) + assert_equal(2, lambda{|a,b|}.arity) + end + + def marity_test(m) + mobj = method(m) + assert_equal(mobj.arity, mobj.to_proc.arity) + end + + def test_marity + marity_test(:assert) + marity_test(:marity_test) + marity_test(:p) + + lambda(&method(:assert)).call(true) + lambda(&get_block{|a,n| assert(a,n)}).call(true, "marity") + end + + def foo + yield(:key, :value) + end + def bar(&blk) + blk.call(:key, :value) + end + + def test_yield_vs_call + foo{|k,v| assert_equal([:key, :value], [k,v])} + bar{|k,v| assert_equal([:key, :value], [k,v])} + end + + class H + def each + yield [:key, :value] + end + alias each_pair each + end + + def test_assoc_yield + [{:key=>:value}, H.new].each {|h| + h.each{|a| assert_equal([:key, :value], a)} + h.each{|a,| assert_equal(:key, a)} + h.each{|*a| assert_equal([[:key, :value]], a)} + h.each{|k,v| assert_equal([:key, :value], [k,v])} + h.each_pair{|a| assert_equal([:key, :value], a)} + h.each_pair{|a,| assert_equal(:key, a)} + h.each_pair{|*a| assert_equal([[:key, :value]], a)} + h.each_pair{|k,v| assert_equal([:key, :value], [k,v])} + } + end + + class ITER_TEST1 + def a + block_given? + end + end + + class ITER_TEST2 < ITER_TEST1 + include Test::Unit::Assertions + def a + assert(super) + super + end + end + + def test_iter_test2 + assert(ITER_TEST2.new.a {}) + end + + class ITER_TEST3 + def foo x + return yield if block_given? + x + end + end + + class ITER_TEST4 < ITER_TEST3 + include Test::Unit::Assertions + def foo x + assert_equal(super, yield) + assert_equal(x, super(x, &nil)) + end + end + + def test_iter4 + ITER_TEST4.new.foo(44){55} + end + + def test_break__nested_loop1 + _test_break__nested_loop1 do + break + end + end + + def _test_break__nested_loop1 + while true + yield + end + assert(false, "must not reach here") + end + + def test_break__nested_loop2 + _test_break__nested_loop2 do + break + end + end + + def _test_break__nested_loop2 + until false + yield + end + assert(false, "must not reach here") + end + + def test_break__nested_loop3 + _test_break__nested_loop3 do + break + end + end + + def _test_break__nested_loop3 + loop do + yield + end + assert(false, "must not reach here") + end + + def test_break_from_enum + result = ["a"].inject("ng") {|x,y| break "ok"} + assert_equal("ok", result) + end + + def _test_return_trace_func(x) + set_trace_func(proc {}) + [].fetch(2) {return x} + ensure + set_trace_func(nil) + end + + def test_return_trace_func + ok = "returned gracefully" + result = "skipped" + result = _test_return_trace_func(ok) + ensure + assert_equal(ok, result) + return + end + + class IterString < ::String + def ===(other) + super if !block_given? + end + end + + # Check that the block passed to an iterator + # does not get propagated inappropriately + def test_block_given_within_iterator + assert_equal(["b"], ["a", "b", "c"].grep(IterString.new("b")) {|s| s}) + end + + def test_enumerator + [1,2,3].each.with_index {|x,i| + assert_equal(x, i+1) + } + + e = [1,2,3].each + assert_equal(1, e.next) + assert_equal(2, e.next) + assert_equal(3, e.next) + assert_raise(StopIteration){e.next} + e.rewind + assert_equal(1, e.next) + e.rewind + a = [] + loop{a.push e.next} + assert_equal([1,2,3], a) + + assert_equal([[8, 1, 10], [6, 2, 11], [4, 3, 12]], + [8,6,4].zip((1..10),(10..100)).to_a) + end +end diff --git a/jni/ruby/test/ruby/test_keyword.rb b/jni/ruby/test/ruby/test_keyword.rb new file mode 100644 index 0000000..9c76e15 --- /dev/null +++ b/jni/ruby/test/ruby/test_keyword.rb @@ -0,0 +1,579 @@ +require 'test/unit' + +class TestKeywordArguments < Test::Unit::TestCase + def f1(str: "foo", num: 424242) + [str, num] + end + + def test_f1 + assert_equal(["foo", 424242], f1) + assert_equal(["bar", 424242], f1(str: "bar")) + assert_equal(["foo", 111111], f1(num: 111111)) + assert_equal(["bar", 111111], f1(str: "bar", num: 111111)) + assert_raise(ArgumentError) { f1(str: "bar", check: true) } + assert_raise(ArgumentError) { f1("string") } + end + + + def f2(x, str: "foo", num: 424242) + [x, str, num] + end + + def test_f2 + assert_equal([:xyz, "foo", 424242], f2(:xyz)) + assert_equal([{"bar"=>42}, "foo", 424242], f2("bar"=>42)) + end + + + def f3(str: "foo", num: 424242, **h) + [str, num, h] + end + + def test_f3 + assert_equal(["foo", 424242, {}], f3) + assert_equal(["bar", 424242, {}], f3(str: "bar")) + assert_equal(["foo", 111111, {}], f3(num: 111111)) + assert_equal(["bar", 111111, {}], f3(str: "bar", num: 111111)) + assert_equal(["bar", 424242, {:check=>true}], f3(str: "bar", check: true)) + assert_raise(ArgumentError) { f3("string") } + end + + + define_method(:f4) {|str: "foo", num: 424242| [str, num] } + + def test_f4 + assert_equal(["foo", 424242], f4) + assert_equal(["bar", 424242], f4(str: "bar")) + assert_equal(["foo", 111111], f4(num: 111111)) + assert_equal(["bar", 111111], f4(str: "bar", num: 111111)) + assert_raise(ArgumentError) { f4(str: "bar", check: true) } + assert_raise(ArgumentError) { f4("string") } + end + + + define_method(:f5) {|str: "foo", num: 424242, **h| [str, num, h] } + + def test_f5 + assert_equal(["foo", 424242, {}], f5) + assert_equal(["bar", 424242, {}], f5(str: "bar")) + assert_equal(["foo", 111111, {}], f5(num: 111111)) + assert_equal(["bar", 111111, {}], f5(str: "bar", num: 111111)) + assert_equal(["bar", 424242, {:check=>true}], f5(str: "bar", check: true)) + assert_raise(ArgumentError) { f5("string") } + end + + + def f6(str: "foo", num: 424242, **h, &blk) + [str, num, h, blk] + end + + def test_f6 # [ruby-core:40518] + assert_equal(["foo", 424242, {}, nil], f6) + assert_equal(["bar", 424242, {}, nil], f6(str: "bar")) + assert_equal(["foo", 111111, {}, nil], f6(num: 111111)) + assert_equal(["bar", 111111, {}, nil], f6(str: "bar", num: 111111)) + assert_equal(["bar", 424242, {:check=>true}, nil], f6(str: "bar", check: true)) + a = f6 {|x| x + 42 } + assert_equal(["foo", 424242, {}], a[0, 3]) + assert_equal(43, a.last.call(1)) + end + + def f7(*r, str: "foo", num: 424242, **h) + [r, str, num, h] + end + + def test_f7 # [ruby-core:41772] + assert_equal([[], "foo", 424242, {}], f7) + assert_equal([[], "bar", 424242, {}], f7(str: "bar")) + assert_equal([[], "foo", 111111, {}], f7(num: 111111)) + assert_equal([[], "bar", 111111, {}], f7(str: "bar", num: 111111)) + assert_equal([[1], "foo", 424242, {}], f7(1)) + assert_equal([[1, 2], "foo", 424242, {}], f7(1, 2)) + assert_equal([[1, 2, 3], "foo", 424242, {}], f7(1, 2, 3)) + assert_equal([[1], "bar", 424242, {}], f7(1, str: "bar")) + assert_equal([[1, 2], "bar", 424242, {}], f7(1, 2, str: "bar")) + assert_equal([[1, 2, 3], "bar", 424242, {}], f7(1, 2, 3, str: "bar")) + end + + define_method(:f8) { |opt = :ion, *rest, key: :word| + [opt, rest, key] + } + + def test_f8 + assert_equal([:ion, [], :word], f8) + assert_equal([1, [], :word], f8(1)) + assert_equal([1, [2], :word], f8(1, 2)) + end + + def f9(r, o=42, *args, p, k: :key, **kw, &b) + [r, o, args, p, k, kw, b] + end + + def test_f9 + assert_equal([1, 42, [], 2, :key, {}, nil], f9(1, 2)) + assert_equal([1, 2, [], 3, :key, {}, nil], f9(1, 2, 3)) + assert_equal([1, 2, [3], 4, :key, {}, nil], f9(1, 2, 3, 4)) + assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], f9(1, 2, 3, 4, 5, str: "bar")) + end + + def f10(a: 1, **) + a + end + + def test_f10 + assert_equal(42, f10(a: 42)) + assert_equal(1, f10(b: 42)) + end + + def test_method_parameters + assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters); + assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters); + assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f3).parameters); + assert_equal([[:key, :str], [:key, :num]], method(:f4).parameters); + assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f5).parameters); + assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], method(:f6).parameters); + assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], method(:f7).parameters); + assert_equal([[:opt, :opt], [:rest, :rest], [:key, :key]], method(:f8).parameters) # [Bug #7540] [ruby-core:50735] + assert_equal([[:req, :r], [:opt, :o], [:rest, :args], [:req, :p], [:key, :k], + [:keyrest, :kw], [:block, :b]], method(:f9).parameters) + end + + def test_lambda + f = ->(str: "foo", num: 424242) { [str, num] } + assert_equal(["foo", 424242], f[]) + assert_equal(["bar", 424242], f[str: "bar"]) + assert_equal(["foo", 111111], f[num: 111111]) + assert_equal(["bar", 111111], f[str: "bar", num: 111111]) + end + + + def p1 + Proc.new do |str: "foo", num: 424242| + [str, num] + end + end + + def test_p1 + assert_equal(["foo", 424242], p1[]) + assert_equal(["bar", 424242], p1[str: "bar"]) + assert_equal(["foo", 111111], p1[num: 111111]) + assert_equal(["bar", 111111], p1[str: "bar", num: 111111]) + assert_raise(ArgumentError) { p1[str: "bar", check: true] } + assert_equal(["foo", 424242], p1["string"] ) + end + + + def p2 + Proc.new do |x, str: "foo", num: 424242| + [x, str, num] + end + end + + def test_p2 + assert_equal([nil, "foo", 424242], p2[]) + assert_equal([:xyz, "foo", 424242], p2[:xyz]) + end + + + def p3 + Proc.new do |str: "foo", num: 424242, **h| + [str, num, h] + end + end + + def test_p3 + assert_equal(["foo", 424242, {}], p3[]) + assert_equal(["bar", 424242, {}], p3[str: "bar"]) + assert_equal(["foo", 111111, {}], p3[num: 111111]) + assert_equal(["bar", 111111, {}], p3[str: "bar", num: 111111]) + assert_equal(["bar", 424242, {:check=>true}], p3[str: "bar", check: true]) + assert_equal(["foo", 424242, {}], p3["string"]) + end + + + def p4 + Proc.new do |str: "foo", num: 424242, **h, &blk| + [str, num, h, blk] + end + end + + def test_p4 + assert_equal(["foo", 424242, {}, nil], p4[]) + assert_equal(["bar", 424242, {}, nil], p4[str: "bar"]) + assert_equal(["foo", 111111, {}, nil], p4[num: 111111]) + assert_equal(["bar", 111111, {}, nil], p4[str: "bar", num: 111111]) + assert_equal(["bar", 424242, {:check=>true}, nil], p4[str: "bar", check: true]) + a = p4.call {|x| x + 42 } + assert_equal(["foo", 424242, {}], a[0, 3]) + assert_equal(43, a.last.call(1)) + end + + + def p5 + Proc.new do |*r, str: "foo", num: 424242, **h| + [r, str, num, h] + end + end + + def test_p5 + assert_equal([[], "foo", 424242, {}], p5[]) + assert_equal([[], "bar", 424242, {}], p5[str: "bar"]) + assert_equal([[], "foo", 111111, {}], p5[num: 111111]) + assert_equal([[], "bar", 111111, {}], p5[str: "bar", num: 111111]) + assert_equal([[1], "foo", 424242, {}], p5[1]) + assert_equal([[1, 2], "foo", 424242, {}], p5[1, 2]) + assert_equal([[1, 2, 3], "foo", 424242, {}], p5[1, 2, 3]) + assert_equal([[1], "bar", 424242, {}], p5[1, str: "bar"]) + assert_equal([[1, 2], "bar", 424242, {}], p5[1, 2, str: "bar"]) + assert_equal([[1, 2, 3], "bar", 424242, {}], p5[1, 2, 3, str: "bar"]) + end + + + def p6 + Proc.new do |o1, o2=42, *args, p, k: :key, **kw, &b| + [o1, o2, args, p, k, kw, b] + end + end + + def test_p6 + assert_equal([nil, 42, [], nil, :key, {}, nil], p6[]) + assert_equal([1, 42, [], 2, :key, {}, nil], p6[1, 2]) + assert_equal([1, 2, [], 3, :key, {}, nil], p6[1, 2, 3]) + assert_equal([1, 2, [3], 4, :key, {}, nil], p6[1, 2, 3, 4]) + assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], p6[1, 2, 3, 4, 5, str: "bar"]) + end + + def test_proc_parameters + assert_equal([[:key, :str], [:key, :num]], p1.parameters); + assert_equal([[:opt, :x], [:key, :str], [:key, :num]], p2.parameters); + assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], p3.parameters); + assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], p4.parameters); + assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], p5.parameters); + assert_equal([[:opt, :o1], [:opt, :o2], [:rest, :args], [:opt, :p], [:key, :k], + [:keyrest, :kw], [:block, :b]], p6.parameters) + end + + def m1(*args) + yield(*args) + end + + def test_block + blk = Proc.new {|str: "foo", num: 424242| [str, num] } + assert_equal(["foo", 424242], m1(&blk)) + assert_equal(["bar", 424242], m1(str: "bar", &blk)) + assert_equal(["foo", 111111], m1(num: 111111, &blk)) + assert_equal(["bar", 111111], m1(str: "bar", num: 111111, &blk)) + end + + def rest_keyrest(*args, **opt) + return *args, opt + end + + def test_rest_keyrest + bug7665 = '[ruby-core:51278]' + bug8463 = '[ruby-core:55203] [Bug #8463]' + expect = [*%w[foo bar], {zzz: 42}] + assert_equal(expect, rest_keyrest(*expect), bug7665) + pr = proc {|*args, **opt| next *args, opt} + assert_equal(expect, pr.call(*expect), bug7665) + assert_equal(expect, pr.call(expect), bug8463) + pr = proc {|a, *b, **opt| next a, *b, opt} + assert_equal(expect, pr.call(expect), bug8463) + pr = proc {|a, **opt| next a, opt} + assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463) + end + + def test_bare_kwrest + # valid syntax, but its semantics is undefined + assert_valid_syntax("def bug7662(**) end") + assert_valid_syntax("def bug7662(*, **) end") + assert_valid_syntax("def bug7662(a, **) end") + end + + def test_without_paren + bug7942 = '[ruby-core:52820] [Bug #7942]' + assert_valid_syntax("def bug7942 a: 1; end") + assert_valid_syntax("def bug7942 a: 1, **; end") + + o = Object.new + eval("def o.bug7942 a: 1; a; end", nil, __FILE__, __LINE__) + assert_equal(1, o.bug7942(), bug7942) + assert_equal(42, o.bug7942(a: 42), bug7942) + + o = Object.new + eval("def o.bug7942 a: 1, **; a; end", nil, __FILE__, __LINE__) + assert_equal(1, o.bug7942(), bug7942) + assert_equal(42, o.bug7942(a: 42), bug7942) + end + + def test_required_keyword + feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument' + o = Object.new + assert_nothing_raised(SyntaxError, feature7701) do + eval("def o.foo(a:) a; end", nil, "xyzzy") + eval("def o.bar(a:,**b) [a, b]; end") + end + assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {o.foo} + assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {o.foo(a:0, b:1)} + begin + o.foo(a: 0, b: 1) + rescue => e + assert_equal('xyzzy', e.backtrace_locations[0].path) + end + assert_equal(42, o.foo(a: 42), feature7701) + assert_equal([[:keyreq, :a]], o.method(:foo).parameters, feature7701) + + bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash' + assert_equal([42, {}], o.bar(a: 42), feature7701) + assert_equal([42, {c: feature7701}], o.bar(a: 42, c: feature7701), feature7701) + assert_equal([[:keyreq, :a], [:keyrest, :b]], o.method(:bar).parameters, feature7701) + assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar(c: bug8139)} + assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar} + end + + def test_required_keyword_with_newline + bug9669 = '[ruby-core:61658] [Bug #9669]' + assert_nothing_raised(SyntaxError, bug9669) do + eval(<<-'end;', nil, __FILE__, __LINE__) + def bug9669.foo a: + return a + end + end; + end + assert_equal(42, bug9669.foo(a: 42)) + o = nil + assert_nothing_raised(SyntaxError, bug9669) do + eval(<<-'end;', nil, __FILE__, __LINE__) + o = { + a: + 1 + } + end; + end + assert_equal({a: 1}, o, bug9669) + end + + def test_required_keyword_with_reserved + bug10279 = '[ruby-core:65211] [Bug #10279]' + h = nil + assert_nothing_raised(SyntaxError, bug10279) do + break eval(<<-'end;', nil, __FILE__, __LINE__) + h = {a: if true then 42 end} + end; + end + assert_equal({a: 42}, h, bug10279) + end + + def test_block_required_keyword + feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument' + b = assert_nothing_raised(SyntaxError, feature7701) do + break eval("proc {|a:| a}", nil, 'xyzzy', __LINE__) + end + assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {b.call} + assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {b.call(a:0, b:1)} + begin + b.call(a: 0, b: 1) + rescue => e + assert_equal('xyzzy', e.backtrace_locations[0].path) + end + + assert_equal(42, b.call(a: 42), feature7701) + assert_equal([[:keyreq, :a]], b.parameters, feature7701) + + bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash' + b = assert_nothing_raised(SyntaxError, feature7701) do + break eval("proc {|a:, **bl| [a, bl]}", nil, __FILE__, __LINE__) + end + assert_equal([42, {}], b.call(a: 42), feature7701) + assert_equal([42, {c: feature7701}], b.call(a: 42, c: feature7701), feature7701) + assert_equal([[:keyreq, :a], [:keyrest, :bl]], b.parameters, feature7701) + assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call(c: bug8139)} + assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call} + end + + def test_super_with_keyword + bug8236 = '[ruby-core:54094] [Bug #8236]' + base = Class.new do + def foo(*args) + args + end + end + a = Class.new(base) do + def foo(arg, bar: 'x') + super + end + end + b = Class.new(base) do + def foo(*args, bar: 'x') + super + end + end + assert_equal([42, {:bar=>"x"}], a.new.foo(42), bug8236) + assert_equal([42, {:bar=>"x"}], b.new.foo(42), bug8236) + end + + def test_zsuper_only_named_kwrest + bug8416 = '[ruby-core:55033] [Bug #8416]' + base = Class.new do + def foo(**h) + h + end + end + a = Class.new(base) do + def foo(**h) + super + end + end + assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416) + end + + def test_zsuper_only_anonymous_kwrest + bug8416 = '[ruby-core:55033] [Bug #8416]' + base = Class.new do + def foo(**h) + h + end + end + a = Class.new(base) do + def foo(**) + super + end + end + assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416) + end + + def test_precedence_of_keyword_arguments + bug8040 = '[ruby-core:53199] [Bug #8040]' + a = Class.new do + def foo(x, **h) + [x, h] + end + end + assert_equal([{}, {}], a.new.foo({})) + assert_equal([{}, {:bar=>"x"}], a.new.foo({}, bar: "x"), bug8040) + end + + def test_precedence_of_keyword_arguments_with_post_argument + bug8993 = '[ruby-core:57706] [Bug #8993]' + a = Class.new do + def foo(a, b, c=1, *d, e, f:2, **g) + [a, b, c, d, e, f, g] + end + end + assert_equal([1, 2, 1, [], {:f=>5}, 2, {}], a.new.foo(1, 2, f:5), bug8993) + end + + def test_splat_keyword_nondestructive + bug9776 = '[ruby-core:62161] [Bug #9776]' + + h = {a: 1} + assert_equal({a:1, b:2}, {**h, b:2}) + assert_equal({a:1}, h, bug9776) + + pr = proc {|**opt| next opt} + assert_equal({a: 1}, pr.call(**h)) + assert_equal({a: 1, b: 2}, pr.call(**h, b: 2)) + assert_equal({a: 1}, h, bug9776) + end + + def test_splat_hash_conversion + bug9898 = '[ruby-core:62921] [Bug #9898]' + + o = Object.new + def o.to_hash() { a: 1 } end + assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898) + o2 = Object.new + def o2.to_hash() { b: 2 } end + assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898) + end + + def test_implicit_hash_conversion + bug10016 = '[ruby-core:63593] [Bug #10016]' + + o = Object.new + def o.to_hash() { k: 9 } end + assert_equal([1, 42, [], o, :key, {}, nil], f9(1, o)) + assert_equal([1, 9], m1(1, o) {|a, k: 0| break [a, k]}, bug10016) + assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016) + end + + def test_gced_object_in_stack + bug8964 = '[ruby-dev:47729] [Bug #8964]' + assert_normal_exit %q{ + def m(a: []) + end + GC.stress = true + tap { m } + GC.start + tap { m } + }, bug8964 + assert_normal_exit %q{ + prc = Proc.new {|a: []|} + GC.stress = true + tap { prc.call } + GC.start + tap { prc.call } + }, bug8964 + end + + def test_dynamic_symbol_keyword + bug10266 = '[ruby-dev:48564] [Bug #10266]' + assert_separately(['-', bug10266], <<-'end;') # do + bug = ARGV.shift + "hoge".to_sym + assert_nothing_raised(bug) {eval("def a(hoge:); end")} + end; + end + + def test_unknown_keyword_with_block + bug10413 = '[ruby-core:65837] [Bug #10413]' + class << (o = Object.new) + def bar(k2: 'v2') + end + + def foo + bar(k1: 1) + end + end + assert_raise_with_message(ArgumentError, /unknown keyword: k1/, bug10413) { + o.foo {raise "unreachable"} + } + end + + def test_super_with_anon_restkeywords + bug10659 = '[ruby-core:67157] [Bug #10659]' + + foo = Class.new do + def foo(**h) + h + end + end + + class << (obj = foo.new) + def foo(bar: "bar", **) + super + end + end + + assert_nothing_raised(TypeError, bug10659) { + assert_equal({:bar => "bar"}, obj.foo, bug10659) + } + end + + def m(a) yield a end + + def test_nonsymbol_key + result = m(["a" => 10]) { |a = nil, **b| [a, b] } + assert_equal([{"a" => 10}, {}], result) + end + + def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw + [k1, k2, rest_kw] + end + + def test_to_hash_call_during_setup_complex_parameters + sym = "sym_#{Time.now}".to_sym + h = method_for_test_to_hash_call_during_setup_complex_parameters k1: "foo", k2: "bar", sym => "baz" + assert_equal ["foo", "bar", {sym => "baz"}], h, '[Bug #11027]' + end +end diff --git a/jni/ruby/test/ruby/test_lambda.rb b/jni/ruby/test/ruby/test_lambda.rb new file mode 100644 index 0000000..0f3382c --- /dev/null +++ b/jni/ruby/test/ruby/test_lambda.rb @@ -0,0 +1,173 @@ +require 'test/unit' + +class TestLambdaParameters < Test::Unit::TestCase + + def test_exact_parameter + assert_raise(ArgumentError){(1..3).each(&lambda{})} + end + + def test_call_simple + assert_equal(1, lambda{|a| a}.call(1)) + assert_equal([1,2], lambda{|a, b| [a,b]}.call(1,2)) + assert_raise(ArgumentError) { lambda{|a|}.call(1,2) } + assert_raise(ArgumentError) { lambda{|a|}.call() } + assert_raise(ArgumentError) { lambda{}.call(1) } + assert_raise(ArgumentError) { lambda{|a, b|}.call(1,2,3) } + + assert_equal(1, ->(a){ a }.call(1)) + assert_equal([1,2], ->(a,b){ [a,b] }.call(1,2)) + assert_raise(ArgumentError) { ->(a){ }.call(1,2) } + assert_raise(ArgumentError) { ->(a){ }.call() } + assert_raise(ArgumentError) { ->(){ }.call(1) } + assert_raise(ArgumentError) { ->(a,b){ }.call(1,2,3) } + end + + def test_lambda_as_iterator + a = 0 + 2.times(&->(_){ a += 1 }) + assert_equal(2, a) + assert_raise(ArgumentError) {1.times(&->(){ a += 1 })} + bug9605 = '[ruby-core:61468] [Bug #9605]' + assert_nothing_raised(ArgumentError, bug9605) {1.times(&->(n){ a += 1 })} + assert_equal(3, a, bug9605) + assert_nothing_raised(ArgumentError, bug9605) {a = [[1, 2]].map(&->(x, y) {x+y})} + assert_equal([3], a, bug9605) + end + + def test_call_rest_args + assert_equal([1,2], ->(*a){ a }.call(1,2)) + assert_equal([1,2,[]], ->(a,b,*c){ [a,b,c] }.call(1,2)) + assert_raise(ArgumentError){ ->(a,*b){ }.call() } + end + + def test_call_opt_args + assert_equal([1,2,3,4], ->(a,b,c=3,d=4){ [a,b,c,d] }.call(1,2)) + assert_equal([1,2,3,4], ->(a,b,c=0,d=4){ [a,b,c,d] }.call(1,2,3)) + assert_raise(ArgumentError){ ->(a,b=1){ }.call() } + assert_raise(ArgumentError){ ->(a,b=1){ }.call(1,2,3) } + end + + def test_call_rest_and_opt + assert_equal([1,2,3,[]], ->(a,b=2,c=3,*d){ [a,b,c,d] }.call(1)) + assert_equal([1,2,3,[]], ->(a,b=0,c=3,*d){ [a,b,c,d] }.call(1,2)) + assert_equal([1,2,3,[4,5,6]], ->(a,b=0,c=0,*d){ [a,b,c,d] }.call(1,2,3,4,5,6)) + assert_raise(ArgumentError){ ->(a,b=1,*c){ }.call() } + end + + def test_call_with_block + f = ->(a,b,c=3,*d,&e){ [a,b,c,d,e.call(d + [a,b,c])] } + assert_equal([1,2,3,[],6], f.call(1,2){|z| z.inject{|s,x| s+x} } ) + assert_equal(nil, ->(&b){ b }.call) + foo { puts "bogus block " } + assert_equal(1, ->(&b){ b.call }.call { 1 }) + b = nil + assert_equal(1, ->(&b){ b.call }.call { 1 }) + assert_nil(b) + end + + def test_call_block_from_lambda + bug9605 = '[ruby-core:61470] [Bug #9605]' + plus = ->(x,y) {x+y} + assert_raise(ArgumentError, bug9605) {proc(&plus).call [1,2]} + end + + def yield_1(arg) + yield arg + end + + tap do |;bug9605, expected, result| + bug9605 = '[ruby-core:65887] [Bug #9605] arity check should be relaxed' + expected = [1,2,3] + + [ + ["array", expected], + ["to_ary", Struct.new(:to_ary).new(expected)], + ].product \ + [ + ["proc", proc {|a, b, c| [a, b, c]}], + ["lambda", lambda {|a, b, c| [a, b, c]}], + ] do + |(vtype, val), (btype, block)| + define_method("test_yeild_relaxed(#{vtype},&#{btype})") do + result = assert_nothing_raised(ArgumentError, bug9605) { + break yield_1(val, &block) + } + assert_equal(expected, result, bug9605) + end + end + end + + def foo + assert_equal(nil, ->(&b){ b }.call) + end + + def test_in_basic_object + bug5966 = '[ruby-core:42349]' + called = false + BasicObject.new.instance_eval {->() {called = true}.()} + assert_equal(true, called, bug5966) + end + + def test_location_on_error + bug6151 = '[ruby-core:43314]' + called = 0 + line, f = __LINE__, lambda do + called += 1 + true + end + e = assert_raise(ArgumentError) do + f.call(42) + end + assert_send([e.backtrace.first, :start_with?, "#{__FILE__}:#{line}:"], bug6151) + assert_equal(0, called) + e = assert_raise(ArgumentError) do + 42.times(&f) + end + assert_send([e.backtrace.first, :start_with?, "#{__FILE__}:#{line}:"], bug6151) + assert_equal(0, called) + end + + def return_in_current(val) + 1.tap(&->(*) {return 0}) + val + end + + def yield_block + yield + end + + def return_in_callee(val) + yield_block(&->(*) {return 0}) + val + end + + def test_return + feature8693 = '[ruby-core:56193] [Feature #8693]' + assert_equal(42, return_in_current(42), feature8693) + assert_equal(42, return_in_callee(42), feature8693) + end + + def test_do_lambda_source_location + exp_lineno = __LINE__ + 3 + lmd = ->(x, + y, + z) do + # + end + file, lineno = lmd.source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(exp_lineno, lineno, "must be at the beginning of the block") + end + + def test_brace_lambda_source_location + exp_lineno = __LINE__ + 3 + lmd = ->(x, + y, + z) { + # + } + file, lineno = lmd.source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(exp_lineno, lineno, "must be at the beginning of the block") + end +end diff --git a/jni/ruby/test/ruby/test_lazy_enumerator.rb b/jni/ruby/test/ruby/test_lazy_enumerator.rb new file mode 100644 index 0000000..75f2458 --- /dev/null +++ b/jni/ruby/test/ruby/test_lazy_enumerator.rb @@ -0,0 +1,494 @@ +require 'test/unit' + +class TestLazyEnumerator < Test::Unit::TestCase + class Step + include Enumerable + attr_reader :current, :args + + def initialize(enum) + @enum = enum + @current = nil + @args = nil + end + + def each(*args) + @args = args + @enum.each {|i| @current = i; yield i} + end + end + + def test_initialize + assert_equal([1, 2, 3], [1, 2, 3].lazy.to_a) + assert_equal([1, 2, 3], Enumerator::Lazy.new([1, 2, 3]){|y, v| y << v}.to_a) + assert_raise(ArgumentError) { Enumerator::Lazy.new([1, 2, 3]) } + + a = [1, 2, 3].lazy + a.freeze + assert_raise(RuntimeError) { + a.__send__ :initialize, [4, 5], &->(y, *v) { y << yield(*v) } + } + end + + def test_each_args + a = Step.new(1..3) + assert_equal(1, a.lazy.each(4).first) + assert_equal([4], a.args) + end + + def test_each_line + name = lineno = nil + File.open(__FILE__) do |f| + f.each("").map do |paragraph| + paragraph[/\A\s*(.*)/, 1] + end.find do |line| + if name = line[/^class\s+(\S+)/, 1] + lineno = f.lineno + true + end + end + end + assert_equal(self.class.name, name) + assert_operator(lineno, :>, 2) + + name = lineno = nil + File.open(__FILE__) do |f| + f.lazy.each("").map do |paragraph| + paragraph[/\A\s*(.*)/, 1] + end.find do |line| + if name = line[/^class\s+(\S+)/, 1] + lineno = f.lineno + true + end + end + end + assert_equal(self.class.name, name) + assert_equal(2, lineno) + end + + def test_select + a = Step.new(1..6) + assert_equal(4, a.select {|x| x > 3}.first) + assert_equal(6, a.current) + assert_equal(4, a.lazy.select {|x| x > 3}.first) + assert_equal(4, a.current) + + a = Step.new(['word', nil, 1]) + assert_raise(TypeError) {a.select {|x| "x"+x}.first} + assert_equal(nil, a.current) + assert_equal("word", a.lazy.select {|x| "x"+x}.first) + assert_equal("word", a.current) + end + + def test_select_multiple_values + e = Enumerator.new { |yielder| + for i in 1..5 + yielder.yield(i, i.to_s) + end + } + assert_equal([[2, "2"], [4, "4"]], + e.select {|x| x[0] % 2 == 0}) + assert_equal([[2, "2"], [4, "4"]], + e.lazy.select {|x| x[0] % 2 == 0}.force) + end + + def test_map + a = Step.new(1..3) + assert_equal(2, a.map {|x| x * 2}.first) + assert_equal(3, a.current) + assert_equal(2, a.lazy.map {|x| x * 2}.first) + assert_equal(1, a.current) + end + + def test_flat_map + a = Step.new(1..3) + assert_equal(2, a.flat_map {|x| [x * 2]}.first) + assert_equal(3, a.current) + assert_equal(2, a.lazy.flat_map {|x| [x * 2]}.first) + assert_equal(1, a.current) + end + + def test_flat_map_nested + a = Step.new(1..3) + assert_equal([1, "a"], + a.flat_map {|x| ("a".."c").map {|y| [x, y]}}.first) + assert_equal(3, a.current) + assert_equal([1, "a"], + a.lazy.flat_map {|x| ("a".."c").lazy.map {|y| [x, y]}}.first) + assert_equal(1, a.current) + end + + def test_flat_map_to_ary + to_ary = Class.new { + def initialize(value) + @value = value + end + + def to_ary + [:to_ary, @value] + end + } + assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3], + [1, 2, 3].flat_map {|x| to_ary.new(x)}) + assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3], + [1, 2, 3].lazy.flat_map {|x| to_ary.new(x)}.force) + end + + def test_flat_map_non_array + assert_equal(["1", "2", "3"], [1, 2, 3].flat_map {|x| x.to_s}) + assert_equal(["1", "2", "3"], [1, 2, 3].lazy.flat_map {|x| x.to_s}.force) + end + + def test_flat_map_hash + assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].flat_map {|x| {x=>x.ord}}) + assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].lazy.flat_map {|x| {x=>x.ord}}.force) + end + + def test_reject + a = Step.new(1..6) + assert_equal(4, a.reject {|x| x < 4}.first) + assert_equal(6, a.current) + assert_equal(4, a.lazy.reject {|x| x < 4}.first) + assert_equal(4, a.current) + + a = Step.new(['word', nil, 1]) + assert_equal(nil, a.reject {|x| x}.first) + assert_equal(1, a.current) + assert_equal(nil, a.lazy.reject {|x| x}.first) + assert_equal(nil, a.current) + end + + def test_reject_multiple_values + e = Enumerator.new { |yielder| + for i in 1..5 + yielder.yield(i, i.to_s) + end + } + assert_equal([[2, "2"], [4, "4"]], + e.reject {|x| x[0] % 2 != 0}) + assert_equal([[2, "2"], [4, "4"]], + e.lazy.reject {|x| x[0] % 2 != 0}.force) + end + + def test_grep + a = Step.new('a'..'f') + assert_equal('c', a.grep(/c/).first) + assert_equal('f', a.current) + assert_equal('c', a.lazy.grep(/c/).first) + assert_equal('c', a.current) + assert_equal(%w[a e], a.grep(proc {|x| /[aeiou]/ =~ x})) + assert_equal(%w[a e], a.lazy.grep(proc {|x| /[aeiou]/ =~ x}).to_a) + end + + def test_grep_with_block + a = Step.new('a'..'f') + assert_equal('C', a.grep(/c/) {|i| i.upcase}.first) + assert_equal('C', a.lazy.grep(/c/) {|i| i.upcase}.first) + end + + def test_grep_multiple_values + e = Enumerator.new { |yielder| + 3.times { |i| + yielder.yield(i, i.to_s) + } + } + assert_equal([[2, "2"]], e.grep(proc {|x| x == [2, "2"]})) + assert_equal([[2, "2"]], e.lazy.grep(proc {|x| x == [2, "2"]}).force) + assert_equal(["22"], + e.lazy.grep(proc {|x| x == [2, "2"]}, &:join).force) + end + + def test_zip + a = Step.new(1..3) + assert_equal([1, "a"], a.zip("a".."c").first) + assert_equal(3, a.current) + assert_equal([1, "a"], a.lazy.zip("a".."c").first) + assert_equal(1, a.current) + end + + def test_zip_short_arg + a = Step.new(1..5) + assert_equal([5, nil], a.zip("a".."c").last) + assert_equal([5, nil], a.lazy.zip("a".."c").force.last) + end + + def test_zip_without_arg + a = Step.new(1..3) + assert_equal([1], a.zip.first) + assert_equal(3, a.current) + assert_equal([1], a.lazy.zip.first) + assert_equal(1, a.current) + end + + def test_zip_bad_arg + a = Step.new(1..3) + assert_raise(TypeError){ a.lazy.zip(42) } + end + + def test_zip_with_block + # zip should be eager when a block is given + a = Step.new(1..3) + ary = [] + assert_equal(nil, a.lazy.zip("a".."c") {|x, y| ary << [x, y]}) + assert_equal(a.zip("a".."c"), ary) + assert_equal(3, a.current) + end + + def test_take + a = Step.new(1..10) + assert_equal(1, a.take(5).first) + assert_equal(5, a.current) + assert_equal(1, a.lazy.take(5).first) + assert_equal(1, a.current) + assert_equal((1..5).to_a, a.lazy.take(5).force) + assert_equal(5, a.current) + a = Step.new(1..10) + assert_equal([], a.lazy.take(0).force) + assert_equal(nil, a.current) + end + + def test_take_recycle + bug6428 = '[ruby-dev:45634]' + a = Step.new(1..10) + take5 = a.lazy.take(5) + assert_equal((1..5).to_a, take5.force, bug6428) + assert_equal((1..5).to_a, take5.force, bug6428) + end + + def test_take_nested + bug7696 = '[ruby-core:51470]' + a = Step.new(1..10) + take5 = a.lazy.take(5) + assert_equal([*(1..5)]*5, take5.flat_map{take5}.force, bug7696) + end + + def test_drop_while_nested + bug7696 = '[ruby-core:51470]' + a = Step.new(1..10) + drop5 = a.lazy.drop_while{|x| x < 6} + assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696) + end + + def test_drop_nested + bug7696 = '[ruby-core:51470]' + a = Step.new(1..10) + drop5 = a.lazy.drop(5) + assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696) + end + + def test_zip_nested + bug7696 = '[ruby-core:51470]' + enum = ('a'..'z').each + enum.next + zip = (1..3).lazy.zip(enum, enum) + assert_equal([[1, 'a', 'a'], [2, 'b', 'b'], [3, 'c', 'c']]*3, zip.flat_map{zip}.force, bug7696) + end + + def test_zip_lazy_on_args + zip = Step.new(1..2).lazy.zip(42..Float::INFINITY) + assert_equal [[1, 42], [2, 43]], zip.force + end + + def test_zip_efficient_on_array_args + ary = [42, :foo] + %i[to_enum enum_for lazy each].each do |forbid| + ary.define_singleton_method(forbid){ fail "#{forbid} was called"} + end + zip = Step.new(1..2).lazy.zip(ary) + assert_equal [[1, 42], [2, :foo]], zip.force + end + + def test_zip_nonsingle + bug8735 = '[ruby-core:56383] [Bug #8735]' + + obj = Object.new + def obj.each + yield + yield 1, 2 + end + + assert_equal(obj.to_enum.zip(obj.to_enum), obj.to_enum.lazy.zip(obj.to_enum).force, bug8735) + end + + def test_take_rewound + bug7696 = '[ruby-core:51470]' + e=(1..42).lazy.take(2) + assert_equal 1, e.next, bug7696 + assert_equal 2, e.next, bug7696 + e.rewind + assert_equal 1, e.next, bug7696 + assert_equal 2, e.next, bug7696 + end + + def test_take_while + a = Step.new(1..10) + assert_equal(1, a.take_while {|i| i < 5}.first) + assert_equal(5, a.current) + assert_equal(1, a.lazy.take_while {|i| i < 5}.first) + assert_equal(1, a.current) + assert_equal((1..4).to_a, a.lazy.take_while {|i| i < 5}.to_a) + end + + def test_drop + a = Step.new(1..10) + assert_equal(6, a.drop(5).first) + assert_equal(10, a.current) + assert_equal(6, a.lazy.drop(5).first) + assert_equal(6, a.current) + assert_equal((6..10).to_a, a.lazy.drop(5).to_a) + end + + def test_drop_while + a = Step.new(1..10) + assert_equal(5, a.drop_while {|i| i % 5 > 0}.first) + assert_equal(10, a.current) + assert_equal(5, a.lazy.drop_while {|i| i % 5 > 0}.first) + assert_equal(5, a.current) + assert_equal((5..10).to_a, a.lazy.drop_while {|i| i % 5 > 0}.to_a) + end + + def test_drop_and_take + assert_equal([4, 5], (1..Float::INFINITY).lazy.drop(3).take(2).to_a) + end + + def test_cycle + a = Step.new(1..3) + assert_equal("1", a.cycle(2).map(&:to_s).first) + assert_equal(3, a.current) + assert_equal("1", a.lazy.cycle(2).map(&:to_s).first) + assert_equal(1, a.current) + end + + def test_cycle_with_block + # cycle should be eager when a block is given + a = Step.new(1..3) + ary = [] + assert_equal(nil, a.lazy.cycle(2) {|i| ary << i}) + assert_equal(a.cycle(2).to_a, ary) + assert_equal(3, a.current) + end + + def test_cycle_chain + a = 1..3 + assert_equal([1,2,3,1,2,3,1,2,3,1], a.lazy.cycle.take(10).force) + assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.cycle.select {|x| x == 2}.take(10).force) + assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.select {|x| x == 2}.cycle.take(10).force) + end + + def test_force + assert_equal([1, 2, 3], (1..Float::INFINITY).lazy.take(3).force) + end + + def test_inspect + assert_equal("#<Enumerator::Lazy: 1..10>", (1..10).lazy.inspect) + assert_equal('#<Enumerator::Lazy: #<Enumerator: "foo":each_char>>', + "foo".each_char.lazy.inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>", + (1..10).lazy.map {}.inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(0)>", + (1..10).lazy.take(0).inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(3)>", + (1..10).lazy.take(3).inspect) + assert_equal('#<Enumerator::Lazy: #<Enumerator::Lazy: "a".."c">:grep(/b/)>', + ("a".."c").lazy.grep(/b/).inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>", + (1..10).lazy.cycle(3).inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle>", + (1..10).lazy.cycle.inspect) + assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>", + (1..10).lazy.cycle(3).inspect) + l = (1..10).lazy.map {}.collect {}.flat_map {}.collect_concat {}.select {}.find_all {}.reject {}.grep(1).zip(?a..?c).take(10).take_while {}.drop(3).drop_while {}.cycle(3) + assert_equal(<<EOS.chomp, l.inspect) +#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>:collect>:flat_map>:collect_concat>:select>:find_all>:reject>:grep(1)>:zip("a".."c")>:take(10)>:take_while>:drop(3)>:drop_while>:cycle(3)> +EOS + end + + def test_lazy_to_enum + lazy = [1, 2, 3].lazy + def lazy.foo(*args) + yield args + yield args + end + enum = lazy.to_enum(:foo, :hello, :world) + assert_equal Enumerator::Lazy, enum.class + assert_equal nil, enum.size + assert_equal [[:hello, :world], [:hello, :world]], enum.to_a + + assert_equal [1, 2, 3], lazy.to_enum.to_a + end + + def test_size + lazy = [1, 2, 3].lazy + assert_equal 3, lazy.size + assert_equal 42, Enumerator::Lazy.new([],->{42}){}.size + assert_equal 42, Enumerator::Lazy.new([],42){}.size + assert_equal 42, Enumerator::Lazy.new([],42){}.lazy.size + assert_equal 42, lazy.to_enum{ 42 }.size + + %i[map collect].each do |m| + assert_equal 3, lazy.send(m){}.size + end + assert_equal 3, lazy.zip([4]).size + %i[flat_map collect_concat select find_all reject take_while drop_while].each do |m| + assert_equal nil, lazy.send(m){}.size + end + assert_equal nil, lazy.grep(//).size + + assert_equal 2, lazy.take(2).size + assert_equal 3, lazy.take(4).size + assert_equal 4, loop.lazy.take(4).size + assert_equal nil, lazy.select{}.take(4).size + + assert_equal 1, lazy.drop(2).size + assert_equal 0, lazy.drop(4).size + assert_equal Float::INFINITY, loop.lazy.drop(4).size + assert_equal nil, lazy.select{}.drop(4).size + + assert_equal 0, lazy.cycle(0).size + assert_equal 6, lazy.cycle(2).size + assert_equal 3 << 80, 4.times.inject(lazy){|enum| enum.cycle(1 << 20)}.size + assert_equal Float::INFINITY, lazy.cycle.size + assert_equal Float::INFINITY, loop.lazy.cycle(4).size + assert_equal Float::INFINITY, loop.lazy.cycle.size + assert_equal nil, lazy.select{}.cycle(4).size + assert_equal nil, lazy.select{}.cycle.size + end + + def test_map_zip + bug7507 = '[ruby-core:50545]' + assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip(){}"], "", bug7507) + assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip().to_a"], "", bug7507) + end + + def test_require_block + %i[select reject drop_while take_while map flat_map].each do |method| + assert_raise(ArgumentError){ [].lazy.send(method) } + end + end + + def test_laziness_conservation + bug7507 = '[ruby-core:51510]' + { + slice_before: //, + slice_after: //, + with_index: nil, + cycle: nil, + each_with_object: 42, + each_slice: 42, + each_entry: nil, + each_cons: 42, + }.each do |method, arg| + assert_equal Enumerator::Lazy, [].lazy.send(method, *arg).class, bug7507 + end + assert_equal Enumerator::Lazy, [].lazy.chunk{}.class, bug7507 + assert_equal Enumerator::Lazy, [].lazy.slice_when{}.class, bug7507 + end + + def test_no_warnings + le = (1..3).lazy + assert_warning("") {le.zip([4,5,6]).force} + assert_warning("") {le.zip(4..6).force} + assert_warning("") {le.take(1).force} + assert_warning("") {le.drop(1).force} + assert_warning("") {le.drop_while{false}.force} + end +end diff --git a/jni/ruby/test/ruby/test_literal.rb b/jni/ruby/test/ruby/test_literal.rb new file mode 100644 index 0000000..ed5f836 --- /dev/null +++ b/jni/ruby/test/ruby/test_literal.rb @@ -0,0 +1,461 @@ +# -*- coding: us-ascii -*- +require 'test/unit' + +class TestRubyLiteral < Test::Unit::TestCase + + def test_special_const + assert_equal 'true', true.inspect + assert_instance_of TrueClass, true + assert_equal 'false', false.inspect + assert_instance_of FalseClass, false + assert_equal 'nil', nil.inspect + assert_instance_of NilClass, nil + assert_equal ':sym', :sym.inspect + assert_instance_of Symbol, :sym + assert_equal '1234', 1234.inspect + assert_instance_of Fixnum, 1234 + assert_equal '1234', 1_2_3_4.inspect + assert_instance_of Fixnum, 1_2_3_4 + assert_equal '18', 0x12.inspect + assert_instance_of Fixnum, 0x12 + assert_raise(SyntaxError) { eval("0x") } + assert_equal '15', 0o17.inspect + assert_instance_of Fixnum, 0o17 + assert_raise(SyntaxError) { eval("0o") } + assert_equal '5', 0b101.inspect + assert_instance_of Fixnum, 0b101 + assert_raise(SyntaxError) { eval("0b") } + assert_equal '123456789012345678901234567890', 123456789012345678901234567890.inspect + assert_instance_of Bignum, 123456789012345678901234567890 + assert_instance_of Float, 1.3 + assert_equal '2', eval("0x00+2").inspect + end + + def test_self + assert_equal self, self + assert_instance_of TestRubyLiteral, self + assert_respond_to self, :test_self + end + + def test_string + assert_instance_of String, ?a + assert_equal "a", ?a + assert_instance_of String, ?A + assert_equal "A", ?A + assert_instance_of String, ?\n + assert_equal "\n", ?\n + assert_equal " ", ?\ # space + assert_equal '', '' + assert_equal 'string', 'string' + assert_equal 'string string', 'string string' + assert_equal ' ', ' ' + assert_equal ' ', " " + assert_equal "\0", "\0" + assert_equal "\1", "\1" + assert_equal "3", "\x33" + assert_equal "\n", "\n" + bug2500 = '[ruby-core:27228]' + bug5262 = '[ruby-core:39222]' + %w[c C- M-].each do |pre| + ["u", %w[u{ }]].each do |open, close| + ["?", ['"', '"']].each do |qopen, qclose| + str = "#{qopen}\\#{pre}\\#{open}5555#{close}#{qclose}" + assert_raise(SyntaxError, "#{bug2500} eval(#{str})") {eval(str)} + + str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}" + assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)} + + str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("euc-jp") + assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)} + + str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("iso-8859-13") + assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)} + + str = "#{qopen}\\#{pre}\\#{open}\xe2\x7f#{close}#{qclose}".force_encoding("utf-8") + assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)} + end + end + end + bug6069 = '[ruby-dev:45278]' + assert_equal "\x13", "\c\x33" + assert_equal "\x13", "\C-\x33" + assert_equal "\xB3", "\M-\x33" + assert_equal "\u201c", eval(%["\\\u{201c}"]), bug5262 + assert_equal "\u201c".encode("euc-jp"), eval(%["\\\u{201c}"].encode("euc-jp")), bug5262 + assert_equal "\u201c".encode("iso-8859-13"), eval(%["\\\u{201c}"].encode("iso-8859-13")), bug5262 + assert_equal "\\\u201c", eval(%['\\\u{201c}']), bug6069 + assert_equal "\\\u201c".encode("euc-jp"), eval(%['\\\u{201c}'].encode("euc-jp")), bug6069 + assert_equal "\\\u201c".encode("iso-8859-13"), eval(%['\\\u{201c}'].encode("iso-8859-13")), bug6069 + assert_equal "\u201c", eval(%[?\\\u{201c}]), bug6069 + assert_equal "\u201c".encode("euc-jp"), eval(%[?\\\u{201c}].encode("euc-jp")), bug6069 + assert_equal "\u201c".encode("iso-8859-13"), eval(%[?\\\u{201c}].encode("iso-8859-13")), bug6069 + end + + def test_dstring + assert_equal '2', "#{1+1}" + assert_equal '16', "#{2 ** 4}" + s = "string" + assert_equal s, "#{s}" + a = 'Foo' + b = "#{a}" << 'Bar' + assert_equal('Foo', a, 'r3842') + assert_equal('FooBar', b, 'r3842') + end + + def test_dsymbol + assert_equal :a3c, :"a#{1+2}c" + end + + def test_xstring + assert_equal "foo\n", `echo foo` + s = 'foo' + assert_equal "foo\n", `echo #{s}` + end + + def test_regexp + assert_instance_of Regexp, // + assert_match(//, 'a') + assert_match(//, '') + assert_instance_of Regexp, /a/ + assert_match(/a/, 'a') + assert_no_match(/test/, 'tes') + re = /test/ + assert_match re, 'test' + str = 'test' + assert_match re, str + assert_match(/test/, str) + assert_equal 0, (/test/ =~ 'test') + assert_equal 0, (re =~ 'test') + assert_equal 0, (/test/ =~ str) + assert_equal 0, (re =~ str) + assert_equal 0, ('test' =~ /test/) + assert_equal 0, ('test' =~ re) + assert_equal 0, (str =~ /test/) + assert_equal 0, (str =~ re) + end + + def test_dregexp + assert_instance_of Regexp, /re#{'ge'}xp/ + assert_equal(/regexp/, /re#{'ge'}xp/) + bug3903 = '[ruby-core:32682]' + assert_raise(SyntaxError, bug3903) {eval('/[#{"\x80"}]/')} + end + + def test_array + assert_instance_of Array, [] + assert_equal [], [] + assert_equal 0, [].size + assert_instance_of Array, [0] + assert_equal [3], [3] + assert_equal 1, [3].size + a = [3] + assert_equal 3, a[0] + assert_instance_of Array, [1,2] + assert_equal [1,2], [1,2] + assert_instance_of Array, [1,2,3,4,5] + assert_equal [1,2,3,4,5], [1,2,3,4,5] + assert_equal 5, [1,2,3,4,5].size + a = [1,2] + assert_equal 1, a[0] + assert_equal 2, a[1] + a = [1 + 2, 3 + 4, 5 + 6] + assert_instance_of Array, a + assert_equal [3, 7, 11], a + assert_equal 7, a[1] + assert_equal 1, ([0][0] += 1) + assert_equal 1, ([2][0] -= 1) + a = [obj = Object.new] + assert_instance_of Array, a + assert_equal 1, a.size + assert_equal obj, a[0] + a = [1,2,3] + a[1] = 5 + assert_equal 5, a[1] + end + + def test_hash + assert_instance_of Hash, {} + assert_equal({}, {}) + assert_instance_of Hash, {1 => 2} + assert_equal({1 => 2}, {1 => 2}) + h = {1 => 2} + assert_equal 2, h[1] + h = {"string" => "literal", "goto" => "hell"} + assert_equal h, h + assert_equal 2, h.size + assert_equal h, h + assert_equal "literal", h["string"] + end + + def test_big_array_and_hash_literal + assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).map{'x'}.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems] + assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).to_a.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems] + assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => x"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems] + assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => #{n}"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems] + end + + def test_big_hash_literal + bug7466 = '[ruby-dev:46658]' + h = { + 0xFE042 => 0xE5CD, + 0xFE043 => 0xE5CD, + 0xFE045 => 0xEA94, + 0xFE046 => 0xE4E3, + 0xFE047 => 0xE4E2, + 0xFE048 => 0xEA96, + 0xFE049 => 0x3013, + 0xFE04A => 0xEB36, + 0xFE04B => 0xEB37, + 0xFE04C => 0xEB38, + 0xFE04D => 0xEB49, + 0xFE04E => 0xEB82, + 0xFE04F => 0xE4D2, + 0xFE050 => 0xEB35, + 0xFE051 => 0xEAB9, + 0xFE052 => 0xEABA, + 0xFE053 => 0xE4D4, + 0xFE054 => 0xE4CD, + 0xFE055 => 0xEABB, + 0xFE056 => 0xEABC, + 0xFE057 => 0xEB32, + 0xFE058 => 0xEB33, + 0xFE059 => 0xEB34, + 0xFE05A => 0xEB39, + 0xFE05B => 0xEB5A, + 0xFE190 => 0xE5A4, + 0xFE191 => 0xE5A5, + 0xFE192 => 0xEAD0, + 0xFE193 => 0xEAD1, + 0xFE194 => 0xEB47, + 0xFE195 => 0xE509, + 0xFE196 => 0xEAA0, + 0xFE197 => 0xE50B, + 0xFE198 => 0xEAA1, + 0xFE199 => 0xEAA2, + 0xFE19A => 0x3013, + 0xFE19B => 0xE4FC, + 0xFE19C => 0xE4FA, + 0xFE19D => 0xE4FC, + 0xFE19E => 0xE4FA, + 0xFE19F => 0xE501, + 0xFE1A0 => 0x3013, + 0xFE1A1 => 0xE5DD, + 0xFE1A2 => 0xEADB, + 0xFE1A3 => 0xEAE9, + 0xFE1A4 => 0xEB13, + 0xFE1A5 => 0xEB14, + 0xFE1A6 => 0xEB15, + 0xFE1A7 => 0xEB16, + 0xFE1A8 => 0xEB17, + 0xFE1A9 => 0xEB18, + 0xFE1AA => 0xEB19, + 0xFE1AB => 0xEB1A, + 0xFE1AC => 0xEB44, + 0xFE1AD => 0xEB45, + 0xFE1AE => 0xE4CB, + 0xFE1AF => 0xE5BF, + 0xFE1B0 => 0xE50E, + 0xFE1B1 => 0xE4EC, + 0xFE1B2 => 0xE4EF, + 0xFE1B3 => 0xE4F8, + 0xFE1B4 => 0x3013, + 0xFE1B5 => 0x3013, + 0xFE1B6 => 0xEB1C, + 0xFE1B9 => 0xEB7E, + 0xFE1D3 => 0xEB22, + 0xFE7DC => 0xE4D8, + 0xFE1D4 => 0xEB23, + 0xFE1D5 => 0xEB24, + 0xFE1D6 => 0xEB25, + 0xFE1CC => 0xEB1F, + 0xFE1CD => 0xEB20, + 0xFE1CE => 0xE4D9, + 0xFE1CF => 0xE48F, + 0xFE1C5 => 0xE5C7, + 0xFE1C6 => 0xEAEC, + 0xFE1CB => 0xEB1E, + 0xFE1DA => 0xE4DD, + 0xFE1E1 => 0xEB57, + 0xFE1E2 => 0xEB58, + 0xFE1E3 => 0xE492, + 0xFE1C9 => 0xEB1D, + 0xFE1D9 => 0xE4D3, + 0xFE1DC => 0xE5D4, + 0xFE1BA => 0xE4E0, + 0xFE1BB => 0xEB76, + 0xFE1C8 => 0xE4E0, + 0xFE1DD => 0xE5DB, + 0xFE1BC => 0xE4DC, + 0xFE1D8 => 0xE4DF, + 0xFE1BD => 0xE49A, + 0xFE1C7 => 0xEB1B, + 0xFE1C2 => 0xE5C2, + 0xFE1C0 => 0xE5C0, + 0xFE1B8 => 0xE4DB, + 0xFE1C3 => 0xE470, + 0xFE1BE => 0xE4D8, + 0xFE1C4 => 0xE4D9, + 0xFE1B7 => 0xE4E1, + 0xFE1BF => 0xE4DE, + 0xFE1C1 => 0xE5C1, + 0xFE1CA => 0x3013, + 0xFE1D0 => 0xE4E1, + 0xFE1D1 => 0xEB21, + 0xFE1D2 => 0xE4D7, + 0xFE1D7 => 0xE4DA, + 0xFE1DB => 0xE4EE, + 0xFE1DE => 0xEB3F, + 0xFE1DF => 0xEB46, + 0xFE1E0 => 0xEB48, + 0xFE336 => 0xE4FB, + 0xFE320 => 0xE472, + 0xFE321 => 0xEB67, + 0xFE322 => 0xEACA, + 0xFE323 => 0xEAC0, + 0xFE324 => 0xE5AE, + 0xFE325 => 0xEACB, + 0xFE326 => 0xEAC9, + 0xFE327 => 0xE5C4, + 0xFE328 => 0xEAC1, + 0xFE329 => 0xE4E7, + 0xFE32A => 0xE4E7, + 0xFE32B => 0xEACD, + 0xFE32C => 0xEACF, + 0xFE32D => 0xEACE, + 0xFE32E => 0xEAC7, + 0xFE32F => 0xEAC8, + 0xFE330 => 0xE471, + 0xFE331 => "[Bug #7466]", + } + k = h.keys + assert_equal([129, 0xFE331], [k.size, k.last], bug7466) + + code = [ + "h = {", + (1..128).map {|i| "#{i} => 0,"}, + (129..140).map {|i| "#{i} => [],"}, + "}", + ].join + assert_separately([], <<-"end;") + GC.stress = true + #{code} + GC.stress = false + assert_equal(140, h.size) + end; + end + + def test_range + assert_instance_of Range, (1..2) + assert_equal(1..2, 1..2) + r = 1..2 + assert_equal 1, r.begin + assert_equal 2, r.end + assert_equal false, r.exclude_end? + assert_instance_of Range, (1...3) + assert_equal(1...3, 1...3) + r = 1...3 + assert_equal 1, r.begin + assert_equal 3, r.end + assert_equal true, r.exclude_end? + r = 1+2 .. 3+4 + assert_instance_of Range, r + assert_equal 3, r.begin + assert_equal 7, r.end + assert_equal false, r.exclude_end? + r = 1+2 ... 3+4 + assert_instance_of Range, r + assert_equal 3, r.begin + assert_equal 7, r.end + assert_equal true, r.exclude_end? + assert_instance_of Range, 'a'..'c' + r = 'a'..'c' + assert_equal 'a', r.begin + assert_equal 'c', r.end + end + + def test__FILE__ + assert_instance_of String, __FILE__ + assert_equal __FILE__, __FILE__ + assert_equal 'test_literal.rb', File.basename(__FILE__) + end + + def test__LINE__ + assert_instance_of Fixnum, __LINE__ + assert_equal __LINE__, __LINE__ + end + + def test_integer + head = ['', '0x', '0o', '0b', '0d', '-', '+'] + chars = ['0', '1', '_', '9', 'f'] + head.each {|h| + 4.times {|len| + a = [h] + len.times { a = a.product(chars).map {|x| x.join('') } } + a.each {|s| + next if s.empty? + begin + r1 = Integer(s) + rescue ArgumentError + r1 = :err + end + begin + r2 = eval(s) + rescue NameError, SyntaxError + r2 = :err + end + assert_equal(r1, r2, "Integer(#{s.inspect}) != eval(#{s.inspect})") + } + } + } + bug2407 = '[ruby-dev:39798]' + head.each {|h| + if /^0/ =~ h + begin + eval("#{h}_") + rescue SyntaxError => e + assert_match(/numeric literal without digits\Z/, e.message, bug2407) + end + end + } + end + + def test_float + head = ['', '-', '+'] + chars = ['0', '1', '_', '9', 'f', '.'] + head.each {|h| + 6.times {|len| + a = [h] + len.times { a = a.product(chars).map {|x| x.join('') } } + a.each {|s| + next if s.empty? + next if /\.\z/ =~ s + next if /\A[-+]?\./ =~ s + next if /\A[-+]?0/ =~ s + begin + r1 = Float(s) + rescue ArgumentError + r1 = :err + end + begin + r2 = eval(s) + rescue NameError, SyntaxError + r2 = :err + end + r2 = :err if Range === r2 + assert_equal(r1, r2, "Float(#{s.inspect}) != eval(#{s.inspect})") + } + } + } + end + + def test_symbol_list + assert_equal([:foo, :bar], %i[foo bar]) + assert_equal([:"\"foo"], %i["foo]) + + x = 10 + assert_equal([:foo, :b10], %I[foo b#{x}]) + assert_equal([:"\"foo10"], %I["foo#{x}]) + + assert_ruby_status(["--disable-gems", "--dump=parsetree"], "%I[foo bar]") + end +end diff --git a/jni/ruby/test/ruby/test_m17n.rb b/jni/ruby/test/ruby/test_m17n.rb new file mode 100644 index 0000000..980f9c8 --- /dev/null +++ b/jni/ruby/test/ruby/test_m17n.rb @@ -0,0 +1,1599 @@ +# coding: US-ASCII +require 'test/unit' + +class TestM17N < Test::Unit::TestCase + def assert_encoding(encname, actual, message=nil) + assert_equal(Encoding.find(encname), actual, message) + end + + module AESU + def ua(str) str.dup.force_encoding("US-ASCII") end + def a(str) str.dup.force_encoding("ASCII-8BIT") end + def e(str) str.dup.force_encoding("EUC-JP") end + def s(str) str.dup.force_encoding("Windows-31J") end + def u(str) str.dup.force_encoding("UTF-8") end + end + include AESU + extend AESU + + def assert_strenc(bytes, enc, actual, message=nil) + assert_instance_of(String, actual, message) + enc = Encoding.find(enc) if String === enc + assert_equal(enc, actual.encoding, message) + assert_equal(a(bytes), a(actual), message) + end + + def assert_regexp_generic_encoding(r) + assert_not_predicate(r, :fixed_encoding?) + %w[ASCII-8BIT EUC-JP Windows-31J UTF-8].each {|ename| + # "\xc2\xa1" is a valid sequence for ASCII-8BIT, EUC-JP, Windows-31J and UTF-8. + assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(ename) } + } + end + + def assert_regexp_fixed_encoding(r) + assert_predicate(r, :fixed_encoding?) + %w[ASCII-8BIT EUC-JP Windows-31J UTF-8].each {|ename| + enc = Encoding.find(ename) + if enc == r.encoding + assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(enc) } + else + assert_raise(Encoding::CompatibilityError) { r =~ "\xc2\xa1".force_encoding(enc) } + end + } + end + + def assert_regexp_generic_ascii(r) + assert_encoding("US-ASCII", r.encoding) + assert_regexp_generic_encoding(r) + end + + def assert_regexp_fixed_ascii8bit(r) + assert_encoding("ASCII-8BIT", r.encoding) + assert_regexp_fixed_encoding(r) + end + + def assert_regexp_fixed_eucjp(r) + assert_encoding("EUC-JP", r.encoding) + assert_regexp_fixed_encoding(r) + end + + def assert_regexp_fixed_sjis(r) + assert_encoding("Windows-31J", r.encoding) + assert_regexp_fixed_encoding(r) + end + + def assert_regexp_fixed_utf8(r) + assert_encoding("UTF-8", r.encoding) + assert_regexp_fixed_encoding(r) + end + + def assert_regexp_usascii_literal(r, enc, ex = nil) + code = "# -*- encoding: US-ASCII -*-\n#{r}.encoding" + if ex + assert_raise(ex) { eval(code) } + else + assert_equal(enc, eval(code)) + end + end + + def encdump(str) + d = str.dump + if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d + d + else + "#{d}.force_encoding(#{str.encoding.name.dump})" + end + end + + def encdumpargs(args) + r = '(' + args.each_with_index {|a, i| + r << ',' if 0 < i + if String === a + r << encdump(a) + else + r << a.inspect + end + } + r << ')' + r + end + + def assert_str_enc_propagation(t, s1, s2) + if !s1.ascii_only? + assert_equal(s1.encoding, t.encoding) + elsif !s2.ascii_only? + assert_equal(s2.encoding, t.encoding) + else + assert_include([s1.encoding, s2.encoding], t.encoding) + end + end + + def assert_same_result(expected_proc, actual_proc) + e = nil + begin + t = expected_proc.call + rescue + e = $! + end + if e + assert_raise(e.class) { actual_proc.call } + else + assert_equal(t, actual_proc.call) + end + end + + def str_enc_compatible?(*strs) + encs = [] + strs.each {|s| + encs << s.encoding if !s.ascii_only? + } + encs.uniq! + encs.length <= 1 + end + + # tests start + + def test_string_ascii_literal + assert_encoding("ASCII-8BIT", eval(a(%{""})).encoding) + assert_encoding("ASCII-8BIT", eval(a(%{"a"})).encoding) + end + + def test_string_eucjp_literal + assert_encoding("EUC-JP", eval(e(%{""})).encoding) + assert_encoding("EUC-JP", eval(e(%{"a"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\xa1\xa1"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\xa1\\xa1"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\x20"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\n"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\x80"})).encoding) + end + + def test_utf8_literal + assert_equal(Encoding::UTF_8, "\u3042".encoding, "[ruby-dev:33406] \"\\u3042\".encoding") + assert_raise(SyntaxError) { eval(a('\u3052\x80')) } + end + + def test_string_mixed_unicode + assert_raise(SyntaxError) { eval(a(%{"\xc2\xa1\\u{6666}"})) } + assert_raise(SyntaxError) { eval(e(%{"\xc2\xa1\\u{6666}"})) } + assert_raise(SyntaxError) { eval(s(%{"\xc2\xa1\\u{6666}"})) } + assert_nothing_raised { eval(u(%{"\xc2\xa1\\u{6666}"})) } + assert_raise(SyntaxError) { eval(a(%{"\\u{6666}\xc2\xa1"})) } + assert_raise(SyntaxError) { eval(e(%{"\\u{6666}\xc2\xa1"})) } + assert_raise(SyntaxError) { eval(s(%{"\\u{6666}\xc2\xa1"})) } + assert_nothing_raised { eval(u(%{"\\u{6666}\xc2\xa1"})) } + end + + def test_string_inspect_invalid + assert_equal('"\xFE"', e("\xfe").inspect) + assert_equal('"\x8E"', e("\x8e").inspect) + assert_equal('"\x8F"', e("\x8f").inspect) + assert_equal('"\x8F\xA1"', e("\x8f\xa1").inspect) + assert_equal('"\xEF"', s("\xef").inspect) + assert_equal('"\xC2"', u("\xc2").inspect) + assert_equal('"\xE0\x80"', u("\xe0\x80").inspect) + assert_equal('"\xF0\x80\x80"', u("\xf0\x80\x80").inspect) + assert_equal('"\xF8\x80\x80\x80"', u("\xf8\x80\x80\x80").inspect) + assert_equal('"\xFC\x80\x80\x80\x80"', u("\xfc\x80\x80\x80\x80").inspect) + + assert_equal('"\xFE "', e("\xfe ").inspect) + assert_equal('"\x8E "', e("\x8e ").inspect) + assert_equal('"\x8F "', e("\x8f ").inspect) + assert_equal('"\x8F\xA1 "', e("\x8f\xa1 ").inspect) + assert_equal('"\xEF "', s("\xef ").inspect) + assert_equal('"\xC2 "', u("\xc2 ").inspect) + assert_equal('"\xE0\x80 "', u("\xe0\x80 ").inspect) + assert_equal('"\xF0\x80\x80 "', u("\xf0\x80\x80 ").inspect) + assert_equal('"\xF8\x80\x80\x80 "', u("\xf8\x80\x80\x80 ").inspect) + assert_equal('"\xFC\x80\x80\x80\x80 "', u("\xfc\x80\x80\x80\x80 ").inspect) + + assert_equal('"\x81."', s("\x81.").inspect) + assert_equal('"\xFC"', u("\xfc").inspect) + end + + def test_string_inspect_encoding + EnvUtil.suppress_warning do + begin + orig_int = Encoding.default_internal + orig_ext = Encoding.default_external + Encoding.default_internal = nil + [Encoding::UTF_8, Encoding::EUC_JP, Encoding::Windows_31J, Encoding::GB18030]. + each do |e| + Encoding.default_external = e + str = "\x81\x30\x81\x30".force_encoding('GB18030') + assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect) + str = e("\xa1\x8f\xa1\xa1") + expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP") + assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect) + str = s("\x81@") + assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect) + str = "\u3042\u{10FFFD}" + assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect) + end + Encoding.default_external = Encoding::UTF_8 + [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE, + Encoding::UTF8_SOFTBANK].each do |e| + str = "abc".encode(e) + assert_equal('"abc"', str.inspect) + end + ensure + Encoding.default_internal = orig_int + Encoding.default_external = orig_ext + end + end + end + + STR_WITHOUT_BOM = "\u3042".freeze + STR_WITH_BOM = "\uFEFF\u3042".freeze + bug8940 = '[ruby-core:59757] [Bug #8940]' + bug9415 = '[ruby-dev:47895] [Bug #9415]' + %w/UTF-16 UTF-32/.each do |enc| + %w/BE LE/.each do |endian| + bom = "\uFEFF".encode("#{enc}#{endian}").force_encoding(enc) + + define_method("test_utf_16_32_inspect(#{enc}#{endian})") do + s = STR_WITHOUT_BOM.encode(enc + endian) + # When a UTF-16/32 string doesn't have a BOM, + # inspect as a dummy encoding string. + assert_equal(s.dup.force_encoding("ISO-2022-JP").inspect, + s.dup.force_encoding(enc).inspect) + assert_normal_exit("#{bom.b.dump}.force_encoding('#{enc}').inspect", bug8940) + end + + define_method("test_utf_16_32_codepoints(#{enc}#{endian})") do + assert_equal([0xFEFF], bom.codepoints, bug9415) + end + + define_method("test_utf_16_32_ord(#{enc}#{endian})") do + assert_equal(0xFEFF, bom.ord, bug9415) + end + + define_method("test_utf_16_32_inspect(#{enc}#{endian}-BOM)") do + s = STR_WITH_BOM.encode(enc + endian) + # When a UTF-16/32 string has a BOM, + # inspect as a particular encoding string. + assert_equal(s.inspect, + s.dup.force_encoding(enc).inspect) + end + end + end + + def test_utf_without_bom_asciionly + bug10598 = '[ruby-core:66835] [Bug #10598]' + encs = [Encoding::UTF_16, Encoding::UTF_32].find_all {|enc| + "abcd".force_encoding(enc).ascii_only? + } + assert_empty(encs, bug10598) + end + + def test_object_utf16_32_inspect + EnvUtil.suppress_warning do + begin + orig_int = Encoding.default_internal + orig_ext = Encoding.default_external + Encoding.default_internal = nil + Encoding.default_external = Encoding::UTF_8 + o = Object.new + [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e| + o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end" + assert_raise(Encoding::CompatibilityError) { [o].inspect } + end + ensure + Encoding.default_internal = orig_int + Encoding.default_external = orig_ext + end + end + end + + def test_object_inspect_external + orig_v, $VERBOSE = $VERBOSE, false + orig_int, Encoding.default_internal = Encoding.default_internal, nil + orig_ext = Encoding.default_external + o = Object.new + + Encoding.default_external = Encoding::UTF_16BE + def o.inspect + "abc" + end + assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect } + + def o.inspect + "abc".encode(Encoding.default_external) + end + assert_raise(Encoding::CompatibilityError) { [o].inspect } + + Encoding.default_external = Encoding::US_ASCII + def o.inspect + "\u3042" + end + assert_raise(Encoding::CompatibilityError) { [o].inspect } + ensure + Encoding.default_internal = orig_int + Encoding.default_external = orig_ext + $VERBOSE = orig_v + end + + def test_str_dump + [ + e("\xfe"), + e("\x8e"), + e("\x8f"), + e("\x8f\xa1"), + s("\xef"), + u("\xc2"), + u("\xe0\x80"), + u("\xf0\x80\x80"), + u("\xf8\x80\x80\x80"), + u("\xfc\x80\x80\x80\x80"), + + e("\xfe "), + e("\x8e "), + e("\x8f "), + e("\x8f\xa1 "), + s("\xef "), + u("\xc2 "), + u("\xe0\x80 "), + u("\xf0\x80\x80 "), + u("\xf8\x80\x80\x80 "), + u("\xfc\x80\x80\x80\x80 "), + + + e("\xa1\x8f\xa1\xa1"), + + s("\x81."), + s("\x81@"), + + u("\xfc"), + "\u3042", + "ascii", + + "\u3042".encode("UTF-16LE"), + "\u3042".encode("UTF-16BE"), + ].each do |str| + assert_equal(str, eval(str.dump), "[ruby-dev:33142]") + end + end + + def test_validate_redundant_utf8 + bits_0x10ffff = "11110100 10001111 10111111 10111111" + [ + "0xxxxxxx", + "110XXXXx 10xxxxxx", + "1110XXXX 10Xxxxxx 10xxxxxx", + "11110XXX 10XXxxxx 10xxxxxx 10xxxxxx", + "111110XX 10XXXxxx 10xxxxxx 10xxxxxx 10xxxxxx", + "1111110X 10XXXXxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx", + "11111110 10XXXXXx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx", + "11111111 10XXXXXX 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx", + ].each {|pat0| + [ + pat0.gsub(/x/, '1'), + pat0.gsub(/x/, '0') + ].each {|pat1| + [ + pat1.sub(/X([^X]*)\z/, '1\1').gsub(/X/, "0"), + pat1.gsub(/X/, "1"), + ].each {|pat2| + s = [pat2.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + if pat2 <= bits_0x10ffff + assert_predicate(s, :valid_encoding?, "#{pat2}") + else + assert_not_predicate(s, :valid_encoding?, "#{pat2}") + end + } + if / / =~ pat0 + pat3 = pat1.gsub(/X/, "0") + s = [pat3.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + assert_not_predicate(s, :valid_encoding?, "#{pat3}") + end + } + } + end + + def test_validate_surrogate + # 1110XXXX 10Xxxxxx 10xxxxxx : 3 bytes UTF-8 + pats = [ + "11101101 10011111 10111111", # just before surrogate high + "11101101 1010xxxx 10xxxxxx", # surrogate high + "11101101 1011xxxx 10xxxxxx", # surrogate low + "11101110 10000000 10000000", # just after surrogate low + ] + pats.values_at(1,2).each {|pat0| + [ + pat0.gsub(/x/, '0'), + pat0.gsub(/x/, '1'), + ].each {|pat1| + s = [pat1.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + assert_not_predicate(s, :valid_encoding?, "#{pat1}") + } + } + pats.values_at(0,3).each {|pat| + s = [pat.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + assert_predicate(s, :valid_encoding?, "#{pat}") + } + end + + def test_regexp_too_short_multibyte_character + assert_raise(SyntaxError) { eval('/\xfe/e') } + assert_raise(SyntaxError) { eval('/\x8e/e') } + assert_raise(SyntaxError) { eval('/\x8f/e') } + assert_raise(SyntaxError) { eval('/\x8f\xa1/e') } + assert_raise(SyntaxError) { eval('/\xef/s') } + assert_raise(SyntaxError) { eval('/\xc2/u') } + assert_raise(SyntaxError) { eval('/\xe0\x80/u') } + assert_raise(SyntaxError) { eval('/\xf0\x80\x80/u') } + assert_raise(SyntaxError) { eval('/\xf8\x80\x80\x80/u') } + assert_raise(SyntaxError) { eval('/\xfc\x80\x80\x80\x80/u') } + + # raw 8bit + assert_raise(SyntaxError) { eval("/\xfe/e") } + assert_raise(SyntaxError) { eval("/\xc2/u") } + + # invalid suffix + assert_raise(SyntaxError) { eval('/\xc2\xff/u') } + assert_raise(SyntaxError) { eval('/\xc2 /u') } + assert_raise(SyntaxError) { eval('/\xc2\x20/u') } + end + + def test_regexp_generic + assert_regexp_generic_ascii(/a/) + assert_regexp_generic_ascii(Regexp.new(a("a"))) + assert_regexp_generic_ascii(Regexp.new(e("a"))) + assert_regexp_generic_ascii(Regexp.new(s("a"))) + assert_regexp_generic_ascii(Regexp.new(u("a"))) + + [/a/, Regexp.new(a("a"))].each {|r| + assert_equal(0, r =~ a("a")) + assert_equal(0, r =~ e("a")) + assert_equal(0, r =~ s("a")) + assert_equal(0, r =~ u("a")) + assert_equal(nil, r =~ a("\xc2\xa1")) + assert_equal(nil, r =~ e("\xc2\xa1")) + assert_equal(nil, r =~ s("\xc2\xa1")) + assert_equal(nil, r =~ u("\xc2\xa1")) + } + end + + def test_regexp_ascii_none + r = /a/n + + assert_warning(%r{regexp match /.../n against to}) { + assert_regexp_generic_ascii(r) + } + + assert_equal(0, r =~ a("a")) + assert_equal(0, r =~ e("a")) + assert_equal(0, r =~ s("a")) + assert_equal(0, r =~ u("a")) + assert_equal(nil, r =~ a("\xc2\xa1")) + assert_warning(%r{regexp match /.../n against to EUC-JP string}) { + assert_equal(nil, r =~ e("\xc2\xa1")) + } + assert_warning(%r{regexp match /.../n against to Windows-31J string}) { + assert_equal(nil, r =~ s("\xc2\xa1")) + } + assert_warning(%r{regexp match /.../n against to UTF-8 string}) { + assert_equal(nil, r =~ u("\xc2\xa1")) + } + + assert_nothing_raised { eval(e("/\\x80/n")) } + end + + def test_regexp_ascii + assert_regexp_fixed_ascii8bit(/\xc2\xa1/n) + assert_regexp_fixed_ascii8bit(eval(a(%{/\xc2\xa1/}))) + assert_regexp_fixed_ascii8bit(eval(a(%{/\xc2\xa1/n}))) + assert_regexp_fixed_ascii8bit(eval(a(%q{/\xc2\xa1/}))) + + s = '\xc2\xa1' + assert_regexp_fixed_ascii8bit(/#{s}/) + + assert_raise(SyntaxError) { eval("/\xa1\xa1/n".force_encoding("euc-jp")) } + + [/\xc2\xa1/n, eval(a(%{/\xc2\xa1/})), eval(a(%{/\xc2\xa1/n}))].each {|r| + assert_equal(nil, r =~ a("a")) + assert_equal(nil, r =~ e("a")) + assert_equal(nil, r =~ s("a")) + assert_equal(nil, r =~ u("a")) + assert_equal(0, r =~ a("\xc2\xa1")) + assert_raise(Encoding::CompatibilityError) { r =~ e("\xc2\xa1") } + assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") } + assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") } + } + end + + def test_regexp_euc + assert_regexp_fixed_eucjp(/a/e) + assert_regexp_fixed_eucjp(/\xc2\xa1/e) + assert_regexp_fixed_eucjp(eval(e(%{/\xc2\xa1/}))) + assert_regexp_fixed_eucjp(eval(e(%q{/\xc2\xa1/}))) + + [/a/e].each {|r| + assert_equal(0, r =~ a("a")) + assert_equal(0, r =~ e("a")) + assert_equal(0, r =~ s("a")) + assert_equal(0, r =~ u("a")) + assert_raise(Encoding::CompatibilityError) { r =~ a("\xc2\xa1") } + assert_equal(nil, r =~ e("\xc2\xa1")) + assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") } + assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") } + } + + [/\xc2\xa1/e, eval(e(%{/\xc2\xa1/})), eval(e(%q{/\xc2\xa1/}))].each {|r| + assert_equal(nil, r =~ a("a")) + assert_equal(nil, r =~ e("a")) + assert_equal(nil, r =~ s("a")) + assert_equal(nil, r =~ u("a")) + assert_raise(Encoding::CompatibilityError) { r =~ a("\xc2\xa1") } + assert_equal(0, r =~ e("\xc2\xa1")) + assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") } + assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") } + } + end + + def test_regexp_sjis + assert_regexp_fixed_sjis(/a/s) + assert_regexp_fixed_sjis(/\xc2\xa1/s) + assert_regexp_fixed_sjis(eval(s(%{/\xc2\xa1/}))) + assert_regexp_fixed_sjis(eval(s(%q{/\xc2\xa1/}))) + end + + def test_regexp_windows_31j + begin + Regexp.new("\xa1".force_encoding("windows-31j")) =~ "\xa1\xa1".force_encoding("euc-jp") + rescue Encoding::CompatibilityError + err = $! + end + assert_match(/windows-31j/i, err.message) + end + + def test_regexp_embed + r = eval(e("/\xc2\xa1/")) + assert_raise(RegexpError) { eval(s("/\xc2\xa1\#{r}/s")) } + assert_raise(RegexpError) { eval(s("/\#{r}\xc2\xa1/s")) } + + r = /\xc2\xa1/e + assert_raise(RegexpError) { eval(s("/\xc2\xa1\#{r}/s")) } + assert_raise(RegexpError) { eval(s("/\#{r}\xc2\xa1/s")) } + + r = eval(e("/\xc2\xa1/")) + assert_raise(RegexpError) { /\xc2\xa1#{r}/s } + + r = /\xc2\xa1/e + assert_raise(RegexpError) { /\xc2\xa1#{r}/s } + + r1 = Regexp.new('foo'.force_encoding("ascii-8bit")) + r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::US_ASCII, r2.encoding) + + r1 = Regexp.new('foo'.force_encoding("us-ascii")) + r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::US_ASCII, r2.encoding) + + r1 = Regexp.new('foo'.force_encoding("ascii-8bit")) + r2 = eval('/bar#{r1}/'.force_encoding('us-ascii')) + assert_equal(Encoding::US_ASCII, r2.encoding) + + r1 = Regexp.new('foo'.force_encoding("us-ascii")) + r2 = eval('/bar#{r1}/'.force_encoding('us-ascii')) + assert_equal(Encoding::US_ASCII, r2.encoding) + + r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit")) + r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::ASCII_8BIT, r2.encoding) + + r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit")) + r2 = eval('/bar#{r1}/'.force_encoding('us-ascii')) + assert_equal(Encoding::ASCII_8BIT, r2.encoding) + + r1 = Regexp.new('foo'.force_encoding("ascii-8bit")) + r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::ASCII_8BIT, r2.encoding) + + r1 = Regexp.new('foo'.force_encoding("us-ascii")) + r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::ASCII_8BIT, r2.encoding) + + r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit")) + r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit')) + assert_equal(Encoding::ASCII_8BIT, r2.encoding) + end + + def test_regexp_named_class + assert_match(/[[:space:]]/u, "\u{00a0}") + assert_match(/[[:space:]]/, "\u{00a0}") + end + + def test_regexp_property + s = '\p{Hiragana}'.force_encoding("euc-jp") + assert_equal(Encoding::EUC_JP, s.encoding) + r = nil + assert_nothing_raised { + r = Regexp.new(s) + } + assert_predicate(r, :fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\p{Hiragana}/'.force_encoding("euc-jp")) + assert_predicate(r, :fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = /\p{Hiragana}/e + assert_predicate(r, :fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = /\p{AsciI}/e + assert_predicate(r, :fixed_encoding?) + assert_match(r, "a".force_encoding("euc-jp")) + + r = /\p{hiraganA}/e + assert_predicate(r, :fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\u{3042}\p{Hiragana}/'.force_encoding("euc-jp")) + assert_predicate(r, :fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + + r = eval('/\p{Hiragana}\u{3042}/'.force_encoding("euc-jp")) + assert_predicate(r, :fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + end + + def test_regexp_embed_preprocess + r1 = /\xa4\xa2/e + r2 = /#{r1}/ + assert_include(r2.source, r1.source) + end + + def test_begin_end_offset + str = e("\244\242\244\244\244\246\244\250\244\252a") + assert(/(a)/ =~ str) + assert_equal("a", $&) + assert_equal(5, $~.begin(0)) + assert_equal(6, $~.end(0)) + assert_equal([5,6], $~.offset(0)) + assert_equal(5, $~.begin(1)) + assert_equal(6, $~.end(1)) + assert_equal([5,6], $~.offset(1)) + end + + def test_begin_end_offset_sjis + str = s("\x81@@") + assert(/@/ =~ str) + assert_equal(s("\x81@"), $`) + assert_equal("@", $&) + assert_equal("", $') + assert_equal([1,2], $~.offset(0)) + end + + def test_quote + assert_regexp_generic_ascii(/#{Regexp.quote(a("a"))}#{Regexp.quote(e("e"))}/) + + assert_encoding("US-ASCII", Regexp.quote(a("")).encoding) + assert_encoding("US-ASCII", Regexp.quote(e("")).encoding) + assert_encoding("US-ASCII", Regexp.quote(s("")).encoding) + assert_encoding("US-ASCII", Regexp.quote(u("")).encoding) + assert_encoding("US-ASCII", Regexp.quote(a("a")).encoding) + assert_encoding("US-ASCII", Regexp.quote(e("a")).encoding) + assert_encoding("US-ASCII", Regexp.quote(s("a")).encoding) + assert_encoding("US-ASCII", Regexp.quote(u("a")).encoding) + + assert_encoding("ASCII-8BIT", Regexp.quote(a("\xc2\xa1")).encoding) + assert_encoding("EUC-JP", Regexp.quote(e("\xc2\xa1")).encoding) + assert_encoding("Windows-31J", Regexp.quote(s("\xc2\xa1")).encoding) + assert_encoding("UTF-8", Regexp.quote(u("\xc2\xa1")).encoding) + end + + def test_union_0 + r = Regexp.union + assert_regexp_generic_ascii(r) + assert_not_match(r, a("")) + assert_not_match(r, e("")) + assert_not_match(r, s("")) + assert_not_match(r, u("")) + end + + def test_union_1_asciionly_string + assert_regexp_generic_ascii(Regexp.union(a(""))) + assert_regexp_generic_ascii(Regexp.union(e(""))) + assert_regexp_generic_ascii(Regexp.union(s(""))) + assert_regexp_generic_ascii(Regexp.union(u(""))) + assert_regexp_generic_ascii(Regexp.union(a("a"))) + assert_regexp_generic_ascii(Regexp.union(e("a"))) + assert_regexp_generic_ascii(Regexp.union(s("a"))) + assert_regexp_generic_ascii(Regexp.union(u("a"))) + assert_regexp_generic_ascii(Regexp.union(a("\t"))) + assert_regexp_generic_ascii(Regexp.union(e("\t"))) + assert_regexp_generic_ascii(Regexp.union(s("\t"))) + assert_regexp_generic_ascii(Regexp.union(u("\t"))) + end + + def test_union_1_nonascii_string + assert_regexp_fixed_ascii8bit(Regexp.union(a("\xc2\xa1"))) + assert_regexp_fixed_eucjp(Regexp.union(e("\xc2\xa1"))) + assert_regexp_fixed_sjis(Regexp.union(s("\xc2\xa1"))) + assert_regexp_fixed_utf8(Regexp.union(u("\xc2\xa1"))) + end + + def test_union_1_regexp + assert_regexp_generic_ascii(Regexp.union(//)) + assert_warning(%r{regexp match /.../n against to}) { + assert_regexp_generic_ascii(Regexp.union(//n)) + } + assert_regexp_fixed_eucjp(Regexp.union(//e)) + assert_regexp_fixed_sjis(Regexp.union(//s)) + assert_regexp_fixed_utf8(Regexp.union(//u)) + end + + def test_union_2 + ary = [ + a(""), e(""), s(""), u(""), + a("\xc2\xa1"), e("\xc2\xa1"), s("\xc2\xa1"), u("\xc2\xa1") + ] + ary.each {|s1| + ary.each {|s2| + if s1.empty? + if s2.empty? + assert_regexp_generic_ascii(Regexp.union(s1, s2)) + else + r = Regexp.union(s1, s2) + assert_regexp_fixed_encoding(r) + assert_equal(s2.encoding, r.encoding) + end + else + if s2.empty? + r = Regexp.union(s1, s2) + assert_regexp_fixed_encoding(r) + assert_equal(s1.encoding, r.encoding) + else + if s1.encoding == s2.encoding + r = Regexp.union(s1, s2) + assert_regexp_fixed_encoding(r) + assert_equal(s1.encoding, r.encoding) + else + assert_raise(ArgumentError) { Regexp.union(s1, s2) } + end + end + end + } + } + end + + def test_dynamic_ascii_regexp + assert_warning(%r{regexp match /.../n against to}) { + assert_regexp_generic_ascii(/#{ }/n) + } + assert_regexp_fixed_ascii8bit(/#{ }\xc2\xa1/n) + assert_regexp_fixed_ascii8bit(/\xc2\xa1#{ }/n) + assert_nothing_raised { s1, s2 = a('\xc2'), a('\xa1'); /#{s1}#{s2}/ } + end + + def test_dynamic_eucjp_regexp + assert_regexp_fixed_eucjp(/#{ }/e) + assert_regexp_fixed_eucjp(/#{ }\xc2\xa1/e) + assert_regexp_fixed_eucjp(/\xc2\xa1#{ }/e) + assert_raise(SyntaxError) { eval('/\xc2#{ }/e') } + assert_raise(SyntaxError) { eval('/#{ }\xc2/e') } + assert_raise(SyntaxError) { eval('/\xc2#{ }\xa1/e') } + assert_raise(ArgumentError) { s1, s2 = e('\xc2'), e('\xa1'); /#{s1}#{s2}/ } + end + + def test_dynamic_sjis_regexp + assert_regexp_fixed_sjis(/#{ }/s) + assert_regexp_fixed_sjis(/#{ }\xc2\xa1/s) + assert_regexp_fixed_sjis(/\xc2\xa1#{ }/s) + assert_raise(SyntaxError) { eval('/\x81#{ }/s') } + assert_raise(SyntaxError) { eval('/#{ }\x81/s') } + assert_raise(SyntaxError) { eval('/\x81#{ }\xa1/s') } + assert_raise(ArgumentError) { s1, s2 = s('\x81'), s('\xa1'); /#{s1}#{s2}/ } + end + + def test_dynamic_utf8_regexp + assert_regexp_fixed_utf8(/#{ }/u) + assert_regexp_fixed_utf8(/#{ }\xc2\xa1/u) + assert_regexp_fixed_utf8(/\xc2\xa1#{ }/u) + assert_raise(SyntaxError) { eval('/\xc2#{ }/u') } + assert_raise(SyntaxError) { eval('/#{ }\xc2/u') } + assert_raise(SyntaxError) { eval('/\xc2#{ }\xa1/u') } + assert_raise(ArgumentError) { s1, s2 = u('\xc2'), u('\xa1'); /#{s1}#{s2}/ } + end + + def test_regexp_unicode + assert_nothing_raised { eval '/\u{0}/u' } + assert_nothing_raised { eval '/\u{D7FF}/u' } + assert_raise(SyntaxError) { eval '/\u{D800}/u' } + assert_raise(SyntaxError) { eval '/\u{DFFF}/u' } + assert_nothing_raised { eval '/\u{E000}/u' } + assert_nothing_raised { eval '/\u{10FFFF}/u' } + assert_raise(SyntaxError) { eval '/\u{110000}/u' } + end + + def test_regexp_mixed_unicode + assert_raise(SyntaxError) { eval(a(%{/\xc2\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(e(%{/\xc2\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(s(%{/\xc2\xa1\\u{6666}/})) } + assert_nothing_raised { eval(u(%{/\xc2\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(a(%{/\\u{6666}\xc2\xa1/})) } + assert_raise(SyntaxError) { eval(e(%{/\\u{6666}\xc2\xa1/})) } + assert_raise(SyntaxError) { eval(s(%{/\\u{6666}\xc2\xa1/})) } + assert_nothing_raised { eval(u(%{/\\u{6666}\xc2\xa1/})) } + + assert_raise(SyntaxError) { eval(a(%{/\\xc2\\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(e(%{/\\xc2\\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(s(%{/\\xc2\\xa1\\u{6666}/})) } + assert_nothing_raised { eval(u(%{/\\xc2\\xa1\\u{6666}/})) } + assert_raise(SyntaxError) { eval(a(%{/\\u{6666}\\xc2\\xa1/})) } + assert_raise(SyntaxError) { eval(e(%{/\\u{6666}\\xc2\\xa1/})) } + assert_raise(SyntaxError) { eval(s(%{/\\u{6666}\\xc2\\xa1/})) } + assert_nothing_raised { eval(u(%{/\\u{6666}\\xc2\\xa1/})) } + + assert_raise(SyntaxError) { eval(a(%{/\xc2\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(e(%{/\xc2\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(s(%{/\xc2\xa1#{ }\\u{6666}/})) } + assert_nothing_raised { eval(u(%{/\xc2\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(a(%{/\\u{6666}#{ }\xc2\xa1/})) } + assert_raise(SyntaxError) { eval(e(%{/\\u{6666}#{ }\xc2\xa1/})) } + assert_raise(SyntaxError) { eval(s(%{/\\u{6666}#{ }\xc2\xa1/})) } + assert_nothing_raised { eval(u(%{/\\u{6666}#{ }\xc2\xa1/})) } + + assert_raise(SyntaxError) { eval(a(%{/\\xc2\\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(e(%{/\\xc2\\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(s(%{/\\xc2\\xa1#{ }\\u{6666}/})) } + assert_nothing_raised { eval(u(%{/\\xc2\\xa1#{ }\\u{6666}/})) } + assert_raise(SyntaxError) { eval(a(%{/\\u{6666}#{ }\\xc2\\xa1/})) } + assert_raise(SyntaxError) { eval(e(%{/\\u{6666}#{ }\\xc2\\xa1/})) } + assert_raise(SyntaxError) { eval(s(%{/\\u{6666}#{ }\\xc2\\xa1/})) } + assert_nothing_raised { eval(u(%{/\\u{6666}#{ }\\xc2\\xa1/})) } + end + + def test_str_allocate + s = String.allocate + assert_equal(Encoding::ASCII_8BIT, s.encoding) + end + + def test_str_String + s = String(10) + assert_equal(Encoding::US_ASCII, s.encoding) + end + + def test_sprintf_c + assert_strenc("\x80", 'ASCII-8BIT', a("%c") % 128) + #assert_raise(ArgumentError) { a("%c") % 0xc2a1 } + assert_strenc("\xc2\xa1", 'EUC-JP', e("%c") % 0xc2a1) + assert_raise(ArgumentError) { e("%c") % 0xc2 } + assert_strenc("\xc2", 'Windows-31J', s("%c") % 0xc2) + #assert_raise(ArgumentError) { s("%c") % 0xc2a1 } + assert_strenc("\u{c2a1}", 'UTF-8', u("%c") % 0xc2a1) + assert_strenc("\u{c2}", 'UTF-8', u("%c") % 0xc2) + assert_raise(Encoding::CompatibilityError) { + "%s%s" % [s("\xc2\xa1"), e("\xc2\xa1")] + } + end + + def test_sprintf_p + Encoding.list.each do |e| + format = "%p".force_encoding(e) + ['', 'a', "\xC2\xA1", "\x00"].each do |s| + s.force_encoding(e) + enc = (''.force_encoding(e) + s.inspect).encoding + assert_strenc(s.inspect, enc, format % s) + end + s = "\xC2\xA1".force_encoding(e) + enc = ('' + s.inspect).encoding + assert_strenc('%10s' % s.inspect, enc, "%10p" % s) + end + end + + def test_sprintf_s + assert_strenc('', 'ASCII-8BIT', a("%s") % a("")) + assert_strenc('', 'EUC-JP', e("%s") % e("")) + assert_strenc('', 'Windows-31J', s("%s") % s("")) + assert_strenc('', 'UTF-8', u("%s") % u("")) + + assert_strenc('a', 'ASCII-8BIT', a("%s") % a("a")) + assert_strenc('a', 'EUC-JP', e("%s") % e("a")) + assert_strenc('a', 'Windows-31J', s("%s") % s("a")) + assert_strenc('a', 'UTF-8', u("%s") % u("a")) + + assert_strenc("\xC2\xA1", 'ASCII-8BIT', a("%s") % a("\xc2\xa1")) + assert_strenc("\xC2\xA1", 'EUC-JP', e("%s") % e("\xc2\xa1")) + #assert_strenc("\xC2\xA1", 'Windows-31J', s("%s") % s("\xc2\xa1")) + assert_strenc("\xC2\xA1", 'UTF-8', u("%s") % u("\xc2\xa1")) + + assert_strenc(" \xC2\xA1", 'ASCII-8BIT', "%10s" % a("\xc2\xa1")) + assert_strenc(" \xA1\xA1", 'EUC-JP', "%10s" % e("\xa1\xa1")) + #assert_strenc(" \xC2\xA1", 'Windows-31J', "%10s" % s("\xc2\xa1")) + assert_strenc(" \xC2\xA1", 'UTF-8', "%10s" % u("\xc2\xa1")) + + assert_strenc("\x00", 'ASCII-8BIT', a("%s") % a("\x00")) + assert_strenc("\x00", 'EUC-JP', e("%s") % e("\x00")) + assert_strenc("\x00", 'Windows-31J', s("%s") % s("\x00")) + assert_strenc("\x00", 'UTF-8', u("%s") % u("\x00")) + assert_equal("EUC-JP", (e("\xc2\xa1 %s") % "foo").encoding.name) + end + + def test_str_lt + assert_operator(a("a"), :<, a("\xa1")) + assert_operator(a("a"), :<, s("\xa1")) + assert_operator(s("a"), :<, a("\xa1")) + end + + def test_str_multiply + str = "\u3042" + assert_equal(true, (str * 0).ascii_only?, "[ruby-dev:33895]") + assert_equal(false, (str * 1).ascii_only?) + assert_equal(false, (str * 2).ascii_only?) + end + + def test_str_aref + assert_equal(a("\xc2"), a("\xc2\xa1")[0]) + assert_equal(a("\xa1"), a("\xc2\xa1")[1]) + assert_equal(nil, a("\xc2\xa1")[2]) + assert_equal(e("\xc2\xa1"), e("\xc2\xa1")[0]) + assert_equal(nil, e("\xc2\xa1")[1]) + assert_equal(s("\xc2"), s("\xc2\xa1")[0]) + assert_equal(s("\xa1"), s("\xc2\xa1")[1]) + assert_equal(nil, s("\xc2\xa1")[2]) + assert_equal(u("\xc2\xa1"), u("\xc2\xa1")[0]) + assert_equal(nil, u("\xc2\xa1")[1]) + + str = "\u3042" + assert_equal(true, str[0, 0].ascii_only?, "[ruby-dev:33895]") + assert_equal(false, str[0, 1].ascii_only?) + assert_equal(false, str[0..-1].ascii_only?) + end + + def test_utf8str_aref + s = "abcdefghijklmnopqrstuvwxyz\u{3042 3044 3046 3048 304A}" + assert_equal("a", s[0]) + assert_equal("h", s[7]) + assert_equal("i", s[8]) + assert_equal("j", s[9]) + assert_equal("\u{3044}", s[27]) + assert_equal("\u{3046}", s[28]) + assert_equal("\u{3048}", s[29]) + s = "abcdefghijklmnopqrstuvw\u{3042 3044 3046 3048 304A}" + assert_equal("\u{3044}", s[24]) + end + + def test_str_aref_len + assert_equal(a("\xa1"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1]) + assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2]) + + assert_equal(e("\xc2\xa2"), e("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1]) + assert_equal(e("\xc2\xa2\xc2\xa3"), e("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2]) + + assert_equal(s("\xa1"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1]) + assert_equal(s("\xa1\xc2"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2]) + + assert_equal(u("\xc2\xa2"), u("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1]) + assert_equal(u("\xc2\xa2\xc2\xa3"), u("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2]) + end + + def test_str_aref_substr + assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")]) + assert_raise(Encoding::CompatibilityError) { a("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")] } + + assert_equal(nil, e("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")]) + assert_raise(Encoding::CompatibilityError) { e("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")] } + + assert_equal(s("\xa1\xc2"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")]) + assert_raise(Encoding::CompatibilityError) { s("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")] } + + assert_equal(nil, u("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")]) + assert_raise(Encoding::CompatibilityError) { u("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")] } + assert_nil(e("\xa1\xa2\xa3\xa4")[e("\xa2\xa3")]) + + bug2379 = '[ruby-core:26787]' + assert_equal("\u{439}", "\u{439}"[0, 30], bug2379) + assert_equal("\u{439}", "a\u{439}"[1, 30], bug2379) + assert_equal("\u{439}", "a\u{439}bcdefghijklmnop"[1, 1][0, 1], bug2379) + end + + def test_str_aref_force_encoding + bug5836 = '[ruby-core:41896]' + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + s = "abc".force_encoding(enc) + assert_equal("", s[3, 1], bug5836) + end + end + + def test_aset + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s["\xb0\xa3"] = "foo"} + + a = ua("a") + a[/a/] = u("") + assert_equal Encoding::US_ASCII, a.encoding + end + + def test_str_center + assert_encoding("EUC-JP", "a".center(5, e("\xa1\xa2")).encoding) + assert_encoding("EUC-JP", e("\xa3\xb0").center(10).encoding) + end + + def test_squeeze + s = e("\xa3\xb0\xa3\xb1\xa3\xb1\xa3\xb3\xa3\xb4") + assert_equal(e("\xa3\xb0\xa3\xb1\xa3\xb3\xa3\xb4"), s.squeeze) + end + + def test_tr + s = s("\x81\x41") + assert_equal(s.tr("A", "B"), s) + assert_equal(s.tr_s("A", "B"), s) + + assert_nothing_raised { + "a".force_encoding("ASCII-8BIT").tr(a("a"), a("a")) + } + + assert_equal(e("\xA1\xA1"), a("a").tr(a("a"), e("\xA1\xA1"))) + + assert_equal("X\u3042\u3044X", "A\u3042\u3044\u3046".tr("^\u3042\u3044", "X")) + assert_equal("\u3042\u3046" * 100, ("\u3042\u3044" * 100).tr("\u3044", "\u3046")) + assert_equal("Y", "\u3042".tr("^X", "Y")) + end + + def test_tr_s + assert_equal("\xA1\xA1".force_encoding("EUC-JP"), + "a".force_encoding("ASCII-8BIT").tr("a".force_encoding("ASCII-8BIT"), "\xA1\xA1".force_encoding("EUC-JP"))) + end + + def test_count + assert_equal(0, e("\xa1\xa2").count("z")) + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s.count(a("\xa3\xb0"))} + end + + def test_count_sjis_trailing_byte + bug10078 = '[ruby-dev:48442] [Bug #10078]' + assert_equal(0, s("\x98\x61").count("a"), bug10078) + end + + def test_delete + assert_equal(1, e("\xa1\xa2").delete("z").length) + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s.delete(a("\xa3\xb2"))} + + a = "\u3042\u3044\u3046\u3042\u3044\u3046" + a.delete!("\u3042\u3044", "^\u3044") + assert_equal("\u3044\u3046\u3044\u3046", a) + end + + def test_include? + assert_equal(false, e("\xa1\xa2\xa3\xa4").include?(e("\xa3"))) + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_equal(false, s.include?(e("\xb0\xa3"))) + end + + def test_index + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_nil(s.index(e("\xb3\xa3"))) + assert_nil(e("\xa1\xa2\xa3\xa4").index(e("\xa3"))) + assert_nil(e("\xa1\xa2\xa3\xa4").rindex(e("\xa3"))) + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s.rindex(a("\xb1\xa3"))} + end + + def test_next + s1 = e("\xa1\xa1") + s2 = s1.dup + (94*94+94).times { s2.next! } + assert_not_equal(s1, s2) + end + + def test_sub + s = "abc".sub(/b/, "\xa1\xa1".force_encoding("euc-jp")) + assert_encoding("EUC-JP", s.encoding) + assert_equal(Encoding::EUC_JP, "\xa4\xa2".force_encoding("euc-jp").sub(/./, '\&').encoding) + assert_equal(Encoding::EUC_JP, "\xa4\xa2".force_encoding("euc-jp").gsub(/./, '\&').encoding) + end + + def test_sub2 + s = "\x80".force_encoding("ASCII-8BIT") + r = Regexp.new("\x80".force_encoding("ASCII-8BIT")) + s2 = s.sub(r, "") + assert_empty(s2) + assert_predicate(s2, :ascii_only?) + end + + def test_sub3 + repl = "\x81".force_encoding("sjis") + assert_equal(false, repl.valid_encoding?) + s = "a@".sub(/a/, repl) + assert_predicate(s, :valid_encoding?) + end + + def test_insert + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_equal(e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4a"), s.insert(-1, "a")) + end + + def test_scan + assert_equal(["a"], e("\xa1\xa2a\xa3\xa4").scan(/a/)) + end + + def test_dup_scan + s1 = e("\xa4\xa2")*100 + s2 = s1.dup.force_encoding("ascii-8bit") + s2.scan(/\A./n) {|f| + assert_equal(Encoding::ASCII_8BIT, f.encoding) + } + end + + def test_dup_aref + s1 = e("\xa4\xa2")*100 + s2 = s1.dup.force_encoding("ascii-8bit") + assert_equal(Encoding::ASCII_8BIT, s2[10..-1].encoding) + end + + def test_upto + s1 = e("\xa1\xa2") + s2 = s("\xa1\xa2") + assert_raise(Encoding::CompatibilityError){s1.upto(s2) {|x| break }} + end + + def test_casecmp + s1 = s("\x81\x41") + s2 = s("\x81\x61") + assert_not_equal(0, s1.casecmp(s2)) + end + + def test_reverse + bug11387 = '[ruby-dev:49189] [Bug #11387]' + s1 = u("abcdefghij\xf0") + s2 = s1.reverse + assert_not_predicate(s1, :valid_encoding?, bug11387) + assert_equal(u("\xf0jihgfedcba"), s2) + assert_not_predicate(s2, :valid_encoding?, bug11387) + end + + def test_reverse_bang + s = u("abcdefghij\xf0") + s.reverse! + assert_equal(u("\xf0jihgfedcba"), s) + end + + def test_plus + assert_raise(Encoding::CompatibilityError){u("\xe3\x81\x82") + a("\xa1")} + end + + def test_chomp + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s.chomp(s("\xa3\xb4"))} + end + + def test_gsub + s = 'abc' + s.ascii_only? + s.gsub!(/b/, "\x80") + assert_equal(false, s.ascii_only?, "[ruby-core:14566] reported by Sam Ruby") + + s = "abc".force_encoding(Encoding::ASCII_8BIT) + assert_equal(Encoding::ASCII_8BIT, s.encoding) + + assert_raise(Encoding::CompatibilityError) { + "abc".gsub(/[ac]/) { + $& == "a" ? "\xc2\xa1".force_encoding("euc-jp") : + "\xc2\xa1".force_encoding("utf-8") + } + } + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_equal(e("\xa3\xb0z\xa3\xb2\xa3\xb3\xa3\xb4"), s.gsub(/\xa3\xb1/e, "z")) + + assert_equal(Encoding::ASCII_8BIT, (a("").gsub(//) { e("") }.encoding)) + assert_equal(Encoding::ASCII_8BIT, (a("a").gsub(/a/) { e("") }.encoding)) + end + + def test_end_with + s1 = s("\x81\x40") + s2 = "@" + assert_equal(false, s1.end_with?(s2), "#{encdump s1}.end_with?(#{encdump s2})") + each_encoding("\u3042\u3044", "\u3044") do |_s1, _s2| + assert_equal(true, _s1.end_with?(_s2), "#{encdump _s1}.end_with?(#{encdump _s2})") + end + each_encoding("\u3042a\u3044", "a\u3044") do |_s1, _s2| + assert_equal(true, _s1.end_with?(_s2), "#{encdump _s1}.end_with?(#{encdump _s2})") + end + end + + def test_each_line + s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") + assert_raise(Encoding::CompatibilityError){s.each_line(a("\xa3\xb1")) {|l| }} + s = e("\xa4\xa2\nfoo") + + actual = [] + s.each_line {|line| actual << line } + expected = [e("\xa4\xa2\n"), e("foo")] + assert_equal(expected, actual) + end + + def test_each_char + a = [e("\xa4\xa2"), "b", e("\xa4\xa4"), "c"] + s = "\xa4\xa2b\xa4\xa4c".force_encoding("euc-jp") + assert_equal(a, s.each_char.to_a, "[ruby-dev:33211] #{encdump s}.each_char.to_a") + end + + def test_str_concat + assert_equal(1, "".concat(0xA2).size) + assert_equal(Encoding::ASCII_8BIT, "".force_encoding("US-ASCII").concat(0xA2).encoding) + assert_equal("A\x84\x31\xA4\x39".force_encoding("GB18030"), + "A".force_encoding("GB18030") << 0x8431A439) + end + + def test_regexp_match + assert_equal([0,0], //.match("\xa1\xa1".force_encoding("euc-jp"),-1).offset(0)) + assert_equal(0, // =~ :a) + end + + def test_split + assert_equal(e("\xa1\xa2\xa1\xa3").split(//), + [e("\xa1\xa2"), e("\xa1\xa3")], + '[ruby-dev:32452]') + + each_encoding("abc,def", ",", "abc", "def") do |str, sep, *expected| + assert_equal(expected, str.split(sep, -1)) + end + each_encoding("abc\0def", "\0", "abc", "def") do |str, sep, *expected| + assert_equal(expected, str.split(sep, -1)) + end + end + + def test_nonascii_method_name + eval(e("def \xc2\xa1() @nonascii_method_name = :e end")) + eval(u("def \xc2\xa1() @nonascii_method_name = :u end")) + eval(e("\xc2\xa1()")) + assert_equal(:e, @nonascii_method_name) + eval(u("\xc2\xa1()")) + assert_equal(:u, @nonascii_method_name) + me = method(e("\xc2\xa1")) + mu = method(u("\xc2\xa1")) + assert_not_equal(me.name, mu.name) + assert_not_equal(me.inspect, mu.inspect) + assert_equal(e("\xc2\xa1"), me.name.to_s) + assert_equal(u("\xc2\xa1"), mu.name.to_s) + end + + def test_symbol + s1 = "\xc2\xa1".force_encoding("euc-jp").intern + s2 = "\xc2\xa1".force_encoding("utf-8").intern + assert_not_equal(s1, s2) + end + + def test_symbol_op + ops = %w" + .. ... + - * / % ** +@ -@ | ^ & ! <=> > >= < <= == + === != =~ !~ ~ ! [] []= << >> :: ` + " + ops.each do |op| + assert_equal(Encoding::US_ASCII, op.intern.encoding, "[ruby-dev:33449]") + end + end + + def test_chr + 0.upto(255) {|b| + assert_equal([b].pack("C"), b.chr) + } + assert_equal("\x84\x31\xA4\x39".force_encoding("GB18030"), 0x8431A439.chr("GB18030")) + e = assert_raise(RangeError) { + 2206368128.chr(Encoding::UTF_8) + } + assert_not_match(/-\d+ out of char range/, e.message) + + assert_raise(RangeError){ 0x80.chr("US-ASCII") } + assert_raise(RangeError){ 0x80.chr("SHIFT_JIS") } + assert_raise(RangeError){ 0xE0.chr("SHIFT_JIS") } + assert_raise(RangeError){ 0x100.chr("SHIFT_JIS") } + assert_raise(RangeError){ 0xA0.chr("EUC-JP") } + assert_raise(RangeError){ 0x100.chr("EUC-JP") } + assert_raise(RangeError){ 0xA1A0.chr("EUC-JP") } + end + + def test_marshal + s1 = "\xa1\xa1".force_encoding("euc-jp") + s2 = Marshal.load(Marshal.dump(s1)) + assert_equal(s1, s2) + end + + def test_env + locale_encoding = Encoding.find("locale") + ENV.each {|k, v| + assert_equal(locale_encoding, k.encoding, k) + assert_equal(locale_encoding, v.encoding, v) + } + end + + def test_empty_string + assert_equal(Encoding::US_ASCII, "".encoding) + end + + def test_nil_to_s + assert_equal(Encoding::US_ASCII, nil.to_s.encoding) + end + + def test_nil_inspect + assert_equal(Encoding::US_ASCII, nil.inspect.encoding) + end + + def test_true_to_s + assert_equal(Encoding::US_ASCII, true.to_s.encoding) + end + + def test_false_to_s + assert_equal(Encoding::US_ASCII, false.to_s.encoding) + end + + def test_fixnum_to_s + assert_equal(Encoding::US_ASCII, 1.to_s.encoding) + end + + def test_float_to_s + assert_equal(Encoding::US_ASCII, 1.0.to_s.encoding) + end + + def test_bignum_to_s + assert_equal(Encoding::US_ASCII, (1 << 129).to_s.encoding) + end + + def test_array_to_s + assert_equal(Encoding::US_ASCII, [].to_s.encoding) + assert_equal(Encoding::US_ASCII, [nil].to_s.encoding) + assert_equal(Encoding::US_ASCII, [1].to_s.encoding) + assert_equal("".inspect.encoding, [""].to_s.encoding) + assert_equal("a".inspect.encoding, ["a"].to_s.encoding) + assert_equal(Encoding::US_ASCII, [nil,1,"","a","\x20",[]].to_s.encoding) + end + + def test_hash_to_s + assert_equal(Encoding::US_ASCII, {}.to_s.encoding) + assert_equal(Encoding::US_ASCII, {1=>nil,"foo"=>""}.to_s.encoding) + end + + def test_encoding_find + assert_raise(TypeError) {Encoding.find(nil)} + assert_raise(TypeError) {Encoding.find(0)} + assert_raise(TypeError) {Encoding.find([])} + assert_raise(TypeError) {Encoding.find({})} + end + + def test_encoding_to_s + assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.to_s.encoding) + assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.inspect.encoding) + end + + def test_regexp_source + s = "\xa4\xa2".force_encoding("euc-jp") + r = Regexp.new(s) + t = r.source + assert_equal(s, t, "[ruby-dev:33377] Regexp.new(#{encdump s}).source") + end + + def test_magic_comment + assert_equal(Encoding::US_ASCII, eval("__ENCODING__".force_encoding("US-ASCII"))) + assert_equal(Encoding::ASCII_8BIT, eval("__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::US_ASCII, eval("# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::ASCII_8BIT, eval("# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII"))) + end + + def test_magic_comment_vim + assert_equal(Encoding::US_ASCII, eval("# vim: filetype=ruby, fileencoding: US-ASCII, ts=3, sw=3\n__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::ASCII_8BIT, eval("# vim: filetype=ruby, fileencoding: ASCII-8BIT, ts=3, sw=3\n__ENCODING__".force_encoding("US-ASCII"))) + end + + def test_magic_comment_at_various_positions + # after shebang + assert_equal(Encoding::US_ASCII, eval("#!/usr/bin/ruby\n# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::ASCII_8BIT, eval("#!/usr/bin/ruby\n# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII"))) + # wrong position + assert_equal(Encoding::ASCII_8BIT, eval("\n# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::US_ASCII, eval("\n# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII"))) + + # leading expressions + assert_equal(Encoding::ASCII_8BIT, eval("v=1 # -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT"))) + assert_equal(Encoding::US_ASCII, eval("v=1 # -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII"))) + end + + def test_regexp_usascii + assert_regexp_usascii_literal('//', Encoding::US_ASCII) + assert_regexp_usascii_literal('/#{ }/', Encoding::US_ASCII) + assert_regexp_usascii_literal('/#{"a"}/', Encoding::US_ASCII) + assert_regexp_usascii_literal('/#{%q"\x80"}/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/#{"\x80"}/', nil, SyntaxError) + + assert_regexp_usascii_literal('/a/', Encoding::US_ASCII) + assert_regexp_usascii_literal('/a#{ }/', Encoding::US_ASCII) + assert_regexp_usascii_literal('/a#{"a"}/', Encoding::US_ASCII) + assert_regexp_usascii_literal('/a#{%q"\x80"}/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/a#{"\x80"}/', nil, SyntaxError) + + assert_regexp_usascii_literal('/\x80/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/\x80#{ }/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/\x80#{"a"}/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/\x80#{%q"\x80"}/', Encoding::ASCII_8BIT) + assert_regexp_usascii_literal('/\x80#{"\x80"}/', nil, SyntaxError) + + assert_regexp_usascii_literal('/\u1234/', Encoding::UTF_8) + assert_regexp_usascii_literal('/\u1234#{ }/', Encoding::UTF_8) + assert_regexp_usascii_literal('/\u1234#{"a"}/', Encoding::UTF_8) + assert_regexp_usascii_literal('/\u1234#{%q"\x80"}/', nil, SyntaxError) + assert_regexp_usascii_literal('/\u1234#{"\x80"}/', nil, SyntaxError) + assert_regexp_usascii_literal('/\u1234\x80/', nil, SyntaxError) + assert_regexp_usascii_literal('/\u1234#{ }\x80/', nil, RegexpError) + end + + def test_gbk + assert_equal("", "\x81\x40".force_encoding("GBK").chop) + end + + def test_euc_tw + assert_equal("a", "a\x8e\xa2\xa1\xa1".force_encoding("euc-tw").chop) + end + + def test_valid_encoding + s = "\xa1".force_encoding("euc-jp") + assert_equal(false, s.valid_encoding?) + assert_equal(true, (s+s).valid_encoding?, "[ruby-dev:33826]") + assert_equal(true, (s*2).valid_encoding?, "[ruby-dev:33826]") + assert_equal(true, ("%s%s" % [s, s]).valid_encoding?) + assert_equal(true, (s.dup << s).valid_encoding?) + assert_equal(true, "".center(2, s).valid_encoding?) + + s = "\xa1\xa1\x8f".force_encoding("euc-jp") + assert_equal(false, s.valid_encoding?) + assert_equal(true, s.reverse.valid_encoding?) + + bug4018 = '[ruby-core:33027]' + s = "\xa1\xa1".force_encoding("euc-jp") + assert_equal(true, s.valid_encoding?) + s << "\x8f".force_encoding("euc-jp") + assert_equal(false, s.valid_encoding?, bug4018) + s = "aa".force_encoding("utf-16be") + assert_equal(true, s.valid_encoding?) + s << "\xff".force_encoding("utf-16be") + assert_equal(false, s.valid_encoding?, bug4018) + + bug6190 = '[ruby-core:43557]' + s = "\xe9" + s = s.encode("utf-8", "utf-8") + assert_equal(false, s.valid_encoding?, bug6190) + s = "\xe9" + s.encode!("utf-8", "utf-8") + assert_equal(false, s.valid_encoding?, bug6190) + end + + def test_getbyte + assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(2)) + assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(-4)) + assert_nil(u("\xE3\x81\x82\xE3\x81\x84").getbyte(100)) + end + + def test_setbyte + s = u("\xE3\x81\x82\xE3\x81\x84") + s.setbyte(2, 0x84) + assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s) + + s = u("\xE3\x81\x82\xE3\x81\x84") + assert_raise(IndexError) { s.setbyte(100, 0) } + + s = u("\xE3\x81\x82\xE3\x81\x84") + s.setbyte(-4, 0x84) + assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s) + end + + def test_compatible + assert_nil Encoding.compatible?("",0) + assert_equal(Encoding::UTF_8, Encoding.compatible?(u(""), ua("abc"))) + assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::UTF_8)) + assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::US_ASCII)) + assert_equal(Encoding::ASCII_8BIT, + Encoding.compatible?(Encoding::ASCII_8BIT, Encoding::US_ASCII)) + assert_nil Encoding.compatible?(Encoding::UTF_8, Encoding::ASCII_8BIT) + end + + def test_force_encoding + assert_equal(u("\x80"), "".center(1, u("\x80")), + "moved from btest/knownbug, [ruby-dev:33807]") + a = "".force_encoding("ascii-8bit") << 0xC3 << 0xB6 + assert_equal(1, a.force_encoding("utf-8").size, '[ruby-core:22437]') + b = "".force_encoding("ascii-8bit") << 0xC3.chr << 0xB6.chr + assert_equal(1, b.force_encoding("utf-8").size, '[ruby-core:22437]') + + assert_raise(TypeError){ ''.force_encoding(nil) } + end + + def test_combchar_codepoint + assert_equal([0x30BB, 0x309A], "\u30BB\u309A".codepoints.to_a) + assert_equal([0x30BB, 0x309A], "\u30BB\u309A".codepoints.to_a) + end + + def each_encoding(*strings) + Encoding.list.each do |enc| + next if enc.dummy? + strs = strings.map {|s| s.encode(enc)} rescue next + yield(*strs) + end + end + + def test_str_b + s = "\u3042" + assert_equal(a("\xE3\x81\x82"), s.b) + assert_equal(Encoding::ASCII_8BIT, s.b.encoding) + s.taint + assert_equal(true, s.b.tainted?) + s = "abc".b + assert_equal(true, s.b.ascii_only?) + end + + def test_scrub + str = "\u3042\u3044" + assert_not_same(str, str.scrub) + str.force_encoding(Encoding::ISO_2022_JP) # dummy encoding + assert_not_same(str, str.scrub) + assert_nothing_raised(ArgumentError) {str.scrub(nil)} + + assert_equal("\uFFFD\uFFFD\uFFFD", u("\x80\x80\x80").scrub) + assert_equal("\uFFFDA", u("\xF4\x80\x80A").scrub) + + # examples in Unicode 6.1.0 D93b + assert_equal("\x41\uFFFD\uFFFD\x41\uFFFD\x41", + u("\x41\xC0\xAF\x41\xF4\x80\x80\x41").scrub) + assert_equal("\x41\uFFFD\uFFFD\uFFFD\x41", + u("\x41\xE0\x9F\x80\x41").scrub) + assert_equal("\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064", + u("\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64").scrub) + assert_equal("abcdefghijklmnopqrstuvwxyz\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064", + u("abcdefghijklmnopqrstuvwxyz\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64").scrub) + + assert_equal("\u3042\u3013", u("\xE3\x81\x82\xE3\x81").scrub("\u3013")) + assert_raise(Encoding::CompatibilityError){ u("\xE3\x81\x82\xE3\x81").scrub(e("\xA4\xA2")) } + assert_raise(TypeError){ u("\xE3\x81\x82\xE3\x81").scrub(1) } + assert_raise(ArgumentError){ u("\xE3\x81\x82\xE3\x81\x82\xE3\x81").scrub(u("\x81")) } + assert_equal(e("\xA4\xA2\xA2\xAE"), e("\xA4\xA2\xA4").scrub(e("\xA2\xAE"))) + + assert_equal("\u3042<e381>", u("\xE3\x81\x82\xE3\x81").scrub{|x|'<'+x.unpack('H*')[0]+'>'}) + assert_raise(Encoding::CompatibilityError){ u("\xE3\x81\x82\xE3\x81").scrub{e("\xA4\xA2")} } + assert_raise(TypeError){ u("\xE3\x81\x82\xE3\x81").scrub{1} } + assert_raise(ArgumentError){ u("\xE3\x81\x82\xE3\x81\x82\xE3\x81").scrub{u("\x81")} } + assert_equal(e("\xA4\xA2\xA2\xAE"), e("\xA4\xA2\xA4").scrub{e("\xA2\xAE")}) + + assert_equal(u("\x81"), u("a\x81").scrub {|c| break c}) + assert_raise(ArgumentError) {u("a\x81").scrub {|c| c}} + + assert_equal("\uFFFD\u3042".encode("UTF-16BE"), + "\xD8\x00\x30\x42".force_encoding(Encoding::UTF_16BE). + scrub) + assert_equal("\uFFFD\u3042".encode("UTF-16LE"), + "\x00\xD8\x42\x30".force_encoding(Encoding::UTF_16LE). + scrub) + assert_equal("\uFFFD".encode("UTF-32BE"), + "\xff".force_encoding(Encoding::UTF_32BE). + scrub) + assert_equal("\uFFFD".encode("UTF-32LE"), + "\xff".force_encoding(Encoding::UTF_32LE). + scrub) + end + + def test_scrub_bang + str = "\u3042\u3044" + assert_same(str, str.scrub!) + str.force_encoding(Encoding::ISO_2022_JP) # dummy encoding + assert_same(str, str.scrub!) + assert_nothing_raised(ArgumentError) {str.scrub!(nil)} + + str = u("\x80\x80\x80") + str.scrub! + assert_same(str, str.scrub!) + assert_equal("\uFFFD\uFFFD\uFFFD", str) + end + + def test_escaped_metachar + bug10670 = '[ruby-core:67193] [Bug #10670]' + + escape_plain = /\A[\x5B]*\z/.freeze + + assert_match(escape_plain, 0x5b.chr(::Encoding::UTF_8), bug10670) + assert_match(escape_plain, 0x5b.chr, bug10670) + end +end diff --git a/jni/ruby/test/ruby/test_m17n_comb.rb b/jni/ruby/test/ruby/test_m17n_comb.rb new file mode 100644 index 0000000..3a37ed4 --- /dev/null +++ b/jni/ruby/test/ruby/test_m17n_comb.rb @@ -0,0 +1,1638 @@ +require 'test/unit' +require 'etc' +require_relative 'allpairs' + +class TestM17NComb < Test::Unit::TestCase + def assert_encoding(encname, actual, message=nil) + assert_equal(Encoding.find(encname), actual, message) + end + + module AESU + def a(str) str.dup.force_encoding(Encoding::US_ASCII) end + def b(str) str.b end + def e(str) str.dup.force_encoding(Encoding::EUC_JP) end + def s(str) str.dup.force_encoding(Encoding::SJIS) end + def u(str) str.dup.force_encoding(Encoding::UTF_8) end + end + include AESU + extend AESU + + def assert_strenc(bytes, enc, actual, message=nil) + assert_instance_of(String, actual, message) + enc = Encoding.find(enc) if String === enc + assert_equal(enc, actual.encoding, message) + assert_equal(b(bytes), b(actual), message) + end + + STRINGS = [ + b(""), e(""), s(""), u(""), + b("a"), e("a"), s("a"), u("a"), + b("."), e("."), s("."), u("."), + + # single character + b("\x80"), b("\xff"), + e("\xa1\xa1"), e("\xfe\xfe"), + e("\x8e\xa1"), e("\x8e\xfe"), + e("\x8f\xa1\xa1"), e("\x8f\xfe\xfe"), + s("\x81\x40"), s("\xfc\xfc"), + s("\xa1"), s("\xdf"), + u("\xc2\x80"), u("\xf4\x8f\xbf\xbf"), + + # same byte sequence + b("\xc2\xa1"), e("\xc2\xa1"), s("\xc2\xa1"), u("\xc2\xa1"), + + s("\x81A"), # mutibyte character which contains "A" + s("\x81a"), # mutibyte character which contains "a" + + # invalid + e("\xa1"), e("\x80"), + s("\x81"), s("\x80"), + u("\xc2"), u("\x80"), + + # for transitivity test + u("\xe0\xa0\xa1"), e("\xe0\xa0\xa1"), s("\xe0\xa0\xa1"), # [ruby-dev:32693] + e("\xa1\xa1"), b("\xa1\xa1"), s("\xa1\xa1"), # [ruby-dev:36484] + ] + + WSTRINGS = [ + "aa".force_encoding("utf-16be"), + "aaaa".force_encoding("utf-32be"), + "aaa".force_encoding("utf-32be"), + ] + + def combination(*args, &b) + AllPairs.each(*args, &b) + #AllPairs.exhaustive_each(*args, &b) + end + + def encdump(str) + d = str.dump + if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d + d + else + "#{d}.force_encoding(#{str.encoding.name.dump})" + end + end + + def encdumpargs(args) + r = '(' + args.each_with_index {|a, i| + r << ',' if 0 < i + if String === a + r << encdump(a) + else + r << a.inspect + end + } + r << ')' + r + end + + def encdumpcall(recv, meth, *args, &block) + desc = '' + if String === recv + desc << encdump(recv) + else + desc << recv.inspect + end + desc << '.' << meth.to_s + if !args.empty? + desc << '(' + args.each_with_index {|a, i| + desc << ',' if 0 < i + if String === a + desc << encdump(a) + else + desc << a.inspect + end + } + desc << ')' + end + if block + desc << ' {}' + end + desc + end + + def assert_enccall(recv, meth, *args, &block) + desc = encdumpcall(recv, meth, *args, &block) + result = nil + assert_nothing_raised(desc) { + result = recv.send(meth, *args, &block) + } + result + end + alias enccall assert_enccall + + def assert_str_enc_propagation(t, s1, s2) + if !s1.ascii_only? + assert_equal(s1.encoding, t.encoding) + elsif !s2.ascii_only? + assert_equal(s2.encoding, t.encoding) + else + assert_include([s1.encoding, s2.encoding], t.encoding) + end + end + + def assert_same_result(expected_proc, actual_proc) + e = nil + begin + t = expected_proc.call + rescue + e = $! + end + if e + assert_raise(e.class) { actual_proc.call } + else + assert_equal(t, actual_proc.call) + end + end + + def each_slice_call + combination(STRINGS, -2..2) {|s, nth| + yield s, nth + } + combination(STRINGS, -2..2, 0..2) {|s, nth, len| + yield s, nth, len + } + combination(STRINGS, STRINGS) {|s, substr| + yield s, substr + } + combination(STRINGS, -2..2, 0..2) {|s, first, last| + yield s, first..last + yield s, first...last + } + combination(STRINGS, STRINGS) {|s1, s2| + if !s2.valid_encoding? + next + end + yield s1, Regexp.new(Regexp.escape(s2)) + } + combination(STRINGS, STRINGS, 0..2) {|s1, s2, nth| + if !s2.valid_encoding? + next + end + yield s1, Regexp.new(Regexp.escape(s2)), nth + } + end + + ASCII_INCOMPATIBLE_ENCODINGS = %w[ + UTF-16BE + UTF-16LE + UTF-32BE + UTF-32LE + ] + def str_enc_compatible?(*strs) + encs = [] + ascii_incompatible_encodings = {} + has_ascii_compatible = false + strs.each {|s| + encs << s.encoding if !s.ascii_only? + if /\A#{Regexp.union ASCII_INCOMPATIBLE_ENCODINGS}\z/o =~ s.encoding.name + ascii_incompatible_encodings[s.encoding] = true + else + has_ascii_compatible = true + end + } + if ascii_incompatible_encodings.empty? + encs.uniq! + encs.length <= 1 + else + !has_ascii_compatible && ascii_incompatible_encodings.size == 1 + end + end + + # tests start + + def test_str_new + STRINGS.each {|s| + t = String.new(s) + assert_strenc(b(s), s.encoding, t) + } + end + + def test_str_plus + combination(STRINGS, STRINGS) {|s1, s2| + if s1.encoding != s2.encoding && !s1.ascii_only? && !s2.ascii_only? + assert_raise(Encoding::CompatibilityError) { s1 + s2 } + else + t = enccall(s1, :+, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(b(s1) + b(s2), b(t)) + assert_str_enc_propagation(t, s1, s2) + end + } + end + + def test_str_times + STRINGS.each {|s| + [0,1,2].each {|n| + t = s * n + assert_predicate(t, :valid_encoding?) if s.valid_encoding? + assert_strenc(b(s) * n, s.encoding, t) + } + } + end + + def test_sprintf_s + STRINGS.each {|s| + assert_strenc(b(s), s.encoding, "%s".force_encoding(s.encoding) % s) + if !s.empty? # xxx + t = enccall(b("%s"), :%, s) + assert_strenc(b(s), (b('')+s).encoding, t) + end + } + end + + def test_str_eq_reflexive + STRINGS.each {|s| + assert_equal(s, s, "#{encdump s} == #{encdump s}") + } + end + + def test_str_eq_symmetric + combination(STRINGS, STRINGS) {|s1, s2| + if s1 == s2 + assert_equal(s2, s1, "#{encdump s2} == #{encdump s1}") + else + assert_not_equal(s2, s1, "!(#{encdump s2} == #{encdump s1})") + end + } + end + + def test_str_eq_transitive + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + if s1 == s2 && s2 == s3 + assert_equal(s1, s3, "transitive: #{encdump s1} == #{encdump s2} == #{encdump s3}") + end + } + end + + def test_str_eq + combination(STRINGS, STRINGS) {|s1, s2| + desc_eq = "#{encdump s1} == #{encdump s2}" + if b(s1) == b(s2) and + (s1.ascii_only? && s2.ascii_only? or + s1.encoding == s2.encoding) then + assert_operator(s1, :==, s2, desc_eq) + assert_not_operator(s1, :!=, s2) + assert_equal(0, s1 <=> s2) + assert_operator(s1, :eql?, s2, desc_eq) + else + assert_not_operator(s1, :==, s2, "!(#{desc_eq})") + assert_operator(s1, :!=, s2) + assert_not_equal(0, s1 <=> s2) + assert_not_operator(s1, :eql?, s2) + end + } + end + + def test_str_concat + combination(STRINGS, STRINGS) {|s1, s2| + s = s1.dup + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + s << s2 + assert_predicate(s, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(b(s), b(s1) + b(s2)) + assert_str_enc_propagation(s, s1, s2) + else + assert_raise(Encoding::CompatibilityError) { s << s2 } + end + } + end + + def test_str_aref + STRINGS.each {|s| + t = ''.force_encoding(s.encoding) + 0.upto(s.length-1) {|i| + u = s[i] + assert_predicate(u, :valid_encoding?) if s.valid_encoding? + t << u + } + assert_equal(t, s) + } + end + + def test_str_aref_len + STRINGS.each {|s| + t = ''.force_encoding(s.encoding) + 0.upto(s.length-1) {|i| + u = s[i,1] + assert_predicate(u, :valid_encoding?) if s.valid_encoding? + t << u + } + assert_equal(t, s) + } + + STRINGS.each {|s| + t = ''.force_encoding(s.encoding) + 0.step(s.length-1, 2) {|i| + u = s[i,2] + assert_predicate(u, :valid_encoding?) if s.valid_encoding? + t << u + } + assert_equal(t, s) + } + end + + def test_str_aref_substr + combination(STRINGS, STRINGS) {|s1, s2| + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + t = enccall(s1, :[], s2) + if t != nil + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(s2, t) + assert_match(/#{Regexp.escape(b(s2))}/, b(s1)) + if s1.valid_encoding? + assert_match(/#{Regexp.escape(s2)}/, s1) + end + end + else + assert_raise(Encoding::CompatibilityError) { s1[s2] } + end + } + end + + def test_str_aref_range2 + combination(STRINGS, -2..2, -2..2) {|s, first, last| + desc = "#{encdump s}[#{first}..#{last}]" + t = s[first..last] + if first < 0 + first += s.length + if first < 0 + assert_nil(t, desc) + next + end + end + if s.length < first + assert_nil(t, desc) + next + end + assert_predicate(t, :valid_encoding?) if s.valid_encoding? + if last < 0 + last += s.length + end + t2 = '' + first.upto(last) {|i| + c = s[i] + t2 << c if c + } + assert_equal(t2, t, desc) + } + end + + def test_str_aref_range3 + combination(STRINGS, -2..2, -2..2) {|s, first, last| + desc = "#{encdump s}[#{first}..#{last}]" + t = s[first...last] + if first < 0 + first += s.length + if first < 0 + assert_nil(t, desc) + next + end + end + if s.length < first + assert_nil(t, desc) + next + end + if last < 0 + last += s.length + end + assert_predicate(t, :valid_encoding?) if s.valid_encoding? + t2 = '' + first.upto(last-1) {|i| + c = s[i] + t2 << c if c + } + assert_equal(t2, t, desc) + } + end + + def test_str_assign + combination(STRINGS, STRINGS) {|s1, s2| + (-2).upto(2) {|i| + t = s1.dup + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + if i < -s1.length || s1.length < i + assert_raise(IndexError) { t[i] = s2 } + else + t[i] = s2 + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s2)]) + if s1.valid_encoding? && s2.valid_encoding? + if i == s1.length && s2.empty? + assert_nil(t[i]) + elsif i < 0 + assert_equal(s2, t[i-s2.length+1,s2.length], + "t = #{encdump(s1)}; t[#{i}] = #{encdump(s2)}; t[#{i-s2.length+1},#{s2.length}]") + else + assert_equal(s2, t[i,s2.length], + "t = #{encdump(s1)}; t[#{i}] = #{encdump(s2)}; t[#{i},#{s2.length}]") + end + end + end + else + assert_raise(Encoding::CompatibilityError) { t[i] = s2 } + end + } + } + end + + def test_str_assign_len + combination(STRINGS, -2..2, 0..2, STRINGS) {|s1, i, len, s2| + t = s1.dup + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + if i < -s1.length || s1.length < i + assert_raise(IndexError) { t[i,len] = s2 } + else + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + t[i,len] = s2 + assert_send([b(t), :index, b(s2)]) + if s1.valid_encoding? && s2.valid_encoding? + if i == s1.length && s2.empty? + assert_nil(t[i]) + elsif i < 0 + if -i < len + len = -i + end + assert_equal(s2, t[i-s2.length+len,s2.length], + "t = #{encdump(s1)}; t[#{i},#{len}] = #{encdump(s2)}; t[#{i-s2.length+len},#{s2.length}]") + else + assert_equal(s2, t[i,s2.length], + "t = #{encdump(s1)}; t[#{i},#{len}] = #{encdump(s2)}; t[#{i},#{s2.length}]") + end + end + end + else + assert_raise(Encoding::CompatibilityError) { t[i,len] = s2 } + end + } + end + + def test_str_assign_substr + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + t = s1.dup + encs = [ + !s1.ascii_only? ? s1.encoding : nil, + !s2.ascii_only? ? s2.encoding : nil, + !s3.ascii_only? ? s3.encoding : nil].uniq.compact + if 1 < encs.length + assert_raise(Encoding::CompatibilityError, IndexError) { t[s2] = s3 } + else + if encs.empty? + encs = [ + s1.encoding, + s2.encoding, + s3.encoding].uniq.reject {|e| e == Encoding.find("ASCII-8BIT") } + if encs.empty? + encs = [Encoding.find("ASCII-8BIT")] + end + end + if !t[s2] + else + enccall(t, :[]=, s2, s3) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? && s3.valid_encoding? + end + end + } + end + + def test_str_assign_range2 + combination(STRINGS, -2..2, -2..2, STRINGS) {|s1, first, last, s2| + t = s1.dup + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + if first < -s1.length || s1.length < first + assert_raise(RangeError) { t[first..last] = s2 } + else + enccall(t, :[]=, first..last, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s2)]) + if s1.valid_encoding? && s2.valid_encoding? + if first < 0 + assert_equal(s2, t[s1.length+first, s2.length]) + else + assert_equal(s2, t[first, s2.length]) + end + end + end + else + assert_raise(Encoding::CompatibilityError, RangeError, + "t=#{encdump(s1)};t[#{first}..#{last}]=#{encdump(s2)}") { + t[first..last] = s2 + } + end + } + end + + def test_str_assign_range3 + combination(STRINGS, -2..2, -2..2, STRINGS) {|s1, first, last, s2| + t = s1.dup + if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding + if first < -s1.length || s1.length < first + assert_raise(RangeError) { t[first...last] = s2 } + else + enccall(t, :[]=, first...last, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s2)]) + if s1.valid_encoding? && s2.valid_encoding? + if first < 0 + assert_equal(s2, t[s1.length+first, s2.length]) + else + assert_equal(s2, t[first, s2.length]) + end + end + end + else + assert_raise(Encoding::CompatibilityError, RangeError, + "t=#{encdump(s1)};t[#{first}...#{last}]=#{encdump(s2)}") { + t[first...last] = s2 + } + end + } + end + + def test_str_cmp + combination(STRINGS, STRINGS) {|s1, s2| + desc = "#{encdump s1} <=> #{encdump s2}" + r = s1 <=> s2 + if s1 == s2 + assert_equal(0, r, desc) + else + assert_not_equal(0, r, desc) + end + } + end + + def test_str_capitalize + STRINGS.each {|s| + begin + t1 = s.capitalize + rescue ArgumentError + assert_not_predicate(s, :valid_encoding?) + next + end + assert_predicate(t1, :valid_encoding?) if s.valid_encoding? + assert_operator(t1, :casecmp, s) + t2 = s.dup + t2.capitalize! + assert_equal(t1, t2) + r = s.downcase + r = enccall(r, :sub, /\A[a-z]/) {|ch| b(ch).upcase } + assert_equal(r, t1) + } + end + + def test_str_casecmp + combination(STRINGS, STRINGS) {|s1, s2| + #puts "#{encdump(s1)}.casecmp(#{encdump(s2)})" + next unless s1.valid_encoding? && s2.valid_encoding? && Encoding.compatible?(s1, s2) + r = s1.casecmp(s2) + assert_equal(s1.upcase <=> s2.upcase, r) + } + end + + def test_str_center + combination(STRINGS, [0,1,2,3,10]) {|s1, width| + t = s1.center(width) + assert_send([b(t), :index, b(s1)]) + } + combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2| + if s2.empty? + assert_raise(ArgumentError) { s1.center(width, s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.center(width, s2) } + next + end + t = enccall(s1, :center, width, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s1)]) + assert_str_enc_propagation(t, s1, s2) if (t != s1) + } + end + + def test_str_ljust + combination(STRINGS, [0,1,2,3,10]) {|s1, width| + t = s1.ljust(width) + assert_send([b(t), :index, b(s1)]) + } + combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2| + if s2.empty? + assert_raise(ArgumentError) { s1.ljust(width, s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.ljust(width, s2) } + next + end + t = enccall(s1, :ljust, width, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s1)]) + assert_str_enc_propagation(t, s1, s2) if (t != s1) + } + end + + def test_str_rjust + combination(STRINGS, [0,1,2,3,10]) {|s1, width| + t = s1.rjust(width) + assert_send([b(t), :index, b(s1)]) + } + combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2| + if s2.empty? + assert_raise(ArgumentError) { s1.rjust(width, s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.rjust(width, s2) } + next + end + t = enccall(s1, :rjust, width, s2) + assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_send([b(t), :index, b(s1)]) + assert_str_enc_propagation(t, s1, s2) if (t != s1) + } + end + + def test_str_chomp + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.ascii_only? && !s2.ascii_only? && !Encoding.compatible?(s1,s2) + if s1.bytesize > s2.bytesize + assert_raise(Encoding::CompatibilityError, "#{encdump(s1)}.chomp(#{encdump(s2)})") do + s1.chomp(s2) + end + end + next + end + t = enccall(s1, :chomp, s2) + assert_predicate(t, :valid_encoding?, "#{encdump(s1)}.chomp(#{encdump(s2)})") if s1.valid_encoding? && s2.valid_encoding? + assert_equal(s1.encoding, t.encoding) + t2 = s1.dup + t2.chomp!(s2) + assert_equal(t, t2) + } + end + + def test_str_smart_chomp + bug10893 = '[ruby-core:68258] [Bug #10893]' + encodings = Encoding.list.select {|enc| !enc.dummy?} + combination(encodings, encodings) do |e1, e2| + expected = "abc".encode(e1) + combination(["abc\n", "abc\r\n"], ["", "\n"]) do |str, rs| + assert_equal(expected, str.encode(e1).chomp(rs.encode(e2)), bug10893) + end + end + end + + def test_str_chop + STRINGS.each {|s| + s = s.dup + desc = "#{encdump s}.chop" + t = nil + assert_nothing_raised(desc) { t = s.chop } + assert_predicate(t, :valid_encoding?) if s.valid_encoding? + assert_send([b(s), :index, b(t)]) + t2 = s.dup + t2.chop! + assert_equal(t, t2) + } + end + + def test_str_clear + STRINGS.each {|s| + t = s.dup + t.clear + assert_predicate(t, :valid_encoding?) + assert_empty(t) + } + end + + def test_str_clone + STRINGS.each {|s| + t = s.clone + assert_equal(s, t) + assert_equal(s.encoding, t.encoding) + assert_equal(b(s), b(t)) + } + end + + def test_str_dup + STRINGS.each {|s| + t = s.dup + assert_equal(s, t) + assert_equal(s.encoding, t.encoding) + assert_equal(b(s), b(t)) + } + end + + def test_str_count + combination(STRINGS, STRINGS) {|s1, s2| + desc = proc {encdumpcall(s1, :count, s2)} + if !s1.valid_encoding? || !s2.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.count(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError, desc) { s1.count(s2) } + next + end + n = enccall(s1, :count, s2) + n0 = b(s1).count(b(s2)) + assert_operator(n, :<=, n0) + } + end + + # glibc 2.16 or later denies salt contained other than [0-9A-Za-z./] #7312 + # we use this check to test strict and non-strict behavior separately #11045 + strict_crypt = if defined? Etc::CS_GNU_LIBC_VERSION + glibcver = Etc.confstr(Etc::CS_GNU_LIBC_VERSION).scan(/\d+/).map(&:to_i) + (glibcver <=> [2, 16]) >= 0 + end + + def test_str_crypt + combination(STRINGS, STRINGS) {|str, salt| + # skip input other than [0-9A-Za-z./] to confirm strict behavior + next unless salt.ascii_only? && /\A[0-9a-zA-Z.\/]+\z/ =~ salt + + confirm_crypt_result(str, salt) + } + end + + if !strict_crypt + def test_str_crypt_nonstrict + combination(STRINGS, STRINGS) {|str, salt| + # only test input other than [0-9A-Za-z./] to confirm non-strict behavior + next if salt.ascii_only? && /\A[0-9a-zA-Z.\/]+\z/ =~ salt + + confirm_crypt_result(str, salt) + } + end + end + + private def confirm_crypt_result(str, salt) + if b(salt).length < 2 + assert_raise(ArgumentError) { str.crypt(salt) } + return + end + t = str.crypt(salt) + assert_equal(b(str).crypt(b(salt)), t, "#{encdump(str)}.crypt(#{encdump(salt)})") + assert_encoding('ASCII-8BIT', t.encoding) + end + + def test_str_delete + combination(STRINGS, STRINGS) {|s1, s2| + if s1.empty? + assert_equal(s1, s1.delete(s2)) + next + end + if !s1.valid_encoding? || !s2.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.delete(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.delete(s2) } + next + end + t = enccall(s1, :delete, s2) + assert_predicate(t, :valid_encoding?) + assert_equal(t.encoding, s1.encoding) + assert_operator(t.length, :<=, s1.length) + t2 = s1.dup + t2.delete!(s2) + assert_equal(t, t2) + } + end + + def test_str_downcase + STRINGS.each {|s| + if !s.valid_encoding? + assert_raise(ArgumentError) { s.downcase } + next + end + t = s.downcase + assert_predicate(t, :valid_encoding?) + assert_equal(t.encoding, s.encoding) + assert_operator(t, :casecmp, s) + t2 = s.dup + t2.downcase! + assert_equal(t, t2) + } + end + + def test_str_dump + STRINGS.each {|s| + t = s.dump + assert_predicate(t, :valid_encoding?) + assert_predicate(t, :ascii_only?) + u = eval(t) + assert_equal(b(s), b(u)) + } + end + + def test_str_each_line + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.each_line(s2) {} } + next + end + lines = [] + enccall(s1, :each_line, s2) {|line| + assert_equal(s1.encoding, line.encoding) + lines << line + } + next if lines.size == 0 + s2 = lines.join('') + assert_equal(s1.encoding, s2.encoding) + assert_equal(s1, s2) + } + end + + def test_str_each_byte + STRINGS.each {|s| + bytes = [] + s.each_byte {|b| + bytes << b + } + b(s).split(//).each_with_index {|ch, i| + assert_equal(ch.ord, bytes[i]) + } + } + end + + def test_str_empty? + STRINGS.each {|s| + if s.length == 0 + assert_empty(s) + else + assert_not_empty(s) + end + } + end + + def test_str_hex + STRINGS.each {|s| + t = s.hex + t2 = b(s)[/\A[0-9a-fA-Fx]*/].hex + assert_equal(t2, t) + } + end + + def test_str_include? + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.include?(s2) } + assert_raise(Encoding::CompatibilityError) { s1.index(s2) } + assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) } + next + end + t = enccall(s1, :include?, s2) + if t + assert_include(b(s1), b(s2)) + assert_send([s1, :index, s2]) + assert_send([s1, :rindex, s2]) + else + assert_not_send([s1, :index, s2]) + assert_not_send([s1, :rindex, s2], "!#{encdump(s1)}.rindex(#{encdump(s2)})") + end + if s2.empty? + assert_equal(true, t) + next + end + if !s1.valid_encoding? || !s2.valid_encoding? + assert_equal(false, t, "#{encdump s1}.include?(#{encdump s2})") + next + end + if t && s1.valid_encoding? && s2.valid_encoding? + assert_match(/#{Regexp.escape(s2)}/, s1) + else + assert_no_match(/#{Regexp.escape(s2)}/, s1) + end + } + end + + def test_str_index + combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos| + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.index(s2) } + next + end + t = enccall(s1, :index, s2, pos) + if s2.empty? + if pos < 0 && pos+s1.length < 0 + assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})"); + elsif pos < 0 + assert_equal(s1.length+pos, t, "#{encdump s1}.index(#{encdump s2}, #{pos})"); + elsif s1.length < pos + assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})"); + else + assert_equal(pos, t, "#{encdump s1}.index(#{encdump s2}, #{pos})"); + end + next + end + if !s1.valid_encoding? || !s2.valid_encoding? + assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})"); + next + end + if t + re = /#{Regexp.escape(s2)}/ + assert(re.match(s1, pos)) + assert_equal($`.length, t, "#{encdump s1}.index(#{encdump s2}, #{pos})") + else + assert_no_match(/#{Regexp.escape(s2)}/, s1[pos..-1]) + end + } + end + + def test_str_rindex + combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos| + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) } + next + end + t = enccall(s1, :rindex, s2, pos) + if s2.empty? + if pos < 0 && pos+s1.length < 0 + assert_equal(nil, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + elsif pos < 0 + assert_equal(s1.length+pos, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + elsif s1.length < pos + assert_equal(s1.length, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + else + assert_equal(pos, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + end + next + end + if !s1.valid_encoding? || !s2.valid_encoding? + assert_equal(nil, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + next + end + if t + #puts "#{encdump s1}.rindex(#{encdump s2}, #{pos}) => #{t}" + assert_send([b(s1), :index, b(s2)]) + pos2 = pos + pos2 += s1.length if pos < 0 + re = /\A(.{0,#{pos2}})#{Regexp.escape(s2)}/m + m = enccall(re, :match, s1) + assert(m, "#{re.inspect}.match(#{encdump(s1)})") + assert_equal(m[1].length, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})") + else + re = /#{Regexp.escape(s2)}/ + n = re =~ s1 + if n + if pos < 0 + assert_operator(n, :>, s1.length+pos) + else + assert_operator(n, :>, pos) + end + end + end + } + end + + def test_str_insert + combination(STRINGS, 0..2, STRINGS) {|s1, nth, s2| + t1 = s1.dup + t2 = s1.dup + begin + t1[nth, 0] = s2 + rescue Encoding::CompatibilityError, IndexError => e1 + end + begin + t2.insert(nth, s2) + rescue Encoding::CompatibilityError, IndexError => e2 + end + assert_equal(t1, t2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t") + assert_equal(e1.class, e2.class, "begin #{encdump s1}.insert(#{nth},#{encdump s2}); rescue ArgumentError, IndexError => e; e end") + } + combination(STRINGS, -2..-1, STRINGS) {|s1, nth, s2| + next if s1.length + nth < 0 + next unless s1.valid_encoding? + next unless s2.valid_encoding? + t1 = s1.dup + begin + t1.insert(nth, s2) + slen = s2.length + assert_equal(t1[nth-slen+1,slen], s2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t") + rescue Encoding::CompatibilityError, IndexError + end + } + end + + def test_str_intern + STRINGS.each {|s| + if /\0/ =~ b(s) + assert_raise(ArgumentError) { s.intern } + elsif s.valid_encoding? + sym = s.intern + assert_equal(s, sym.to_s, "#{encdump s}.intern.to_s") + assert_equal(sym, s.to_sym) + else + assert_raise(EncodingError) { s.intern } + end + } + end + + def test_str_length + STRINGS.each {|s| + assert_operator(s.length, :<=, s.bytesize) + } + end + + def test_str_oct + STRINGS.each {|s| + t = s.oct + t2 = b(s)[/\A[0-9a-fA-FxX]*/].oct + assert_equal(t2, t) + } + end + + def test_str_replace + combination(STRINGS, STRINGS) {|s1, s2| + t = s1.dup + t.replace s2 + assert_equal(s2, t) + assert_equal(s2.encoding, t.encoding) + } + end + + def test_str_reverse + STRINGS.each {|s| + t = s.reverse + assert_equal(s.bytesize, t.bytesize) + if !s.valid_encoding? + assert_operator(t.length, :<=, s.length) + next + end + assert_equal(s, t.reverse) + } + end + + def test_str_scan + combination(STRINGS, STRINGS) {|s1, s2| + desc = proc {"#{s1.dump}.scan(#{s2.dump})"} + if !s2.valid_encoding? + assert_raise(RegexpError, desc) { s1.scan(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + if s1.valid_encoding? + assert_raise(Encoding::CompatibilityError, desc) { s1.scan(s2) } + else + assert_raise_with_message(ArgumentError, /invalid byte sequence/, desc) { s1.scan(s2) } + end + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError, desc) { s1.scan(s2) } + next + end + r = enccall(s1, :scan, s2) + r.each {|t| + assert_equal(s2, t, desc) + } + } + end + + def test_str_slice + each_slice_call {|obj, *args| + assert_same_result(lambda { obj[*args] }, lambda { obj.slice(*args) }) + } + end + + def test_str_slice! + each_slice_call {|s, *args| + desc_slice = "#{encdump s}.slice#{encdumpargs args}" + desc_slice_bang = "#{encdump s}.slice!#{encdumpargs args}" + t = s.dup + begin + r = t.slice!(*args) + rescue + e = $! + end + if e + assert_raise(e.class, desc_slice) { s.slice(*args) } + next + end + if !r + assert_nil(s.slice(*args), desc_slice) + next + end + assert_equal(s.slice(*args), r, desc_slice_bang) + assert_equal(s.bytesize, r.bytesize + t.bytesize) + if args.length == 1 && String === args[0] + assert_equal(args[0].encoding, r.encoding, + "#{encdump s}.slice!#{encdumpargs args}.encoding") + else + assert_equal(s.encoding, r.encoding, + "#{encdump s}.slice!#{encdumpargs args}.encoding") + end + if [s, *args].all? {|o| !(String === o) || o.valid_encoding? } + assert_predicate(r, :valid_encoding?) + assert_predicate(t, :valid_encoding?) + assert_equal(s.length, r.length + t.length) + end + } + end + + def test_str_split + combination(STRINGS, STRINGS) {|s1, s2| + if !s2.valid_encoding? + assert_raise(ArgumentError, RegexpError) { s1.split(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.split(s2) } + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError) { s1.split(s2) } + next + end + t = enccall(s1, :split, s2) + t.each {|r| + assert_include(b(s1), b(r)) + assert_equal(s1.encoding, r.encoding) + } + assert_include(b(s1), t.map {|u| b(u) }.join(b(s2))) + if s1.valid_encoding? && s2.valid_encoding? + t.each {|r| + assert_predicate(r, :valid_encoding?) + } + end + } + end + + def test_str_squeeze + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.valid_encoding? || !s2.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError, "#{encdump s1}.squeeze(#{encdump s2})") { s1.squeeze(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.squeeze(s2) } + next + end + t = enccall(s1, :squeeze, s2) + assert_operator(t.length, :<=, s1.length) + t2 = s1.dup + t2.squeeze!(s2) + assert_equal(t, t2) + } + end + + def test_str_strip + STRINGS.each {|s| + if !s.valid_encoding? + assert_raise(ArgumentError, "#{encdump s}.strip") { s.strip } + next + end + t = s.strip + l = s.lstrip + r = s.rstrip + assert_operator(l.length, :<=, s.length) + assert_operator(r.length, :<=, s.length) + assert_operator(t.length, :<=, l.length) + assert_operator(t.length, :<=, r.length) + t2 = s.dup + t2.strip! + assert_equal(t, t2) + l2 = s.dup + l2.lstrip! + assert_equal(l, l2) + r2 = s.dup + r2.rstrip! + assert_equal(r, r2) + } + end + + def test_str_sum + STRINGS.each {|s| + assert_equal(b(s).sum, s.sum) + } + end + + def test_str_swapcase + STRINGS.each {|s| + if !s.valid_encoding? + assert_raise(ArgumentError, "#{encdump s}.swapcase") { s.swapcase } + next + end + t1 = s.swapcase + assert_predicate(t1, :valid_encoding?) if s.valid_encoding? + assert_operator(t1, :casecmp, s) + t2 = s.dup + t2.swapcase! + assert_equal(t1, t2) + t3 = t1.swapcase + assert_equal(s, t3); + } + end + + + def test_str_to_f + STRINGS.each {|s| + assert_nothing_raised { s.to_f } + } + end + + def test_str_to_i + STRINGS.each {|s| + assert_nothing_raised { s.to_i } + 2.upto(36) {|radix| + assert_nothing_raised { s.to_i(radix) } + } + } + end + + def test_str_to_s + STRINGS.each {|s| + assert_same(s, s.to_s) + assert_same(s, s.to_str) + } + end + + def test_tr + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + desc = "#{encdump s1}.tr(#{encdump s2}, #{encdump s3})" + if s1.empty? + assert_equal(s1, s1.tr(s2, s3), desc) + next + end + if !str_enc_compatible?(s1, s2, s3) + assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) } + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError, desc) { s1.tr(s2, s3) } + next + end + if s2.empty? + t = enccall(s1, :tr, s2, s3) + assert_equal(s1, t, desc) + next + end + if !s2.valid_encoding? || !s3.valid_encoding? + assert_raise(ArgumentError, desc) { s1.tr(s2, s3) } + next + end + t = enccall(s1, :tr, s2, s3) + assert_operator(s1.length, :>=, t.length, desc) + } + end + + def test_tr_sjis + expected = "\x83}\x83~\x83\x80\x83\x81\x83\x82".force_encoding(Encoding::SJIS) + source = "\xCF\xD0\xD1\xD2\xD3".force_encoding(Encoding::SJIS) + from = "\xCF-\xD3".force_encoding(Encoding::SJIS) + to = "\x83}-\x83\x82".force_encoding(Encoding::SJIS) + assert_equal(expected, source.tr(from, to)) + + expected = "\x84}\x84~\x84\x80\x84\x81\x84\x82".force_encoding(Encoding::SJIS) + source = "\x84M\x84N\x84O\x84P\x84Q".force_encoding(Encoding::SJIS) + from = "\x84@-\x84`".force_encoding(Encoding::SJIS) + to = "\x84p-\x84\x91".force_encoding(Encoding::SJIS) + assert_equal(expected, source.tr(from, to)) + end + + def test_tr_s + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + desc = "#{encdump s1}.tr_s(#{encdump s2}, #{encdump s3})" + if s1.empty? + assert_equal(s1, s1.tr_s(s2, s3), desc) + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.tr_s(s2, s3) } + next + end + if !str_enc_compatible?(s1, s2, s3) + assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) } + next + end + if s2.empty? + t = enccall(s1, :tr_s, s2, s3) + assert_equal(s1, t, desc) + next + end + if !s2.valid_encoding? || !s3.valid_encoding? + assert_raise(ArgumentError, desc) { s1.tr_s(s2, s3) } + next + end + + t = enccall(s1, :tr_s, s2, s3) + assert_operator(s1.length, :>=, t.length, desc) + } + end + + def test_str_upcase + STRINGS.each {|s| + desc = "#{encdump s}.upcase" + if !s.valid_encoding? + assert_raise(ArgumentError, desc) { s.upcase } + next + end + t1 = s.upcase + assert_predicate(t1, :valid_encoding?) + assert_operator(t1, :casecmp, s) + t2 = s.dup + t2.upcase! + assert_equal(t1, t2) + } + end + + def test_str_succ + STRINGS.each {|s0| + next if s0.empty? + s = s0.dup + n = 300 + h = {} + n.times {|i| + if h[s] + assert(false, "#{encdump s} cycle with succ #{i-h[s]} times") + end + h[s] = i + assert_operator(s.length, :<=, s0.length + Math.log2(i+1) + 1, "#{encdump s0} succ #{i} times => #{encdump s}") + #puts encdump(s) + t = s.succ + if s.valid_encoding? + assert_predicate(t, :valid_encoding?, "#{encdump s}.succ.valid_encoding?") + end + s = t + } + } + + Encoding.list.each do |enc| + next if enc.dummy? + {"A"=>"B", "A1"=>"A2", "A9"=>"B0", "9"=>"10", "Z"=>"AA"}.each do |orig, expected| + s = orig.encode(enc) + assert_strenc(expected.encode(enc), enc, s.succ, proc {"#{orig.dump}.encode(#{enc}).succ"}) + end + end + end + + def test_str_succ2 + assert_equal(a("\x01\x00"), a("\x7f").succ) + assert_equal(b("\x01\x00"), b("\xff").succ) + end + + def test_str_hash + combination(STRINGS, STRINGS) {|s1, s2| + if s1.eql?(s2) + assert_equal(s1.hash, s2.hash, "#{encdump s1}.hash == #{encdump s2}.dump") + end + } + end + + def test_marshal + STRINGS.each {|s| + m = Marshal.dump(s) + t = Marshal.load(m) + assert_equal(s, t) + } + end + + def test_str_sub + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + if !s2.valid_encoding? + assert_raise(RegexpError) { Regexp.new(Regexp.escape(s2)) } + next + end + r2 = Regexp.new(Regexp.escape(s2)) + [ + [ + "#{encdump s1}.sub(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { s1.sub(r2, s3) }, + false + ], + [ + "#{encdump s1}.sub(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { s1.sub(r2) { s3 } }, + false + ], + [ + "#{encdump s1}.gsub(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { s1.gsub(r2, s3) }, + true + ], + [ + "#{encdump s1}.gsub(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { s1.gsub(r2) { s3 } }, + true + ] + ].each {|desc, doit, g| + if !s1.valid_encoding? + assert_raise(ArgumentError, desc) { doit.call } + next + end + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { doit.call } + next + end + if !enccall(s1, :include?, s2) + assert_equal(s1, doit.call) + next + end + if !str_enc_compatible?(g ? s1.gsub(r2, '') : s1.sub(r2, ''), s3) + assert_raise(Encoding::CompatibilityError, desc) { doit.call } + next + end + t = nil + assert_nothing_raised(desc) { + t = doit.call + } + if s2 == s3 + assert_equal(s1, t, desc) + else + assert_not_equal(s1, t, desc) + end + } + } + end + + def test_str_sub! + combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3| + if !s2.valid_encoding? + assert_raise(RegexpError) { Regexp.new(Regexp.escape(s2)) } + next + end + r2 = Regexp.new(Regexp.escape(s2)) + [ + [ + "t=#{encdump s1}.dup;t.sub!(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { t=s1.dup; [t, t.sub!(r2, s3)] }, + false + ], + [ + "t=#{encdump s1}.dup;t.sub!(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { t=s1.dup; [t, t.sub!(r2) { s3 }] }, + false + ], + [ + "t=#{encdump s1}.dup;t.gsub!(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { t=s1.dup; [t, t.gsub!(r2, s3)] }, + true + ], + [ + "t=#{encdump s1}.dup;t.gsub!(Regexp.new(#{encdump s2}), #{encdump s3})", + lambda { t=s1.dup; [t, t.gsub!(r2) { s3 }] }, + true + ] + ].each {|desc, doit, g| + if !s1.valid_encoding? + assert_raise(ArgumentError, desc) { doit.call } + next + end + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { doit.call } + next + end + if !enccall(s1, :include?, s2) + assert_equal([s1, nil], doit.call) + next + end + if !str_enc_compatible?(g ? s1.gsub(r2, '') : s1.sub(r2, ''), s3) + assert_raise(Encoding::CompatibilityError, desc) { doit.call } + next + end + t = ret = nil + assert_nothing_raised(desc) { + t, ret = doit.call + } + assert(ret) + if s2 == s3 + assert_equal(s1, t, desc) + else + assert_not_equal(s1, t, desc) + end + } + } + end + + def test_str_bytes + STRINGS.each {|s1| + ary = [] + s1.bytes.each {|b| + ary << b + } + assert_equal(s1.unpack("C*"), ary) + } + end + + def test_str_bytesize + STRINGS.each {|s1| + assert_equal(s1.unpack("C*").length, s1.bytesize) + } + end + + def test_str_chars + STRINGS.each {|s1| + ary = [] + s1.chars.each {|c| + ary << c + } + expected = [] + s1.length.times {|i| + expected << s1[i] + } + assert_equal(expected, ary) + } + end + + def test_str_chr + STRINGS.each {|s1| + if s1.empty? + assert_equal("", s1.chr) + next + end + assert_equal(s1[0], s1.chr) + } + end + + def test_str_end_with? + combination(STRINGS, STRINGS) {|s1, s2| + desc = "#{encdump s1}.end_with?(#{encdump s2})" + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { s1.end_with?(s2) } + next + end + if s1.length < s2.length + assert_equal(false, enccall(s1, :end_with?, s2), desc) + next + end + if s1[s1.length-s2.length, s2.length] == s2 + assert_equal(true, enccall(s1, :end_with?, s2), desc) + next + end + assert_equal(false, enccall(s1, :end_with?, s2), desc) + } + end + + def test_str_start_with? + combination(STRINGS, STRINGS) {|s1, s2| + desc = "#{encdump s1}.start_with?(#{encdump s2})" + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { s1.start_with?(s2) } + next + end + s1 = s1.dup.force_encoding("ASCII-8BIT") + s2 = s2.dup.force_encoding("ASCII-8BIT") + if s1.length < s2.length + assert_equal(false, enccall(s1, :start_with?, s2), desc) + next + end + if s1[0, s2.length] == s2 + assert_equal(true, enccall(s1, :start_with?, s2), desc) + next + end + assert_equal(false, enccall(s1, :start_with?, s2), desc) + } + end + + def test_str_ord + STRINGS.each {|s1| + if s1.empty? + assert_raise(ArgumentError) { s1.ord } + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError) { s1.ord } + next + end + assert_equal(s1[0].ord, s1.ord) + } + end + + def test_str_partition + combination(STRINGS, STRINGS) {|s1, s2| + desc = "#{encdump s1}.partition(#{encdump s2})" + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { s1.partition(s2) } + next + end + i = enccall(s1, :index, s2) + if !i + assert_equal([s1, "", ""], s1.partition(s2), desc) + next + end + assert_equal([s1[0,i], s2, s1[(i+s2.length)..-1]], s1.partition(s2), desc) + } + end + + def test_str_rpartition + combination(STRINGS, STRINGS) {|s1, s2| + desc = "#{encdump s1}.rpartition(#{encdump s2})" + if !str_enc_compatible?(s1, s2) + assert_raise(Encoding::CompatibilityError, desc) { s1.rpartition(s2) } + next + end + i = enccall(s1, :rindex, s2) + if !i + assert_equal(["", "", s1], s1.rpartition(s2), desc) + next + end + assert_equal([s1[0,i], s2, s1[(i+s2.length)..-1]], s1.rpartition(s2), desc) + } + end + +end diff --git a/jni/ruby/test/ruby/test_marshal.rb b/jni/ruby/test/ruby/test_marshal.rb new file mode 100644 index 0000000..3d5d6c9 --- /dev/null +++ b/jni/ruby/test/ruby/test_marshal.rb @@ -0,0 +1,650 @@ +require 'test/unit' +require 'tempfile' +require_relative 'marshaltestlib' + +class TestMarshal < Test::Unit::TestCase + include MarshalTestLib + + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def encode(o) + Marshal.dump(o) + end + + def decode(s) + Marshal.load(s) + end + + def fact(n) + return 1 if n == 0 + f = 1 + while n>0 + f *= n + n -= 1 + end + return f + end + + def test_marshal + a = [1, 2, 3, [4,5,"foo"], {1=>"bar"}, 2.5, fact(30)] + assert_equal a, Marshal.load(Marshal.dump(a)) + + [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z| + obj = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f)) + assert_equal obj, Marshal.load(Marshal.dump(obj)) + } + + bug3659 = '[ruby-dev:41936]' + [1.0, 10.0, 100.0, 110.0].each {|x| + assert_equal(x, Marshal.load(Marshal.dump(x)), bug3659) + } + end + + StrClone = String.clone + def test_marshal_cloned_class + assert_instance_of(StrClone, Marshal.load(Marshal.dump(StrClone.new("abc")))) + end + + def test_inconsistent_struct + TestMarshal.const_set :StructOrNot, Struct.new(:a) + s = Marshal.dump(StructOrNot.new(1)) + TestMarshal.instance_eval { remove_const :StructOrNot } + TestMarshal.const_set :StructOrNot, Class.new + assert_raise(TypeError, "[ruby-dev:31709]") { Marshal.load(s) } + end + + def test_struct_invalid_members + TestMarshal.const_set :StructInvalidMembers, Struct.new(:a) + assert_raise(TypeError, "[ruby-dev:31759]") { + Marshal.load("\004\bIc&TestMarshal::StructInvalidMembers\006:\020__members__\"\bfoo") + TestMarshal::StructInvalidMembers.members + } + end + + class C + def initialize(str) + @str = str + end + attr_reader :str + def _dump(limit) + @str + end + def self._load(s) + new(s) + end + end + + def test_too_long_string + data = Marshal.dump(C.new("a".force_encoding("ascii-8bit"))) + data[-2, 1] = "\003\377\377\377" + assert_raise_with_message(ArgumentError, "marshal data too short", "[ruby-dev:32054]") { + Marshal.load(data) + } + end + + + def test_userdef_encoding + s1 = "\xa4\xa4".force_encoding("euc-jp") + o1 = C.new(s1) + m = Marshal.dump(o1) + o2 = Marshal.load(m) + s2 = o2.str + assert_equal(s1, s2) + end + + def test_pipe + o1 = C.new("a" * 10000) + + IO.pipe do |r, w| + th = Thread.new {Marshal.dump(o1, w)} + o2 = Marshal.load(r) + th.join + assert_equal(o1.str, o2.str) + end + + IO.pipe do |r, w| + th = Thread.new {Marshal.dump(o1, w, 2)} + o2 = Marshal.load(r) + th.join + assert_equal(o1.str, o2.str) + end + + assert_raise(TypeError) { Marshal.dump("foo", Object.new) } + assert_raise(TypeError) { Marshal.load(Object.new) } + end + + def test_limit + assert_equal([[[]]], Marshal.load(Marshal.dump([[[]]], 3))) + assert_raise(ArgumentError) { Marshal.dump([[[]]], 2) } + assert_nothing_raised(ArgumentError, '[ruby-core:24100]') { Marshal.dump("\u3042", 1) } + end + + def test_userdef_invalid + o = C.new(nil) + assert_raise(TypeError) { Marshal.dump(o) } + end + + def test_class + o = class << Object.new; self; end + assert_raise(TypeError) { Marshal.dump(o) } + assert_equal(Object, Marshal.load(Marshal.dump(Object))) + assert_equal(Enumerable, Marshal.load(Marshal.dump(Enumerable))) + end + + class C2 + def initialize(ary) + @ary = ary + end + def _dump(s) + @ary.clear + "foo" + end + end + + def test_modify_array_during_dump + a = [] + o = C2.new(a) + a << o << nil + assert_raise(RuntimeError) { Marshal.dump(a) } + end + + def test_change_class_name + eval("class C3; def _dump(s); 'foo'; end; end") + m = Marshal.dump(C3.new) + assert_raise(TypeError) { Marshal.load(m) } + eval("C3 = nil") + assert_raise(TypeError) { Marshal.load(m) } + end + + def test_change_struct + eval("C3 = Struct.new(:foo, :bar)") + m = Marshal.dump(C3.new("FOO", "BAR")) + eval("C3 = Struct.new(:foo)") + assert_raise(TypeError) { Marshal.load(m) } + eval("C3 = Struct.new(:foo, :baz)") + assert_raise(TypeError) { Marshal.load(m) } + end + + class C4 + def initialize(gc) + @gc = gc + end + def _dump(s) + GC.start if @gc + "foo" + end + end + + def test_gc + assert_nothing_raised do + Marshal.dump((0..1000).map {|x| C4.new(x % 50 == 25) }) + end + end + + def test_taint + x = Object.new + x.taint + s = Marshal.dump(x) + assert_equal(true, s.tainted?) + y = Marshal.load(s) + assert_equal(true, y.tainted?) + end + + def test_taint_each_object + x = Object.new + obj = [[x]] + + # clean object causes crean stream + assert_equal(false, obj.tainted?) + assert_equal(false, obj.first.tainted?) + assert_equal(false, obj.first.first.tainted?) + s = Marshal.dump(obj) + assert_equal(false, s.tainted?) + + # tainted object causes tainted stream + x.taint + assert_equal(false, obj.tainted?) + assert_equal(false, obj.first.tainted?) + assert_equal(true, obj.first.first.tainted?) + t = Marshal.dump(obj) + assert_equal(true, t.tainted?) + + # clean stream causes clean objects + assert_equal(false, s.tainted?) + y = Marshal.load(s) + assert_equal(false, y.tainted?) + assert_equal(false, y.first.tainted?) + assert_equal(false, y.first.first.tainted?) + + # tainted stream causes tainted objects + assert_equal(true, t.tainted?) + y = Marshal.load(t) + assert_equal(true, y.tainted?) + assert_equal(true, y.first.tainted?) + assert_equal(true, y.first.first.tainted?) + + # same tests by different senario + s.taint + assert_equal(true, s.tainted?) + y = Marshal.load(s) + assert_equal(true, y.tainted?) + assert_equal(true, y.first.tainted?) + assert_equal(true, y.first.first.tainted?) + end + + def test_symbol2 + [:ruby, :"\u{7d05}\u{7389}"].each do |sym| + assert_equal(sym, Marshal.load(Marshal.dump(sym)), '[ruby-core:24788]') + end + bug2548 = '[ruby-core:27375]' + ary = [:$1, nil] + assert_equal(ary, Marshal.load(Marshal.dump(ary)), bug2548) + end + + def test_symlink + assert_include(Marshal.dump([:a, :a]), ';') + end + + def test_symlink_in_ivar + bug10991 = '[ruby-core:68587] [Bug #10991]' + sym = Marshal.load("\x04\x08" + + "I" ":\x0bKernel" + + ("\x06" + + ("I" ":\x07@a" + + ("\x06" ":\x07@b" "e;\x0""o:\x0bObject""\x0")) + + "0")) + assert_equal(:Kernel, sym, bug10991) + end + + ClassUTF8 = eval("class R\u{e9}sum\u{e9}; self; end") + + iso_8859_1 = Encoding::ISO_8859_1 + + structISO8859_1 = Struct.new("r\xe9sum\xe9".force_encoding(iso_8859_1).intern) + const_set("R\xe9sum\xe9".force_encoding(iso_8859_1), structISO8859_1) + structISO8859_1.name + StructISO8859_1 = structISO8859_1 + classISO8859_1 = Class.new do + attr_accessor "r\xe9sum\xe9".force_encoding(iso_8859_1) + eval("def initialize(x) @r\xe9sum\xe9 = x; end".force_encoding(iso_8859_1)) + end + const_set("R\xe9sum\xe92".force_encoding(iso_8859_1), classISO8859_1) + classISO8859_1.name + ClassISO8859_1 = classISO8859_1 + + def test_class_nonascii + a = ClassUTF8.new + assert_instance_of(ClassUTF8, Marshal.load(Marshal.dump(a)), '[ruby-core:24790]') + + bug1932 = '[ruby-core:24882]' + + a = StructISO8859_1.new(10) + assert_nothing_raised(bug1932) do + assert_equal(a, Marshal.load(Marshal.dump(a)), bug1932) + end + a.__send__("#{StructISO8859_1.members[0]}=", a) + assert_nothing_raised(bug1932) do + assert_equal(a, Marshal.load(Marshal.dump(a)), bug1932) + end + + a = ClassISO8859_1.new(10) + assert_nothing_raised(bug1932) do + b = Marshal.load(Marshal.dump(a)) + assert_equal(ClassISO8859_1, b.class, bug1932) + assert_equal(a.instance_variables, b.instance_variables, bug1932) + a.instance_variables.each do |i| + assert_equal(a.instance_variable_get(i), b.instance_variable_get(i), bug1932) + end + end + a.__send__(a.methods(true).grep(/=\z/)[0], a) + assert_nothing_raised(bug1932) do + b = Marshal.load(Marshal.dump(a)) + assert_equal(ClassISO8859_1, b.class, bug1932) + assert_equal(a.instance_variables, b.instance_variables, bug1932) + assert_equal(b, b.instance_variable_get(a.instance_variables[0]), bug1932) + end + end + + def test_regexp2 + assert_equal(/\\u/, Marshal.load("\004\b/\b\\\\u\000")) + assert_equal(/u/, Marshal.load("\004\b/\a\\u\000")) + assert_equal(/u/, Marshal.load("\004\bI/\a\\u\000\006:\016@encoding\"\vEUC-JP")) + + bug2109 = '[ruby-core:25625]' + a = "\x82\xa0".force_encoding(Encoding::Windows_31J) + b = "\x82\xa2".force_encoding(Encoding::Windows_31J) + c = [/#{a}/, /#{b}/] + assert_equal(c, Marshal.load(Marshal.dump(c)), bug2109) + + assert_nothing_raised(ArgumentError, '[ruby-dev:40386]') do + re = Tempfile.create("marshal_regexp") do |f| + f.binmode.write("\x04\bI/\x00\x00\x06:\rencoding\"\rUS-ASCII") + f.rewind + re2 = Marshal.load(f) + re2 + end + assert_equal(//, re) + end + end + + class DumpTest + def marshal_dump + @@block.call(:marshal_dump) + end + + def dump_each(&block) + @@block = block + Marshal.dump(self) + end + end + + class LoadTest + def marshal_dump + nil + end + def marshal_load(obj) + @@block.call(:marshal_load) + end + def self.load_each(m, &block) + @@block = block + Marshal.load(m) + end + end + + def test_context_switch + o = DumpTest.new + e = o.enum_for(:dump_each) + assert_equal(:marshal_dump, e.next) + GC.start + assert(true, '[ruby-dev:39425]') + assert_raise(StopIteration) {e.next} + + o = LoadTest.new + m = Marshal.dump(o) + e = LoadTest.enum_for(:load_each, m) + assert_equal(:marshal_load, e.next) + GC.start + assert(true, '[ruby-dev:39425]') + assert_raise(StopIteration) {e.next} + end + + def test_dump_buffer + bug2390 = '[ruby-dev:39744]' + w = "" + def w.write(str) + self << str.to_s + end + Marshal.dump(Object.new, w) + assert_not_empty(w, bug2390) + end + + class C5 + def marshal_dump + "foo" + end + def marshal_load(foo) + @foo = foo + end + def initialize(x) + @x = x + end + end + def test_marshal_dump + c = C5.new("bar") + s = Marshal.dump(c) + d = Marshal.load(s) + assert_equal("foo", d.instance_variable_get(:@foo)) + assert_equal(false, d.instance_variable_defined?(:@x)) + end + + class C6 + def initialize + @stdin = STDIN + end + attr_reader :stdin + def marshal_dump + 1 + end + def marshal_load(x) + @stdin = STDIN + end + end + def test_marshal_dump_extra_iv + o = C6.new + m = nil + assert_nothing_raised("[ruby-dev:21475] [ruby-dev:39845]") { + m = Marshal.dump(o) + } + o2 = Marshal.load(m) + assert_equal(STDIN, o2.stdin) + end + + def test_marshal_string_encoding + o1 = ["foo".force_encoding("EUC-JP")] + [ "bar" ] * 2 + m = Marshal.dump(o1) + o2 = Marshal.load(m) + assert_equal(o1, o2, "[ruby-dev:40388]") + end + + def test_marshal_regexp_encoding + o1 = [Regexp.new("r1".force_encoding("EUC-JP"))] + ["r2"] * 2 + m = Marshal.dump(o1) + o2 = Marshal.load(m) + assert_equal(o1, o2, "[ruby-dev:40416]") + end + + def test_marshal_encoding_encoding + o1 = [Encoding.find("EUC-JP")] + ["r2"] * 2 + m = Marshal.dump(o1) + o2 = Marshal.load(m) + assert_equal(o1, o2) + end + + def test_marshal_symbol_ascii8bit + bug6209 = '[ruby-core:43762]' + o1 = "\xff".force_encoding("ASCII-8BIT").intern + m = Marshal.dump(o1) + o2 = nil + assert_nothing_raised(EncodingError, bug6209) {o2 = Marshal.load(m)} + assert_equal(o1, o2, bug6209) + end + + class PrivateClass + def initialize(foo) + @foo = foo + end + attr_reader :foo + end + private_constant :PrivateClass + + def test_marshal_private_class + o1 = PrivateClass.new("test") + o2 = Marshal.load(Marshal.dump(o1)) + assert_equal(o1.class, o2.class) + assert_equal(o1.foo, o2.foo) + end + + def test_marshal_complex + assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x05")} + assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x06i\x00")} + assert_equal(Complex(1, 2), Marshal.load("\x04\bU:\fComplex[\ai\x06i\a")) + assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\bi\x00i\x00i\x00")} + end + + def test_marshal_rational + assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\x05")} + assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\x06i\x00")} + assert_equal(Rational(1, 2), Marshal.load("\x04\bU:\rRational[\ai\x06i\a")) + assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\bi\x00i\x00i\x00")} + end + + def test_marshal_flonum_reference + bug7348 = '[ruby-core:49323]' + e = [] + ary = [ [2.0, e], [e] ] + assert_equal(ary, Marshal.load(Marshal.dump(ary)), bug7348) + end + + class TestClass + end + + module TestModule + end + + def test_marshal_load_should_not_taint_classes + bug7325 = '[ruby-core:49198]' + for c in [TestClass, TestModule] + assert_not_predicate(c, :tainted?) + c2 = Marshal.load(Marshal.dump(c).taint) + assert_same(c, c2) + assert_not_predicate(c, :tainted?, bug7325) + end + end + + class Bug7627 < Struct.new(:bar) + attr_accessor :foo + + def marshal_dump; 'dump'; end # fake dump data + def marshal_load(*); end # do nothing + end + + def test_marshal_dump_struct_ivar + bug7627 = '[ruby-core:51163]' + obj = Bug7627.new + obj.foo = '[Bug #7627]' + + dump = Marshal.dump(obj) + loaded = Marshal.load(dump) + + assert_equal(obj, loaded, bug7627) + assert_nil(loaded.foo, bug7627) + end + + class LoadData + attr_reader :data + def initialize(data) + @data = data + end + alias marshal_dump data + alias marshal_load initialize + end + + class Bug8276 < LoadData + def initialize(*) + super + freeze + end + alias marshal_load initialize + end + + class FrozenData < LoadData + def marshal_load(data) + super + data.instance_variables.each do |iv| + instance_variable_set(iv, data.instance_variable_get(iv)) + end + freeze + end + end + + def test_marshal_dump_excess_encoding + bug8276 = '[ruby-core:54334] [Bug #8276]' + t = Bug8276.new(bug8276) + s = Marshal.dump(t) + assert_nothing_raised(RuntimeError, bug8276) {s = Marshal.load(s)} + assert_equal(t.data, s.data, bug8276) + end + + def test_marshal_dump_ivar + s = "data with ivar" + s.instance_variable_set(:@t, 42) + t = Bug8276.new(s) + s = Marshal.dump(t) + assert_raise(RuntimeError) {Marshal.load(s)} + end + + def test_marshal_load_ivar + s = "data with ivar" + s.instance_variable_set(:@t, 42) + hook = ->(v) { + if LoadData === v + assert_send([v, :instance_variable_defined?, :@t], v.class.name) + assert_equal(42, v.instance_variable_get(:@t), v.class.name) + end + v + } + [LoadData, FrozenData].each do |klass| + t = klass.new(s) + d = Marshal.dump(t) + v = assert_nothing_raised(RuntimeError) {break Marshal.load(d, hook)} + assert_send([v, :instance_variable_defined?, :@t], klass.name) + assert_equal(42, v.instance_variable_get(:@t), klass.name) + end + end + + def test_class_ivar + assert_raise(TypeError) {Marshal.load("\x04\x08Ic\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")} + assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")} + assert_not_operator(TestClass, :instance_variable_defined?, :@bug) + end + + def test_module_ivar + assert_raise(TypeError) {Marshal.load("\x04\x08Im\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")} + assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")} + assert_not_operator(TestModule, :instance_variable_defined?, :@bug) + end + + class TestForRespondToFalse + def respond_to?(a) + false + end + end + + def test_marshal_respond_to_arity + assert_nothing_raised(ArgumentError, '[Bug #7722]') do + Marshal.dump(TestForRespondToFalse.new) + end + end + + def test_packed_string + packed = ["foo"].pack("p") + bare = "".force_encoding(Encoding::ASCII_8BIT) << packed + assert_equal(Marshal.dump(bare), Marshal.dump(packed)) + end + + def test_untainted_numeric + bug8945 = '[ruby-core:57346] [Bug #8945] Numerics never be tainted' + b = 1 << 32 + b *= b until Bignum === b + tainted = [0, 1.0, 1.72723e-77, b].select do |x| + Marshal.load(Marshal.dump(x).taint).tainted? + end + assert_empty(tainted.map {|x| [x, x.class]}, bug8945) + end + + class Bug9523 + attr_reader :cc + def marshal_dump + callcc {|c| @cc = c } + nil + end + def marshal_load(v) + end + end + + def test_continuation + require "continuation" + c = Bug9523.new + assert_raise_with_message(RuntimeError, /Marshal\.dump reentered at marshal_dump/) do + Marshal.dump(c) + c.cc.call + end + end +end diff --git a/jni/ruby/test/ruby/test_math.rb b/jni/ruby/test/ruby/test_math.rb new file mode 100644 index 0000000..c4d0ff9 --- /dev/null +++ b/jni/ruby/test/ruby/test_math.rb @@ -0,0 +1,292 @@ +require 'test/unit' + +class TestMath < Test::Unit::TestCase + def assert_infinity(a, *rest) + rest = ["not infinity: #{a.inspect}"] if rest.empty? + assert_predicate(a, :infinite?, *rest) + end + + def assert_nan(a, *rest) + rest = ["not nan: #{a.inspect}"] if rest.empty? + assert_predicate(a, :nan?, *rest) + end + + def assert_float(a, b) + err = [Float::EPSILON * 4, [a.abs, b.abs].max * Float::EPSILON * 256].max + assert_in_delta(a, b, err) + end + alias check assert_float + + def test_atan2 + check(+0.0, Math.atan2(+0.0, +0.0)) + check(-0.0, Math.atan2(-0.0, +0.0)) + check(+Math::PI, Math.atan2(+0.0, -0.0)) + check(-Math::PI, Math.atan2(-0.0, -0.0)) + + inf = Float::INFINITY + expected = 3.0 * Math::PI / 4.0 + assert_nothing_raised { check(+expected, Math.atan2(+inf, -inf)) } + assert_nothing_raised { check(-expected, Math.atan2(-inf, -inf)) } + expected = Math::PI / 4.0 + assert_nothing_raised { check(+expected, Math.atan2(+inf, +inf)) } + assert_nothing_raised { check(-expected, Math.atan2(-inf, +inf)) } + + check(0, Math.atan2(0, 1)) + check(Math::PI / 4, Math.atan2(1, 1)) + check(Math::PI / 2, Math.atan2(1, 0)) + end + + def test_cos + check(1.0, Math.cos(0 * Math::PI / 4)) + check(1.0 / Math.sqrt(2), Math.cos(1 * Math::PI / 4)) + check(0.0, Math.cos(2 * Math::PI / 4)) + check(-1.0, Math.cos(4 * Math::PI / 4)) + check(0.0, Math.cos(6 * Math::PI / 4)) + end + + def test_sin + check(0.0, Math.sin(0 * Math::PI / 4)) + check(1.0 / Math.sqrt(2), Math.sin(1 * Math::PI / 4)) + check(1.0, Math.sin(2 * Math::PI / 4)) + check(0.0, Math.sin(4 * Math::PI / 4)) + check(-1.0, Math.sin(6 * Math::PI / 4)) + end + + def test_tan + check(0.0, Math.tan(0 * Math::PI / 4)) + check(1.0, Math.tan(1 * Math::PI / 4)) + assert_operator(Math.tan(2 * Math::PI / 4).abs, :>, 1024) + check(0.0, Math.tan(4 * Math::PI / 4)) + assert_operator(Math.tan(6 * Math::PI / 4).abs, :>, 1024) + end + + def test_acos + check(0 * Math::PI / 4, Math.acos( 1.0)) + check(1 * Math::PI / 4, Math.acos( 1.0 / Math.sqrt(2))) + check(2 * Math::PI / 4, Math.acos( 0.0)) + check(4 * Math::PI / 4, Math.acos(-1.0)) + assert_raise(Math::DomainError) { Math.acos(+1.0 + Float::EPSILON) } + assert_raise(Math::DomainError) { Math.acos(-1.0 - Float::EPSILON) } + assert_raise(Math::DomainError) { Math.acos(2.0) } + end + + def test_asin + check( 0 * Math::PI / 4, Math.asin( 0.0)) + check( 1 * Math::PI / 4, Math.asin( 1.0 / Math.sqrt(2))) + check( 2 * Math::PI / 4, Math.asin( 1.0)) + check(-2 * Math::PI / 4, Math.asin(-1.0)) + assert_raise(Math::DomainError) { Math.asin(+1.0 + Float::EPSILON) } + assert_raise(Math::DomainError) { Math.asin(-1.0 - Float::EPSILON) } + assert_raise(Math::DomainError) { Math.asin(2.0) } + end + + def test_atan + check( 0 * Math::PI / 4, Math.atan( 0.0)) + check( 1 * Math::PI / 4, Math.atan( 1.0)) + check( 2 * Math::PI / 4, Math.atan(1.0 / 0.0)) + check(-1 * Math::PI / 4, Math.atan(-1.0)) + end + + def test_cosh + check(1, Math.cosh(0)) + check((Math::E ** 1 + Math::E ** -1) / 2, Math.cosh(1)) + check((Math::E ** 2 + Math::E ** -2) / 2, Math.cosh(2)) + end + + def test_sinh + check(0, Math.sinh(0)) + check((Math::E ** 1 - Math::E ** -1) / 2, Math.sinh(1)) + check((Math::E ** 2 - Math::E ** -2) / 2, Math.sinh(2)) + end + + def test_tanh + check(Math.sinh(0) / Math.cosh(0), Math.tanh(0)) + check(Math.sinh(1) / Math.cosh(1), Math.tanh(1)) + check(Math.sinh(2) / Math.cosh(2), Math.tanh(2)) + end + + def test_acosh + check(0, Math.acosh(1)) + check(1, Math.acosh((Math::E ** 1 + Math::E ** -1) / 2)) + check(2, Math.acosh((Math::E ** 2 + Math::E ** -2) / 2)) + assert_raise(Math::DomainError) { Math.acosh(1.0 - Float::EPSILON) } + assert_raise(Math::DomainError) { Math.acosh(0) } + end + + def test_asinh + check(0, Math.asinh(0)) + check(1, Math.asinh((Math::E ** 1 - Math::E ** -1) / 2)) + check(2, Math.asinh((Math::E ** 2 - Math::E ** -2) / 2)) + end + + def test_atanh + check(0, Math.atanh(Math.sinh(0) / Math.cosh(0))) + check(1, Math.atanh(Math.sinh(1) / Math.cosh(1))) + check(2, Math.atanh(Math.sinh(2) / Math.cosh(2))) + assert_nothing_raised { assert_infinity(Math.atanh(1)) } + assert_nothing_raised { assert_infinity(-Math.atanh(-1)) } + assert_raise(Math::DomainError) { Math.atanh(+1.0 + Float::EPSILON) } + assert_raise(Math::DomainError) { Math.atanh(-1.0 - Float::EPSILON) } + end + + def test_exp + check(1, Math.exp(0)) + check(Math.sqrt(Math::E), Math.exp(0.5)) + check(Math::E, Math.exp(1)) + check(Math::E ** 2, Math.exp(2)) + end + + def test_log + check(0, Math.log(1)) + check(1, Math.log(Math::E)) + check(0, Math.log(1, 10)) + check(1, Math.log(10, 10)) + check(2, Math.log(100, 10)) + check(Math.log(2.0 ** 64), Math.log(1 << 64)) + assert_equal(1.0/0, Math.log(1.0/0)) + assert_nothing_raised { assert_infinity(-Math.log(+0.0)) } + assert_nothing_raised { assert_infinity(-Math.log(-0.0)) } + assert_raise(Math::DomainError) { Math.log(-1.0) } + assert_raise(TypeError) { Math.log(1,nil) } + assert_raise(Math::DomainError, '[ruby-core:62309] [ruby-Bug #9797]') { Math.log(1.0, -1.0) } + assert_nothing_raised { assert_nan(Math.log(0.0, 0.0)) } + end + + def test_log2 + check(0, Math.log2(1)) + check(1, Math.log2(2)) + check(2, Math.log2(4)) + check(Math.log2(2.0 ** 64), Math.log2(1 << 64)) + assert_equal(1.0/0, Math.log2(1.0/0)) + assert_nothing_raised { assert_infinity(-Math.log2(+0.0)) } + assert_nothing_raised { assert_infinity(-Math.log2(-0.0)) } + assert_raise(Math::DomainError) { Math.log2(-1.0) } + end + + def test_log10 + check(0, Math.log10(1)) + check(1, Math.log10(10)) + check(2, Math.log10(100)) + check(Math.log10(2.0 ** 64), Math.log10(1 << 64)) + assert_equal(1.0/0, Math.log10(1.0/0)) + assert_nothing_raised { assert_infinity(-Math.log10(+0.0)) } + assert_nothing_raised { assert_infinity(-Math.log10(-0.0)) } + assert_raise(Math::DomainError) { Math.log10(-1.0) } + end + + def test_sqrt + check(0, Math.sqrt(0)) + check(1, Math.sqrt(1)) + check(2, Math.sqrt(4)) + assert_equal(1.0/0, Math.sqrt(1.0/0)) + assert_equal("0.0", Math.sqrt(-0.0).to_s) # insure it is +0.0, not -0.0 + assert_raise(Math::DomainError) { Math.sqrt(-1.0) } + end + + def test_frexp + check(0.0, Math.frexp(0.0).first) + assert_equal(0, Math.frexp(0).last) + check(0.5, Math.frexp(0.5).first) + assert_equal(0, Math.frexp(0.5).last) + check(0.5, Math.frexp(1.0).first) + assert_equal(1, Math.frexp(1.0).last) + check(0.5, Math.frexp(2.0).first) + assert_equal(2, Math.frexp(2.0).last) + check(0.75, Math.frexp(3.0).first) + assert_equal(2, Math.frexp(3.0).last) + end + + def test_ldexp + check(0.0, Math.ldexp(0.0, 0.0)) + check(0.5, Math.ldexp(0.5, 0.0)) + check(1.0, Math.ldexp(0.5, 1.0)) + check(2.0, Math.ldexp(0.5, 2.0)) + check(3.0, Math.ldexp(0.75, 2.0)) + end + + def test_hypot + check(5, Math.hypot(3, 4)) + end + + def test_erf + check(0, Math.erf(0)) + check(1, Math.erf(1.0 / 0.0)) + end + + def test_erfc + check(1, Math.erfc(0)) + check(0, Math.erfc(1.0 / 0.0)) + end + + def test_gamma + sqrt_pi = Math.sqrt(Math::PI) + check(4 * sqrt_pi / 3, Math.gamma(-1.5)) + check(-2 * sqrt_pi, Math.gamma(-0.5)) + check(sqrt_pi, Math.gamma(0.5)) + check(1, Math.gamma(1)) + check(sqrt_pi / 2, Math.gamma(1.5)) + check(1, Math.gamma(2)) + check(3 * sqrt_pi / 4, Math.gamma(2.5)) + check(2, Math.gamma(3)) + check(15 * sqrt_pi / 8, Math.gamma(3.5)) + check(6, Math.gamma(4)) + + # no SEGV [ruby-core:25257] + 31.upto(65) do |i| + i = 1 << i + assert_infinity(Math.gamma(i), "Math.gamma(#{i}) should be INF") + assert_infinity(Math.gamma(i-1), "Math.gamma(#{i-1}) should be INF") + end + + assert_raise(Math::DomainError) { Math.gamma(-Float::INFINITY) } + end + + def test_lgamma + sqrt_pi = Math.sqrt(Math::PI) + + g, s = Math.lgamma(-1.5) + check(Math.log(4 * sqrt_pi / 3), g) + assert_equal(s, 1) + + g, s = Math.lgamma(-0.5) + check(Math.log(2 * sqrt_pi), g) + assert_equal(s, -1) + + g, s = Math.lgamma(0.5) + check(Math.log(sqrt_pi), g) + assert_equal(s, 1) + + assert_equal([0, 1], Math.lgamma(1)) + + g, s = Math.lgamma(1.5) + check(Math.log(sqrt_pi / 2), g) + assert_equal(s, 1) + + assert_equal([0, 1], Math.lgamma(2)) + + g, s = Math.lgamma(2.5) + check(Math.log(3 * sqrt_pi / 4), g) + assert_equal(s, 1) + + g, s = Math.lgamma(3) + check(Math.log(2), g) + assert_equal(s, 1) + + g, s = Math.lgamma(3.5) + check(Math.log(15 * sqrt_pi / 8), g) + assert_equal(s, 1) + + g, s = Math.lgamma(4) + check(Math.log(6), g) + assert_equal(s, 1) + + assert_raise(Math::DomainError) { Math.lgamma(-Float::INFINITY) } + end + + def test_cbrt + check(1, Math.cbrt(1)) + check(-2, Math.cbrt(-8)) + check(3, Math.cbrt(27)) + check(-0.1, Math.cbrt(-0.001)) + end +end diff --git a/jni/ruby/test/ruby/test_metaclass.rb b/jni/ruby/test/ruby/test_metaclass.rb new file mode 100644 index 0000000..6386a02 --- /dev/null +++ b/jni/ruby/test/ruby/test_metaclass.rb @@ -0,0 +1,167 @@ +require 'test/unit' + +class TestMetaclass < Test::Unit::TestCase + class Foo; end + class Bar < Foo; end + class Baz; end + + def setup + Object.class_eval do + def method_o; end + end + Module.class_eval do + def method_m; end + end + Class.class_eval do + def method_c; end + end + end + def teardown + Object.class_eval do + remove_method :method_o rescue nil + end + Module.class_eval do + remove_method :method_m rescue nil + end + Class.class_eval do + remove_method :method_c rescue nil + end + Object.class_eval do + class << self + remove_method :class_method_o rescue nil + end + end + Module.class_eval do + class << self + remove_method :class_method_m rescue nil + end + end + Class.class_eval do + class << self + remove_method :class_method_c rescue nil + end + end + Object.class_eval do + class << self + class << self + remove_method :metaclass_method_o rescue nil + end + end + end + Module.class_eval do + class << self + class << self + remove_method :metaclass_method_m rescue nil + end + end + end + Class.class_eval do + class << self + class << self + remove_method :metaclass_method_c rescue nil + end + end + end + end + + def test_metaclass + class << Object + def class_method_o; end + end + class << Foo + def class_method_f; end + end + class << Baz + def class_method_b; end + end + assert_nothing_raised{ Bar.method_o } + assert_nothing_raised{ Bar.method_m } + assert_nothing_raised{ Bar.method_c } + assert_nothing_raised{ Bar.class_method_o } + assert_nothing_raised{ Bar.class_method_f } + assert_raise(NoMethodError){ Bar.class_method_b } + + class << Module + def class_method_m; end + end + class << Class + def class_method_c; end + end + class << Object + class << self + def metaclass_method_o; end + end + end + class << Foo + class << self + def metaclass_method_f; end + end + end + class << Baz + class << self + def metaclass_method_b; end + end + end + metaclass_of_bar = class << Bar; self end + assert_nothing_raised{ metaclass_of_bar.method_o } + assert_nothing_raised{ metaclass_of_bar.method_m } + assert_nothing_raised{ metaclass_of_bar.method_c } + assert_nothing_raised{ metaclass_of_bar.class_method_o } + assert_raise(NoMethodError){ metaclass_of_bar.class_method_f } + assert_raise(NoMethodError){ metaclass_of_bar.class_method_b } + assert_nothing_raised{ metaclass_of_bar.class_method_m } + assert_nothing_raised{ metaclass_of_bar.class_method_c } + assert_nothing_raised{ metaclass_of_bar.metaclass_method_o } + assert_nothing_raised{ metaclass_of_bar.metaclass_method_f } + assert_raise(NoMethodError){ metaclass_of_bar.metaclass_method_b } + + class << Module + class << self + def metaclass_method_m; end + end + end + class << Class + class << self + def metaclass_method_c; end + end + end + class << Object + class << self + class << self + def metametaclass_method_o; end + end + end + end + class << Foo + class << self + class << self + def metametaclass_method_f; end + end + end + end + class << Baz + class << self + class << self + def metametaclass_method_b; end + end + end + end + metametaclass_of_bar = class << metaclass_of_bar; self end + assert_nothing_raised{ metametaclass_of_bar.method_o } + assert_nothing_raised{ metametaclass_of_bar.method_m } + assert_nothing_raised{ metametaclass_of_bar.method_c } + assert_nothing_raised{ metametaclass_of_bar.class_method_o } + assert_raise(NoMethodError){ metametaclass_of_bar.class_method_f } + assert_raise(NoMethodError){ metametaclass_of_bar.class_method_b } + assert_nothing_raised{ metametaclass_of_bar.class_method_m } + assert_nothing_raised{ metametaclass_of_bar.class_method_c } + assert_nothing_raised{ metametaclass_of_bar.metaclass_method_o } + assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_f } + assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b } + assert_nothing_raised{ metametaclass_of_bar.metaclass_method_m } + assert_nothing_raised{ metametaclass_of_bar.metaclass_method_c } + assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_o } + assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_f } + assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b } + end +end diff --git a/jni/ruby/test/ruby/test_method.rb b/jni/ruby/test/ruby/test_method.rb new file mode 100644 index 0000000..35ddc87 --- /dev/null +++ b/jni/ruby/test/ruby/test_method.rb @@ -0,0 +1,894 @@ +# -*- coding: us-ascii -*- +require 'test/unit' + +class TestMethod < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def m0() end + def m1(a) end + def m2(a, b) end + def mo1(a = nil, &b) end + def mo2(a, b = nil) end + def mo3(*a) end + def mo4(a, *b, &c) end + def mo5(a, *b, c) end + def mo6(a, *b, c, &d) end + def mo7(a, b = nil, *c, d, &e) end + def ma1((a), &b) nil && a end + def mk1(**) end + def mk2(**o) nil && o end + def mk3(a, **o) nil && o end + def mk4(a = nil, **o) nil && o end + def mk5(a, b = nil, **o) nil && o end + def mk6(a, b = nil, c, **o) nil && o end + def mk7(a, b = nil, *c, d, **o) nil && o end + + class Base + def foo() :base end + end + class Derived < Base + def foo() :derived end + end + class T + def initialize; end + def initialize_copy(*) super end + def initialize_clone(*) super end + def initialize_dup(*) super end + def respond_to_missing?(*) super end + def normal_method; end + end + module M + def func; end + module_function :func + def meth; :meth end + end + + def mv1() end + def mv2() end + private :mv2 + def mv3() end + protected :mv3 + + class Visibility + def mv1() end + def mv2() end + private :mv2 + def mv3() end + protected :mv3 + end + + def test_arity + assert_equal(0, method(:m0).arity) + assert_equal(1, method(:m1).arity) + assert_equal(2, method(:m2).arity) + assert_equal(-1, method(:mo1).arity) + assert_equal(-2, method(:mo2).arity) + assert_equal(-1, method(:mo3).arity) + assert_equal(-2, method(:mo4).arity) + assert_equal(-3, method(:mo5).arity) + assert_equal(-3, method(:mo6).arity) + assert_equal(-1, method(:mk1).arity) + assert_equal(-1, method(:mk2).arity) + assert_equal(-2, method(:mk3).arity) + assert_equal(-1, method(:mk4).arity) + assert_equal(-2, method(:mk5).arity) + assert_equal(-3, method(:mk6).arity) + assert_equal(-3, method(:mk7).arity) + end + + def test_arity_special + assert_equal(-1, method(:__send__).arity) + end + + def test_unbind + assert_equal(:derived, Derived.new.foo) + um = Derived.new.method(:foo).unbind + assert_instance_of(UnboundMethod, um) + Derived.class_eval do + def foo() :changed end + end + assert_equal(:changed, Derived.new.foo) + assert_equal(:derived, um.bind(Derived.new).call) + assert_raise(TypeError) do + um.bind(Base.new) + end + end + + def test_callee + assert_equal(:test_callee, __method__) + assert_equal(:m, Class.new {def m; __method__; end}.new.m) + assert_equal(:m, Class.new {def m; tap{return __method__}; end}.new.m) + assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m) + assert_equal(:m, Class.new {define_method(:m) {tap{return __method__}}}.new.m) + assert_nil(eval("class TestCallee; __method__; end")) + + assert_equal(:test_callee, __callee__) + [ + ["method", Class.new {def m; __callee__; end},], + ["block", Class.new {def m; tap{return __callee__}; end},], + ["define_method", Class.new {define_method(:m) {__callee__}}], + ["define_method block", Class.new {define_method(:m) {tap{return __callee__}}}], + ].each do |mesg, c| + c.class_eval {alias m2 m} + o = c.new + assert_equal(:m, o.m, mesg) + assert_equal(:m2, o.m2, mesg) + end + assert_nil(eval("class TestCallee; __callee__; end")) + end + + def test_method_in_define_method_block + bug4606 = '[ruby-core:35386]' + c = Class.new do + [:m1, :m2].each do |m| + define_method(m) do + __method__ + end + end + end + assert_equal(:m1, c.new.m1, bug4606) + assert_equal(:m2, c.new.m2, bug4606) + end + + def test_method_in_block_in_define_method_block + bug4606 = '[ruby-core:35386]' + c = Class.new do + [:m1, :m2].each do |m| + define_method(m) do + tap { return __method__ } + end + end + end + assert_equal(:m1, c.new.m1, bug4606) + assert_equal(:m2, c.new.m2, bug4606) + end + + def test_body + o = Object.new + def o.foo; end + assert_nothing_raised { RubyVM::InstructionSequence.disasm(o.method(:foo)) } + assert_nothing_raised { RubyVM::InstructionSequence.disasm("x".method(:upcase)) } + assert_nothing_raised { RubyVM::InstructionSequence.disasm(method(:to_s).to_proc) } + end + + def test_new + c1 = Class.new + c1.class_eval { def foo; :foo; end } + c2 = Class.new(c1) + c2.class_eval { private :foo } + o = c2.new + o.extend(Module.new) + assert_raise(NameError) { o.method(:bar) } + assert_raise(NameError) { o.public_method(:foo) } + assert_equal(:foo, o.method(:foo).call) + end + + def test_eq + o = Object.new + class << o + def foo; end + alias bar foo + def baz; end + end + assert_not_equal(o.method(:foo), nil) + m = o.method(:foo) + def m.foo; end + assert_not_equal(o.method(:foo), m) + 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)) + end + + def test_hash + o = Object.new + def o.foo; end + assert_kind_of(Integer, o.method(:foo).hash) + assert_equal(Array.instance_method(:map).hash, Array.instance_method(:collect).hash) + end + + def test_owner + c = Class.new do + def foo; end + end + assert_equal(c, c.instance_method(:foo).owner) + c2 = Class.new(c) + assert_equal(c, c2.instance_method(:foo).owner) + end + + def test_owner_missing + c = Class.new do + def respond_to_missing?(name, bool) + name == :foo + end + end + c2 = Class.new(c) + assert_equal(c, c.new.method(:foo).owner) + assert_equal(c2, c2.new.method(:foo).owner) + end + + def test_receiver_name_owner + o = Object.new + def o.foo; end + m = o.method(:foo) + assert_equal(o, m.receiver) + assert_equal(:foo, m.name) + assert_equal(class << o; self; end, m.owner) + assert_equal(:foo, m.unbind.name) + assert_equal(class << o; self; end, m.unbind.owner) + class << o + alias bar foo + end + m = o.method(:bar) + assert_equal(:bar, m.name) + assert_equal(:foo, m.original_name) + end + + def test_instance_method + c = Class.new + c.class_eval do + def foo; :foo; end + private :foo + end + o = c.new + o.method(:foo).unbind + assert_raise(NoMethodError) { o.foo } + c.instance_method(:foo).bind(o) + assert_equal(:foo, o.instance_eval { foo }) + assert_raise(NameError) { c.public_instance_method(:foo) } + def o.bar; end + m = o.method(:bar).unbind + assert_raise(TypeError) { m.bind(Object.new) } + + feature4254 = '[ruby-core:34267]' + m = M.instance_method(:meth) + assert_equal(:meth, m.bind(Object.new).call, feature4254) + end + + def test_define_method + c = Class.new + c.class_eval { def foo; :foo; end } + o = c.new + def o.bar; :bar; end + assert_raise(TypeError) do + c.class_eval { define_method(:foo, :foo) } + end + assert_raise(ArgumentError) do + c.class_eval { define_method } + end + c2 = Class.new(c) + c2.class_eval { define_method(:baz, o.method(:foo)) } + assert_equal(:foo, c2.new.baz) + assert_raise(TypeError) do + Class.new.class_eval { define_method(:foo, o.method(:foo)) } + end + assert_raise(TypeError) do + Class.new.class_eval { define_method(:bar, o.method(:bar)) } + end + end + + def test_define_singleton_method + o = Object.new + def o.foo(c) + c.class_eval { define_method(:foo) } + end + c = Class.new + o.foo(c) { :foo } + assert_equal(:foo, c.new.foo) + + o = Object.new + o.instance_eval { define_singleton_method(:foo) { :foo } } + assert_equal(:foo, o.foo) + + assert_raise(TypeError) do + Class.new.class_eval { define_method(:foo, Object.new) } + end + + assert_raise(TypeError) do + Module.new.module_eval {define_method(:foo, Base.instance_method(:foo))} + end + end + + def test_define_singleton_method_with_extended_method + bug8686 = "[ruby-core:56174]" + + m = Module.new do + extend self + + def a + "a" + end + end + + assert_nothing_raised(bug8686) do + m.define_singleton_method(:a, m.method(:a)) + end + end + + def test_define_method_transplating + feature4254 = '[ruby-core:34267]' + m = Module.new {define_method(:meth, M.instance_method(:meth))} + assert_equal(:meth, Object.new.extend(m).meth, feature4254) + c = Class.new {define_method(:meth, M.instance_method(:meth))} + assert_equal(:meth, c.new.meth, feature4254) + end + + def test_define_method_visibility + c = Class.new do + public + define_method(:foo) {:foo} + protected + define_method(:bar) {:bar} + private + define_method(:baz) {:baz} + end + + assert_equal(true, c.public_method_defined?(:foo)) + assert_equal(false, c.public_method_defined?(:bar)) + assert_equal(false, c.public_method_defined?(:baz)) + + assert_equal(false, c.protected_method_defined?(:foo)) + assert_equal(true, c.protected_method_defined?(:bar)) + assert_equal(false, c.protected_method_defined?(:baz)) + + assert_equal(false, c.private_method_defined?(:foo)) + assert_equal(false, c.private_method_defined?(:bar)) + assert_equal(true, c.private_method_defined?(:baz)) + + m = Module.new do + module_function + define_method(:foo) {:foo} + end + assert_equal(true, m.respond_to?(:foo)) + assert_equal(false, m.public_method_defined?(:foo)) + assert_equal(false, m.protected_method_defined?(:foo)) + assert_equal(true, m.private_method_defined?(:foo)) + end + + def test_define_method_in_private_scope + bug9005 = '[ruby-core:57747] [Bug #9005]' + c = Class.new + class << c + public :define_method + end + TOPLEVEL_BINDING.eval("proc{|c|c.define_method(:x) {|x|throw x}}").call(c) + o = c.new + assert_throw(bug9005) {o.x(bug9005)} + end + + def test_singleton_define_method_in_private_scope + bug9141 = '[ruby-core:58497] [Bug #9141]' + o = Object.new + class << o + public :define_singleton_method + end + TOPLEVEL_BINDING.eval("proc{|o|o.define_singleton_method(:x) {|x|throw x}}").call(o) + assert_throw(bug9141) do + o.x(bug9141) + end + end + + def test_super_in_proc_from_define_method + c1 = Class.new { + def m + :m1 + end + } + c2 = Class.new(c1) { define_method(:m) { Proc.new { super() } } } + # c2.new.m.call should return :m1, but currently it raise NoMethodError. + # see [Bug #4881] and [Bug #3136] + assert_raise(NoMethodError) { + c2.new.m.call + } + end + + def test_clone + o = Object.new + def o.foo; :foo; end + m = o.method(:foo) + def m.bar; :bar; end + assert_equal(:foo, m.clone.call) + assert_equal(:bar, m.clone.bar) + end + + def test_inspect + o = Object.new + def o.foo; end + m = o.method(:foo) + assert_equal("#<Method: #{ o.inspect }.foo>", m.inspect) + m = o.method(:foo) + assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect) + + c = Class.new + c.class_eval { def foo; end; } + m = c.new.method(:foo) + assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect) + m = c.instance_method(:foo) + assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect) + + c2 = Class.new(c) + c2.class_eval { private :foo } + m2 = c2.new.method(:foo) + assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo>", m2.inspect) + + bug7806 = '[ruby-core:52048] [Bug #7806]' + c3 = Class.new(c) + c3.class_eval { alias bar foo } + m3 = c3.new.method(:bar) + assert_equal("#<Method: #{c3.inspect}(#{c.inspect})#bar(foo)>", m3.inspect, bug7806) + end + + def test_callee_top_level + assert_in_out_err([], "p __callee__", %w(nil), []) + end + + def test_caller_top_level + assert_in_out_err([], "p caller", %w([]), []) + end + + def test_caller_negative_level + assert_raise(ArgumentError) { caller(-1) } + end + + def test_attrset_ivar + c = Class.new + c.class_eval { attr_accessor :foo } + o = c.new + o.method(:foo=).call(42) + assert_equal(42, o.foo) + assert_raise(ArgumentError) { o.method(:foo=).call(1, 2, 3) } + assert_raise(ArgumentError) { o.method(:foo).call(1) } + end + + def test_default_accessibility + tmethods = T.public_instance_methods + assert_include tmethods, :normal_method, 'normal methods are public by default' + assert_not_include tmethods, :initialize, '#initialize is private' + assert_not_include tmethods, :initialize_copy, '#initialize_copy is private' + assert_not_include tmethods, :initialize_clone, '#initialize_clone is private' + assert_not_include tmethods, :initialize_dup, '#initialize_dup is private' + assert_not_include tmethods, :respond_to_missing?, '#respond_to_missing? is private' + mmethods = M.public_instance_methods + assert_not_include mmethods, :func, 'module methods are private by default' + assert_include mmethods, :meth, 'normal methods are public by default' + end + + define_method(:pm0) {||} + define_method(:pm1) {|a|} + define_method(:pm2) {|a, b|} + define_method(:pmo1) {|a = nil, &b|} + define_method(:pmo2) {|a, b = nil|} + define_method(:pmo3) {|*a|} + define_method(:pmo4) {|a, *b, &c|} + define_method(:pmo5) {|a, *b, c|} + define_method(:pmo6) {|a, *b, c, &d|} + define_method(:pmo7) {|a, b = nil, *c, d, &e|} + define_method(:pma1) {|(a), &b| nil && a} + define_method(:pmk1) {|**|} + define_method(:pmk2) {|**o|} + define_method(:pmk3) {|a, **o|} + define_method(:pmk4) {|a = nil, **o|} + define_method(:pmk5) {|a, b = nil, **o|} + define_method(:pmk6) {|a, b = nil, c, **o|} + define_method(:pmk7) {|a, b = nil, *c, d, **o|} + + def test_bound_parameters + assert_equal([], method(:m0).parameters) + assert_equal([[:req, :a]], method(:m1).parameters) + assert_equal([[:req, :a], [:req, :b]], method(:m2).parameters) + assert_equal([[:opt, :a], [:block, :b]], method(:mo1).parameters) + assert_equal([[:req, :a], [:opt, :b]], method(:mo2).parameters) + assert_equal([[:rest, :a]], method(:mo3).parameters) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:mo4).parameters) + 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], [:block, :b]], method(:ma1).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) + assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:mk5).parameters) + assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:mk6).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters) + end + + def test_unbound_parameters + assert_equal([], self.class.instance_method(:m0).parameters) + assert_equal([[:req, :a]], self.class.instance_method(:m1).parameters) + assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:m2).parameters) + assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:mo1).parameters) + assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:mo2).parameters) + assert_equal([[:rest, :a]], self.class.instance_method(:mo3).parameters) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:mo4).parameters) + 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], [:block, :b]], self.class.instance_method(:ma1).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) + assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:mk5).parameters) + assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:mk6).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters) + end + + def test_bmethod_bound_parameters + assert_equal([], method(:pm0).parameters) + assert_equal([[:req, :a]], method(:pm1).parameters) + assert_equal([[:req, :a], [:req, :b]], method(:pm2).parameters) + assert_equal([[:opt, :a], [:block, :b]], method(:pmo1).parameters) + assert_equal([[:req, :a], [:opt, :b]], method(:pmo2).parameters) + assert_equal([[:rest, :a]], method(:pmo3).parameters) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).parameters) + assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).parameters) + 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, :o]], method(:pmk2).parameters) + assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).parameters) + assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).parameters) + assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:pmk5).parameters) + assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:pmk6).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters) + end + + def test_bmethod_unbound_parameters + assert_equal([], self.class.instance_method(:pm0).parameters) + assert_equal([[:req, :a]], self.class.instance_method(:pm1).parameters) + assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:pm2).parameters) + assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:pmo1).parameters) + assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:pmo2).parameters) + assert_equal([[:rest, :a]], self.class.instance_method(:pmo3).parameters) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:pmo4).parameters) + assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:pmo5).parameters) + assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:pmo6).parameters) + 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, :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) + assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:pmk5).parameters) + assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:pmk6).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters) + end + + def test_public_method_with_zsuper_method + c = Class.new + c.class_eval do + def foo + :ok + end + private :foo + end + d = Class.new(c) + d.class_eval do + public :foo + end + assert_equal(:ok, d.new.public_method(:foo).call) + end + + def test_public_methods_with_extended + m = Module.new do def m1; end end + a = Class.new do def a; end end + bug = '[ruby-dev:41553]' + obj = a.new + assert_equal([:a], obj.public_methods(false), bug) + obj.extend(m) + assert_equal([:m1, :a], obj.public_methods(false), bug) + end + + def test_visibility + assert_equal('method', defined?(mv1)) + assert_equal('method', defined?(mv2)) + assert_equal('method', defined?(mv3)) + + assert_equal('method', defined?(self.mv1)) + assert_equal(nil, defined?(self.mv2)) + assert_equal('method', defined?(self.mv3)) + + assert_equal(true, respond_to?(:mv1)) + assert_equal(false, respond_to?(:mv2)) + assert_equal(false, respond_to?(:mv3)) + + assert_equal(true, respond_to?(:mv1, true)) + assert_equal(true, respond_to?(:mv2, true)) + assert_equal(true, respond_to?(:mv3, true)) + + assert_nothing_raised { mv1 } + assert_nothing_raised { mv2 } + assert_nothing_raised { mv3 } + + assert_nothing_raised { self.mv1 } + assert_raise(NoMethodError) { self.mv2 } + assert_nothing_raised { self.mv3 } + + v = Visibility.new + + assert_equal('method', defined?(v.mv1)) + assert_equal(nil, defined?(v.mv2)) + assert_equal(nil, defined?(v.mv3)) + + assert_equal(true, v.respond_to?(:mv1)) + assert_equal(false, v.respond_to?(:mv2)) + assert_equal(false, v.respond_to?(:mv3)) + + assert_equal(true, v.respond_to?(:mv1, true)) + assert_equal(true, v.respond_to?(:mv2, true)) + assert_equal(true, v.respond_to?(:mv3, true)) + + assert_nothing_raised { v.mv1 } + assert_raise(NoMethodError) { v.mv2 } + assert_raise(NoMethodError) { v.mv3 } + + assert_nothing_raised { v.__send__(:mv1) } + assert_nothing_raised { v.__send__(:mv2) } + assert_nothing_raised { v.__send__(:mv3) } + + assert_nothing_raised { v.instance_eval { mv1 } } + assert_nothing_raised { v.instance_eval { mv2 } } + assert_nothing_raised { v.instance_eval { mv3 } } + end + + def test_bound_method_entry + bug6171 = '[ruby-core:43383]' + assert_ruby_status([], <<-EOC, bug6171) + class Bug6171 + def initialize(target) + define_singleton_method(:reverse, target.method(:reverse).to_proc) + end + end + 100.times {p = Bug6171.new('test'); 1000.times {p.reverse}} + EOC + end + + def test___dir__ + assert_instance_of String, __dir__ + assert_equal(File.dirname(File.realpath(__FILE__)), __dir__) + bug8436 = '[ruby-core:55123] [Bug #8436]' + assert_equal(__dir__, eval("__dir__", binding), bug8436) + bug8662 = '[ruby-core:56099] [Bug #8662]' + assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662) + assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662) + end + + def test_alias_owner + bug7613 = '[ruby-core:51105]' + bug7993 = '[Bug #7993]' + c = Class.new { + def foo + end + prepend Module.new + attr_reader :zot + } + x = c.new + class << x + alias bar foo + end + assert_equal(c, c.instance_method(:foo).owner) + assert_equal(c, x.method(:foo).owner) + assert_equal(x.singleton_class, x.method(:bar).owner) + assert_not_equal(x.method(:foo), x.method(:bar), bug7613) + assert_equal(c, x.method(:zot).owner, bug7993) + assert_equal(c, c.instance_method(:zot).owner, bug7993) + end + + def test_included + m = Module.new { + def foo + end + } + c = Class.new { + def foo + end + include m + } + assert_equal(c, c.instance_method(:foo).owner) + end + + def test_prepended + bug7836 = '[ruby-core:52160] [Bug #7836]' + bug7988 = '[ruby-core:53038] [Bug #7988]' + m = Module.new { + def foo + end + } + c = Class.new { + def foo + end + prepend m + } + assert_raise(NameError, bug7988) {Module.new{prepend m}.instance_method(:bar)} + true || c || bug7836 + end + + def test_gced_bmethod + assert_normal_exit %q{ + require 'irb' + IRB::Irb.module_eval do + define_method(:eval_input) do + IRB::Irb.module_eval { alias_method :eval_input, :to_s } + GC.start + Kernel + end + end + IRB.start + }, '[Bug #7825]' + end + + def test_unlinked_method_entry_in_method_object_bug + bug8100 = '[ruby-core:53640] [Bug #8100]' + begin + assert_normal_exit %q{ + loop do + def x + "hello" * 1000 + end + method(:x).call + end + }, bug8100, timeout: 2 + rescue Timeout::Error => e + else + end + assert_raise(Timeout::Error, bug8100) {raise e if e} + end + + def test_singleton_method + feature8391 = '[ruby-core:54914] [Feature #8391]' + c1 = Class.new + c1.class_eval { def foo; :foo; end } + o = c1.new + def o.bar; :bar; end + assert_nothing_raised(NameError) {o.method(:foo)} + assert_raise(NameError, feature8391) {o.singleton_method(:foo)} + m = assert_nothing_raised(NameError, feature8391) {break o.singleton_method(:bar)} + assert_equal(:bar, m.call, feature8391) + end + + Feature9783 = '[ruby-core:62212] [Feature #9783]' + + def assert_curry_three_args(m) + curried = m.curry + assert_equal(6, curried.(1).(2).(3), Feature9783) + + curried = m.curry(3) + assert_equal(6, curried.(1).(2).(3), Feature9783) + + assert_raise_with_message(ArgumentError, /wrong number/) {m.curry(2)} + end + + def test_curry_method + c = Class.new { + def three_args(a,b,c) a + b + c end + } + assert_curry_three_args(c.new.method(:three_args)) + end + + def test_curry_from_proc + c = Class.new { + define_method(:three_args) {|a,b,c| a + b + c} + } + assert_curry_three_args(c.new.method(:three_args)) + end + + def assert_curry_var_args(m) + curried = m.curry(3) + assert_equal([1, 2, 3], curried.(1).(2).(3), Feature9783) + + curried = m.curry(2) + assert_equal([1, 2], curried.(1).(2), Feature9783) + + curried = m.curry(0) + assert_equal([1], curried.(1), Feature9783) + end + + def test_curry_var_args + c = Class.new { + def var_args(*args) args end + } + assert_curry_var_args(c.new.method(:var_args)) + end + + def test_curry_from_proc_var_args + c = Class.new { + define_method(:var_args) {|*args| args} + } + assert_curry_var_args(c.new.method(:var_args)) + end + + Feature9781 = '[ruby-core:62202] [Feature #9781]' + + def test_super_method + o = Derived.new + m = o.method(:foo).super_method + assert_equal(Base, m.owner, Feature9781) + assert_same(o, m.receiver, Feature9781) + assert_equal(:foo, m.name, Feature9781) + m = assert_nothing_raised(NameError, Feature9781) {break m.super_method} + assert_nil(m, Feature9781) + end + + def test_super_method_unbound + m = Derived.instance_method(:foo) + m = m.super_method + assert_equal(Base.instance_method(:foo), m, Feature9781) + m = assert_nothing_raised(NameError, Feature9781) {break m.super_method} + assert_nil(m, Feature9781) + end + + def test_super_method_module + m1 = Module.new {def foo; end} + c1 = Class.new(Derived) {include m1; def foo; end} + m = c1.instance_method(:foo) + assert_equal(c1, m.owner, Feature9781) + m = m.super_method + assert_equal(m1, m.owner, Feature9781) + m = m.super_method + assert_equal(Derived, m.owner, Feature9781) + m = m.super_method + assert_equal(Base, m.owner, Feature9781) + m2 = Module.new {def foo; end} + o = c1.new.extend(m2) + m = o.method(:foo) + assert_equal(m2, m.owner, Feature9781) + m = m.super_method + assert_equal(c1, m.owner, Feature9781) + assert_same(o, m.receiver, Feature9781) + end + + def test_super_method_removed + c1 = Class.new {private def foo; end} + c2 = Class.new(c1) {public :foo} + c3 = Class.new(c2) {def foo; end} + c1.class_eval {undef foo} + m = c3.instance_method(:foo) + m = assert_nothing_raised(NameError, Feature9781) {break m.super_method} + assert_nil(m, Feature9781) + end + + def rest_parameter(*rest) + rest + end + + def test_splat_long_array + n = 10_000_000 + assert_equal n , rest_parameter(*(1..n)).size, '[Feature #10440]' + end + + def test_insecure_method + m = "\u{5371 967a}" + c = Class.new do + proc {$SAFE=3;def foo;end}.call + alias_method m, "foo" + eval "def bar; #{m}; end" + end + obj = c.new + assert_raise_with_message(SecurityError, /#{m}/) do + obj.bar + end + end + + def test_to_proc_binding + bug11012 = '[ruby-core:68673] [Bug #11012]' + class << (obj = Object.new) + src = 1000.times.map {|i|"v#{i} = nil"}.join("\n") + eval("def foo()\n""#{src}\n""end") + end + + b = obj.method(:foo).to_proc.binding + b.local_variables.each_with_index {|n, i| + b.local_variable_set(n, i) + } + assert_equal([998, 999], %w[v998 v999].map {|n| b.local_variable_get(n)}, bug11012) + end +end diff --git a/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb b/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb new file mode 100644 index 0000000..982b57e --- /dev/null +++ b/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb @@ -0,0 +1,25 @@ +# -*- coding: cp932 -*- +# This test is in a differnt file than TestUnicodeEscapes +# So that we can have a different coding comment above + +require 'test/unit' + +class TestMixedUnicodeEscape < Test::Unit::TestCase + def test_basic + # Unicode escapes do work in an sjis encoded file, but only + # if they don't contain other multi-byte chars + assert_equal("A", "\u0041") + # 8-bit character escapes are okay. + assert_equal("B\xFF", "\u0042\xFF") + + # sjis mb chars mixed with Unicode shound not work + assert_raise(SyntaxError) { eval %q("\u1234")} + assert_raise(SyntaxError) { eval %q("\u{1234}")} + + # String interpolation turns into an expression and we get + # a different kind of error, but we still can't mix these + assert_raise(Encoding::CompatibilityError) { eval %q("\u{1234}#{nil}")} + assert_raise(Encoding::CompatibilityError) { eval %q("#{nil}\u1234")} + + end +end diff --git a/jni/ruby/test/ruby/test_module.rb b/jni/ruby/test/ruby/test_module.rb new file mode 100644 index 0000000..2f3e5c2 --- /dev/null +++ b/jni/ruby/test/ruby/test_module.rb @@ -0,0 +1,2032 @@ +require 'test/unit' +require 'pp' + +$m0 = Module.nesting + +class TestModule < Test::Unit::TestCase + def _wrap_assertion + yield + end + + def assert_method_defined?(klass, mid, message="") + message = build_message(message, "#{klass}\##{mid} expected to be defined.") + _wrap_assertion do + klass.method_defined?(mid) or + raise Test::Unit::AssertionFailedError, message, caller(3) + end + end + + def assert_method_not_defined?(klass, mid, message="") + message = build_message(message, "#{klass}\##{mid} expected to not be defined.") + _wrap_assertion do + klass.method_defined?(mid) and + raise Test::Unit::AssertionFailedError, message, caller(3) + end + end + + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_LT_0 + assert_equal true, String < Object + assert_equal false, Object < String + assert_nil String < Array + assert_equal true, Array < Enumerable + assert_equal false, Enumerable < Array + assert_nil Proc < Comparable + assert_nil Comparable < Proc + end + + def test_GT_0 + assert_equal false, String > Object + assert_equal true, Object > String + assert_nil String > Array + assert_equal false, Array > Enumerable + assert_equal true, Enumerable > Array + assert_nil Comparable > Proc + assert_nil Proc > Comparable + end + + def test_CMP_0 + assert_equal(-1, (String <=> Object)) + assert_equal 1, (Object <=> String) + assert_nil(Array <=> String) + end + + ExpectedException = NoMethodError + + # Support stuff + + module Mixin + MIXIN = 1 + def mixin + end + end + + module User + USER = 2 + include Mixin + def user + end + end + + module Other + def other + end + end + + class AClass + def AClass.cm1 + "cm1" + end + def AClass.cm2 + cm1 + "cm2" + cm3 + end + def AClass.cm3 + "cm3" + end + + private_class_method :cm1, "cm3" + + def aClass + :aClass + end + + def aClass1 + :aClass1 + end + + def aClass2 + :aClass2 + end + + private :aClass1 + protected :aClass2 + end + + class BClass < AClass + def bClass1 + :bClass1 + end + + private + + def bClass2 + :bClass2 + end + + protected + def bClass3 + :bClass3 + end + end + + class CClass < BClass + def self.cClass + end + end + + MyClass = AClass.clone + class MyClass + public_class_method :cm1 + end + + # ----------------------------------------------------------- + + def test_CMP # '<=>' + assert_equal( 0, Mixin <=> Mixin) + assert_equal(-1, User <=> Mixin) + assert_equal( 1, Mixin <=> User) + + assert_equal( 0, Object <=> Object) + assert_equal(-1, String <=> Object) + assert_equal( 1, Object <=> String) + end + + def test_GE # '>=' + assert_operator(Mixin, :>=, User) + assert_operator(Mixin, :>=, Mixin) + assert_not_operator(User, :>=, Mixin) + + assert_operator(Object, :>=, String) + assert_operator(String, :>=, String) + assert_not_operator(String, :>=, Object) + end + + def test_GT # '>' + assert_operator(Mixin, :>, User) + assert_not_operator(Mixin, :>, Mixin) + assert_not_operator(User, :>, Mixin) + + assert_operator(Object, :>, String) + assert_not_operator(String, :>, String) + assert_not_operator(String, :>, Object) + end + + def test_LE # '<=' + assert_operator(User, :<=, Mixin) + assert_operator(Mixin, :<=, Mixin) + assert_not_operator(Mixin, :<=, User) + + assert_operator(String, :<=, Object) + assert_operator(String, :<=, String) + assert_not_operator(Object, :<=, String) + end + + def test_LT # '<' + assert_operator(User, :<, Mixin) + assert_not_operator(Mixin, :<, Mixin) + assert_not_operator(Mixin, :<, User) + + assert_operator(String, :<, Object) + assert_not_operator(String, :<, String) + assert_not_operator(Object, :<, String) + end + + def test_VERY_EQUAL # '===' + assert_operator(Object, :===, self) + assert_operator(Test::Unit::TestCase, :===, self) + assert_operator(TestModule, :===, self) + assert_not_operator(String, :===, self) + end + + def test_ancestors + assert_equal([User, Mixin], User.ancestors) + assert_equal([Mixin], Mixin.ancestors) + + ancestors = Object.ancestors + mixins = ancestors - [Object, Kernel, BasicObject] + mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String) + assert_equal([Object, Kernel, BasicObject], ancestors - mixins) + assert_equal([String, Comparable, Object, Kernel, BasicObject], String.ancestors - mixins) + end + + CLASS_EVAL = 2 + @@class_eval = 'b' + + def test_class_eval + Other.class_eval("CLASS_EVAL = 1") + assert_equal(1, Other::CLASS_EVAL) + assert_include(Other.constants, :CLASS_EVAL) + assert_equal(2, Other.class_eval { CLASS_EVAL }) + + Other.class_eval("@@class_eval = 'a'") + assert_equal('a', Other.class_variable_get(:@@class_eval)) + assert_equal('b', Other.class_eval { @@class_eval }) + + Other.class_eval do + module_function + + def class_eval_test + "foo" + end + end + assert_equal("foo", Other.class_eval_test) + + assert_equal([Other], Other.class_eval { |*args| args }) + end + + def test_const_defined? + assert_operator(Math, :const_defined?, :PI) + assert_operator(Math, :const_defined?, "PI") + assert_not_operator(Math, :const_defined?, :IP) + assert_not_operator(Math, :const_defined?, "IP") + end + + def each_bad_constants(m, &b) + [ + "#<Class:0x7b8b718b>", + ":Object", + "", + ":", + ["String::", "[Bug #7573]"], + "\u3042", + "Name?", + ].each do |name, msg| + expected = "wrong constant name %s" % quote(name) + msg = "#{msg}#{': ' if msg}wrong constant name #{name.dump}" + assert_raise_with_message(NameError, expected, "#{msg} to #{m}") do + yield name + end + end + end + + def test_bad_constants_get + each_bad_constants("get") {|name| + Object.const_get name + } + end + + def test_bad_constants_defined + each_bad_constants("defined?") {|name| + Object.const_defined? name + } + end + + def test_leading_colons + assert_equal Object, AClass.const_get('::Object') + end + + def test_const_get + assert_equal(Math::PI, Math.const_get("PI")) + assert_equal(Math::PI, Math.const_get(:PI)) + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "PI"; end + def n.count; @count; end + assert_equal(Math::PI, Math.const_get(n)) + assert_equal(1, n.count) + end + + def test_nested_get + assert_equal Other, Object.const_get([self.class, Other].join('::')) + assert_equal User::USER, self.class.const_get([User, 'USER'].join('::')) + end + + def test_nested_get_symbol + const = [self.class, Other].join('::').to_sym + assert_raise(NameError) {Object.const_get(const)} + + const = [User, 'USER'].join('::').to_sym + assert_raise(NameError) {self.class.const_get(const)} + end + + def test_nested_get_const_missing + classes = [] + klass = Class.new { + define_singleton_method(:const_missing) { |name| + classes << name + klass + } + } + klass.const_get("Foo::Bar::Baz") + assert_equal [:Foo, :Bar, :Baz], classes + end + + def test_nested_get_bad_class + assert_raise(TypeError) do + self.class.const_get([User, 'USER', 'Foo'].join('::')) + end + end + + def test_nested_defined + assert_send([Object, :const_defined?, [self.class.name, 'Other'].join('::')]) + assert_send([self.class, :const_defined?, 'User::USER']) + assert_not_send([self.class, :const_defined?, 'User::Foo']) + end + + def test_nested_defined_symbol + const = [self.class, Other].join('::').to_sym + assert_raise(NameError) {Object.const_defined?(const)} + + const = [User, 'USER'].join('::').to_sym + assert_raise(NameError) {self.class.const_defined?(const)} + end + + def test_nested_defined_bad_class + assert_raise(TypeError) do + self.class.const_defined?('User::USER::Foo') + end + end + + def test_const_set + assert_not_operator(Other, :const_defined?, :KOALA) + Other.const_set(:KOALA, 99) + assert_operator(Other, :const_defined?, :KOALA) + assert_equal(99, Other::KOALA) + Other.const_set("WOMBAT", "Hi") + assert_equal("Hi", Other::WOMBAT) + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "HOGE"; end + def n.count; @count; end + def n.count=(v); @count=v; end + assert_not_operator(Other, :const_defined?, :HOGE) + Other.const_set(n, 999) + assert_equal(1, n.count) + n.count = 0 + assert_equal(999, Other.const_get(n)) + assert_equal(1, n.count) + n.count = 0 + assert_equal(true, Other.const_defined?(n)) + assert_equal(1, n.count) + end + + def test_constants + assert_equal([:MIXIN], Mixin.constants) + assert_equal([:MIXIN, :USER], User.constants.sort) + end + + def test_self_initialize_copy + bug9535 = '[ruby-dev:47989] [Bug #9535]' + m = Module.new do + def foo + :ok + end + initialize_copy(self) + end + assert_equal(:ok, Object.new.extend(m).foo, bug9535) + end + + def test_initialize_copy_empty + bug9813 = '[ruby-dev:48182] [Bug #9813]' + m = Module.new do + def x + end + const_set(:X, 1) + @x = 2 + end + assert_equal([:x], m.instance_methods) + assert_equal([:@x], m.instance_variables) + assert_equal([:X], m.constants) + m.module_eval do + initialize_copy(Module.new) + end + assert_empty(m.instance_methods, bug9813) + assert_empty(m.instance_variables, bug9813) + assert_empty(m.constants, bug9813) + end + + def test_dup + bug6454 = '[ruby-core:45132]' + + a = Module.new + Other.const_set :BUG6454, a + b = a.dup + Other.const_set :BUG6454_dup, b + + assert_equal "TestModule::Other::BUG6454_dup", b.inspect, bug6454 + end + + def test_dup_anonymous + bug6454 = '[ruby-core:45132]' + + a = Module.new + original = a.inspect + + b = a.dup + + assert_not_equal original, b.inspect, bug6454 + end + + def test_public_include + assert_nothing_raised('#8846') do + Module.new.include(Module.new { def foo; end }).instance_methods == [:foo] + end + end + + def test_include_toplevel + assert_separately([], <<-EOS) + Mod = Module.new {def foo; :include_foo end} + TOPLEVEL_BINDING.eval('include Mod') + + assert_equal(:include_foo, TOPLEVEL_BINDING.eval('foo')) + assert_equal([Object, Mod], Object.ancestors.slice(0, 2)) + EOS + end + + def test_included_modules + assert_equal([], Mixin.included_modules) + assert_equal([Mixin], User.included_modules) + + mixins = Object.included_modules - [Kernel] + mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String) + assert_equal([Kernel], Object.included_modules - mixins) + assert_equal([Comparable, Kernel], String.included_modules - mixins) + end + + def test_instance_methods + assert_equal([:user], User.instance_methods(false)) + assert_equal([:user, :mixin].sort, User.instance_methods(true).sort) + assert_equal([:mixin], Mixin.instance_methods) + assert_equal([:mixin], Mixin.instance_methods(true)) + assert_equal([:cClass], (class << CClass; self; end).instance_methods(false)) + assert_equal([], (class << BClass; self; end).instance_methods(false)) + assert_equal([:cm2], (class << AClass; self; end).instance_methods(false)) + # Ruby 1.8 feature change: + # #instance_methods includes protected methods. + #assert_equal([:aClass], AClass.instance_methods(false)) + assert_equal([:aClass, :aClass2], AClass.instance_methods(false).sort) + assert_equal([:aClass, :aClass2], + (AClass.instance_methods(true) - Object.instance_methods(true)).sort) + end + + def test_method_defined? + assert_method_not_defined?(User, :wombat) + assert_method_defined?(User, :user) + assert_method_defined?(User, :mixin) + assert_method_not_defined?(User, :wombat) + assert_method_defined?(User, :user) + assert_method_defined?(User, :mixin) + end + + def module_exec_aux + Proc.new do + def dynamically_added_method_3; end + end + end + def module_exec_aux_2(&block) + User.module_exec(&block) + end + + def test_module_exec + User.module_exec do + def dynamically_added_method_1; end + end + assert_method_defined?(User, :dynamically_added_method_1) + + block = Proc.new do + def dynamically_added_method_2; end + end + User.module_exec(&block) + assert_method_defined?(User, :dynamically_added_method_2) + + User.module_exec(&module_exec_aux) + assert_method_defined?(User, :dynamically_added_method_3) + + module_exec_aux_2 do + def dynamically_added_method_4; end + end + assert_method_defined?(User, :dynamically_added_method_4) + end + + def test_module_eval + User.module_eval("MODULE_EVAL = 1") + assert_equal(1, User::MODULE_EVAL) + assert_include(User.constants, :MODULE_EVAL) + User.instance_eval("remove_const(:MODULE_EVAL)") + assert_not_include(User.constants, :MODULE_EVAL) + end + + def test_name + assert_equal("Fixnum", Fixnum.name) + assert_equal("TestModule::Mixin", Mixin.name) + assert_equal("TestModule::User", User.name) + end + + def test_classpath + m = Module.new + n = Module.new + m.const_set(:N, n) + assert_nil(m.name) + assert_nil(n.name) + assert_equal([:N], m.constants) + m.module_eval("module O end") + assert_equal([:N, :O], m.constants) + m.module_eval("class C; end") + assert_equal([:N, :O, :C], m.constants) + assert_nil(m::N.name) + assert_match(/\A#<Module:.*>::O\z/, m::O.name) + assert_match(/\A#<Module:.*>::C\z/, m::C.name) + self.class.const_set(:M, m) + prefix = self.class.name + "::M::" + assert_equal(prefix+"N", m.const_get(:N).name) + assert_equal(prefix+"O", m.const_get(:O).name) + assert_equal(prefix+"C", m.const_get(:C).name) + end + + def test_private_class_method + assert_raise(ExpectedException) { AClass.cm1 } + assert_raise(ExpectedException) { AClass.cm3 } + assert_equal("cm1cm2cm3", AClass.cm2) + end + + def test_private_instance_methods + assert_equal([:aClass1], AClass.private_instance_methods(false)) + assert_equal([:bClass2], BClass.private_instance_methods(false)) + assert_equal([:aClass1, :bClass2], + (BClass.private_instance_methods(true) - + Object.private_instance_methods(true)).sort) + end + + def test_protected_instance_methods + assert_equal([:aClass2], AClass.protected_instance_methods) + assert_equal([:bClass3], BClass.protected_instance_methods(false)) + assert_equal([:bClass3, :aClass2].sort, + (BClass.protected_instance_methods(true) - + Object.protected_instance_methods(true)).sort) + end + + def test_public_class_method + assert_equal("cm1", MyClass.cm1) + assert_equal("cm1cm2cm3", MyClass.cm2) + assert_raise(ExpectedException) { eval "MyClass.cm3" } + end + + def test_public_instance_methods + assert_equal([:aClass], AClass.public_instance_methods(false)) + assert_equal([:bClass1], BClass.public_instance_methods(false)) + end + + def test_s_constants + c1 = Module.constants + Object.module_eval "WALTER = 99" + c2 = Module.constants + assert_equal([:WALTER], c2 - c1) + + assert_equal([], Module.constants(true)) + assert_equal([], Module.constants(false)) + + src = <<-INPUT + ary = Module.constants + module M + WALTER = 99 + end + class Module + include M + end + p Module.constants - ary, Module.constants(true), Module.constants(false) + INPUT + assert_in_out_err([], src, %w([:M] [:WALTER] []), []) + + klass = Class.new do + const_set(:X, 123) + end + assert_equal(false, klass.class_eval { Module.constants }.include?(:X)) + end + + module M1 + $m1 = Module.nesting + module M2 + $m2 = Module.nesting + end + end + + def test_s_nesting + assert_equal([], $m0) + assert_equal([TestModule::M1, TestModule], $m1) + assert_equal([TestModule::M1::M2, + TestModule::M1, TestModule], $m2) + end + + def test_s_new + m = Module.new + assert_instance_of(Module, m) + end + + def test_freeze + m = Module.new + m.freeze + assert_raise(RuntimeError) do + m.module_eval do + def foo; end + end + end + end + + def test_attr_obsoleted_flag + c = Class.new + c.class_eval do + def initialize + @foo = :foo + @bar = :bar + end + attr :foo, true + attr :bar, false + end + o = c.new + assert_equal(true, o.respond_to?(:foo)) + assert_equal(true, o.respond_to?(:foo=)) + assert_equal(true, o.respond_to?(:bar)) + assert_equal(false, o.respond_to?(:bar=)) + end + + def test_const_get_evaled + c1 = Class.new + c2 = Class.new(c1) + + eval("c1::Foo = :foo") + assert_equal(:foo, c1::Foo) + assert_equal(:foo, c2::Foo) + assert_equal(:foo, c2.const_get(:Foo)) + assert_raise(NameError) { c2.const_get(:Foo, false) } + + eval("c1::Foo = :foo") + assert_raise(NameError) { c1::Bar } + assert_raise(NameError) { c2::Bar } + assert_raise(NameError) { c2.const_get(:Bar) } + assert_raise(NameError) { c2.const_get(:Bar, false) } + assert_raise(NameError) { c2.const_get("Bar", false) } + assert_raise(NameError) { c2.const_get("BaR11", false) } + assert_raise(NameError) { Object.const_get("BaR11", false) } + + c1.instance_eval do + def const_missing(x) + x + end + end + + assert_equal(:Bar, c1::Bar) + assert_equal(:Bar, c2::Bar) + assert_equal(:Bar, c2.const_get(:Bar)) + assert_equal(:Bar, c2.const_get(:Bar, false)) + assert_equal(:Bar, c2.const_get("Bar")) + assert_equal(:Bar, c2.const_get("Bar", false)) + + v = c2.const_get("Bar11", false) + assert_equal("Bar11".to_sym, v) + + assert_raise(NameError) { c1.const_get(:foo) } + end + + def test_const_set_invalid_name + c1 = Class.new + assert_raise_with_message(NameError, /foo/) { c1.const_set(:foo, :foo) } + assert_raise_with_message(NameError, /bar/) { c1.const_set("bar", :foo) } + assert_raise_with_message(TypeError, /1/) { c1.const_set(1, :foo) } + assert_nothing_raised(NameError) { c1.const_set("X\u{3042}", :foo) } + assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16be"), :foo) } + assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16le"), :foo) } + assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32be"), :foo) } + assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32le"), :foo) } + cx = EnvUtil.labeled_class("X\u{3042}") + EnvUtil.with_default_internal(Encoding::UTF_8) { + assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) } + } + end + + def test_const_get_invalid_name + c1 = Class.new + assert_raise(NameError) { c1.const_get(:foo) } + bug5084 = '[ruby-dev:44200]' + assert_raise(TypeError, bug5084) { c1.const_get(1) } + bug7574 = '[ruby-dev:46749]' + assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { + Object.const_get("String\0") + } + end + + def test_const_defined_invalid_name + c1 = Class.new + assert_raise(NameError) { c1.const_defined?(:foo) } + bug5084 = '[ruby-dev:44200]' + assert_raise(TypeError, bug5084) { c1.const_defined?(1) } + bug7574 = '[ruby-dev:46749]' + assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { + Object.const_defined?("String\0") + } + end + + def test_const_get_no_inherited + bug3422 = '[ruby-core:30719]' + assert_in_out_err([], <<-INPUT, %w[1 NameError A], [], bug3422) + BasicObject::A = 1 + puts [true, false].map {|inh| + begin + Object.const_get(:A, inh) + rescue NameError => e + [e.class, e.name] + end + } + INPUT + end + + def test_const_get_inherited + bug3423 = '[ruby-core:30720]' + assert_in_out_err([], <<-INPUT, %w[NameError A NameError A], [], bug3423) + module Foo; A = 1; end + class Object; include Foo; end + class Bar; include Foo; end + + puts [Object, Bar].map {|klass| + begin + klass.const_get(:A, false) + rescue NameError => e + [e.class, e.name] + end + } + INPUT + end + + def test_const_in_module + bug3423 = '[ruby-core:37698]' + assert_in_out_err([], <<-INPUT, %w[ok], [], bug3423) + module LangModuleSpecInObject + module LangModuleTop + end + end + include LangModuleSpecInObject + module LangModuleTop + end + puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop + INPUT + + bug5264 = '[ruby-core:39227]' + assert_in_out_err([], <<-'INPUT', [], [], bug5264) + class A + class X; end + end + class B < A + module X; end + end + INPUT + end + + def test_class_variable_get + c = Class.new + c.class_eval('@@foo = :foo') + assert_equal(:foo, c.class_variable_get(:@@foo)) + assert_raise(NameError) { c.class_variable_get(:@@bar) } # c.f. instance_variable_get + assert_raise(NameError) { c.class_variable_get(:'@@') } + assert_raise(NameError) { c.class_variable_get('@@') } + assert_raise(NameError) { c.class_variable_get(:foo) } + assert_raise(NameError) { c.class_variable_get("bar") } + assert_raise(TypeError) { c.class_variable_get(1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end + def n.count; @count; end + assert_equal(:foo, c.class_variable_get(n)) + assert_equal(1, n.count) + end + + def test_class_variable_set + c = Class.new + c.class_variable_set(:@@foo, :foo) + assert_equal(:foo, c.class_eval('@@foo')) + assert_raise(NameError) { c.class_variable_set(:'@@', 1) } + assert_raise(NameError) { c.class_variable_set('@@', 1) } + assert_raise(NameError) { c.class_variable_set(:foo, 1) } + assert_raise(NameError) { c.class_variable_set("bar", 1) } + assert_raise(TypeError) { c.class_variable_set(1, 1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end + def n.count; @count; end + c.class_variable_set(n, :bar) + assert_equal(:bar, c.class_eval('@@foo')) + assert_equal(1, n.count) + end + + def test_class_variable_defined + c = Class.new + c.class_eval('@@foo = :foo') + assert_equal(true, c.class_variable_defined?(:@@foo)) + assert_equal(false, c.class_variable_defined?(:@@bar)) + assert_raise(NameError) { c.class_variable_defined?(:'@@') } + assert_raise(NameError) { c.class_variable_defined?('@@') } + assert_raise(NameError) { c.class_variable_defined?(:foo) } + assert_raise(NameError) { c.class_variable_defined?("bar") } + assert_raise(TypeError) { c.class_variable_defined?(1) } + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end + def n.count; @count; end + assert_equal(true, c.class_variable_defined?(n)) + assert_equal(1, n.count) + end + + def test_remove_class_variable + c = Class.new + c.class_eval('@@foo = :foo') + c.class_eval { remove_class_variable(:@@foo) } + assert_equal(false, c.class_variable_defined?(:@@foo)) + end + + def test_export_method + m = Module.new + assert_raise(NameError) do + m.instance_eval { public(:foo) } + end + end + + def test_attr + assert_in_out_err([], <<-INPUT, %w(:ok nil), /warning: private attribute\?$/) + $VERBOSE = true + c = Class.new + c.instance_eval do + private + attr_reader :foo + end + o = c.new + o.foo rescue p(:ok) + p(o.instance_eval { foo }) + INPUT + + c = Class.new + assert_raise(NameError) do + c.instance_eval { attr_reader :"." } + end + end + + def test_undef + c = Class.new + assert_raise(NameError) do + c.instance_eval { undef_method(:foo) } + end + + m = Module.new + assert_raise(NameError) do + m.instance_eval { undef_method(:foo) } + end + + o = Object.new + assert_raise(NameError) do + class << o; self; end.instance_eval { undef_method(:foo) } + end + + %w(object_id __send__ initialize).each do |n| + assert_in_out_err([], <<-INPUT, [], %r"warning: undefining `#{n}' may cause serious problems$") + $VERBOSE = false + Class.new.instance_eval { undef_method(:#{n}) } + INPUT + end + end + + def test_alias + m = Module.new + assert_raise(NameError) do + m.class_eval { alias foo bar } + end + + assert_in_out_err([], <<-INPUT, %w(2), /discarding old foo$/) + $VERBOSE = true + c = Class.new + c.class_eval do + def foo; 1; end + def bar; 2; end + end + c.class_eval { alias foo bar } + p c.new.foo + INPUT + end + + def test_mod_constants + m = Module.new + m.const_set(:Foo, :foo) + assert_equal([:Foo], m.constants(true)) + assert_equal([:Foo], m.constants(false)) + m.instance_eval { remove_const(:Foo) } + end + + class Bug9413 + class << self + Foo = :foo + end + end + + def test_singleton_constants + bug9413 = '[ruby-core:59763] [Bug #9413]' + c = Bug9413.singleton_class + assert_include(c.constants(true), :Foo, bug9413) + assert_include(c.constants(false), :Foo, bug9413) + end + + def test_frozen_module + m = Module.new + m.freeze + assert_raise(RuntimeError) do + m.instance_eval { undef_method(:foo) } + end + end + + def test_frozen_class + c = Class.new + c.freeze + assert_raise(RuntimeError) do + c.instance_eval { undef_method(:foo) } + end + end + + def test_frozen_singleton_class + klass = Class.new + o = klass.new + c = class << o; self; end + c.freeze + assert_raise_with_message(RuntimeError, /frozen/) do + c.instance_eval { undef_method(:foo) } + end + klass.class_eval do + def self.foo + end + end + end + + def test_method_defined + c = Class.new + c.class_eval do + def foo; end + def bar; end + def baz; end + public :foo + protected :bar + private :baz + end + + assert_equal(true, c.public_method_defined?(:foo)) + assert_equal(false, c.public_method_defined?(:bar)) + assert_equal(false, c.public_method_defined?(:baz)) + + assert_equal(false, c.protected_method_defined?(:foo)) + assert_equal(true, c.protected_method_defined?(:bar)) + assert_equal(false, c.protected_method_defined?(:baz)) + + assert_equal(false, c.private_method_defined?(:foo)) + assert_equal(false, c.private_method_defined?(:bar)) + assert_equal(true, c.private_method_defined?(:baz)) + end + + def test_top_public_private + assert_in_out_err([], <<-INPUT, %w([:foo] [:bar]), []) + private + def foo; :foo; end + public + def bar; :bar; end + p self.private_methods.grep(/^foo$|^bar$/) + p self.methods.grep(/^foo$|^bar$/) + INPUT + end + + def test_append_features + t = nil + m = Module.new + m.module_eval do + def foo; :foo; end + end + class << m; self; end.class_eval do + define_method(:append_features) do |mod| + t = mod + super(mod) + end + end + + m2 = Module.new + m2.module_eval { include(m) } + assert_equal(m2, t) + + o = Object.new + o.extend(m2) + assert_equal(true, o.respond_to?(:foo)) + end + + def test_append_features_raise + m = Module.new + m.module_eval do + def foo; :foo; end + end + class << m; self; end.class_eval do + define_method(:append_features) {|mod| raise } + end + + m2 = Module.new + assert_raise(RuntimeError) do + m2.module_eval { include(m) } + end + + o = Object.new + o.extend(m2) + assert_equal(false, o.respond_to?(:foo)) + end + + def test_append_features_type_error + assert_raise(TypeError) do + Module.new.instance_eval { append_features(1) } + end + end + + def test_included + m = Module.new + m.module_eval do + def foo; :foo; end + end + class << m; self; end.class_eval do + define_method(:included) {|mod| raise } + end + + m2 = Module.new + assert_raise(RuntimeError) do + m2.module_eval { include(m) } + end + + o = Object.new + o.extend(m2) + assert_equal(true, o.respond_to?(:foo)) + end + + def test_cyclic_include + m1 = Module.new + m2 = Module.new + m1.instance_eval { include(m2) } + assert_raise(ArgumentError) do + m2.instance_eval { include(m1) } + end + end + + def test_include_p + m = Module.new + c1 = Class.new + c1.instance_eval { include(m) } + c2 = Class.new(c1) + assert_equal(true, c1.include?(m)) + assert_equal(true, c2.include?(m)) + assert_equal(false, m.include?(m)) + end + + def test_send + a = AClass.new + assert_equal(:aClass, a.__send__(:aClass)) + assert_equal(:aClass1, a.__send__(:aClass1)) + assert_equal(:aClass2, a.__send__(:aClass2)) + b = BClass.new + assert_equal(:aClass, b.__send__(:aClass)) + assert_equal(:aClass1, b.__send__(:aClass1)) + assert_equal(:aClass2, b.__send__(:aClass2)) + assert_equal(:bClass1, b.__send__(:bClass1)) + assert_equal(:bClass2, b.__send__(:bClass2)) + assert_equal(:bClass3, b.__send__(:bClass3)) + end + + + def test_nonascii_name + c = eval("class ::C\u{df}; self; end") + assert_equal("C\u{df}", c.name, '[ruby-core:24600]') + c = eval("class C\u{df}; self; end") + assert_equal("TestModule::C\u{df}", c.name, '[ruby-core:24600]') + end + + def test_method_added + memo = [] + mod = Module.new do + mod = self + (class << self ; self ; end).class_eval do + define_method :method_added do |sym| + memo << sym + memo << mod.instance_methods(false) + memo << (mod.instance_method(sym) rescue nil) + end + end + def f + end + alias g f + attr_reader :a + attr_writer :a + end + assert_equal :f, memo.shift + assert_equal [:f], memo.shift, '[ruby-core:25536]' + assert_equal mod.instance_method(:f), memo.shift + assert_equal :g, memo.shift + assert_equal [:f, :g], memo.shift + assert_equal mod.instance_method(:f), memo.shift + assert_equal :a, memo.shift + assert_equal [:f, :g, :a], memo.shift + assert_equal mod.instance_method(:a), memo.shift + assert_equal :a=, memo.shift + assert_equal [:f, :g, :a, :a=], memo.shift + assert_equal mod.instance_method(:a=), memo.shift + end + + def test_method_undefined + added = [] + undefed = [] + removed = [] + mod = Module.new do + mod = self + def f + end + (class << self ; self ; end).class_eval do + define_method :method_added do |sym| + added << sym + end + define_method :method_undefined do |sym| + undefed << sym + end + define_method :method_removed do |sym| + removed << sym + end + end + end + assert_method_defined?(mod, :f) + mod.module_eval do + undef :f + end + assert_equal [], added + assert_equal [:f], undefed + assert_equal [], removed + end + + def test_method_removed + added = [] + undefed = [] + removed = [] + mod = Module.new do + mod = self + def f + end + (class << self ; self ; end).class_eval do + define_method :method_added do |sym| + added << sym + end + define_method :method_undefined do |sym| + undefed << sym + end + define_method :method_removed do |sym| + removed << sym + end + end + end + assert_method_defined?(mod, :f) + mod.module_eval do + remove_method :f + end + assert_equal [], added + assert_equal [], undefed + assert_equal [:f], removed + end + + def test_method_redefinition + feature2155 = '[ruby-dev:39400]' + + line = __LINE__+4 + stderr = EnvUtil.verbose_warning do + Module.new do + def foo; end + def foo; end + end + end + assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) + assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) + + assert_warning '' do + Module.new do + def foo; end + alias bar foo + def foo; end + end + end + + assert_warning '' do + Module.new do + def foo; end + alias bar foo + alias bar foo + end + end + + line = __LINE__+4 + stderr = EnvUtil.verbose_warning do + Module.new do + define_method(:foo) do end + def foo; end + end + end + assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) + assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) + + assert_warning '' do + Module.new do + define_method(:foo) do end + alias bar foo + alias bar foo + end + end + + assert_warning('', '[ruby-dev:39397]') do + Module.new do + module_function + def foo; end + module_function :foo + end + end + + assert_warning '' do + Module.new do + def foo; end + undef foo + end + end + end + + def test_protected_singleton_method + klass = Class.new + x = klass.new + class << x + protected + + def foo + end + end + assert_raise(NoMethodError) do + x.foo + end + klass.send(:define_method, :bar) do + x.foo + end + assert_nothing_raised do + x.bar + end + y = klass.new + assert_raise(NoMethodError) do + y.bar + end + end + + def test_uninitialized_toplevel_constant + bug3123 = '[ruby-dev:40951]' + e = assert_raise(NameError) {eval("Bug3123", TOPLEVEL_BINDING)} + assert_not_match(/Object::/, e.message, bug3123) + end + + def test_attr_inherited_visibility + bug3406 = '[ruby-core:30638]' + c = Class.new do + class << self + private + def attr_accessor(*); super; end + end + attr_accessor :x + end.new + assert_nothing_raised(bug3406) {c.x = 1} + assert_equal(1, c.x, bug3406) + end + + def test_attr_writer_with_no_arguments + bug8540 = "[ruby-core:55543]" + c = Class.new do + attr_writer :foo + end + assert_raise(ArgumentError, bug8540) { c.new.send :foo= } + end + + def test_private_constant + c = Class.new + c.const_set(:FOO, "foo") + assert_equal("foo", c::FOO) + c.private_constant(:FOO) + assert_raise(NameError) { c::FOO } + assert_equal("foo", c.class_eval("FOO")) + assert_equal("foo", c.const_get("FOO")) + $VERBOSE, verbose = nil, $VERBOSE + c.const_set(:FOO, "foo") + $VERBOSE = verbose + assert_raise(NameError) { c::FOO } + end + + def test_private_constant2 + c = Class.new + c.const_set(:FOO, "foo") + c.const_set(:BAR, "bar") + assert_equal("foo", c::FOO) + assert_equal("bar", c::BAR) + c.private_constant(:FOO, :BAR) + assert_raise(NameError) { c::FOO } + assert_raise(NameError) { c::BAR } + assert_equal("foo", c.class_eval("FOO")) + assert_equal("bar", c.class_eval("BAR")) + end + + def test_private_constant_with_no_args + assert_in_out_err([], <<-RUBY, [], ["-:3: warning: private_constant with no argument is just ignored"]) + $-w = true + class X + private_constant + end + RUBY + end + + class PrivateClass + end + private_constant :PrivateClass + + def test_define_module_under_private_constant + assert_raise(NameError) do + eval %q{class TestModule::PrivateClass; end} + end + assert_raise(NameError) do + eval %q{module TestModule::PrivateClass::TestModule; end} + end + eval %q{class PrivateClass; end} + eval %q{module PrivateClass::TestModule; end} + assert_instance_of(Module, PrivateClass::TestModule) + PrivateClass.class_eval { remove_const(:TestModule) } + end + + def test_public_constant + c = Class.new + c.const_set(:FOO, "foo") + assert_equal("foo", c::FOO) + c.private_constant(:FOO) + assert_raise(NameError) { c::FOO } + assert_equal("foo", c.class_eval("FOO")) + c.public_constant(:FOO) + assert_equal("foo", c::FOO) + end + + def test_constants_with_private_constant + assert_not_include(::TestModule.constants, :PrivateClass) + end + + def test_toplevel_private_constant + src = <<-INPUT + class Object + private_constant :Object + end + p Object + begin + p ::Object + rescue + p :ok + end + INPUT + assert_in_out_err([], src, %w(Object :ok), []) + end + + def test_private_constants_clear_inlinecache + bug5702 = '[ruby-dev:44929]' + src = <<-INPUT + class A + C = :Const + def self.get_C + A::C + end + # fill cache + A.get_C + private_constant :C, :D rescue nil + begin + A.get_C + rescue NameError + puts "A.get_C" + end + end + INPUT + assert_in_out_err([], src, %w(A.get_C), [], bug5702) + end + + def test_constant_lookup_in_method_defined_by_class_eval + src = <<-INPUT + class A + B = 42 + end + + A.class_eval do + def self.f + B + end + + def f + B + end + end + + begin + A.f + rescue NameError + puts "A.f" + end + begin + A.new.f + rescue NameError + puts "A.new.f" + end + INPUT + assert_in_out_err([], src, %w(A.f A.new.f), []) + end + + def test_constant_lookup_in_toplevel_class_eval + src = <<-INPUT + module X + A = 123 + end + begin + X.class_eval { A } + rescue NameError => e + puts e + end + INPUT + assert_in_out_err([], src, ["uninitialized constant A"], []) + end + + def test_constant_lookup_in_module_in_class_eval + src = <<-INPUT + class A + B = 42 + end + + A.class_eval do + module C + begin + B + rescue NameError + puts "NameError" + end + end + end + INPUT + assert_in_out_err([], src, ["NameError"], []) + end + + module M0 + def m1; [:M0] end + end + module M1 + def m1; [:M1, *super] end + end + module M2 + def m1; [:M2, *super] end + end + M3 = Module.new do + def m1; [:M3, *super] end + end + module M4 + def m1; [:M4, *super] end + end + class C + def m1; end + end + class C0 < C + include M0 + prepend M1 + def m1; [:C0, *super] end + end + class C1 < C0 + prepend M2, M3 + include M4 + def m1; [:C1, *super] end + end + + def test_prepend + obj = C0.new + expected = [:M1,:C0,:M0] + assert_equal(expected, obj.m1) + obj = C1.new + expected = [:M2,:M3,:C1,:M4,:M1,:C0,:M0] + assert_equal(expected, obj.m1) + end + + def test_public_prepend + assert_nothing_raised('#8846') do + Class.new.prepend(Module.new) + end + end + + def test_prepend_inheritance + bug6654 = '[ruby-core:45914]' + a = labeled_module("a") + b = labeled_module("b") {include a} + c = labeled_class("c") {prepend b} + assert_operator(c, :<, b, bug6654) + assert_operator(c, :<, a, bug6654) + bug8357 = '[ruby-core:54736] [Bug #8357]' + b = labeled_module("b") {prepend a} + c = labeled_class("c") {include b} + assert_operator(c, :<, b, bug8357) + assert_operator(c, :<, a, bug8357) + bug8357 = '[ruby-core:54742] [Bug #8357]' + assert_kind_of(b, c.new, bug8357) + end + + def test_prepend_instance_methods + bug6655 = '[ruby-core:45915]' + assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) + end + + def test_prepend_singleton_methods + o = Object.new + o.singleton_class.class_eval {prepend Module.new} + assert_equal([], o.singleton_methods) + end + + def test_prepend_remove_method + c = Class.new do + prepend Module.new {def foo; end} + end + assert_raise(NameError) do + c.class_eval do + remove_method(:foo) + end + end + c.class_eval do + def foo; end + end + removed = nil + c.singleton_class.class_eval do + define_method(:method_removed) {|id| removed = id} + end + assert_nothing_raised(NoMethodError, NameError, '[Bug #7843]') do + c.class_eval do + remove_method(:foo) + end + end + assert_equal(:foo, removed) + end + + def test_prepend_class_ancestors + bug6658 = '[ruby-core:45919]' + m = labeled_module("m") + c = labeled_class("c") {prepend m} + assert_equal([m, c], c.ancestors[0, 2], bug6658) + + bug6662 = '[ruby-dev:45868]' + c2 = labeled_class("c2", c) + anc = c2.ancestors + assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662) + end + + def test_prepend_module_ancestors + bug6659 = '[ruby-dev:45861]' + m0 = labeled_module("m0") {def x; [:m0, *super] end} + m1 = labeled_module("m1") {def x; [:m1, *super] end; prepend m0} + m2 = labeled_module("m2") {def x; [:m2, *super] end; prepend m1} + c0 = labeled_class("c0") {def x; [:c0] end} + c1 = labeled_class("c1") {def x; [:c1] end; prepend m2} + c2 = labeled_class("c2", c0) {def x; [:c2, *super] end; include m2} + + assert_equal([m0, m1], m1.ancestors, bug6659) + + bug6662 = '[ruby-dev:45868]' + assert_equal([m0, m1, m2], m2.ancestors, bug6662) + assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) + assert_equal([:m0, :m1, :m2, :c1], c1.new.x) + assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) + assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x) + + m3 = labeled_module("m3") {include m1; prepend m1} + assert_equal([m3, m0, m1], m3.ancestors) + m3 = labeled_module("m3") {prepend m1; include m1} + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") {prepend m1; prepend m1} + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") {include m1; include m1} + assert_equal([m3, m0, m1], m3.ancestors) + end + + def labeled_module(name, &block) + EnvUtil.labeled_module(name, &block) + end + + def labeled_class(name, superclass = Object, &block) + EnvUtil.labeled_class(name, superclass, &block) + end + + def test_prepend_instance_methods_false + bug6660 = '[ruby-dev:45863]' + assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + end + + def test_cyclic_prepend + bug7841 = '[ruby-core:52205] [Bug #7841]' + m1 = Module.new + m2 = Module.new + m1.instance_eval { prepend(m2) } + assert_raise(ArgumentError, bug7841) do + m2.instance_eval { prepend(m1) } + end + end + + def test_prepend_optmethod + bug7983 = '[ruby-dev:47124] [Bug #7983]' + assert_separately [], %{ + module M + def /(other) + to_f / other + end + end + Fixnum.send(:prepend, M) + assert_equal(0.5, 1 / 2, "#{bug7983}") + } + assert_equal(0, 1 / 2) + end + + def test_prepend_visibility + bug8005 = '[ruby-core:53106] [Bug #8005]' + c = Class.new do + prepend Module.new {} + def foo() end + protected :foo + end + a = c.new + assert_respond_to a, [:foo, true], bug8005 + assert_nothing_raised(NoMethodError, bug8005) {a.send :foo} + end + + def test_prepend_visibility_inherited + bug8238 = '[ruby-core:54105] [Bug #8238]' + assert_separately [], <<-"end;", timeout: 20 + class A + def foo() A; end + private :foo + end + class B < A + public :foo + prepend Module.new + end + assert_equal(A, B.new.foo, "#{bug8238}") + end; + end + + def test_prepend_included_modules + bug8025 = '[ruby-core:53158] [Bug #8025]' + mixin = labeled_module("mixin") + c = labeled_module("c") {prepend mixin} + im = c.included_modules + assert_not_include(im, c, bug8025) + assert_include(im, mixin, bug8025) + c1 = labeled_class("c1") {prepend mixin} + c2 = labeled_class("c2", c1) + im = c2.included_modules + assert_not_include(im, c1, bug8025) + assert_not_include(im, c2, bug8025) + assert_include(im, mixin, bug8025) + end + + def test_prepend_super_in_alias + bug7842 = '[Bug #7842]' + + p = labeled_module("P") do + def m; "P"+super; end + end + a = labeled_class("A") do + def m; "A"; end + end + b = labeled_class("B", a) do + def m; "B"+super; end + alias m2 m + prepend p + alias m3 m + end + assert_equal("BA", b.new.m2, bug7842) + assert_equal("PBA", b.new.m3, bug7842) + end + + def test_include_super_in_alias + bug9236 = '[Bug #9236]' + + fun = labeled_module("Fun") do + def hello + orig_hello + end + end + + m1 = labeled_module("M1") do + def hello + 'hello!' + end + end + + m2 = labeled_module("M2") do + def hello + super + end + end + + foo = labeled_class("Foo") do + include m1 + include m2 + + alias orig_hello hello + include fun + end + + assert_equal('hello!', foo.new.hello, bug9236) + end + + def test_prepend_call_super + assert_separately([], <<-'end;') #do + bug10847 = '[ruby-core:68093] [Bug #10847]' + module M; end + Float.prepend M + assert_nothing_raised(SystemStackError, bug10847) do + 0.3.numerator + end + end; + end + + def test_class_variables + m = Module.new + m.class_variable_set(:@@foo, 1) + m2 = Module.new + m2.send(:include, m) + m2.class_variable_set(:@@bar, 2) + assert_equal([:@@foo], m.class_variables) + assert_equal([:@@bar, :@@foo], m2.class_variables) + assert_equal([:@@bar, :@@foo], m2.class_variables(true)) + assert_equal([:@@bar], m2.class_variables(false)) + end + + Bug6891 = '[ruby-core:47241]' + + def test_extend_module_with_protected_method + list = [] + + x = Class.new { + @list = list + + extend Module.new { + protected + + def inherited(klass) + @list << "protected" + super(klass) + end + } + + extend Module.new { + def inherited(klass) + @list << "public" + super(klass) + end + } + } + + assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)} + assert_equal(['public', 'protected'], list) + end + + def test_extend_module_with_protected_bmethod + list = [] + + x = Class.new { + extend Module.new { + protected + + define_method(:inherited) do |klass| + list << "protected" + super(klass) + end + } + + extend Module.new { + define_method(:inherited) do |klass| + list << "public" + super(klass) + end + } + } + + assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)} + assert_equal(['public', 'protected'], list) + end + + def test_invalid_attr + %W[ + foo? + @foo + @@foo + $foo + \u3042$ + ].each do |name| + assert_raise_with_message(NameError, /#{Regexp.quote(quote(name))}/) do + Module.new { attr_accessor name.to_sym } + end + end + end + + private def quote(name) + encoding = Encoding.default_internal || Encoding.default_external + (name.encoding == encoding || name.ascii_only?) ? name : name.inspect + end + + class AttrTest + class << self + attr_accessor :cattr + end + attr_accessor :iattr + def ivar + @ivar + end + end + + def test_uninitialized_instance_variable + a = AttrTest.new + assert_warning(/instance variable @ivar not initialized/) do + assert_nil(a.ivar) + end + a.instance_variable_set(:@ivar, 42) + assert_warning '' do + assert_equal(42, a.ivar) + end + + name = "@\u{5909 6570}" + assert_warning(/instance variable #{name} not initialized/) do + val = EnvUtil.with_default_external(Encoding::UTF_8) { + a.instance_eval(name) + } + assert_nil(val) + end + end + + def test_uninitialized_attr + a = AttrTest.new + assert_warning '' do + assert_nil(a.iattr) + end + a.iattr = 42 + assert_warning '' do + assert_equal(42, a.iattr) + end + end + + def test_uninitialized_attr_class + assert_warning '' do + assert_nil(AttrTest.cattr) + end + AttrTest.cattr = 42 + assert_warning '' do + assert_equal(42, AttrTest.cattr) + end + end + + def test_uninitialized_attr_non_object + a = Class.new(Array) do + attr_accessor :iattr + end.new + assert_warning '' do + assert_nil(a.iattr) + end + a.iattr = 42 + assert_warning '' do + assert_equal(42, a.iattr) + end + end + + def test_remove_const + m = Module.new + assert_raise(NameError){ m.instance_eval { remove_const(:__FOO__) } } + end + + def test_private_top_methods + assert_top_method_is_private(:include) + assert_top_method_is_private(:public) + assert_top_method_is_private(:private) + assert_top_method_is_private(:define_method) + end + + module PrivateConstantReopen + PRIVATE_CONSTANT = true + private_constant :PRIVATE_CONSTANT + end + + def test_private_constant_reopen + assert_raise(NameError) do + eval <<-EOS, TOPLEVEL_BINDING + module TestModule::PrivateConstantReopen::PRIVATE_CONSTANT + end + EOS + end + assert_raise(NameError) do + eval <<-EOS, TOPLEVEL_BINDING + class TestModule::PrivateConstantReopen::PRIVATE_CONSTANT + end + EOS + end + end + + def test_singleton_class_ancestors + feature8035 = '[ruby-core:53171]' + obj = Object.new + assert_equal [obj.singleton_class, Object], obj.singleton_class.ancestors.first(2), feature8035 + + mod = Module.new + obj.extend mod + assert_equal [obj.singleton_class, mod, Object], obj.singleton_class.ancestors.first(3) + + obj = Object.new + obj.singleton_class.send :prepend, mod + assert_equal [mod, obj.singleton_class, Object], obj.singleton_class.ancestors.first(3) + end + + def test_visibility_by_public_class_method + bug8284 = '[ruby-core:54404] [Bug #8284]' + assert_raise(NoMethodError) {Object.define_method} + Module.new.public_class_method(:define_method) + assert_raise(NoMethodError, bug8284) {Object.define_method} + end + + def test_include_module_with_constants_invalidates_method_cache + assert_in_out_err([], <<-RUBY, %w(123 456), []) + A = 123 + + class Foo + def self.a + A + end + end + + module M + A = 456 + end + + puts Foo.a + Foo.send(:include, M) + puts Foo.a + RUBY + end + + def test_return_value_of_define_method + retvals = [] + Class.new.class_eval do + retvals << define_method(:foo){} + retvals << define_method(:bar, instance_method(:foo)) + end + assert_equal :foo, retvals[0] + assert_equal :bar, retvals[1] + end + + def test_return_value_of_define_singleton_method + retvals = [] + Class.new do + retvals << define_singleton_method(:foo){} + retvals << define_singleton_method(:bar, method(:foo)) + end + assert_equal :foo, retvals[0] + assert_equal :bar, retvals[1] + end + + def test_prepend_gc + assert_separately [], %{ + module Foo + end + class Object + prepend Foo + end + GC.start # make created T_ICLASS old (or remembered shady) + class Object # add methods into T_ICLASS (need WB if it is old) + def foo; end + attr_reader :bar + end + 1_000_000.times{''} # cause GC + } + end + + def test_inspect_segfault + bug_10282 = '[ruby-core:65214] [Bug #10282]' + assert_separately [], <<-RUBY + module ShallowInspect + def shallow_inspect + "foo" + end + end + + module InspectIsShallow + include ShallowInspect + alias_method :inspect, :shallow_inspect + end + + class A + end + + A.prepend InspectIsShallow + + expect = "#<Method: A(Object)#inspect(shallow_inspect)>" + assert_equal expect, A.new.method(:inspect).inspect, "#{bug_10282}" + RUBY + end + + private + + def assert_top_method_is_private(method) + assert_separately [], %{ + methods = singleton_class.private_instance_methods(false) + assert_include(methods, :#{method}, ":#{method} should be private") + + assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") { + self.#{method} + } + } + end +end diff --git a/jni/ruby/test/ruby/test_not.rb b/jni/ruby/test/ruby/test_not.rb new file mode 100644 index 0000000..486075b --- /dev/null +++ b/jni/ruby/test/ruby/test_not.rb @@ -0,0 +1,12 @@ +require 'test/unit' + +class TestIfunless < Test::Unit::TestCase + def test_not_with_grouped_expression + assert_equal(false, (not (true))) + assert_equal(true, (not (false))) + end + + def test_not_with_empty_grouped_expression + assert_equal(true, (not ())) + end +end diff --git a/jni/ruby/test/ruby/test_notimp.rb b/jni/ruby/test/ruby/test_notimp.rb new file mode 100644 index 0000000..9721723 --- /dev/null +++ b/jni/ruby/test/ruby/test_notimp.rb @@ -0,0 +1,84 @@ +require 'test/unit' +require 'timeout' +require 'tmpdir' + +class TestNotImplement < Test::Unit::TestCase + def test_respond_to_fork + assert_include(Process.methods, :fork) + if /linux/ =~ RUBY_PLATFORM + assert_equal(true, Process.respond_to?(:fork)) + end + end + + def test_respond_to_lchmod + assert_include(File.methods, :lchmod) + if /linux/ =~ RUBY_PLATFORM + assert_equal(false, File.respond_to?(:lchmod)) + end + if /freebsd/ =~ RUBY_PLATFORM + assert_equal(true, File.respond_to?(:lchmod)) + end + end + + def test_call_fork + GC.start + pid = nil + ps = + case RUBY_PLATFORM + when /linux/ # assume Linux Distribution uses procps + proc {`ps -eLf #{pid}`} + when /freebsd/ + proc {`ps -lH #{pid}`} + when /darwin/ + proc {`ps -lM #{pid}`} + else + proc {`ps -l #{pid}`} + end + assert_nothing_raised(Timeout::Error, ps) do + Timeout.timeout(5) { + pid = fork {} + Process.wait pid + pid = nil + } + end + ensure + if pid + Process.kill(:KILL, pid) + Process.wait pid + end + end if Process.respond_to?(:fork) + + def test_call_lchmod + if File.respond_to?(:lchmod) + Dir.mktmpdir {|d| + f = "#{d}/f" + g = "#{d}/g" + File.open(f, "w") {} + File.symlink f, g + newmode = 0444 + File.lchmod newmode, "#{d}/g" + snew = File.lstat(g) + assert_equal(newmode, snew.mode & 0777) + } + end + end + + def test_method_inspect_fork + m = Process.method(:fork) + if Process.respond_to?(:fork) + assert_not_match(/not-implemented/, m.inspect) + else + assert_match(/not-implemented/, m.inspect) + end + end + + def test_method_inspect_lchmod + m = File.method(:lchmod) + if File.respond_to?(:lchmod) + assert_not_match(/not-implemented/, m.inspect) + else + assert_match(/not-implemented/, m.inspect) + end + end + +end diff --git a/jni/ruby/test/ruby/test_numeric.rb b/jni/ruby/test/ruby/test_numeric.rb new file mode 100644 index 0000000..4c94c69 --- /dev/null +++ b/jni/ruby/test/ruby/test_numeric.rb @@ -0,0 +1,366 @@ +require 'test/unit' + +class TestNumeric < Test::Unit::TestCase + class DummyNumeric < Numeric + end + + def test_coerce + a, b = 1.coerce(2) + assert_equal(Fixnum, a.class) + assert_equal(Fixnum, b.class) + + a, b = 1.coerce(2.0) + assert_equal(Float, a.class) + assert_equal(Float, b.class) + + assert_raise(TypeError) { -Numeric.new } + + assert_raise_with_message(TypeError, /can't be coerced into /) {1+:foo} + assert_raise_with_message(TypeError, /can't be coerced into /) {1&:foo} + assert_raise_with_message(TypeError, /can't be coerced into /) {1|:foo} + assert_raise_with_message(TypeError, /can't be coerced into /) {1^:foo} + + EnvUtil.with_default_external(Encoding::UTF_8) do + assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"} + end + EnvUtil.with_default_external(Encoding::US_ASCII) do + assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"} + end + + bug10711 = '[ruby-core:67405] [Bug #10711]' + exp = "1.2 can't be coerced into Fixnum" + assert_raise_with_message(TypeError, exp, bug10711) { 1 & 1.2 } + end + + def test_dummynumeric + a = DummyNumeric.new + + DummyNumeric.class_eval do + def coerce(x); nil; end + end + assert_raise(TypeError) { -a } + assert_nil(1 <=> a) + assert_raise(ArgumentError) { 1 <= a } + + DummyNumeric.class_eval do + remove_method :coerce + def coerce(x); 1.coerce(x); end + end + assert_equal(2, 1 + a) + assert_equal(0, 1 <=> a) + assert_operator(1, :<=, a) + + DummyNumeric.class_eval do + remove_method :coerce + def coerce(x); [x, 1]; end + end + assert_equal(-1, -a) + + bug7688 = '[ruby-core:51389] [Bug #7688]' + DummyNumeric.class_eval do + remove_method :coerce + def coerce(x); raise StandardError; end + end + assert_raise_with_message(TypeError, /can't be coerced into /) { 1 + a } + warn = /will no more rescue exceptions of #coerce.+ in the next release/m + assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } } + + DummyNumeric.class_eval do + remove_method :coerce + def coerce(x); :bad_return_value; end + end + assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 + a } + warn = /Bad return value for #coerce.+next release will raise an error/m + assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } } + + ensure + DummyNumeric.class_eval do + remove_method :coerce + end + end + + def test_singleton_method + a = Numeric.new + assert_raise_with_message(TypeError, /foo/) { def a.foo; end } + assert_raise_with_message(TypeError, /\u3042/) { eval("def a.\u3042; end") } + end + + def test_dup + a = Numeric.new + assert_raise(TypeError) { a.dup } + + c = Module.new do + break eval("class C\u{3042} < Numeric; self; end") + end + assert_raise_with_message(TypeError, /C\u3042/) {c.new.dup} + end + + def test_quo + assert_raise(TypeError) {DummyNumeric.new.quo(1)} + end + + def test_quo_ruby_core_41575 + x = DummyNumeric.new + rat = 84.quo(1) + DummyNumeric.class_eval do + define_method(:to_r) { rat } + end + assert_equal(2.quo(1), x.quo(42), '[ruby-core:41575]') + ensure + DummyNumeric.class_eval do + remove_method :to_r + end + end + + def test_divmod +=begin + DummyNumeric.class_eval do + def /(x); 42.0; end + def %(x); :mod; end + end + + assert_equal(42, DummyNumeric.new.div(1)) + assert_equal(:mod, DummyNumeric.new.modulo(1)) + assert_equal([42, :mod], DummyNumeric.new.divmod(1)) +=end + + assert_kind_of(Integer, 11.divmod(3.5).first, '[ruby-dev:34006]') + +=begin + ensure + DummyNumeric.class_eval do + remove_method :/, :% + end +=end + end + + def test_real_p + assert_predicate(Numeric.new, :real?) + end + + def test_integer_p + assert_not_predicate(Numeric.new, :integer?) + end + + def test_abs + a = DummyNumeric.new + DummyNumeric.class_eval do + def -@; :ok; end + def <(x); true; end + end + + assert_equal(:ok, a.abs) + + DummyNumeric.class_eval do + remove_method :< + def <(x); false; end + end + + assert_equal(a, a.abs) + + ensure + DummyNumeric.class_eval do + remove_method :-@, :< + end + end + + def test_zero_p + DummyNumeric.class_eval do + def ==(x); true; end + end + + assert_predicate(DummyNumeric.new, :zero?) + + ensure + DummyNumeric.class_eval do + remove_method :== + end + end + + def test_to_int + DummyNumeric.class_eval do + def to_i; :ok; end + end + + assert_equal(:ok, DummyNumeric.new.to_int) + + ensure + DummyNumeric.class_eval do + remove_method :to_i + end + end + + def test_cmp + a = Numeric.new + assert_equal(0, a <=> a) + assert_nil(a <=> :foo) + end + + def test_floor_ceil_round_truncate + DummyNumeric.class_eval do + def to_f; 1.5; end + end + + a = DummyNumeric.new + assert_equal(1, a.floor) + assert_equal(2, a.ceil) + assert_equal(2, a.round) + assert_equal(1, a.truncate) + + DummyNumeric.class_eval do + remove_method :to_f + def to_f; 1.4; end + end + + a = DummyNumeric.new + assert_equal(1, a.floor) + assert_equal(2, a.ceil) + assert_equal(1, a.round) + assert_equal(1, a.truncate) + + DummyNumeric.class_eval do + remove_method :to_f + def to_f; -1.5; end + end + + a = DummyNumeric.new + assert_equal(-2, a.floor) + assert_equal(-1, a.ceil) + assert_equal(-2, a.round) + assert_equal(-1, a.truncate) + + ensure + DummyNumeric.class_eval do + remove_method :to_f + end + end + + def assert_step(expected, (from, *args), inf: false) + enum = from.step(*args) + size = enum.size + xsize = expected.size + + if inf + assert_send [size, :infinite?], "step size: +infinity" + assert_send [size, :>, 0], "step size: +infinity" + + a = [] + from.step(*args) { |x| a << x; break if a.size == xsize } + assert_equal expected, a, "step" + + a = [] + enum.each { |x| a << x; break if a.size == xsize } + assert_equal expected, a, "step enumerator" + else + assert_equal expected.size, size, "step size" + + a = [] + from.step(*args) { |x| a << x } + assert_equal expected, a, "step" + + a = [] + enum.each { |x| a << x } + assert_equal expected, a, "step enumerator" + end + end + + def test_step + i, bignum = 32, 1 << 30 + bignum <<= (i <<= 1) - 32 until bignum.is_a?(Bignum) + assert_raise(ArgumentError) { 1.step(10, 1, 0) { } } + assert_raise(ArgumentError) { 1.step(10, 1, 0).size } + assert_raise(ArgumentError) { 1.step(10, 0) { } } + assert_raise(ArgumentError) { 1.step(10, 0).size } + assert_raise(ArgumentError) { 1.step(10, "1") { } } + assert_raise(ArgumentError) { 1.step(10, "1").size } + assert_raise(TypeError) { 1.step(10, nil) { } } + assert_raise(TypeError) { 1.step(10, nil).size } + assert_nothing_raised { 1.step(by: 0, to: nil) } + assert_nothing_raised { 1.step(by: 0, to: nil).size } + assert_nothing_raised { 1.step(by: 0) } + assert_nothing_raised { 1.step(by: 0).size } + assert_nothing_raised { 1.step(by: nil) } + assert_nothing_raised { 1.step(by: nil).size } + + bug9811 = '[ruby-dev:48177] [Bug #9811]' + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11).size } + + assert_equal(bignum*2+1, (-bignum).step(bignum, 1).size) + assert_equal(bignum*2, (-bignum).step(bignum-1, 1).size) + + assert_equal(10+1, (0.0).step(10.0, 1.0).size) + + i, bigflo = 1, bignum.to_f + i <<= 1 until (bigflo - i).to_i < bignum + bigflo -= i >> 1 + assert_equal(bigflo.to_i, (0.0).step(bigflo-1.0, 1.0).size) + assert_operator((0.0).step(bignum.to_f, 1.0).size, :>=, bignum) # may loose precision + + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10] + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10] + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10, by: nil] + assert_step [1, 3, 5, 7, 9], [1, 10, 2] + assert_step [1, 3, 5, 7, 9], [1, to: 10, by: 2] + + assert_step [10, 8, 6, 4, 2], [10, 1, -2] + assert_step [10, 8, 6, 4, 2], [10, to: 1, by: -2] + assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, 10.0, 2.0] + assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, to: 10.0, by: 2.0] + assert_step [1], [1, 10, bignum] + assert_step [1], [1, to: 10, by: bignum] + + assert_step [], [2, 1, 3] + assert_step [], [-2, -1, -3] + assert_step [3, 3, 3, 3], [3, by: 0], inf: true + assert_step [3, 3, 3, 3], [3, by: 0, to: 42], inf: true + assert_step [10], [10, 1, -bignum] + + assert_step [], [1, 0, Float::INFINITY] + assert_step [], [0, 1, -Float::INFINITY] + assert_step [10], [10, to: 1, by: -bignum] + + assert_step [10, 11, 12, 13], [10], inf: true + assert_step [10, 9, 8, 7], [10, by: -1], inf: true + assert_step [10, 9, 8, 7], [10, by: -1, to: nil], inf: true + + assert_step [42, 42, 42, 42], [42, by: 0, to: -Float::INFINITY], inf: true + assert_step [42, 42, 42, 42], [42, by: 0, to: 42.5], inf: true + assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: 0.0], inf: true + assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: -0.0], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 44], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 0], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: -0.0, to: 44], inf: true + + assert_step [bignum]*4, [bignum, by: 0], inf: true + assert_step [bignum]*4, [bignum, by: 0.0], inf: true + assert_step [bignum]*4, [bignum, by: 0, to: bignum+1], inf: true + assert_step [bignum]*4, [bignum, by: 0, to: 0], inf: true + end + + def test_num2long + assert_raise(TypeError) { 1 & nil } + assert_raise(TypeError) { 1 & 1.0 } + assert_raise(TypeError) { 1 & 2147483648.0 } + assert_raise(TypeError) { 1 & 9223372036854777856.0 } + o = Object.new + def o.to_int; 1; end + assert_raise(TypeError) { assert_equal(1, 1 & o) } + end + + def test_eql + assert_equal(1, 1.0) + assert_not_operator(1, :eql?, 1.0) + assert_not_operator(1, :eql?, 2) + end +end diff --git a/jni/ruby/test/ruby/test_object.rb b/jni/ruby/test/ruby/test_object.rb new file mode 100644 index 0000000..d5b4a1b --- /dev/null +++ b/jni/ruby/test/ruby/test_object.rb @@ -0,0 +1,861 @@ +# -*- coding: us-ascii -*- +require 'test/unit' + +class TestObject < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_itself + feature6373 = '[ruby-core:44704] [Feature #6373]' + object = Object.new + assert_same(object, object.itself, feature6373) + end + + def test_dup + assert_raise(TypeError) { 1.dup } + assert_raise(TypeError) { true.dup } + assert_raise(TypeError) { nil.dup } + + assert_raise(TypeError) do + Object.new.instance_eval { initialize_copy(1) } + end + end + + def test_init_dupclone + cls = Class.new do + def initialize_clone(orig); throw :initialize_clone; end + def initialize_dup(orig); throw :initialize_dup; end + end + + obj = cls.new + assert_throw(:initialize_clone) {obj.clone} + assert_throw(:initialize_dup) {obj.dup} + end + + def test_instance_of + assert_raise(TypeError) { 1.instance_of?(1) } + end + + def test_kind_of + assert_raise(TypeError) { 1.kind_of?(1) } + end + + def test_taint_frozen_obj + o = Object.new + o.freeze + assert_raise(RuntimeError) { o.taint } + + o = Object.new + o.taint + o.freeze + assert_raise(RuntimeError) { o.untaint } + end + + def test_freeze_immediate + assert_equal(true, 1.frozen?) + 1.freeze + assert_equal(true, 1.frozen?) + assert_equal(true, 2.frozen?) + assert_equal(true, true.frozen?) + assert_equal(true, false.frozen?) + assert_equal(true, nil.frozen?) + end + + def test_frozen_error_message + name = "C\u{30c6 30b9 30c8}" + klass = EnvUtil.labeled_class(name) { + attr_accessor :foo + } + obj = klass.new.freeze + assert_raise_with_message(RuntimeError, /#{name}/) { + obj.foo = 1 + } + end + + def test_nil_to_f + assert_equal(0.0, nil.to_f) + end + + def test_not + assert_equal(false, Object.new.send(:!)) + assert_equal(true, nil.send(:!)) + end + + def test_true_and + assert_equal(true, true & true) + assert_equal(true, true & 1) + assert_equal(false, true & false) + assert_equal(false, true & nil) + end + + def test_true_or + assert_equal(true, true | true) + assert_equal(true, true | 1) + assert_equal(true, true | false) + assert_equal(true, true | nil) + end + + def test_true_xor + assert_equal(false, true ^ true) + assert_equal(false, true ^ 1) + assert_equal(true, true ^ false) + assert_equal(true, true ^ nil) + end + + def test_false_and + assert_equal(false, false & true) + assert_equal(false, false & 1) + assert_equal(false, false & false) + assert_equal(false, false & nil) + end + + def test_false_or + assert_equal(true, false | true) + assert_equal(true, false | 1) + assert_equal(false, false | false) + assert_equal(false, false | nil) + end + + def test_false_xor + assert_equal(true, false ^ true) + assert_equal(true, false ^ 1) + assert_equal(false, false ^ false) + assert_equal(false, false ^ nil) + end + + def test_methods + o = Object.new + a1 = o.methods + a2 = o.methods(false) + + def o.foo; end + + assert_equal([:foo], o.methods(true) - a1) + assert_equal([:foo], o.methods(false) - a2) + end + + def test_methods2 + c0 = Class.new + c1 = Class.new(c0) + c1.module_eval do + public ; def foo; end + protected; def bar; end + private ; def baz; end + end + c2 = Class.new(c1) + c2.module_eval do + public ; def foo2; end + protected; def bar2; end + private ; def baz2; end + end + + o0 = c0.new + o2 = c2.new + + assert_equal([:baz, :baz2], (o2.private_methods - o0.private_methods).sort) + assert_equal([:baz2], (o2.private_methods(false) - o0.private_methods(false)).sort) + + assert_equal([:bar, :bar2], (o2.protected_methods - o0.protected_methods).sort) + assert_equal([:bar2], (o2.protected_methods(false) - o0.protected_methods(false)).sort) + + assert_equal([:foo, :foo2], (o2.public_methods - o0.public_methods).sort) + assert_equal([:foo2], (o2.public_methods(false) - o0.public_methods(false)).sort) + end + + def test_methods_prepend + bug8044 = '[ruby-core:53207] [Bug #8044]' + o = Object.new + def o.foo; end + assert_equal([:foo], o.methods(false)) + class << o; prepend Module.new; end + assert_equal([:foo], o.methods(false), bug8044) + end + + def test_instance_variable_get + o = Object.new + o.instance_eval { @foo = :foo } + assert_equal(:foo, o.instance_variable_get(:@foo)) + assert_equal(nil, o.instance_variable_get(:@bar)) + assert_raise(NameError) { o.instance_variable_get('@') } + assert_raise(NameError) { o.instance_variable_get(:'@') } + assert_raise(NameError) { o.instance_variable_get(:foo) } + assert_raise(NameError) { o.instance_variable_get("bar") } + assert_raise(TypeError) { o.instance_variable_get(1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + assert_equal(:foo, o.instance_variable_get(n)) + assert_equal(1, n.count) + end + + def test_instance_variable_set + o = Object.new + o.instance_variable_set(:@foo, :foo) + assert_equal(:foo, o.instance_eval { @foo }) + assert_raise(NameError) { o.instance_variable_set(:'@', 1) } + assert_raise(NameError) { o.instance_variable_set('@', 1) } + assert_raise(NameError) { o.instance_variable_set(:foo, 1) } + assert_raise(NameError) { o.instance_variable_set("bar", 1) } + assert_raise(TypeError) { o.instance_variable_set(1, 1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + o.instance_variable_set(n, :bar) + assert_equal(:bar, o.instance_eval { @foo }) + assert_equal(1, n.count) + end + + def test_instance_variable_defined + o = Object.new + o.instance_eval { @foo = :foo } + assert_equal(true, o.instance_variable_defined?(:@foo)) + assert_equal(false, o.instance_variable_defined?(:@bar)) + assert_raise(NameError) { o.instance_variable_defined?(:'@') } + assert_raise(NameError) { o.instance_variable_defined?('@') } + assert_raise(NameError) { o.instance_variable_defined?(:foo) } + assert_raise(NameError) { o.instance_variable_defined?("bar") } + assert_raise(TypeError) { o.instance_variable_defined?(1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + assert_equal(true, o.instance_variable_defined?(n)) + assert_equal(1, n.count) + end + + def test_remove_instance_variable + o = Object.new + o.instance_eval { @foo = :foo } + o.remove_instance_variable(:@foo) + assert_equal(false, o.instance_variable_defined?(:@foo)) + end + + def test_convert_type + o = Object.new + def o.to_s; 1; end + assert_raise(TypeError) { String(o) } + def o.to_s; "o"; end + assert_equal("o", String(o)) + def o.respond_to?(*) false; end + assert_raise(TypeError) { String(o) } + end + + def test_check_convert_type + o = Object.new + def o.to_a; 1; end + assert_raise(TypeError) { Array(o) } + def o.to_a; [1]; end + assert_equal([1], Array(o)) + def o.respond_to?(*) false; end + assert_equal([o], Array(o)) + end + + def test_convert_hash + assert_equal({}, Hash(nil)) + assert_equal({}, Hash([])) + assert_equal({key: :value}, Hash(key: :value)) + assert_raise(TypeError) { Hash([1,2]) } + assert_raise(TypeError) { Hash(Object.new) } + o = Object.new + def o.to_hash; {a: 1, b: 2}; end + assert_equal({a: 1, b: 2}, Hash(o)) + def o.to_hash; 9; end + assert_raise(TypeError) { Hash(o) } + end + + def test_to_integer + o = Object.new + def o.to_i; nil; end + assert_raise(TypeError) { Integer(o) } + def o.to_i; 42; end + assert_equal(42, Integer(o)) + def o.respond_to?(*) false; end + assert_raise(TypeError) { Integer(o) } + end + + class MyInteger + def initialize(n); @num = n; end + def to_int; @num; end + def <=>(n); @num <=> n.to_int; end + def <=(n); @num <= n.to_int; end + def +(n); MyInteger.new(@num + n.to_int); end + end + + def test_check_to_integer + o1 = MyInteger.new(1) + o9 = MyInteger.new(9) + n = 0 + Range.new(o1, o9).step(2) {|x| n += x.to_int } + assert_equal(1+3+5+7+9, n) + end + + def test_redefine_method_under_verbose + assert_in_out_err([], <<-INPUT, %w(2), /warning: method redefined; discarding old foo$/) + $VERBOSE = true + o = Object.new + def o.foo; 1; end + def o.foo; 2; end + p o.foo + INPUT + end + + def test_redefine_method_which_may_case_serious_problem + assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `object_id' may cause serious problems$") + $VERBOSE = false + def (Object.new).object_id; end + INPUT + + assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `__send__' may cause serious problems$") + $VERBOSE = false + def (Object.new).__send__; end + INPUT + + bug10421 = '[ruby-dev:48691] [Bug #10421]' + assert_in_out_err([], <<-INPUT, ["1"], [], bug10421) + $VERBOSE = false + class C < BasicObject + def object_id; 1; end + end + puts C.new.object_id + INPUT + end + + def test_remove_method + c = Class.new + c.freeze + assert_raise(RuntimeError) do + c.instance_eval { remove_method(:foo) } + end + + c = Class.new do + def meth1; "meth" end + end + d = Class.new(c) do + alias meth2 meth1 + end + o1 = c.new + assert_respond_to(o1, :meth1) + assert_equal("meth", o1.meth1) + o2 = d.new + assert_respond_to(o2, :meth1) + assert_equal("meth", o2.meth1) + assert_respond_to(o2, :meth2) + assert_equal("meth", o2.meth2) + d.class_eval do + remove_method :meth2 + end + bug2202 = '[ruby-core:26074]' + assert_raise(NoMethodError, bug2202) {o2.meth2} + + %w(object_id __send__ initialize).each do |m| + assert_in_out_err([], <<-INPUT, %w(:ok), %r"warning: removing `#{m}' may cause serious problems$") + $VERBOSE = false + begin + Class.new.instance_eval { remove_method(:#{m}) } + rescue NameError + p :ok + end + INPUT + end + + m = "\u{30e1 30bd 30c3 30c9}" + c = Class.new + assert_raise_with_message(NameError, /#{m}/) do + c.class_eval {remove_method m} + end + c = Class.new { + define_method(m) {} + remove_method(m) + } + assert_raise_with_message(NameError, /#{m}/) do + c.class_eval {remove_method m} + end + end + + def test_method_missing + assert_raise(ArgumentError) do + 1.instance_eval { method_missing } + end + + c = Class.new + c.class_eval do + protected + def foo; end + end + assert_raise(NoMethodError) do + c.new.foo + end + + assert_raise(NoMethodError) do + 1.instance_eval { method_missing(:method_missing) } + end + + c.class_eval do + undef_method(:method_missing) + end + + assert_raise(ArgumentError) do + c.new.method_missing + end + + bug2494 = '[ruby-core:27219]' + c = Class.new do + def method_missing(meth, *args) + super + end + end + b = c.new + foo rescue nil + assert_nothing_raised(bug2494) {[b].flatten} + end + + def test_respond_to_missing_string + c = Class.new do + def respond_to_missing?(id, priv) + !(id !~ /\Agadzoks\d+\z/) ^ priv + end + end + foo = c.new + assert_equal(false, foo.respond_to?("gadzooks16")) + assert_equal(true, foo.respond_to?("gadzooks17", true)) + assert_equal(true, foo.respond_to?("gadzoks16")) + assert_equal(false, foo.respond_to?("gadzoks17", true)) + end + + def test_respond_to_missing + c = Class.new do + def respond_to_missing?(id, priv) + if id == :foobar + true + else + false + end + end + def method_missing(id, *args) + if id == :foobar + return [:foo, *args] + else + super + end + end + end + + foo = c.new + assert_equal([:foo], foo.foobar); + assert_equal([:foo, 1], foo.foobar(1)); + assert_equal([:foo, 1, 2, 3, 4, 5], foo.foobar(1, 2, 3, 4, 5)); + assert_respond_to(foo, :foobar) + assert_not_respond_to(foo, :foobarbaz) + assert_raise(NoMethodError) do + foo.foobarbaz + end + + foobar = foo.method(:foobar) + assert_equal(-1, foobar.arity); + assert_equal([:foo], foobar.call); + assert_equal([:foo, 1], foobar.call(1)); + assert_equal([:foo, 1, 2, 3, 4, 5], foobar.call(1, 2, 3, 4, 5)); + assert_equal(foobar, foo.method(:foobar)) + assert_not_equal(foobar, c.new.method(:foobar)) + + c = Class.new(c) + assert_equal(false, c.method_defined?(:foobar)) + assert_raise(NameError, '[ruby-core:25748]') do + c.instance_method(:foobar) + end + + m = Module.new + assert_equal(false, m.method_defined?(:foobar)) + assert_raise(NameError, '[ruby-core:25748]') do + m.instance_method(:foobar) + end + end + + def test_implicit_respond_to + bug5158 = '[ruby-core:38799]' + + p = Object.new + + called = [] + p.singleton_class.class_eval do + define_method(:to_ary) do + called << [:to_ary, bug5158] + end + end + [[p]].flatten + assert_equal([[:to_ary, bug5158]], called, bug5158) + + called = [] + p.singleton_class.class_eval do + define_method(:respond_to?) do |*a| + called << [:respond_to?, *a] + false + end + end + [[p]].flatten + assert_equal([[:respond_to?, :to_ary, true]], called, bug5158) + end + + def test_implicit_respond_to_arity_1 + p = Object.new + + called = [] + p.singleton_class.class_eval do + define_method(:respond_to?) do |a| + called << [:respond_to?, a] + false + end + end + [[p]].flatten + assert_equal([[:respond_to?, :to_ary]], called, '[bug:6000]') + end + + def test_implicit_respond_to_arity_3 + p = Object.new + + called = [] + p.singleton_class.class_eval do + define_method(:respond_to?) do |a, b, c| + called << [:respond_to?, a, b, c] + false + end + end + + msg = 'respond_to? must accept 1 or 2 arguments (requires 3)' + assert_raise_with_message(ArgumentError, msg, '[bug:6000]') do + [[p]].flatten + end + end + + def test_method_missing_passed_block + bug5731 = '[ruby-dev:44961]' + + c = Class.new do + def method_missing(meth, *args) yield(meth, *args) end + end + a = c.new + result = nil + assert_nothing_raised(LocalJumpError, bug5731) do + a.foo {|x| result = x} + end + assert_equal(:foo, result, bug5731) + result = nil + e = a.enum_for(:foo) + assert_nothing_raised(LocalJumpError, bug5731) do + e.each {|x| result = x} + end + assert_equal(:foo, result, bug5731) + + c = Class.new do + def respond_to_missing?(id, priv) + true + end + def method_missing(id, *args, &block) + return block.call(:foo, *args) + end + end + foo = c.new + + result = nil + assert_nothing_raised(LocalJumpError, bug5731) do + foo.foobar {|x| result = x} + end + assert_equal(:foo, result, bug5731) + result = nil + assert_nothing_raised(LocalJumpError, bug5731) do + foo.enum_for(:foobar).each {|x| result = x} + end + assert_equal(:foo, result, bug5731) + + result = nil + foobar = foo.method(:foobar) + foobar.call {|x| result = x} + assert_equal(:foo, result, bug5731) + + result = nil + foobar = foo.method(:foobar) + foobar.enum_for(:call).each {|x| result = x} + assert_equal(:foo, result, bug5731) + end + + def test_send_with_no_arguments + assert_raise(ArgumentError) { 1.send } + end + + def test_send_with_block + x = :ng + 1.send(:times) { x = :ok } + assert_equal(:ok, x) + + x = :ok + o = Object.new + def o.inspect + yield if block_given? + super + end + begin + nil.public_send(o) { x = :ng } + rescue TypeError + end + assert_equal(:ok, x) + end + + def test_public_send + c = Class.new do + def pub + :ok + end + + def invoke(m) + public_send(m) + end + + protected + def prot + :ng + end + + private + def priv + :ng + end + end.new + assert_equal(:ok, c.public_send(:pub)) + assert_raise(NoMethodError) {c.public_send(:priv)} + assert_raise(NoMethodError) {c.public_send(:prot)} + assert_raise(NoMethodError) {c.invoke(:priv)} + bug7499 = '[ruby-core:50489]' + assert_raise(NoMethodError, bug7499) {c.invoke(:prot)} + end + + def test_no_superclass_method + bug2312 = '[ruby-dev:39581]' + + o = Object.new + e = assert_raise(NoMethodError) { + o.method(:__send__).call(:never_defined_test_no_superclass_method) + } + m1 = e.message + assert_no_match(/no superclass method/, m1, bug2312) + e = assert_raise(NoMethodError) { + o.method(:__send__).call(:never_defined_test_no_superclass_method) + } + assert_equal(m1, e.message, bug2312) + e = assert_raise(NoMethodError) { + o.never_defined_test_no_superclass_method + } + assert_equal(m1, e.message, bug2312) + end + + def test_superclass_method + bug2312 = '[ruby-dev:39581]' + assert_in_out_err(["-e", "module Enumerable;undef min;end; (1..2).min{}"], + "", [], /no superclass method/, bug2312) + end + + def test_specific_eval_with_wrong_arguments + assert_raise(ArgumentError) do + 1.instance_eval("foo") { foo } + end + + assert_raise(ArgumentError) do + 1.instance_eval + end + + assert_raise(ArgumentError) do + 1.instance_eval("", 1, 1, 1) + end + end + + class InstanceExec + INSTANCE_EXEC = 123 + end + + def test_instance_exec + x = 1.instance_exec(42) {|a| self + a } + assert_equal(43, x) + + x = "foo".instance_exec("bar") {|a| self + a } + assert_equal("foobar", x) + + assert_raise(NameError) do + InstanceExec.new.instance_exec { INSTANCE_EXEC } + end + end + + def test_extend + assert_raise(ArgumentError) do + 1.extend + end + end + + def test_untrusted + verbose = $VERBOSE + $VERBOSE = false + begin + obj = Object.new + assert_equal(false, obj.untrusted?) + assert_equal(false, obj.tainted?) + obj.untrust + assert_equal(true, obj.untrusted?) + assert_equal(true, obj.tainted?) + obj.trust + assert_equal(false, obj.untrusted?) + assert_equal(false, obj.tainted?) + obj.taint + assert_equal(true, obj.untrusted?) + assert_equal(true, obj.tainted?) + obj.untaint + assert_equal(false, obj.untrusted?) + assert_equal(false, obj.tainted?) + ensure + $VERBOSE = verbose + end + end + + def test_to_s + x = Object.new + x.taint + s = x.to_s + assert_equal(true, s.tainted?) + + x = eval(<<-EOS) + class ToS\u{3042} + new.to_s + end + EOS + assert_match(/\bToS\u{3042}:/, x) + end + + def test_inspect + x = Object.new + assert_match(/\A#<Object:0x\h+>\z/, x.inspect) + + x.instance_variable_set(:@ivar, :value) + assert_match(/\A#<Object:0x\h+ @ivar=:value>\z/, x.inspect) + + x = Object.new + x.instance_variable_set(:@recur, x) + assert_match(/\A#<Object:0x\h+ @recur=#<Object:0x\h+ \.\.\.>>\z/, x.inspect) + + x = Object.new + x.instance_variable_set(:@foo, "value") + x.instance_variable_set(:@bar, 42) + assert_match(/\A#<Object:0x\h+ (?:@foo="value", @bar=42|@bar=42, @foo="value")>\z/, x.inspect) + + # #inspect does not call #to_s anymore + feature6130 = '[ruby-core:43238]' + x = Object.new + def x.to_s + "to_s" + end + assert_match(/\A#<Object:0x\h+>\z/, x.inspect, feature6130) + + x = eval(<<-EOS) + class Inspect\u{3042} + new.inspect + end + EOS + assert_match(/\bInspect\u{3042}:/, x) + + x = eval(<<-EOS) + class Inspect\u{3042} + def initialize + @\u{3044} = 42 + end + new + end + EOS + assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x.inspect) + x.instance_variable_set("@\u{3046}".encode(Encoding::EUC_JP), 6) + assert_match(/@\u{3046}=6\b/, x.inspect) + end + + def test_singleton_class + x = Object.new + xs = class << x; self; end + assert_equal(xs, x.singleton_class) + + y = Object.new + ys = y.singleton_class + assert_equal(class << y; self; end, ys) + + assert_equal(NilClass, nil.singleton_class) + assert_equal(TrueClass, true.singleton_class) + assert_equal(FalseClass, false.singleton_class) + + assert_raise(TypeError) do + 123.singleton_class + end + assert_raise(TypeError) do + :foo.singleton_class + end + end + + def test_redef_method_missing + bug5473 = '[ruby-core:40287]' + ['ArgumentError.new("bug5473")', 'ArgumentError, "bug5473"', '"bug5473"'].each do |code| + out, err, status = EnvUtil.invoke_ruby([], <<-SRC, true, true) + class ::Object + def method_missing(m, *a, &b) + raise #{code} + end + end + + p((1.foo rescue $!)) + SRC + assert_send([status, :success?], bug5473) + assert_equal("", err, bug5473) + assert_equal((eval("raise #{code}") rescue $!.inspect), out.chomp, bug5473) + end + end + + def assert_not_initialize_copy + a = yield + b = yield + assert_nothing_raised("copy") {a.instance_eval {initialize_copy(b)}} + c = a.dup.freeze + assert_raise(RuntimeError, "frozen") {c.instance_eval {initialize_copy(b)}} + d = a.dup.trust + [a, b, c, d] + end + + def test_bad_initialize_copy + assert_not_initialize_copy {Object.new} + assert_not_initialize_copy {[].to_enum} + assert_not_initialize_copy {Enumerator::Generator.new {}} + assert_not_initialize_copy {Enumerator::Yielder.new {}} + assert_not_initialize_copy {File.stat(__FILE__)} + assert_not_initialize_copy {open(__FILE__)}.each(&:close) + assert_not_initialize_copy {ARGF.class.new} + assert_not_initialize_copy {Random.new} + assert_not_initialize_copy {//} + assert_not_initialize_copy {/.*/.match("foo")} + st = Struct.new(:foo) + assert_not_initialize_copy {st.new} + end + + def test_type_error_message + _issue = "Bug #7539" + assert_raise_with_message(TypeError, "can't convert Array into Integer") {Integer([42])} + assert_raise_with_message(TypeError, 'no implicit conversion of Array into Integer') {[].first([42])} + end + + def test_copied_ivar_memory_leak + bug10191 = '[ruby-core:64700] [Bug #10191]' + assert_no_memory_leak([], <<-"end;", <<-"end;", bug10191, timeout: 60, limit: 1.8) + def (a = Object.new).set; @v = nil; end + num = 500_000 + end; + num.times {a.clone.set} + end; + end +end diff --git a/jni/ruby/test/ruby/test_objectspace.rb b/jni/ruby/test/ruby/test_objectspace.rb new file mode 100644 index 0000000..d519041 --- /dev/null +++ b/jni/ruby/test/ruby/test_objectspace.rb @@ -0,0 +1,112 @@ +require 'test/unit' + +class TestObjectSpace < Test::Unit::TestCase + def self.deftest_id2ref(obj) + /:(\d+)/ =~ caller[0] + file = $` + line = $1.to_i + code = <<"End" + define_method("test_id2ref_#{line}") {\ + o = ObjectSpace._id2ref(obj.object_id);\ + assert_same(obj, o, "didn't round trip: \#{obj.inspect}");\ + } +End + eval code, binding, file, line + end + + deftest_id2ref(-0x4000000000000001) + deftest_id2ref(-0x4000000000000000) + deftest_id2ref(-0x40000001) + deftest_id2ref(-0x40000000) + deftest_id2ref(-1) + deftest_id2ref(0) + deftest_id2ref(1) + deftest_id2ref(0x3fffffff) + deftest_id2ref(0x40000000) + deftest_id2ref(0x3fffffffffffffff) + deftest_id2ref(0x4000000000000000) + deftest_id2ref(:a) + deftest_id2ref(:abcdefghijilkjl) + deftest_id2ref(:==) + deftest_id2ref(Object.new) + deftest_id2ref(self) + deftest_id2ref(true) + deftest_id2ref(false) + deftest_id2ref(nil) + + def test_count_objects + h = {} + ObjectSpace.count_objects(h) + assert_kind_of(Hash, h) + assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert_empty(h.values.delete_if {|x| x.is_a?(Integer) }) + + h = ObjectSpace.count_objects + assert_kind_of(Hash, h) + assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert_empty(h.values.delete_if {|x| x.is_a?(Integer) }) + + assert_raise(TypeError) { ObjectSpace.count_objects(1) } + + h0 = {:T_FOO=>1000} + h = ObjectSpace.count_objects(h0) + assert_same(h0, h) + assert_equal(0, h0[:T_FOO]) + end + + def test_finalizer + assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok :ok), []) + a = [] + ObjectSpace.define_finalizer(a) { p :ok } + b = a.dup + ObjectSpace.define_finalizer(a) { p :ok } + !b + END + assert_raise(ArgumentError) { ObjectSpace.define_finalizer([], Object.new) } + + code = proc do |priv| + <<-"CODE" + fin = Object.new + class << fin + #{priv}def call(id) + puts "finalized" + end + end + ObjectSpace.define_finalizer([], fin) + CODE + end + assert_in_out_err([], code[""], ["finalized"]) + assert_in_out_err([], code["private "], ["finalized"]) + c = EnvUtil.labeled_class("C\u{3042}").new + o = Object.new + assert_raise_with_message(ArgumentError, /C\u{3042}/) { + ObjectSpace.define_finalizer(o, c) + } + end + + def test_each_object + assert_separately([], <<-End) + GC.disable + eval('begin; 1.times{}; rescue; ensure; end') + arys = [] + ObjectSpace.each_object(Array){|ary| + arys << ary + } + GC.enable + arys.each{|ary| + begin + assert_equal(String, ary.inspect.class) # should not cause SEGV + rescue RuntimeError + # rescue "can't modify frozen File" error. + end + } + End + end + + def test_each_object_recursive_key + assert_normal_exit(<<-'end;', '[ruby-core:66742] [Bug #10579]') + h = {["foo"]=>nil} + p Thread.current[:__recursive_key__] + end; + end +end diff --git a/jni/ruby/test/ruby/test_optimization.rb b/jni/ruby/test/ruby/test_optimization.rb new file mode 100644 index 0000000..4a5484e --- /dev/null +++ b/jni/ruby/test/ruby/test_optimization.rb @@ -0,0 +1,292 @@ +require 'test/unit' + +class TestRubyOptimization < Test::Unit::TestCase + + BIGNUM_POS_MIN_32 = 1073741824 # 2 ** 30 + if BIGNUM_POS_MIN_32.kind_of?(Fixnum) + FIXNUM_MAX = 4611686018427387903 # 2 ** 62 - 1 + else + FIXNUM_MAX = 1073741823 # 2 ** 30 - 1 + end + + BIGNUM_NEG_MAX_32 = -1073741825 # -2 ** 30 - 1 + if BIGNUM_NEG_MAX_32.kind_of?(Fixnum) + FIXNUM_MIN = -4611686018427387904 # -2 ** 62 + else + FIXNUM_MIN = -1073741824 # -2 ** 30 + end + + def assert_redefine_method(klass, method, code, msg = nil) + assert_separately([], <<-"end;")# do + class #{klass} + undef #{method} + def #{method}(*args) + args[0] + end + end + #{code} + end; + end + + def test_fixnum_plus + a, b = 1, 2 + assert_equal 3, a + b + assert_instance_of Fixnum, FIXNUM_MAX + assert_instance_of Bignum, FIXNUM_MAX + 1 + + assert_equal 21, 10 + 11 + assert_redefine_method('Fixnum', '+', 'assert_equal 11, 10 + 11') + end + + def test_fixnum_minus + assert_equal 5, 8 - 3 + assert_instance_of Fixnum, FIXNUM_MIN + assert_instance_of Bignum, FIXNUM_MIN - 1 + + assert_equal 5, 8 - 3 + assert_redefine_method('Fixnum', '-', 'assert_equal 3, 8 - 3') + end + + def test_fixnum_mul + assert_equal 15, 3 * 5 + assert_redefine_method('Fixnum', '*', 'assert_equal 5, 3 * 5') + end + + def test_fixnum_div + assert_equal 3, 15 / 5 + assert_redefine_method('Fixnum', '/', 'assert_equal 5, 15 / 5') + end + + def test_fixnum_mod + assert_equal 1, 8 % 7 + assert_redefine_method('Fixnum', '%', 'assert_equal 7, 8 % 7') + end + + def test_float_plus + assert_equal 4.0, 2.0 + 2.0 + assert_redefine_method('Float', '+', 'assert_equal 2.0, 2.0 + 2.0') + end + + def test_float_minus + assert_equal 4.0, 2.0 + 2.0 + assert_redefine_method('Float', '+', 'assert_equal 2.0, 2.0 + 2.0') + end + + def test_float_mul + assert_equal 29.25, 4.5 * 6.5 + assert_redefine_method('Float', '*', 'assert_equal 6.5, 4.5 * 6.5') + end + + def test_float_div + assert_in_delta 0.63063063063063063, 4.2 / 6.66 + assert_redefine_method('Float', '/', 'assert_equal 6.66, 4.2 / 6.66', "[Bug #9238]") + end + + def test_string_length + assert_equal 6, "string".length + assert_redefine_method('String', 'length', 'assert_nil "string".length') + end + + def test_string_size + assert_equal 6, "string".size + assert_redefine_method('String', 'size', 'assert_nil "string".size') + end + + def test_string_empty? + assert_equal true, "".empty? + assert_equal false, "string".empty? + assert_redefine_method('String', 'empty?', 'assert_nil "string".empty?') + end + + def test_string_plus + assert_equal "", "" + "" + assert_equal "x", "x" + "" + assert_equal "x", "" + "x" + assert_equal "ab", "a" + "b" + assert_redefine_method('String', '+', 'assert_equal "b", "a" + "b"') + end + + def test_string_succ + assert_equal 'b', 'a'.succ + assert_equal 'B', 'A'.succ + end + + def test_string_format + assert_equal '2', '%d' % 2 + assert_redefine_method('String', '%', 'assert_equal 2, "%d" % 2') + end + + def test_string_freeze + assert_equal "foo", "foo".freeze + assert_equal "foo".freeze.object_id, "foo".freeze.object_id + assert_redefine_method('String', 'freeze', 'assert_nil "foo".freeze') + end + + def test_string_eq_neq + %w(== !=).each do |m| + assert_redefine_method('String', m, <<-end) + assert_equal :b, ("a" #{m} "b").to_sym + b = 'b' + assert_equal :b, ("a" #{m} b).to_sym + assert_equal :b, (b #{m} "b").to_sym + end + end + end + + def test_string_ltlt + assert_equal "", "" << "" + assert_equal "x", "x" << "" + assert_equal "x", "" << "x" + assert_equal "ab", "a" << "b" + assert_redefine_method('String', '<<', 'assert_equal "b", "a" << "b"') + end + + def test_array_plus + assert_equal [1,2], [1]+[2] + assert_redefine_method('Array', '+', 'assert_equal [2], [1]+[2]') + end + + def test_array_minus + assert_equal [2], [1,2] - [1] + assert_redefine_method('Array', '-', 'assert_equal [1], [1,2]-[1]') + end + + def test_array_length + assert_equal 0, [].length + assert_equal 3, [1,2,3].length + assert_redefine_method('Array', 'length', 'assert_nil([].length); assert_nil([1,2,3].length)') + end + + def test_array_empty? + assert_equal true, [].empty? + assert_equal false, [1,2,3].empty? + assert_redefine_method('Array', 'empty?', 'assert_nil([].empty?); assert_nil([1,2,3].empty?)') + end + + def test_hash_length + assert_equal 0, {}.length + assert_equal 1, {1=>1}.length + assert_redefine_method('Hash', 'length', 'assert_nil({}.length); assert_nil({1=>1}.length)') + end + + def test_hash_empty? + assert_equal true, {}.empty? + assert_equal false, {1=>1}.empty? + assert_redefine_method('Hash', 'empty?', 'assert_nil({}.empty?); assert_nil({1=>1}.empty?)') + end + + def test_hash_aref_with + h = { "foo" => 1 } + assert_equal 1, h["foo"] + assert_redefine_method('Hash', '[]', <<-end) + h = { "foo" => 1 } + assert_equal "foo", h["foo"] + end + end + + def test_hash_aset_with + h = {} + assert_equal 1, h["foo"] = 1 + assert_redefine_method('Hash', '[]=', <<-end) + h = {} + assert_equal 1, h["foo"] = 1, "assignment always returns value set" + assert_nil h["foo"] + end + end + + class MyObj + def ==(other) + true + end + end + + def test_eq + assert_equal true, nil == nil + assert_equal true, 1 == 1 + assert_equal true, 'string' == 'string' + assert_equal true, 1 == MyObj.new + assert_equal false, nil == MyObj.new + assert_equal true, MyObj.new == 1 + assert_equal true, MyObj.new == nil + end + + def test_tailcall + bug4082 = '[ruby-core:33289]' + + option = { + tailcall_optimization: true, + trace_instruction: false, + } + RubyVM::InstructionSequence.new(<<-EOF, "Bug#4082", bug4082, nil, option).eval + class #{self.class}::Tailcall + def fact_helper(n, res) + if n == 1 + res + else + fact_helper(n - 1, n * res) + end + end + def fact(n) + fact_helper(n, 1) + end + end + EOF + assert_equal(9131, Tailcall.new.fact(3000).to_s.size, bug4082) + end + + def test_tailcall_with_block + bug6901 = '[ruby-dev:46065]' + + option = { + tailcall_optimization: true, + trace_instruction: false, + } + RubyVM::InstructionSequence.new(<<-EOF, "Bug#6901", bug6901, nil, option).eval + def identity(val) + val + end + + def delay + -> { + identity(yield) + } + end + EOF + assert_equal(123, delay { 123 }.call, bug6901) + end + + class Bug10557 + def [](_) + block_given? + end + + def []=(_, _) + block_given? + end + end + + def test_block_given_aset_aref + bug10557 = '[ruby-core:66595]' + assert_equal(true, Bug10557.new.[](nil){}, bug10557) + assert_equal(true, Bug10557.new.[](0){}, bug10557) + assert_equal(true, Bug10557.new.[](false){}, bug10557) + assert_equal(true, Bug10557.new.[](''){}, bug10557) + assert_equal(true, Bug10557.new.[]=(nil, 1){}, bug10557) + assert_equal(true, Bug10557.new.[]=(0, 1){}, bug10557) + assert_equal(true, Bug10557.new.[]=(false, 1){}, bug10557) + assert_equal(true, Bug10557.new.[]=('', 1){}, bug10557) + end + + def test_string_freeze_block + assert_separately([], <<-"end;")# do + class String + undef freeze + def freeze + block_given? + end + end + assert_equal(true, "block".freeze {}) + assert_equal(false, "block".freeze) + end; + end +end diff --git a/jni/ruby/test/ruby/test_pack.rb b/jni/ruby/test/ruby/test_pack.rb new file mode 100644 index 0000000..5d2b656 --- /dev/null +++ b/jni/ruby/test/ruby/test_pack.rb @@ -0,0 +1,730 @@ +# coding: US-ASCII +require 'test/unit' + +class TestPack < Test::Unit::TestCase + def test_pack + $format = "c2x5CCxsdils_l_a6"; + # Need the expression in here to force ary[5] to be numeric. This avoids + # test2 failing because ary2 goes str->numeric->str and ary does not. + ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"] + $x = ary.pack($format) + ary2 = $x.unpack($format) + + assert_equal(ary.length, ary2.length) + assert_equal(ary.join(':'), ary2.join(':')) + assert_match(/def/, $x) + + $x = [-1073741825] + assert_equal($x, $x.pack("q").unpack("q")) + + $x = [-1] + assert_equal($x, $x.pack("l").unpack("l")) + end + + def test_pack_n + assert_equal "\000\000", [0].pack('n') + assert_equal "\000\001", [1].pack('n') + assert_equal "\000\002", [2].pack('n') + assert_equal "\000\003", [3].pack('n') + assert_equal "\377\376", [65534].pack('n') + assert_equal "\377\377", [65535].pack('n') + + assert_equal "\200\000", [2**15].pack('n') + assert_equal "\177\377", [-2**15-1].pack('n') + assert_equal "\377\377", [-1].pack('n') + + assert_equal "\000\001\000\001", [1,1].pack('n*') + assert_equal "\000\001\000\001\000\001", [1,1,1].pack('n*') + end + + def test_unpack_n + assert_equal 1, "\000\001".unpack('n')[0] + assert_equal 2, "\000\002".unpack('n')[0] + assert_equal 3, "\000\003".unpack('n')[0] + assert_equal 65535, "\377\377".unpack('n')[0] + assert_equal [1,1], "\000\001\000\001".unpack('n*') + assert_equal [1,1,1], "\000\001\000\001\000\001".unpack('n*') + end + + def test_pack_N + assert_equal "\000\000\000\000", [0].pack('N') + assert_equal "\000\000\000\001", [1].pack('N') + assert_equal "\000\000\000\002", [2].pack('N') + assert_equal "\000\000\000\003", [3].pack('N') + assert_equal "\377\377\377\376", [4294967294].pack('N') + assert_equal "\377\377\377\377", [4294967295].pack('N') + + assert_equal "\200\000\000\000", [2**31].pack('N') + assert_equal "\177\377\377\377", [-2**31-1].pack('N') + assert_equal "\377\377\377\377", [-1].pack('N') + + assert_equal "\000\000\000\001\000\000\000\001", [1,1].pack('N*') + assert_equal "\000\000\000\001\000\000\000\001\000\000\000\001", [1,1,1].pack('N*') + end + + def test_unpack_N + assert_equal 1, "\000\000\000\001".unpack('N')[0] + assert_equal 2, "\000\000\000\002".unpack('N')[0] + assert_equal 3, "\000\000\000\003".unpack('N')[0] + assert_equal 4294967295, "\377\377\377\377".unpack('N')[0] + assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*') + assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*') + end + + def _integer_big_endian(mod='') + assert_equal("\x01\x02", [0x0102].pack("s"+mod)) + assert_equal("\x01\x02", [0x0102].pack("S"+mod)) + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l"+mod)) + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"+mod)) + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"+mod)) + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"+mod)) + assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"+mod)) + assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"+mod)) + %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + fmt += mod + nuls = [0].pack(fmt) + v = 0 + s = "".force_encoding("ascii-8bit") + nuls.bytesize.times {|i| + j = i + 40 + v = v * 256 + j + s << [j].pack("C") + } + assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})") + assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})") + s2 = s+s + fmt2 = fmt+"*" + assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})") + } + end + + def _integer_little_endian(mod='') + assert_equal("\x02\x01", [0x0102].pack("s"+mod)) + assert_equal("\x02\x01", [0x0102].pack("S"+mod)) + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l"+mod)) + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"+mod)) + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"+mod)) + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"+mod)) + assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"+mod)) + assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"+mod)) + %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + fmt += mod + nuls = [0].pack(fmt) + v = 0 + s = "".force_encoding("ascii-8bit") + nuls.bytesize.times {|i| + j = i+40 + v = v * 256 + j + s << [j].pack("C") + } + s.reverse! + assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})") + assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})") + s2 = s+s + fmt2 = fmt+"*" + assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})") + } + end + + def test_integer_endian + s = [1].pack("s") + assert_include(["\0\1", "\1\0"], s) + if s == "\0\1" + _integer_big_endian() + else + _integer_little_endian() + end + assert_equal("\x01\x02\x02\x01", [0x0102,0x0102].pack("s>s<")) + assert_equal([0x0102,0x0102], "\x01\x02\x02\x01".unpack("s>s<")) + end + + def test_integer_endian_explicit + _integer_big_endian('>') + _integer_little_endian('<') + end + + def test_pack_U + assert_raise(RangeError) { [-0x40000001].pack("U") } + assert_raise(RangeError) { [-0x40000000].pack("U") } + assert_raise(RangeError) { [-1].pack("U") } + assert_equal "\000", [0].pack("U") + assert_equal "\374\277\277\277\277\277".force_encoding(Encoding::UTF_8), [0x3fffffff].pack("U") + assert_equal "\375\200\200\200\200\200".force_encoding(Encoding::UTF_8), [0x40000000].pack("U") + assert_equal "\375\277\277\277\277\277".force_encoding(Encoding::UTF_8), [0x7fffffff].pack("U") + assert_raise(RangeError) { [0x80000000].pack("U") } + assert_raise(RangeError) { [0x100000000].pack("U") } + end + + def test_pack_P + a = ["abc"] + assert_equal a, a.pack("P").unpack("P*") + assert_equal "a", a.pack("P").unpack("P")[0] + assert_equal a, a.pack("P").freeze.unpack("P*") + assert_raise(ArgumentError) { (a.pack("P") + "").unpack("P*") } + end + + def test_pack_p + a = ["abc"] + assert_equal a, a.pack("p").unpack("p*") + assert_equal a[0], a.pack("p").unpack("p")[0] + assert_equal a, a.pack("p").freeze.unpack("p*") + assert_raise(ArgumentError) { (a.pack("p") + "").unpack("p*") } + assert_equal a, (a.pack("p") << "d").unpack("p*") + end + + def test_format_string_modified + fmt = "CC" + o = Object.new + class << o; self; end.class_eval do + define_method(:to_int) { fmt.clear; 0 } + end + assert_raise(RuntimeError) do + [o, o].pack(fmt) + end + end + + def test_comment + assert_equal("\0\1", [0,1].pack(" C #foo \n C ")) + assert_equal([0,1], "\0\1".unpack(" C #foo \n C ")) + end + + def test_illegal_bang + assert_raise(ArgumentError) { [].pack("a!") } + assert_raise(ArgumentError) { "".unpack("a!") } + end + + def test_pack_unpack_aA + assert_equal("f", ["foo"].pack("A")) + assert_equal("f", ["foo"].pack("a")) + assert_equal("foo", ["foo"].pack("A*")) + assert_equal("foo", ["foo"].pack("a*")) + assert_equal("fo", ["foo"].pack("A2")) + assert_equal("fo", ["foo"].pack("a2")) + assert_equal("foo ", ["foo"].pack("A4")) + assert_equal("foo\0", ["foo"].pack("a4")) + assert_equal(" ", [nil].pack("A")) + assert_equal("\0", [nil].pack("a")) + assert_equal("", [nil].pack("A*")) + assert_equal("", [nil].pack("a*")) + assert_equal(" ", [nil].pack("A2")) + assert_equal("\0\0", [nil].pack("a2")) + + assert_equal("foo" + "\0" * 27, ["foo"].pack("a30")) + + assert_equal(["f"], "foo\0".unpack("A")) + assert_equal(["f"], "foo\0".unpack("a")) + assert_equal(["foo"], "foo\0".unpack("A4")) + assert_equal(["foo\0"], "foo\0".unpack("a4")) + assert_equal(["foo"], "foo ".unpack("A4")) + assert_equal(["foo "], "foo ".unpack("a4")) + assert_equal(["foo"], "foo".unpack("A4")) + assert_equal(["foo"], "foo".unpack("a4")) + end + + def test_pack_unpack_Z + assert_equal("f", ["foo"].pack("Z")) + assert_equal("foo\0", ["foo"].pack("Z*")) + assert_equal("fo", ["foo"].pack("Z2")) + assert_equal("foo\0\0", ["foo"].pack("Z5")) + assert_equal("\0", [nil].pack("Z")) + assert_equal("\0", [nil].pack("Z*")) + assert_equal("\0\0", [nil].pack("Z2")) + + assert_equal(["f"], "foo\0".unpack("Z")) + assert_equal(["foo"], "foo".unpack("Z*")) + assert_equal(["foo"], "foo\0".unpack("Z*")) + assert_equal(["foo"], "foo".unpack("Z5")) + end + + def test_pack_unpack_bB + assert_equal("\xff\x00", ["1111111100000000"].pack("b*")) + assert_equal("\x01\x02", ["1000000001000000"].pack("b*")) + assert_equal("", ["1"].pack("b0")) + assert_equal("\x01", ["1"].pack("b1")) + assert_equal("\x01\x00", ["1"].pack("b2")) + assert_equal("\x01\x00", ["1"].pack("b3")) + assert_equal("\x01\x00\x00", ["1"].pack("b4")) + assert_equal("\x01\x00\x00", ["1"].pack("b5")) + assert_equal("\x01\x00\x00\x00", ["1"].pack("b6")) + + assert_equal("\xff\x00", ["1111111100000000"].pack("B*")) + assert_equal("\x01\x02", ["0000000100000010"].pack("B*")) + assert_equal("", ["1"].pack("B0")) + assert_equal("\x80", ["1"].pack("B1")) + assert_equal("\x80\x00", ["1"].pack("B2")) + assert_equal("\x80\x00", ["1"].pack("B3")) + assert_equal("\x80\x00\x00", ["1"].pack("B4")) + assert_equal("\x80\x00\x00", ["1"].pack("B5")) + assert_equal("\x80\x00\x00\x00", ["1"].pack("B6")) + + assert_equal(["1111111100000000"], "\xff\x00".unpack("b*")) + assert_equal(["1000000001000000"], "\x01\x02".unpack("b*")) + assert_equal([""], "".unpack("b0")) + assert_equal(["1"], "\x01".unpack("b1")) + assert_equal(["10"], "\x01".unpack("b2")) + assert_equal(["100"], "\x01".unpack("b3")) + + assert_equal(["1111111100000000"], "\xff\x00".unpack("B*")) + assert_equal(["0000000100000010"], "\x01\x02".unpack("B*")) + assert_equal([""], "".unpack("B0")) + assert_equal(["1"], "\x80".unpack("B1")) + assert_equal(["10"], "\x80".unpack("B2")) + assert_equal(["100"], "\x80".unpack("B3")) + + assert_equal(Encoding::US_ASCII, "\xff\x00".unpack("b*")[0].encoding) + assert_equal(Encoding::US_ASCII, "\xff\x00".unpack("B*")[0].encoding) + end + + def test_pack_unpack_hH + assert_equal("\x01\xfe", ["10ef"].pack("h*")) + assert_equal("", ["10ef"].pack("h0")) + assert_equal("\x01\x0e", ["10ef"].pack("h3")) + assert_equal("\x01\xfe\x0", ["10ef"].pack("h5")) + assert_equal("\xff\x0f", ["fff"].pack("h3")) + assert_equal("\xff\x0f", ["fff"].pack("h4")) + assert_equal("\xff\x0f\0", ["fff"].pack("h5")) + assert_equal("\xff\x0f\0", ["fff"].pack("h6")) + assert_equal("\xff\x0f\0\0", ["fff"].pack("h7")) + assert_equal("\xff\x0f\0\0", ["fff"].pack("h8")) + + assert_equal("\x10\xef", ["10ef"].pack("H*")) + assert_equal("", ["10ef"].pack("H0")) + assert_equal("\x10\xe0", ["10ef"].pack("H3")) + assert_equal("\x10\xef\x0", ["10ef"].pack("H5")) + assert_equal("\xff\xf0", ["fff"].pack("H3")) + assert_equal("\xff\xf0", ["fff"].pack("H4")) + assert_equal("\xff\xf0\0", ["fff"].pack("H5")) + assert_equal("\xff\xf0\0", ["fff"].pack("H6")) + assert_equal("\xff\xf0\0\0", ["fff"].pack("H7")) + assert_equal("\xff\xf0\0\0", ["fff"].pack("H8")) + + assert_equal(["10ef"], "\x01\xfe".unpack("h*")) + assert_equal([""], "\x01\xfe".unpack("h0")) + assert_equal(["1"], "\x01\xfe".unpack("h1")) + assert_equal(["10"], "\x01\xfe".unpack("h2")) + assert_equal(["10e"], "\x01\xfe".unpack("h3")) + assert_equal(["10ef"], "\x01\xfe".unpack("h4")) + assert_equal(["10ef"], "\x01\xfe".unpack("h5")) + + assert_equal(["10ef"], "\x10\xef".unpack("H*")) + assert_equal([""], "\x10\xef".unpack("H0")) + assert_equal(["1"], "\x10\xef".unpack("H1")) + assert_equal(["10"], "\x10\xef".unpack("H2")) + assert_equal(["10e"], "\x10\xef".unpack("H3")) + assert_equal(["10ef"], "\x10\xef".unpack("H4")) + assert_equal(["10ef"], "\x10\xef".unpack("H5")) + + assert_equal(Encoding::US_ASCII, "\x10\xef".unpack("h*")[0].encoding) + assert_equal(Encoding::US_ASCII, "\x10\xef".unpack("H*")[0].encoding) + end + + def test_pack_unpack_cC + assert_equal("\0\1\xff", [0, 1, 255].pack("c*")) + assert_equal("\0\1\xff", [0, 1, -1].pack("c*")) + + assert_equal("\0\1\xff", [0, 1, 255].pack("C*")) + assert_equal("\0\1\xff", [0, 1, -1].pack("C*")) + + assert_equal([0, 1, -1], "\0\1\xff".unpack("c*")) + + assert_equal([0, 1, 255], "\0\1\xff".unpack("C*")) + end + + def test_pack_unpack_sS + s1 = [513, -514].pack("s*") + s2 = [513, 65022].pack("S*") + assert_equal(s1, s2) + assert_equal([513, -514], s2.unpack("s*")) + assert_equal([513, 65022], s1.unpack("S*")) + + s1 = [513, -514].pack("s!*") + s2 = [513, 65022].pack("S!*") + assert_equal(s1, s2) + assert_equal([513, -514], s2.unpack("s!*")) + assert_equal([513, 65022], s1.unpack("S!*")) + + assert_equal(2, [1].pack("s").bytesize) + assert_equal(2, [1].pack("S").bytesize) + assert_operator(2, :<=, [1].pack("s!").bytesize) + assert_operator(2, :<=, [1].pack("S!").bytesize) + end + + def test_pack_unpack_iI + s1 = [67305985, -50462977].pack("i*") + s2 = [67305985, 4244504319].pack("I*") + assert_equal(s1, s2) + assert_equal([67305985, -50462977], s2.unpack("i*")) + assert_equal([67305985, 4244504319], s1.unpack("I*")) + + s1 = [67305985, -50462977].pack("i!*") + s2 = [67305985, 4244504319].pack("I!*") + assert_equal([67305985, -50462977], s1.unpack("i!*")) + assert_equal([67305985, 4244504319], s2.unpack("I!*")) + + assert_operator(4, :<=, [1].pack("i").bytesize) + assert_operator(4, :<=, [1].pack("I").bytesize) + assert_operator(4, :<=, [1].pack("i!").bytesize) + assert_operator(4, :<=, [1].pack("I!").bytesize) + end + + def test_pack_unpack_lL + s1 = [67305985, -50462977].pack("l*") + s2 = [67305985, 4244504319].pack("L*") + assert_equal(s1, s2) + assert_equal([67305985, -50462977], s2.unpack("l*")) + assert_equal([67305985, 4244504319], s1.unpack("L*")) + + s1 = [67305985, -50462977].pack("l!*") + s2 = [67305985, 4244504319].pack("L!*") + assert_equal([67305985, -50462977], s1.unpack("l!*")) + assert_equal([67305985, 4244504319], s2.unpack("L!*")) + + assert_equal(4, [1].pack("l").bytesize) + assert_equal(4, [1].pack("L").bytesize) + assert_operator(4, :<=, [1].pack("l!").bytesize) + assert_operator(4, :<=, [1].pack("L!").bytesize) + end + + def test_pack_unpack_qQ + s1 = [578437695752307201, -506097522914230529].pack("q*") + s2 = [578437695752307201, 17940646550795321087].pack("Q*") + assert_equal(s1, s2) + assert_equal([578437695752307201, -506097522914230529], s2.unpack("q*")) + assert_equal([578437695752307201, 17940646550795321087], s1.unpack("Q*")) + + # Note: q! and Q! should not work on platform which has no long long type. + # Is there a such platform now? + s1 = [578437695752307201, -506097522914230529].pack("q!*") + s2 = [578437695752307201, 17940646550795321087].pack("Q!*") + assert_equal([578437695752307201, -506097522914230529], s2.unpack("q!*")) + assert_equal([578437695752307201, 17940646550795321087], s1.unpack("Q!*")) + + assert_equal(8, [1].pack("q").bytesize) + assert_equal(8, [1].pack("Q").bytesize) + assert_operator(8, :<=, [1].pack("q!").bytesize) + assert_operator(8, :<=, [1].pack("Q!").bytesize) + end + + def test_pack_unpack_nN + assert_equal("\000\000\000\001\377\377\177\377\200\000\377\377", [0,1,-1,32767,-32768,65535].pack("n*")) + assert_equal("\000\000\000\000\000\000\000\001\377\377\377\377", [0,1,-1].pack("N*")) + + assert_equal([0,1,65535,32767,32768,65535], "\000\000\000\001\377\377\177\377\200\000\377\377".unpack("n*")) + assert_equal([0,1,4294967295], "\000\000\000\000\000\000\000\001\377\377\377\377".unpack("N*")) + + assert_equal(2, [1].pack("n").bytesize) + assert_equal(4, [1].pack("N").bytesize) + end + + def test_pack_unpack_vV + assert_equal("\000\000\001\000\377\377\377\177\000\200\377\377", [0,1,-1,32767,-32768,65535].pack("v*")) + assert_equal("\000\000\000\000\001\000\000\000\377\377\377\377", [0,1,-1].pack("V*")) + + assert_equal([0,1,65535,32767,32768,65535], "\000\000\001\000\377\377\377\177\000\200\377\377".unpack("v*")) + assert_equal([0,1,4294967295], "\000\000\000\000\001\000\000\000\377\377\377\377".unpack("V*")) + + assert_equal(2, [1].pack("v").bytesize) + assert_equal(4, [1].pack("V").bytesize) + end + + def test_pack_unpack_fdeEgG + inf = 1.0/0.0 + nan = inf/inf + [0.0, 1.0, 3.0, inf, -inf, nan].each do |x| + %w(f d e E g G).each do |f| + v = [x].pack(f).unpack(f) + if x.nan? + assert_predicate(v.first, :nan?) + else + assert_equal([x], v) + end + end + end + end + + def test_pack_unpack_x + assert_equal("", [].pack("x0")) + assert_equal("\0", [].pack("x")) + assert_equal("\0" * 30, [].pack("x30")) + + assert_equal([0, 2], "\x00\x00\x02".unpack("CxC")) + assert_raise(ArgumentError) { "".unpack("x") } + end + + def test_pack_unpack_X + assert_equal("\x00\x02", [0, 1, 2].pack("CCXC")) + assert_equal("\x02", [0, 1, 2].pack("CCX2C")) + assert_raise(ArgumentError) { [].pack("X") } + + assert_equal([0, 2, 2], "\x00\x02".unpack("CCXC")) + assert_raise(ArgumentError) { "".unpack("X") } + end + + def test_pack_unpack_atmark + assert_equal("\x01\x00\x00\x02", [1, 2].pack("C@3C")) + assert_equal("\x02", [1, 2].pack("C@0C")) + assert_equal("\x01\x02", [1, 2].pack("C@1C")) + + assert_equal([1, 2], "\x01\x00\x00\x02".unpack("C@3C")) + assert_equal([nil], "\x00".unpack("@1C")) # is it OK? + assert_raise(ArgumentError) { "\x00".unpack("@2C") } + end + + def test_pack_unpack_percent + assert_raise(ArgumentError) { [].pack("%") } + assert_raise(ArgumentError) { "".unpack("%") } + end + + def test_pack_unpack_U + assert_equal([0], [0].pack("U").unpack("U")) + assert_equal([0x80], [0x80].pack("U").unpack("U")) + assert_equal([0x800], [0x800].pack("U").unpack("U")) + assert_equal([0x10000], [0x10000].pack("U").unpack("U")) + assert_equal([0x400000], [0x400000].pack("U").unpack("U")) + + assert_raise(ArgumentError) { "\x80".unpack("U") } + assert_raise(ArgumentError) { "\xff".unpack("U") } + assert_raise(ArgumentError) { "\xfc\x00".unpack("U") } + assert_raise(ArgumentError) { "\xc0\xc0".unpack("U") } + assert_raise(ArgumentError) { "\xe0\x80\x80".unpack("U") } + end + + def test_pack_unpack_u + assert_equal("", [""].pack("u")) + assert_equal("!80``\n", ["a"].pack("u")) + assert_equal("#86)C\n", ["abc"].pack("u")) + assert_equal("$86)C9```\n", ["abcd"].pack("u")) + assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n", ["a"*45].pack("u")) + assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u")) + assert_equal("&86)C9&5F\n#9VAI\n", ["abcdefghi"].pack("u6")) + + assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u0")) + assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u1")) + assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u2")) + assert_equal(<<EXPECTED, ["a"*80].pack("u68")) +_86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A +186%A86%A86%A86%A86%A86$` +EXPECTED + + assert_equal([""], "".unpack("u")) + assert_equal(["a"], "!80``\n".unpack("u")) + assert_equal(["abc"], "#86)C\n".unpack("u")) + assert_equal(["abcd"], "$86)C9```\n".unpack("u")) + assert_equal(["a"*45], "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n".unpack("u")) + assert_equal(["a"*46], "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n".unpack("u")) + assert_equal(["abcdefghi"], "&86)C9&5F\n#9VAI\n".unpack("u")) + + assert_equal(["abcdef"], "#86)C\n#9&5F\n".unpack("u")) + assert_equal(["abcdef"], "#86)CX\n#9&5FX\n".unpack("u")) # X is a (dummy) checksum. + assert_equal(["abcdef"], "#86)C\r\n#9&5F\r\n".unpack("u")) + assert_equal(["abcdef"], "#86)CX\r\n#9&5FX\r\n".unpack("u")) # X is a (dummy) checksum. + + assert_equal(["\x00"], "\"\n".unpack("u")) + assert_equal(["\x00"], "! \r \n".unpack("u")) + end + + def test_pack_unpack_m + assert_equal("", [""].pack("m")) + assert_equal("AA==\n", ["\0"].pack("m")) + assert_equal("AAA=\n", ["\0\0"].pack("m")) + assert_equal("AAAA\n", ["\0\0\0"].pack("m")) + assert_equal("/w==\n", ["\377"].pack("m")) + assert_equal("//8=\n", ["\377\377"].pack("m")) + assert_equal("////\n", ["\377\377\377"].pack("m")) + + assert_equal([""], "".unpack("m")) + assert_equal(["\0"], "AA==\n".unpack("m")) + assert_equal(["\0\0"], "AAA=\n".unpack("m")) + assert_equal(["\0\0\0"], "AAAA\n".unpack("m")) + assert_equal(["\377"], "/w==\n".unpack("m")) + assert_equal(["\377\377"], "//8=\n".unpack("m")) + assert_equal(["\377\377\377"], "////\n".unpack("m")) + assert_equal([""], "A\n".unpack("m")) + assert_equal(["\0"], "AA\n".unpack("m")) + assert_equal(["\0"], "AA=\n".unpack("m")) + assert_equal(["\0\0"], "AAA\n".unpack("m")) + + bug10019 = '[ruby-core:63604] [Bug #10019]' + size = ((4096-4)/4*3+1) + assert_separately(%W[- #{size} #{bug10019}], <<-'end;') + size = ARGV.shift.to_i + bug = ARGV.shift + assert_equal(size, ["a"*size].pack("m#{size+2}").unpack("m")[0].size, bug) + end; + end + + def test_pack_unpack_m0 + assert_equal("", [""].pack("m0")) + assert_equal("AA==", ["\0"].pack("m0")) + assert_equal("AAA=", ["\0\0"].pack("m0")) + assert_equal("AAAA", ["\0\0\0"].pack("m0")) + assert_equal("/w==", ["\377"].pack("m0")) + assert_equal("//8=", ["\377\377"].pack("m0")) + assert_equal("////", ["\377\377\377"].pack("m0")) + + assert_equal([""], "".unpack("m0")) + assert_equal(["\0"], "AA==".unpack("m0")) + assert_equal(["\0\0"], "AAA=".unpack("m0")) + assert_equal(["\0\0\0"], "AAAA".unpack("m0")) + assert_equal(["\377"], "/w==".unpack("m0")) + assert_equal(["\377\377"], "//8=".unpack("m0")) + assert_equal(["\377\377\377"], "////".unpack("m0")) + + assert_raise(ArgumentError) { "^".unpack("m0") } + assert_raise(ArgumentError) { "A".unpack("m0") } + assert_raise(ArgumentError) { "A^".unpack("m0") } + assert_raise(ArgumentError) { "AA".unpack("m0") } + assert_raise(ArgumentError) { "AA=".unpack("m0") } + assert_raise(ArgumentError) { "AA===".unpack("m0") } + assert_raise(ArgumentError) { "AA=x".unpack("m0") } + assert_raise(ArgumentError) { "AAA".unpack("m0") } + assert_raise(ArgumentError) { "AAA^".unpack("m0") } + assert_raise(ArgumentError) { "AB==".unpack("m0") } + assert_raise(ArgumentError) { "AAB=".unpack("m0") } + end + + def test_pack_unpack_M + assert_equal("a b c\td =\n\ne=\n", ["a b c\td \ne"].pack("M")) + assert_equal(["a b c\td \ne"], "a b c\td =\n\ne=\n".unpack("M")) + assert_equal("=00=\n", ["\0"].pack("M")) + assert_equal("a"*73+"=\na=\n", ["a"*74].pack("M")) + assert_equal(("a"*73+"=\n")*14+"a=\n", ["a"*1023].pack("M")) + assert_equal(["\0"], "=00=\n".unpack("M")) + assert_equal(["a"*74], ("a"*73+"=\na=\n").unpack("M")) + assert_equal(["a"*1023], (("a"*73+"=\n")*14+"a=\n").unpack("M")) + assert_equal(["\x0a"], "=0a=\n".unpack("M")) + assert_equal(["\x0a"], "=0A=\n".unpack("M")) + assert_equal(["=0Z=\n"], "=0Z=\n".unpack("M")) + assert_equal([""], "=\r\n".unpack("M")) + assert_equal(["\xC6\xF7"], "=C6=F7".unpack('M*')) + + assert_equal(["pre123after"], "pre=31=32=33after".unpack("M")) + assert_equal(["preafter"], "pre=\nafter".unpack("M")) + assert_equal(["preafter"], "pre=\r\nafter".unpack("M")) + assert_equal(["pre="], "pre=".unpack("M")) + assert_equal(["pre=\r"], "pre=\r".unpack("M")) + assert_equal(["pre=hoge"], "pre=hoge".unpack("M")) + assert_equal(["pre==31after"], "pre==31after".unpack("M")) + assert_equal(["pre===31after"], "pre===31after".unpack("M")) + end + + def test_pack_unpack_P2 + assert_raise(ArgumentError) { ["abc"].pack("P4") } + assert_raise(ArgumentError) { [""].pack("P") } + + assert_equal([], ".".unpack("P")) + assert_equal([], ".".unpack("p")) + assert_equal([nil], ("\0" * 1024).unpack("P")) + end + + def test_pack_p2 + assert_match(/\A\0*\Z/, [nil].pack("p")) + end + + def test_pack_unpack_w + assert_equal("\000", [0].pack("w")) + assert_equal("\001", [1].pack("w")) + assert_equal("\177", [127].pack("w")) + assert_equal("\201\000", [128].pack("w")) + assert_equal("\377\177", [0x3fff].pack("w")) + assert_equal("\201\200\000", [0x4000].pack("w")) + assert_equal("\203\377\377\377\177", [0x3fffffff].pack("w")) + assert_equal("\204\200\200\200\000", [0x40000000].pack("w")) + assert_equal("\217\377\377\377\177", [0xffffffff].pack("w")) + assert_equal("\220\200\200\200\000", [0x100000000].pack("w")) + assert_raise(ArgumentError) { [-1].pack("w") } + + assert_equal([0], "\000".unpack("w")) + assert_equal([1], "\001".unpack("w"), [1]) + assert_equal([127], "\177".unpack("w"), [127]) + assert_equal([128], "\201\000".unpack("w"), [128]) + assert_equal([0x3fff], "\377\177".unpack("w"), [0x3fff]) + assert_equal([0x4000], "\201\200\000".unpack("w"), [0x4000]) + assert_equal([0x3fffffff], "\203\377\377\377\177".unpack("w"), [0x3fffffff]) + assert_equal([0x40000000], "\204\200\200\200\000".unpack("w"), [0x40000000]) + assert_equal([0xffffffff], "\217\377\377\377\177".unpack("w"), [0xffffffff]) + assert_equal([0x100000000], "\220\200\200\200\000".unpack("w"), [0x100000000]) + end + + def test_length_too_big + assert_raise(RangeError) { [].pack("C100000000000000000000") } + end + + def test_short_string + %w[n N v V s S i I l L q Q s! S! i! I! l! l!].each {|fmt| + str = [1].pack(fmt) + assert_equal([1,nil], str.unpack("#{fmt}2")) + } + end + + def test_short_with_block + bug4059 = '[ruby-core:33193]' + result = :ok + assert_nil("".unpack("i") {|x| result = x}, bug4059) + assert_equal(:ok, result) + end + + def test_pack_garbage + verbose = $VERBOSE + $VERBOSE = false + + assert_silent do + assert_equal "\000", [0].pack("*U") + end + + $VERBOSE = true + + _, err = capture_io do + assert_equal "\000", [0].pack("*U") + end + + assert_match %r%unknown pack directive '\*' in '\*U'$%, err + ensure + $VERBOSE = verbose + end + + def test_unpack_garbage + verbose = $VERBOSE + $VERBOSE = false + + assert_silent do + assert_equal [0], "\000".unpack("*U") + end + + $VERBOSE = true + + _, err = capture_io do + assert_equal [0], "\000".unpack("*U") + end + + assert_match %r%unknown unpack directive '\*' in '\*U'$%, err + ensure + $VERBOSE = verbose + end + + def test_invalid_warning + assert_warning(/unknown pack directive ',' in ','/) { + [].pack(",") + } + assert_warning(/\A[ -~]+\Z/) { + [].pack("\x7f") + } + assert_warning(/\A(.* in '\u{3042}'\n)+\z/) { + EnvUtil.with_default_external(Encoding::UTF_8) { + [].pack("\u{3042}") + } + } + end +end diff --git a/jni/ruby/test/ruby/test_parse.rb b/jni/ruby/test/ruby/test_parse.rb new file mode 100644 index 0000000..43de64b --- /dev/null +++ b/jni/ruby/test/ruby/test_parse.rb @@ -0,0 +1,882 @@ +# coding: US-ASCII +require 'test/unit' +require 'stringio' + +class TestParse < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_else_without_rescue + x = eval <<-END, nil, __FILE__, __LINE__+1 + begin + else + 42 + end + END + assert_equal(42, x) + end + + def test_alias_backref + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + alias $foo $1 + END + end + end + + def test_command_call + t = Object.new + def t.foo(x); x; end + + a = false + b = c = d = true + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a &&= t.foo 42 + b &&= t.foo 42 + c &&= t.foo nil + d &&= t.foo false + END + end + assert_equal([false, 42, nil, false], [a, b, c, d]) + + a = 3 + assert_nothing_raised { eval("a &= t.foo 5") } + assert_equal(1, a) + + a = [nil, nil, true, true] + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a[0] ||= t.foo 42 + a[1] &&= t.foo 42 + a[2] ||= t.foo 42 + a[3] &&= t.foo 42 + END + end + assert_equal([42, nil, true, 42], a) + + o = Object.new + class << o + attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux + end + o.foo = o.Foo = o::baz = nil + o.bar = o.Bar = o::qux = 1 + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + o.foo ||= t.foo 42 + o.bar &&= t.foo 42 + o.Foo ||= t.foo 42 + o.Bar &&= t.foo 42 + o::baz ||= t.foo 42 + o::qux &&= t.foo 42 + END + end + assert_equal([42, 42], [o.foo, o.bar]) + assert_equal([42, 42], [o.Foo, o.Bar]) + assert_equal([42, 42], [o::baz, o::qux]) + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + $1 ||= t.foo 42 + END + end + + def t.bar(x); x + yield; end + + a = b = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = t.bar "foo" do + "bar" + end.gsub "ob", "OB" + b = t.bar "foo" do + "bar" + end::gsub "ob", "OB" + END + end + assert_equal("foOBar", a) + assert_equal("foOBar", b) + + a = nil + assert_nothing_raised do + t.instance_eval <<-END, __FILE__, __LINE__+1 + a = bar "foo" do "bar" end + END + end + assert_equal("foobar", a) + + a = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = t::bar "foo" do "bar" end + END + end + assert_equal("foobar", a) + + def t.baz(*r) + @baz = r + (block_given? ? [yield] : []) + end + + assert_nothing_raised do + t.instance_eval "baz (1), 2" + end + assert_equal([1, 2], t.instance_eval { @baz }) + end + + def test_mlhs_node + c = Class.new + class << c + attr_accessor :foo, :bar, :Foo, :Bar + FOO = BAR = nil + end + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + c::foo, c::bar = 1, 2 + c.Foo, c.Bar = 1, 2 + c::FOO, c::BAR = 1, 2 + END + end + assert_equal([1, 2], [c::foo, c::bar]) + assert_equal([1, 2], [c.Foo, c.Bar]) + assert_equal([1, 2], [c::FOO, c::BAR]) + end + + def test_dynamic_constant_assignment + assert_raise(SyntaxError) do + Object.new.instance_eval <<-END, __FILE__, __LINE__+1 + def foo + self::FOO, self::BAR = 1, 2 + ::FOO, ::BAR = 1, 2 + end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + $1, $2 = 1, 2 + END + end + + assert_raise(SyntaxError) do + Object.new.instance_eval <<-END, __FILE__, __LINE__+1 + def foo + ::FOO = 1 + end + END + end + + c = Class.new + assert_nothing_raised(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + if false + c::FOO &= 1 + ::FOO &= 1 + end + END + end + + c = Class.new + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + $1 &= 1 + END + end + end + + def test_class_module + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + class foo; end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo + class Foo; end + module Bar; end + end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + class Foo Bar; end + END + end + end + + def test_op_name + o = Object.new + def o.>(x); x; end + def o./(x); x; end + + assert_nothing_raised do + o.instance_eval <<-END, __FILE__, __LINE__+1 + undef >, / + END + end + end + + def test_arg + o = Object.new + class << o + attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux + end + o.foo = o.Foo = o::baz = nil + o.bar = o.Bar = o::qux = 1 + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + o.foo ||= 42 + o.bar &&= 42 + o.Foo ||= 42 + o.Bar &&= 42 + o::baz ||= 42 + o::qux &&= 42 + END + end + assert_equal([42, 42], [o.foo, o.bar]) + assert_equal([42, 42], [o.Foo, o.Bar]) + assert_equal([42, 42], [o::baz, o::qux]) + + a = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = -2.0 ** 2 + END + end + assert_equal(-4.0, a) + end + + def test_block_variable + o = Object.new + def o.foo(*r); yield(*r); end + + a = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + o.foo 1 do|; a| a = 42 end + END + end + assert_nil(a) + end + + def test_bad_arg + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo(FOO); end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo(@foo); end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo($foo); end + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo(@@foo); end + END + end + + o = Object.new + def o.foo(*r); yield(*r); end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + o.foo 1 {|; @a| @a = 42 } + END + end + end + + def test_do_lambda + a = b = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = -> do + b = 42 + end + END + end + a.call + assert_equal(42, b) + end + + def test_block_call_colon2 + o = Object.new + def o.foo(x); x + yield; end + + a = b = nil + assert_nothing_raised do + o.instance_eval <<-END, __FILE__, __LINE__+1 + a = foo 1 do 42 end.to_s + b = foo 1 do 42 end::to_s + END + end + assert_equal("43", a) + assert_equal("43", b) + end + + def test_call_method + a = b = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = proc {|x| x + "bar" }.("foo") + b = proc {|x| x + "bar" }::("foo") + END + end + assert_equal("foobar", a) + assert_equal("foobar", b) + end + + def test_xstring + assert_raise(Errno::ENOENT) do + eval("``") + end + end + + def test_words + assert_equal([], %W( )) + end + + def test_dstr + @@foo = 1 + assert_equal("foo 1 bar", "foo #@@foo bar") + "1" =~ /(.)/ + assert_equal("foo 1 bar", "foo #$1 bar") + end + + def test_dstr_disallowed_variable + bug8375 = '[ruby-core:54885] [Bug #8375]' + %w[@ @1 @@. @@ @@1 @@. $ $%].each do |src| + src = '#'+src+' ' + str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do + break eval('"'+src+'"') + end + assert_equal(src, str, bug8375) + end + end + + def test_dsym + assert_nothing_raised { eval(':""') } + end + + def test_arg2 + o = Object.new + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + def o.foo(a=42,*r,z,&b); b.call(r.inject(a*1000+z*100, :+)); end + END + end + assert_equal(-1405, o.foo(1,2,3,4) {|x| -x }) + assert_equal(-1302, o.foo(1,2,3) {|x| -x }) + assert_equal(-1200, o.foo(1,2) {|x| -x }) + assert_equal(-42100, o.foo(1) {|x| -x }) + assert_raise(ArgumentError) { o.foo() } + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + def o.foo(a=42,z,&b); b.call(a*1000+z*100); end + END + end + assert_equal(-1200, o.foo(1,2) {|x| -x } ) + assert_equal(-42100, o.foo(1) {|x| -x } ) + assert_raise(ArgumentError) { o.foo() } + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + def o.foo(*r,z,&b); b.call(r.inject(z*100, :+)); end + END + end + assert_equal(-303, o.foo(1,2,3) {|x| -x } ) + assert_equal(-201, o.foo(1,2) {|x| -x } ) + assert_equal(-100, o.foo(1) {|x| -x } ) + assert_raise(ArgumentError) { o.foo() } + end + + def test_duplicate_argument + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + 1.times {|&b?| } + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + 1.times {|a, a|} + END + end + + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo(a, a); end + END + end + end + + def test_define_singleton_error + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def ("foo").foo; end + END + end + end + + def test_backquote + t = Object.new + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + def t.`(x); "foo" + x + "bar"; end + END + end + a = b = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + a = t.` "zzz" + 1.times {|;z| t.` ("zzz") } + END + t.instance_eval <<-END, __FILE__, __LINE__+1 + b = `zzz` + END + end + assert_equal("foozzzbar", a) + assert_equal("foozzzbar", b) + end + + def test_carrige_return + assert_equal(2, eval("1 +\r\n1")) + end + + def test_string + assert_raise(SyntaxError) do + eval '"\xg1"' + end + + assert_raise(SyntaxError) do + eval '"\u{1234"' + end + + assert_raise(SyntaxError) do + eval '"\M1"' + end + + assert_raise(SyntaxError) do + eval '"\C1"' + end + + assert_equal("\x81", eval('"\C-\M-a"')) + assert_equal("\177", eval('"\c?"')) + end + + def test_question + assert_raise(SyntaxError) { eval('?') } + assert_raise(SyntaxError) { eval('? ') } + assert_raise(SyntaxError) { eval("?\n") } + assert_raise(SyntaxError) { eval("?\t") } + assert_raise(SyntaxError) { eval("?\v") } + assert_raise(SyntaxError) { eval("?\r") } + assert_raise(SyntaxError) { eval("?\f") } + assert_equal("\u{1234}", eval("?\u{1234}")) + assert_equal("\u{1234}", eval('?\u{1234}')) + end + + def test_percent + assert_equal(:foo, eval('%s(foo)')) + assert_raise(SyntaxError) { eval('%s') } + assert_raise(SyntaxError) { eval('%ss') } + assert_raise(SyntaxError) { eval('%z()') } + end + + def test_symbol + bug = '[ruby-dev:41447]' + sym = "foo\0bar".to_sym + assert_nothing_raised(SyntaxError, bug) do + assert_equal(sym, eval(":'foo\0bar'")) + end + assert_nothing_raised(SyntaxError, bug) do + assert_equal(sym, eval(':"foo\u0000bar"')) + end + assert_nothing_raised(SyntaxError, bug) do + assert_equal(sym, eval(':"foo\u{0}bar"')) + end + assert_raise(SyntaxError) do + eval ':"foo\u{}bar"' + end + end + + def test_parse_string + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 +/ + END + end + end + + def test_here_document + x = nil + + assert_raise(SyntaxError) do + eval %Q( +<\<FOO + ) + end + + assert_nothing_raised(SyntaxError) do + x = eval %q( +<<FOO +#$ +FOO + ) + end + assert_equal "\#$\n", x + + assert_raise(SyntaxError) do + eval %Q( +<\<\" + ) + end + + assert_raise(SyntaxError) do + eval %q( +<<`` + ) + end + + assert_raise(SyntaxError) do + eval %q( +<<-- + ) + end + + assert_nothing_raised(SyntaxError) do + x = eval %q( +<<FOO +#$ +foo +FOO + ) + end + assert_equal "\#$\nfoo\n", x + + assert_nothing_raised do + eval "x = <<""FOO\r\n1\r\nFOO" + end + assert_equal("1\n", x) + end + + def test_magic_comment + x = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 +# coding = utf-8 +x = __ENCODING__ + END + end + assert_equal(Encoding.find("UTF-8"), x) + + assert_raise(ArgumentError) do + eval <<-END, nil, __FILE__, __LINE__+1 +# coding = foobarbazquxquux_dummy_enconding +x = __ENCODING__ + END + end + end + + def test_utf8_bom + x = nil + assert_nothing_raised do + eval "\xef\xbb\xbf x = __ENCODING__" + end + assert_equal(Encoding.find("UTF-8"), x) + assert_raise(NameError) { eval "\xef" } + end + + def test_dot_in_next_line + x = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + x = 1 + .to_s + END + end + assert_equal("1", x) + end + + def test_pow_asgn + x = 3 + assert_nothing_raised { eval("x **= 2") } + assert_equal(9, x) + end + + def test_embedded_rd + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 +=begin + END + end + end + + def test_float + assert_equal(1.0/0, eval("1e10000")) + assert_raise(SyntaxError) { eval('1_E') } + assert_raise(SyntaxError) { eval('1E1E1') } + end + + def test_global_variable + assert_equal(nil, eval('$-x')) + assert_equal(nil, eval('alias $preserve_last_match $&')) + assert_equal(nil, eval('alias $& $test_parse_foobarbazqux')) + $test_parse_foobarbazqux = nil + assert_equal(nil, $&) + assert_equal(nil, eval('alias $& $preserve_last_match')) + assert_raise(SyntaxError) { eval('$#') } + end + + def test_invalid_instance_variable + assert_raise(SyntaxError) { eval('@#') } + assert_raise(SyntaxError) { eval('@') } + end + + def test_invalid_class_variable + assert_raise(SyntaxError) { eval('@@1') } + assert_raise(SyntaxError) { eval('@@') } + end + + def test_invalid_char + bug10117 = '[ruby-core:64243] [Bug #10117]' + invalid_char = /Invalid char `\\x01'/ + x = 1 + assert_in_out_err(%W"-e \x01x", "", [], invalid_char, bug10117) + assert_syntax_error("\x01x", invalid_char, bug10117) + assert_equal(nil, eval("\x04x")) + end + + def test_literal_concat + x = "baz" + assert_equal("foobarbaz", eval('"foo" "bar#{x}"')) + end + + def test_unassignable + assert_raise(SyntaxError) do + eval %q(self = 1) + end + assert_raise(SyntaxError) do + eval %q(nil = 1) + end + assert_raise(SyntaxError) do + eval %q(true = 1) + end + assert_raise(SyntaxError) do + eval %q(false = 1) + end + assert_raise(SyntaxError) do + eval %q(__FILE__ = 1) + end + assert_raise(SyntaxError) do + eval %q(__LINE__ = 1) + end + assert_raise(SyntaxError) do + eval %q(__ENCODING__ = 1) + end + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + def foo + FOO = 1 + end + END + end + end + + def test_block_dup + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + foo(&proc{}) {} + END + end + end + + def test_set_backref + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + $& = 1 + END + end + end + + def test_arg_concat + o = Object.new + class << o; self; end.instance_eval do + define_method(:[]=) {|*r, &b| b.call(r) } + end + r = nil + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + o[&proc{|x| r = x }] = 1 + END + end + assert_equal([1], r) + end + + def test_void_expr_stmts_value + # This test checks if void contexts are warned correctly. + # Thus, warnings MUST NOT be suppressed. + $VERBOSE = true + stderr = $stderr + $stderr = StringIO.new("") + x = 1 + assert_nil eval("x; nil") + assert_nil eval("1+1; nil") + assert_nil eval("TestParse; nil") + assert_nil eval("::TestParse; nil") + assert_nil eval("x..x; nil") + assert_nil eval("x...x; nil") + assert_nil eval("self; nil") + assert_nil eval("nil; nil") + assert_nil eval("true; nil") + assert_nil eval("false; nil") + assert_nil eval("defined?(1); nil") + + assert_raise(SyntaxError) do + eval %q(1; next; 2) + end + + assert_equal(13, $stderr.string.lines.to_a.size) + $stderr = stderr + end + + def test_assign_in_conditional + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + (x, y = 1, 2) ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + if @x = true + 1 + else + 2 + end + END + end + end + + def test_literal_in_conditional + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + "foo" ? 1 : 2 + END + end + + assert_nothing_raised do + x = "bar" + eval <<-END, nil, __FILE__, __LINE__+1 + /foo#{x}baz/ ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + (true..false) ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END, nil, __FILE__, __LINE__+1 + ("foo".."bar") ? 1 : 2 + END + end + + assert_nothing_raised do + x = "bar" + eval <<-END, nil, __FILE__, __LINE__+1 + :"foo#{"x"}baz" ? 1 : 2 + END + end + end + + def test_no_blockarg + assert_raise(SyntaxError) do + eval <<-END, nil, __FILE__, __LINE__+1 + yield(&:+) + END + end + end + + def test_intern + assert_equal(':""', ''.intern.inspect) + assert_equal(':$foo', '$foo'.intern.inspect) + assert_equal(':"!foo"', '!foo'.intern.inspect) + assert_equal(':"foo=="', "foo==".intern.inspect) + end + + def test_all_symbols + x = Symbol.all_symbols + assert_kind_of(Array, x) + assert_empty(x.reject {|s| s.is_a?(Symbol) }) + end + + def test_is_class_id + c = Class.new + assert_raise(NameError) do + c.instance_eval { remove_class_variable(:@var) } + end + end + + def test_method_block_location + bug5614 = '[ruby-core:40936]' + expected = nil + e = assert_raise(NoMethodError) do + 1.times do + expected = __LINE__+1 + end.print do + # + end + end + actual = e.backtrace.first[/\A#{Regexp.quote(__FILE__)}:(\d+):/o, 1].to_i + assert_equal(expected, actual, bug5614) + end + + def test_shadowing_variable + assert_warning(/shadowing outer local variable/) {eval("a=1; tap {|a|}")} + a = "\u{3042}" + assert_warning(/#{a}/o) {eval("#{a}=1; tap {|#{a}|}")} + end + + def test_unused_variable + o = Object.new + assert_warning(/assigned but unused variable/) {o.instance_eval("def foo; a=1; nil; end")} + a = "\u{3042}" + assert_warning(/#{a}/) {o.instance_eval("def foo; #{a}=1; nil; end")} + end + + def test_named_capture_conflict + a = 1 + assert_warning(/named capture conflict/) {eval("a = 1; /(?<a>)/ =~ ''")} + a = "\u{3042}" + assert_warning(/#{a}/) {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")} + end + +=begin + def test_past_scope_variable + assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}} + end +=end +end diff --git a/jni/ruby/test/ruby/test_path.rb b/jni/ruby/test/ruby/test_path.rb new file mode 100644 index 0000000..2db7be0 --- /dev/null +++ b/jni/ruby/test/ruby/test_path.rb @@ -0,0 +1,259 @@ +require 'test/unit' + +class TestPath < Test::Unit::TestCase + def test_path + assert_equal("a", File.basename("a")) + assert_equal("b", File.basename("a/b")) + assert_equal("b", File.basename("a/b/")) + assert_equal("/", File.basename("/")) + assert_equal("/", File.basename("//")) + assert_equal("/", File.basename("///")) + assert_equal("b", File.basename("a/b////")) + assert_equal("a", File.basename("a.rb", ".rb")) + assert_equal("a", File.basename("a.rb///", ".rb")) + assert_equal("a", File.basename("a.rb///", ".*")) + assert_equal("a.rb", File.basename("a.rb///", ".c")) + assert_equal(".", File.dirname("a")) + assert_equal("/", File.dirname("/")) + assert_equal("/", File.dirname("/a")) + assert_equal("a", File.dirname("a/b")) + assert_equal("a/b", File.dirname("a/b/c")) + assert_equal("/a/b", File.dirname("/a/b/c")) + assert_equal("/a", File.dirname("/a/b/")) + assert_equal("/a", File.dirname("/a/b///")) + case Dir.pwd + when %r'\A\w:' + assert_match(/\A\w:\/\z/, File.expand_path(".", "/")) + assert_match(/\A\w:\/a\z/, File.expand_path("a", "/")) + dosish = true + when %r'\A//' + assert_match(%r'\A//[^/]+/[^/]+\z', File.expand_path(".", "/")) + assert_match(%r'\A//[^/]+/[^/]+/a\z', File.expand_path(".", "/")) + dosish = true + else + assert_equal("/", File.expand_path(".", "/")) + assert_equal("/sub", File.expand_path("sub", "/")) + end + if dosish + assert_equal("//127.0.0.1/share", File.expand_path("/", "//127.0.0.1/share/sub")) + assert_equal("//127.0.0.1/share/dir", File.expand_path("/dir", "//127.0.0.1/share/sub")) + assert_equal("z:/", File.expand_path("/", "z:/sub")) + assert_equal("z:/dir", File.expand_path("/dir", "z:/sub")) + end + assert_equal("//", File.expand_path(".", "//")) + assert_equal("//sub", File.expand_path("sub", "//")) + + assert_equal("//127.0.0.1/\u3042", File.expand_path("\u3042", "//127.0.0.1")) + end + + def test_dirname + if /(bcc|ms)win\d|mingw|cygwin|emx/ =~ RUBY_PLATFORM + # DOSISH_DRIVE_LETTER + assert_equal('C:.', File.dirname('C:')) + assert_equal('C:.', File.dirname('C:a')) + assert_equal('C:.', File.dirname('C:a/')) + assert_equal('C:a', File.dirname('C:a/b'), "[ruby-dev:27738]") + + assert_equal('C:/', File.dirname('C:/')) + assert_equal('C:/', File.dirname('C:/a')) + assert_equal('C:/', File.dirname('C:/a/')) + assert_equal('C:/a', File.dirname('C:/a/b')) + + assert_equal('C:/', File.dirname('C://')) + assert_equal('C:/', File.dirname('C://a')) + assert_equal('C:/', File.dirname('C://a/')) + assert_equal('C:/a', File.dirname('C://a/b')) + + assert_equal('C:/', File.dirname('C:///'), "[ruby-dev:27738]") + assert_equal('C:/', File.dirname('C:///a')) + assert_equal('C:/', File.dirname('C:///a/')) + assert_equal('C:/a', File.dirname('C:///a/b')) + else + # others + assert_equal('.', File.dirname('C:')) + assert_equal('.', File.dirname('C:a')) + assert_equal('.', File.dirname('C:a/')) + assert_equal('C:a', File.dirname('C:a/b')) + + assert_equal('.', File.dirname('C:/')) + assert_equal('C:', File.dirname('C:/a')) + assert_equal('C:', File.dirname('C:/a/')) + assert_equal('C:/a', File.dirname('C:/a/b')) + + assert_equal('.', File.dirname('C://')) + assert_equal('C:', File.dirname('C://a')) + assert_equal('C:', File.dirname('C://a/')) + # not spec. + #assert_equal('C://a', File.dirname('C://a/b')) + + assert_equal('.', File.dirname('C:///')) + assert_equal('C:', File.dirname('C:///a')) + assert_equal('C:', File.dirname('C:///a/')) + # not spec. + #assert_equal('C:///a', File.dirname('C:///a/b')) + end + + assert_equal('.', File.dirname('')) + assert_equal('.', File.dirname('a')) + assert_equal('.', File.dirname('a/')) + assert_equal('a', File.dirname('a/b')) + + assert_equal('/', File.dirname('/')) + assert_equal('/', File.dirname('/a')) + assert_equal('/', File.dirname('/a/')) + assert_equal('/a', File.dirname('/a/b')) + + if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM + # DOSISH_UNC + assert_equal('//', File.dirname('//')) + assert_equal('//a', File.dirname('//a')) + assert_equal('//a', File.dirname('//a/')) + assert_equal('//a/b', File.dirname('//a/b')) + assert_equal('//a/b', File.dirname('//a/b/')) + assert_equal('//a/b', File.dirname('//a/b/c')) + + assert_equal('//', File.dirname('///')) + assert_equal('//a', File.dirname('///a')) + assert_equal('//a', File.dirname('///a/')) + assert_equal('//a/b', File.dirname('///a/b')) + assert_equal('//a/b', File.dirname('///a/b/')) + assert_equal('//a/b', File.dirname('///a/b/c')) + else + # others + assert_equal('/', File.dirname('//')) + assert_equal('/', File.dirname('//a')) + assert_equal('/', File.dirname('//a/')) + assert_equal('/a', File.dirname('//a/b')) + assert_equal('/a', File.dirname('//a/b/')) + assert_equal('/a/b', File.dirname('//a/b/c')) + + assert_equal('/', File.dirname('///')) + assert_equal('/', File.dirname('///a')) + assert_equal('/', File.dirname('///a/')) + assert_equal('/a', File.dirname('///a/b')) + assert_equal('/a', File.dirname('///a/b/')) + assert_equal('/a/b', File.dirname('///a/b/c')) + end + end + + def test_basename + if /(bcc|ms)win\d|mingw|cygwin|emx/ =~ RUBY_PLATFORM + # DOSISH_DRIVE_LETTER + assert_equal('', File.basename('C:')) + assert_equal('a', File.basename('C:a')) + assert_equal('a', File.basename('C:a/')) + assert_equal('b', File.basename('C:a/b')) + + assert_equal('/', File.basename('C:/')) + assert_equal('a', File.basename('C:/a')) + assert_equal('a', File.basename('C:/a/')) + assert_equal('b', File.basename('C:/a/b')) + + assert_equal('/', File.basename('C://')) + assert_equal('a', File.basename('C://a')) + assert_equal('a', File.basename('C://a/')) + assert_equal('b', File.basename('C://a/b')) + + assert_equal('/', File.basename('C:///')) + assert_equal('a', File.basename('C:///a')) + assert_equal('a', File.basename('C:///a/')) + assert_equal('b', File.basename('C:///a/b')) + else + # others + assert_equal('C:', File.basename('C:')) + assert_equal('C:a', File.basename('C:a')) + assert_equal('C:a', File.basename('C:a/')) + assert_equal('b', File.basename('C:a/b')) + + assert_equal('C:', File.basename('C:/')) + assert_equal('a', File.basename('C:/a')) + assert_equal('a', File.basename('C:/a/')) + assert_equal('b', File.basename('C:/a/b')) + + assert_equal('C:', File.basename('C://')) + assert_equal('a', File.basename('C://a')) + assert_equal('a', File.basename('C://a/')) + assert_equal('b', File.basename('C://a/b')) + + assert_equal('C:', File.basename('C:///')) + assert_equal('a', File.basename('C:///a')) + assert_equal('a', File.basename('C:///a/')) + assert_equal('b', File.basename('C:///a/b')) + end + + assert_equal('', File.basename('')) + assert_equal('a', File.basename('a')) + assert_equal('a', File.basename('a/')) + assert_equal('b', File.basename('a/b')) + + assert_equal('/', File.basename('/')) + assert_equal('a', File.basename('/a')) + assert_equal('a', File.basename('/a/')) + assert_equal('b', File.basename('/a/b')) + + assert_equal("..", File.basename("..", ".*")) + + if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM + # DOSISH_UNC + assert_equal('/', File.basename('//')) + assert_equal('/', File.basename('//a')) + assert_equal('/', File.basename('//a/')) + assert_equal('/', File.basename('//a/b'), "[ruby-dev:27776]") + assert_equal('/', File.basename('//a/b/')) + assert_equal('c', File.basename('//a/b/c')) + + assert_equal('/', File.basename('///')) + assert_equal('/', File.basename('///a')) + assert_equal('/', File.basename('///a/')) + assert_equal('/', File.basename('///a/b')) + assert_equal('/', File.basename('///a/b/')) + assert_equal('c', File.basename('///a/b/c')) + else + # others + assert_equal('/', File.basename('//')) + assert_equal('a', File.basename('//a')) + assert_equal('a', File.basename('//a/')) + assert_equal('b', File.basename('//a/b')) + assert_equal('b', File.basename('//a/b/')) + assert_equal('c', File.basename('//a/b/c')) + + assert_equal('/', File.basename('///')) + assert_equal('a', File.basename('///a')) + assert_equal('a', File.basename('///a/')) + assert_equal('b', File.basename('///a/b')) + assert_equal('b', File.basename('///a/b/')) + assert_equal('c', File.basename('///a/b/c')) + end + end + + def test_extname + assert_equal('', File.extname('a')) + ext = '.rb' + assert_equal(ext, File.extname('a.rb')) + unless /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + # trailing spaces and dots are ignored on NTFS. + ext = '' + end + assert_equal(ext, File.extname('a.rb.')) + assert_equal('', File.extname('a.')) + assert_equal('', File.extname('.x')) + assert_equal('', File.extname('..x')) + end + + def test_ascii_incompatible_path + s = "\u{221e}\u{2603}" + assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-16be"))} + assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-16le"))} + assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-32be"))} + assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-32le"))} + end + + def test_join + bug5483 = '[ruby-core:40338]' + path = %w[a b] + Encoding.list.each do |e| + next unless e.ascii_compatible? + assert_equal(e, File.join(*path.map {|s| s.force_encoding(e)}).encoding, bug5483) + end + end +end diff --git a/jni/ruby/test/ruby/test_pipe.rb b/jni/ruby/test/ruby/test_pipe.rb new file mode 100644 index 0000000..bcea91b --- /dev/null +++ b/jni/ruby/test/ruby/test_pipe.rb @@ -0,0 +1,29 @@ +require 'test/unit' +require_relative 'ut_eof' + +class TestPipe < Test::Unit::TestCase + include TestEOF + def open_file(content) + r, w = IO.pipe + w << content + w.close + begin + yield r + ensure + r.close + end + end + class WithConversion < self + def open_file(content) + r, w = IO.pipe + w << content + w.close + r.set_encoding("us-ascii:utf-8") + begin + yield r + ensure + r.close + end + end + end +end diff --git a/jni/ruby/test/ruby/test_primitive.rb b/jni/ruby/test/ruby/test_primitive.rb new file mode 100644 index 0000000..9d451e2 --- /dev/null +++ b/jni/ruby/test/ruby/test_primitive.rb @@ -0,0 +1,423 @@ +require 'test/unit' + +class TestRubyPrimitive < Test::Unit::TestCase + + def test_not + assert_equal false, !true + assert_equal true, !false + assert_equal true, !nil + assert_equal false, !(1+1) + assert_equal false, !!nil + assert_equal true, !!1 + end + + def test_lvar + a = 1 + assert_equal 1, a + b = 2 + assert_equal 1, a + a = b = 3 + assert_equal 3, a + assert_equal 3, b + a = b = c = 4 + assert_equal 4, a + assert_equal 4, b + assert_equal 4, c + end + + C = 1 + class A + Const = 1 + class B + Const = 2 + class C + Const = 3 + def const + Const + end + end + end + end + (1..2).map { + A::B::C::Const + } + + def test_constant + assert_equal 1, C + assert_equal 1, C + assert_equal 1, A::Const + assert_equal 2, A::B::Const + assert_equal 3, A::B::C::Const + assert_equal 3, A::B::C.new.const + assert_equal 1, ::TestRubyPrimitive::A::Const + A::B::C.send(:remove_const, :Const) + assert_equal 2, A::B::C.new.const + assert_raise(TypeError) { + C::CONST + } + end + + class A2 + class B2 + class C2 + C = 7 + end + end + end + + def test_constant_cache + i = 0 + while i < 3 + r = A2::B2::C2::C + i += 1 + end + assert_equal 7, r + end + + class A3 + class B3 + C = 99 + end + end + i = 0 + while i < 3 + r = A3::B3::C # cache + class A3::B3 + remove_const :C + end + A3::B3::C = i ** i + i += 1 + end + + def test_constant_cache2 + assert_equal 4, A3::B3::C + end + + class A4 + Const = 7 + (1..3).map { + $test_ruby_primitive_constant_cache3 = self::Const + } + end + + def test_constant_cache3 + assert_equal 7, $test_ruby_primitive_constant_cache3 + end + + class A5 + Const = 8 + (1..3).map { + $test_ruby_primitive_constant_cache4 = eval('self')::Const + } + end + + def test_constatant_cache4 + assert_equal 8, $test_ruby_primitive_constant_cache4 + end + + class A6 + Const = 0 + def self.foo + self::Const + end + end + class B6 < A6 + Const = 1 + end + class C6 < B6 + Const = 2 + end + $test_ruby_primitive_constant_cache5 = [A6.foo, B6.foo, C6.foo] + + def test_constant_cache5 + assert_equal [0, 1, 2], $test_ruby_primitive_constant_cache5 + end + + def test_gvar + $test_ruby_primitive_gvar = 7 + assert_equal 7, $test_ruby_primitive_gvar + assert_equal 7, $test_ruby_primitive_gvar + $test_ruby_primitive_gvar = 88 + assert_equal 88, $test_ruby_primitive_gvar + assert_equal 88, $test_ruby_primitive_gvar + assert_equal 7, ($test_ruby_primitive_gvar = 7) + assert_equal 7, ($test_ruby_primitive_gvar = 7) + end + + class A7 + @@c = 1 + def m + @@c += 1 + end + end + + def test_cvar_from_instance_method + assert_equal 2, A7.new.m + assert_equal 3, A7.new.m + assert_equal 4, A7.new.m + end + + class A8 + @@c = 1 + class << self + def m + @@c += 1 + end + end + end + + def test_cvar_from_singleton_method + assert_equal 2, A8.m + assert_equal 3, A8.m + assert_equal 4, A8.m + end + + class A9 + @@c = 1 + def self.m + @@c += 1 + end + end + + def test_cvar_from_singleton_method2 + assert_equal 2, A9.m + assert_equal 3, A9.m + assert_equal 4, A9.m + end + + class A10 + attr_accessor :a + end + + def test_opassign + i = 0 + i += 1 + assert_equal 1, i + + @iv = 2 + @iv += 2 + assert_equal 4, @iv + + @@cv ||= 1 + assert_equal 1, @@cv + @@cv &&= 2 + assert_equal 2, @@cv + @@cv ||= 99 + assert_equal 2, @@cv + + $gv = 3 + $gv += 4 + assert_equal 7, $gv + + obj = A10.new + obj.a = 9 + obj.a &&= 7 + assert_equal 7, obj.a + + obj.a = nil + obj.a ||= 2 + assert_equal 2, obj.a + + obj.a &&= 3 + assert_equal 3, obj.a + + a = [] + a[0] ||= 3 + assert_equal 3, a[0] + a[0] &&= 7 + assert_equal 7, a[0] + a[0] ||= 3 + assert_equal 7, a[0] + + a = [0, 1, nil, 3, 4] + a[*[2]] ||= :foo + assert_equal [0, 1, :foo, 3, 4], a + a[*[1,3]] &&= [:bar] + assert_equal [0, :bar, 4], a + end + + def test_opassign_and_or + a = 1 + a ||= 2 + assert_equal 1, a + a = nil + a ||= 2 + assert_equal 2, a + a = 1 + a &&= 3 + assert_equal 3, a + a = nil + a &&= 4 + assert_nil a + + h = {} + h[0] ||= 1 + assert_equal 1, h[0] + h = {} + h[0] &&= 1 + assert_nil h[0] + h = {0 => 7} + h[0] ||= 1 + assert_equal 7, h[0] + h = {0 => 7} + h[0] &&= 1 + assert_equal 1, h[0] + end + + def test_backref + /a(b)(c)d/ =~ 'xyzabcdefgabcdefg' + assert_equal 'b', $1 + assert_equal 'c', $2 + assert_nil $3 + assert_instance_of MatchData, $~ + assert_equal 'abcd', $& + assert_equal 'xyz', $` + assert_equal 'efgabcdefg', $' + assert_equal 'c', $+ + + /(?!)/ =~ 'xyzabcdefgabcdefg' + assert_nil $1 + assert_nil $2 + assert_nil $3 + assert_nil $~ + assert_nil $& + assert_nil $` + assert_nil $' + assert_nil $+ + end + + def test_fact + assert_equal 306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000, fact(300) + end + + def fact(n) + if n > 1 + n * fact(n - 1) + else + 1 + end + end + + def test_mul + assert_equal 0, 2 * 0 + assert_equal 0, 0 * 2 + assert_equal 4, 2 * 2 + end + + class MyNum + def /(a) + a * 100 + end + end + + def test_div + assert_equal 1, 3 / 2 + assert_equal 1.5, 3.0 / 2.0 + assert_equal 300, MyNum.new / 3 + end + + class MyArr + def length + 'string' + end + end + + def test_length + assert_equal 0, [].length + assert_equal 1, [1].length + assert_equal 2, [1,2].length + assert_equal 0, {}.length + assert_equal 1, {1=>1}.length + assert_equal 2, {1=>1, 2=>2}.length + assert_equal 'string', MyArr.new.length + end + + class MyNum2 + def %(a) + a * 100 + end + end + + def test_mod + assert_equal 2, 5 % 3 + assert_equal 1.0, 3.0 % 2.0 + assert_equal 300, MyNum2.new % 3 + end + + class MyObj + def [](*args) + args + end + + def []=(*args) + args + end + end + + def test_aref + a = [0,1] + assert_equal 0, a[0] + assert_equal 1, a[1] + assert_nil a[2] + h = {0=>0, 1=>1} + obj = MyObj.new + assert_equal 0, h[0] + assert_equal 1, h[1] + assert_nil h[2] + assert_equal [0], obj[0] + assert_equal [0,1], obj[0,1] + assert_equal [0,1,2], obj[0,1,2] + end + + def test_aset + obj = MyObj.new + assert_equal 7, (obj[0] = 7) + assert_equal 7, (obj[0,1] = 7) + assert_equal 7, (obj[0,1,2] = 7) + end + + class MyObj2 + def attr=(*args) + args + end + end + + def test_attr_setter + obj = MyObj2.new + assert_equal 1, (obj.attr = 1) + end + + def test_list_expand + a = [] + assert_equal [0], [0, *a] + a = [1] + assert_equal [0,1], [0, *a] + a = [1,2] + assert_equal [0,1,2], [0, *a] + a = [1,2,3] + assert_equal [0,1,2,3], [0, *a] + #a = [1,2,3] + #assert_equal [0,1,2,3,4], [0, *a, 4] + end + + def test_concatarray_ruby_dev_41933 + bug3658 = '[ruby-dev:41933]' + [0, *x=1] + assert_equal(1, x, bug3658) + [0, *x=1, 2] + assert_equal(1, x, bug3658) + class << (x = Object.new) + attr_accessor :to_a_called + def to_a + @to_a_called = true + [self] + end + end + x.to_a_called = false + [0, *x] + assert_predicate(x, :to_a_called, bug3658) + x.to_a_called = false + [0, *x, 2] + assert_predicate(x, :to_a_called, bug3658) + end +end diff --git a/jni/ruby/test/ruby/test_proc.rb b/jni/ruby/test/ruby/test_proc.rb new file mode 100644 index 0000000..728e2b7 --- /dev/null +++ b/jni/ruby/test/ruby/test_proc.rb @@ -0,0 +1,1323 @@ +require 'test/unit' + +class TestProc < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_proc + p1 = proc{|i| i} + assert_equal(2, p1.call(2)) + assert_equal(3, p1.call(3)) + + p1 = proc{|i| i*2} + assert_equal(4, p1.call(2)) + assert_equal(6, p1.call(3)) + + p2 = nil + x=0 + + proc{ + iii=5 # nested local variable + p1 = proc{|i| + iii = i + } + p2 = proc { + x = iii # nested variables shared by procs + } + # scope of nested variables + assert(defined?(iii)) + }.call + assert(!defined?(iii)) # out of scope + + loop{iii=iii=5; assert(eval("defined? iii")); break} + loop { + iii=iii = 10 + def self.dyna_var_check + loop { + assert(!defined?(iii)) + break + } + end + dyna_var_check + break + } + p1.call(5) + p2.call + assert_equal(5, x) + end + + def assert_arity(n) + meta = class << self; self; end + meta.class_eval {define_method(:foo, Proc.new)} + assert_equal(n, method(:foo).arity) + end + + def test_arity + assert_equal(0, proc{}.arity) + assert_equal(0, proc{||}.arity) + assert_equal(1, proc{|x|}.arity) + assert_equal(0, proc{|x=1|}.arity) + assert_equal(2, proc{|x, y|}.arity) + assert_equal(1, proc{|x=0, y|}.arity) + assert_equal(0, proc{|x=0, y=0|}.arity) + assert_equal(1, proc{|x, y=0|}.arity) + assert_equal(-2, proc{|x, *y|}.arity) + assert_equal(-1, proc{|x=0, *y|}.arity) + assert_equal(-1, proc{|*x|}.arity) + assert_equal(-1, proc{|*|}.arity) + assert_equal(-3, proc{|x, *y, z|}.arity) + assert_equal(-2, proc{|x=0, *y, z|}.arity) + assert_equal(2, proc{|(x, y), z|[x,y]}.arity) + assert_equal(1, proc{|(x, y), z=0|[x,y]}.arity) + assert_equal(-4, proc{|x, *y, z, a|}.arity) + assert_equal(0, proc{|**|}.arity) + assert_equal(0, proc{|**o|}.arity) + assert_equal(1, proc{|x, **o|}.arity) + assert_equal(0, proc{|x=0, **o|}.arity) + assert_equal(1, proc{|x, y=0, **o|}.arity) + assert_equal(2, proc{|x, y=0, z, **o|}.arity) + assert_equal(-3, proc{|x, y=0, *z, w, **o|}.arity) + + assert_equal(2, proc{|x, y=0, z, a:1|}.arity) + assert_equal(3, proc{|x, y=0, z, a:|}.arity) + assert_equal(-4, proc{|x, y, *rest, a:, b:, c:|}.arity) + assert_equal(3, proc{|x, y=0, z, a:, **o|}.arity) + + assert_equal(0, lambda{}.arity) + assert_equal(0, lambda{||}.arity) + assert_equal(1, lambda{|x|}.arity) + assert_equal(-1, lambda{|x=1|}.arity) # different from proc + assert_equal(2, lambda{|x, y|}.arity) + assert_equal(-2, lambda{|x=0, y|}.arity) # different from proc + assert_equal(-1, lambda{|x=0, y=0|}.arity) # different from proc + assert_equal(-2, lambda{|x, y=0|}.arity) # different from proc + assert_equal(-2, lambda{|x, *y|}.arity) + assert_equal(-1, lambda{|x=0, *y|}.arity) + assert_equal(-1, lambda{|*x|}.arity) + assert_equal(-1, lambda{|*|}.arity) + assert_equal(-3, lambda{|x, *y, z|}.arity) + assert_equal(-2, lambda{|x=0, *y, z|}.arity) + assert_equal(2, lambda{|(x, y), z|[x,y]}.arity) + assert_equal(-2, lambda{|(x, y), z=0|[x,y]}.arity) + assert_equal(-4, lambda{|x, *y, z, a|}.arity) + assert_equal(-1, lambda{|**|}.arity) + assert_equal(-1, lambda{|**o|}.arity) + assert_equal(-2, lambda{|x, **o|}.arity) + assert_equal(-1, lambda{|x=0, **o|}.arity) + assert_equal(-2, lambda{|x, y=0, **o|}.arity) + assert_equal(-3, lambda{|x, y=0, z, **o|}.arity) + assert_equal(-3, lambda{|x, y=0, *z, w, **o|}.arity) + + assert_arity(0) {} + assert_arity(0) {||} + assert_arity(1) {|x|} + assert_arity(2) {|x, y|} + assert_arity(-2) {|x, *y|} + assert_arity(-3) {|x, *y, z|} + assert_arity(-1) {|*x|} + assert_arity(-1) {|*|} + assert_arity(-1) {|**o|} + assert_arity(-1) {|**|} + assert_arity(-2) {|x, *y, **|} + assert_arity(-3) {|x, *y, z, **|} + end + + def m(x) + lambda { x } + end + + def test_eq + a = m(1) + b = m(2) + assert_not_equal(a, b, "[ruby-dev:22592]") + assert_not_equal(a.call, b.call, "[ruby-dev:22592]") + + assert_not_equal(proc {||}, proc {|x,y|}, "[ruby-dev:22599]") + + a = lambda {|x| lambda {} }.call(1) + b = lambda {} + assert_not_equal(a, b, "[ruby-dev:22601]") + end + + def test_block_par + assert_equal(10, Proc.new{|&b| b.call(10)}.call {|x| x}) + assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x}) + end + + def test_safe + safe = $SAFE + c = Class.new + x = c.new + + p = proc { + $SAFE += 1 + proc {$SAFE} + }.call + assert_equal(safe, $SAFE) + assert_equal(safe + 1, p.call) + assert_equal(safe, $SAFE) + + c.class_eval {define_method(:safe, p)} + assert_equal(safe, x.safe) + assert_equal(safe, x.method(:safe).call) + assert_equal(safe, x.method(:safe).to_proc.call) + + p = proc {$SAFE += 1} + assert_equal(safe + 1, p.call) + assert_equal(safe, $SAFE) + + c.class_eval {define_method(:inc, p)} + assert_equal(safe + 1, proc {x.inc; $SAFE}.call) + assert_equal(safe, $SAFE) + assert_equal(safe + 1, proc {x.method(:inc).call; $SAFE}.call) + assert_equal(safe, $SAFE) + assert_equal(safe + 1, proc {x.method(:inc).to_proc.call; $SAFE}.call) + assert_equal(safe, $SAFE) + end + + def m2 + "OK" + end + + def block + method(:m2).to_proc + end + + def m1(var) + var + end + + def m_block_given? + m1(block_given?) + end + + # [yarv-dev:777] block made by Method#to_proc + def test_method_to_proc + b = block() + assert_equal "OK", b.call + b = b.binding + assert_instance_of(Binding, b, '[ruby-core:25589]') + bug10432 = '[ruby-core:65919] [Bug #10432]' + assert_same(self, b.receiver, bug10432) + assert_not_send [b, :local_variable_defined?, :value] + assert_raise(NameError) { + b.local_variable_get(:value) + } + assert_equal 42, b.local_variable_set(:value, 42) + assert_send [b, :local_variable_defined?, :value] + assert_equal 42, b.local_variable_get(:value) + end + + def test_block_given_method + m = method(:m_block_given?) + assert(!m.call, "without block") + assert(m.call {}, "with block") + assert(!m.call, "without block second") + end + + def test_block_given_method_to_proc + bug8341 = '[Bug #8341]' + m = method(:m_block_given?).to_proc + assert(!m.call, "#{bug8341} without block") + assert(m.call {}, "#{bug8341} with block") + assert(!m.call, "#{bug8341} without block second") + end + + def test_block_persist_between_calls + bug8341 = '[Bug #8341]' + o = Object.new + def o.m1(top=true) + if top + [block_given?, @m.call(false)] + else + block_given? + end + end + m = o.method(:m1).to_proc + o.instance_variable_set(:@m, m) + assert_equal([true, false], m.call {}, "#{bug8341} nested with block") + assert_equal([false, false], m.call, "#{bug8341} nested without block") + end + + def test_curry + b = proc {|x, y, z| (x||0) + (y||0) + (z||0) } + assert_equal(6, b.curry[1][2][3]) + assert_equal(6, b.curry[1, 2][3, 4]) + assert_equal(6, b.curry(5)[1][2][3][4][5]) + assert_equal(6, b.curry(5)[1, 2][3, 4][5]) + assert_equal(1, b.curry(1)[1]) + + b = proc {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } + assert_equal(6, b.curry[1][2][3]) + assert_equal(10, b.curry[1, 2][3, 4]) + assert_equal(15, b.curry(5)[1][2][3][4][5]) + assert_equal(15, b.curry(5)[1, 2][3, 4][5]) + assert_equal(1, b.curry(1)[1]) + + b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) } + assert_equal(6, b.curry[1][2][3]) + assert_raise(ArgumentError) { b.curry[1, 2][3, 4] } + assert_raise(ArgumentError) { b.curry(5) } + assert_raise(ArgumentError) { b.curry(1) } + + b = lambda {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } + assert_equal(6, b.curry[1][2][3]) + assert_equal(10, b.curry[1, 2][3, 4]) + assert_equal(15, b.curry(5)[1][2][3][4][5]) + assert_equal(15, b.curry(5)[1, 2][3, 4][5]) + assert_raise(ArgumentError) { b.curry(1) } + + b = proc { :foo } + assert_equal(:foo, b.curry[]) + + b = lambda {|x, y, &blk| blk.call(x + y) }.curry + b = b.call(2) { raise } + b = b.call(3) {|x| x + 4 } + assert_equal(9, b) + + l = proc {} + assert_equal(false, l.lambda?) + assert_equal(false, l.curry.lambda?, '[ruby-core:24127]') + l = lambda {} + assert_equal(true, l.lambda?) + assert_equal(true, l.curry.lambda?, '[ruby-core:24127]') + end + + def test_curry_ski_fib + s = proc {|f, g, x| f[x][g[x]] }.curry + k = proc {|x, y| x }.curry + i = proc {|x| x }.curry + + fib = [] + inc = proc {|x| fib[-1] += 1; x }.curry + ret = proc {|x| throw :end if fib.size > 10; fib << 0; x }.curry + + catch(:end) do + s[ + s[s[i][i]][k[i]] + ][ + k[inc] + ][ + s[ + s[ + k[s] + ][ + s[k[s[k[s]]] + ][ + s[s[k[s]][s[k[s[k[ret]]]][s[k[s[i]]][k]]]][k]] + ] + ][ + k[s[k[s]][k]] + ] + ] + end + + assert_equal(fib, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]) + end + + def test_curry_from_knownbug + a = lambda {|x, y, &b| b } + b = a.curry[1] + + assert_equal(:ok, + if b.call(2){} == nil + :ng + else + :ok + end, 'moved from btest/knownbug, [ruby-core:15551]') + end + + def test_curry_instance_exec + a = lambda { |x, y| [x + y, self] } + b = a.curry.call(1) + result = instance_exec 2, &b + + assert_equal(3, result[0]) + assert_equal(self, result[1]) + end + + def test_curry_optional_params + obj = Object.new + def obj.foo(a, b=42); end + assert_raise(ArgumentError) { obj.method(:foo).to_proc.curry(3) } + assert_raise(ArgumentError) { ->(a, b=42){}.curry(3) } + end + + def test_dup_clone + b = proc {|x| x + "bar" } + class << b; attr_accessor :foo; end + + bd = b.dup + assert_equal("foobar", bd.call("foo")) + assert_raise(NoMethodError) { bd.foo = :foo } + assert_raise(NoMethodError) { bd.foo } + + bc = b.clone + assert_equal("foobar", bc.call("foo")) + bc.foo = :foo + assert_equal(:foo, bc.foo) + end + + def test_binding + b = proc {|x, y, z| proc {}.binding }.call(1, 2, 3) + class << b; attr_accessor :foo; end + + bd = b.dup + assert_equal([1, 2, 3], bd.eval("[x, y, z]")) + assert_raise(NoMethodError) { bd.foo = :foo } + assert_raise(NoMethodError) { bd.foo } + + bc = b.clone + assert_equal([1, 2, 3], bc.eval("[x, y, z]")) + bc.foo = :foo + assert_equal(:foo, bc.foo) + + b = nil + 1.times { x, y, z = 1, 2, 3; [x,y,z]; b = binding } + assert_equal([1, 2, 3], b.eval("[x, y, z]")) + end + + def test_proc_lambda + assert_raise(ArgumentError) { proc } + assert_raise(ArgumentError) { lambda } + + o = Object.new + def o.foo + b = nil + 1.times { b = lambda } + b + end + assert_equal(:foo, o.foo { :foo }.call) + + def o.foo(&b) + b = nil + 1.times { b = lambda } + b + end + assert_equal(:foo, o.foo { :foo }.call) + end + + def test_arity2 + assert_equal(0, method(:proc).to_proc.arity) + assert_equal(-1, proc {}.curry.arity) + + c = Class.new + c.class_eval { attr_accessor :foo } + assert_equal(1, c.new.method(:foo=).to_proc.arity) + end + + def test_proc_location + t = Thread.new { sleep } + assert_raise(ThreadError) { t.instance_eval { initialize { } } } + t.kill + t.join + end + + def test_to_proc + b = proc { :foo } + assert_equal(:foo, b.to_proc.call) + end + + def test_localjump_error + o = o = Object.new + def foo; yield; end + exc = foo rescue $! + assert_nil(exc.exit_value) + assert_equal(:noreason, exc.reason) + end + + def test_binding2 + assert_raise(ArgumentError) { proc {}.curry.binding } + end + + def test_proc_args_plain + pr = proc {|a,b,c,d,e| + [a,b,c,d,e] + } + assert_equal [nil,nil,nil,nil,nil], pr.call() + assert_equal [1,nil,nil,nil,nil], pr.call(1) + assert_equal [1,2,nil,nil,nil], pr.call(1,2) + assert_equal [1,2,3,nil,nil], pr.call(1,2,3) + assert_equal [1,2,3,4,nil], pr.call(1,2,3,4) + assert_equal [1,2,3,4,5], pr.call(1,2,3,4,5) + assert_equal [1,2,3,4,5], pr.call(1,2,3,4,5,6) + + assert_equal [nil,nil,nil,nil,nil], pr.call([]) + assert_equal [1,nil,nil,nil,nil], pr.call([1]) + assert_equal [1,2,nil,nil,nil], pr.call([1,2]) + assert_equal [1,2,3,nil,nil], pr.call([1,2,3]) + assert_equal [1,2,3,4,nil], pr.call([1,2,3,4]) + assert_equal [1,2,3,4,5], pr.call([1,2,3,4,5]) + assert_equal [1,2,3,4,5], pr.call([1,2,3,4,5,6]) + + r = proc{|a| a}.call([1,2,3]) + assert_equal [1,2,3], r + + r = proc{|a,| a}.call([1,2,3]) + assert_equal 1, r + + r = proc{|a,| a}.call([]) + assert_equal nil, r + end + + + def test_proc_args_rest + pr = proc {|a,b,c,*d| + [a,b,c,d] + } + assert_equal [nil,nil,nil,[]], pr.call() + assert_equal [1,nil,nil,[]], pr.call(1) + assert_equal [1,2,nil,[]], pr.call(1,2) + assert_equal [1,2,3,[]], pr.call(1,2,3) + assert_equal [1,2,3,[4]], pr.call(1,2,3,4) + assert_equal [1,2,3,[4,5]], pr.call(1,2,3,4,5) + assert_equal [1,2,3,[4,5,6]], pr.call(1,2,3,4,5,6) + + assert_equal [nil,nil,nil,[]], pr.call([]) + assert_equal [1,nil,nil,[]], pr.call([1]) + assert_equal [1,2,nil,[]], pr.call([1,2]) + assert_equal [1,2,3,[]], pr.call([1,2,3]) + assert_equal [1,2,3,[4]], pr.call([1,2,3,4]) + assert_equal [1,2,3,[4,5]], pr.call([1,2,3,4,5]) + assert_equal [1,2,3,[4,5,6]], pr.call([1,2,3,4,5,6]) + + r = proc{|*a| a}.call([1,2,3]) + assert_equal [[1,2,3]], r + end + + def test_proc_args_pos_rest_post + pr = proc {|a,b,*c,d,e| + [a,b,c,d,e] + } + assert_equal [nil, nil, [], nil, nil], pr.call() + assert_equal [1, nil, [], nil, nil], pr.call(1) + assert_equal [1, 2, [], nil, nil], pr.call(1,2) + assert_equal [1, 2, [], 3, nil], pr.call(1,2,3) + assert_equal [1, 2, [], 3, 4], pr.call(1,2,3,4) + assert_equal [1, 2, [3], 4, 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, [3, 4], 5, 6], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7) + + assert_equal [nil, nil, [], nil, nil], pr.call([]) + assert_equal [1, nil, [], nil, nil], pr.call([1]) + assert_equal [1, 2, [], nil, nil], pr.call([1,2]) + assert_equal [1, 2, [], 3, nil], pr.call([1,2,3]) + assert_equal [1, 2, [], 3, 4], pr.call([1,2,3,4]) + assert_equal [1, 2, [3], 4, 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, [3, 4], 5, 6], pr.call([1,2,3,4,5,6]) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7]) + end + + def test_proc_args_rest_post + pr = proc {|*a,b,c| + [a,b,c] + } + assert_equal [[], nil, nil], pr.call() + assert_equal [[], 1, nil], pr.call(1) + assert_equal [[], 1, 2], pr.call(1,2) + assert_equal [[1], 2, 3], pr.call(1,2,3) + assert_equal [[1, 2], 3, 4], pr.call(1,2,3,4) + assert_equal [[1, 2, 3], 4, 5], pr.call(1,2,3,4,5) + assert_equal [[1, 2, 3, 4], 5, 6], pr.call(1,2,3,4,5,6) + assert_equal [[1, 2, 3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7) + + assert_equal [[], nil, nil], pr.call([]) + assert_equal [[], 1, nil], pr.call([1]) + assert_equal [[], 1, 2], pr.call([1,2]) + assert_equal [[1], 2, 3], pr.call([1,2,3]) + assert_equal [[1, 2], 3, 4], pr.call([1,2,3,4]) + assert_equal [[1, 2, 3], 4, 5], pr.call([1,2,3,4,5]) + assert_equal [[1, 2, 3, 4], 5, 6], pr.call([1,2,3,4,5,6]) + assert_equal [[1, 2, 3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7]) + end + + def test_proc_args_pos_opt + pr = proc {|a,b,c=:c| + [a,b,c] + } + assert_equal [nil, nil, :c], pr.call() + assert_equal [1, nil, :c], pr.call(1) + assert_equal [1, 2, :c], pr.call(1,2) + assert_equal [1, 2, 3], pr.call(1,2,3) + assert_equal [1, 2, 3], pr.call(1,2,3,4) + assert_equal [1, 2, 3], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3], pr.call(1,2,3,4,5,6) + + assert_equal [nil, nil, :c], pr.call([]) + assert_equal [1, nil, :c], pr.call([1]) + assert_equal [1, 2, :c], pr.call([1,2]) + assert_equal [1, 2, 3], pr.call([1,2,3]) + assert_equal [1, 2, 3], pr.call([1,2,3,4]) + assert_equal [1, 2, 3], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_opt + pr = proc {|a=:a,b=:b,c=:c| + [a,b,c] + } + assert_equal [:a, :b, :c], pr.call() + assert_equal [1, :b, :c], pr.call(1) + assert_equal [1, 2, :c], pr.call(1,2) + assert_equal [1, 2, 3], pr.call(1,2,3) + assert_equal [1, 2, 3], pr.call(1,2,3,4) + assert_equal [1, 2, 3], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3], pr.call(1,2,3,4,5,6) + + assert_equal [:a, :b, :c], pr.call([]) + assert_equal [1, :b, :c], pr.call([1]) + assert_equal [1, 2, :c], pr.call([1,2]) + assert_equal [1, 2, 3], pr.call([1,2,3]) + assert_equal [1, 2, 3], pr.call([1,2,3,4]) + assert_equal [1, 2, 3], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_opt_signle + bug7621 = '[ruby-dev:46801]' + pr = proc {|a=:a| + a + } + assert_equal :a, pr.call() + assert_equal 1, pr.call(1) + assert_equal 1, pr.call(1,2) + + assert_equal [], pr.call([]), bug7621 + assert_equal [1], pr.call([1]), bug7621 + assert_equal [1, 2], pr.call([1,2]), bug7621 + assert_equal [1, 2, 3], pr.call([1,2,3]), bug7621 + assert_equal [1, 2, 3, 4], pr.call([1,2,3,4]), bug7621 + end + + def test_proc_args_pos_opt_post + pr = proc {|a,b,c=:c,d,e| + [a,b,c,d,e] + } + assert_equal [nil, nil, :c, nil, nil], pr.call() + assert_equal [1, nil, :c, nil, nil], pr.call(1) + assert_equal [1, 2, :c, nil, nil], pr.call(1,2) + assert_equal [1, 2, :c, 3, nil], pr.call(1,2,3) + assert_equal [1, 2, :c, 3, 4], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5,6) + + assert_equal [nil, nil, :c, nil, nil], pr.call([]) + assert_equal [1, nil, :c, nil, nil], pr.call([1]) + assert_equal [1, 2, :c, nil, nil], pr.call([1,2]) + assert_equal [1, 2, :c, 3, nil], pr.call([1,2,3]) + assert_equal [1, 2, :c, 3, 4], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_opt_post + pr = proc {|a=:a,b=:b,c=:c,d,e| + [a,b,c,d,e] + } + assert_equal [:a, :b, :c, nil, nil], pr.call() + assert_equal [:a, :b, :c, 1, nil], pr.call(1) + assert_equal [:a, :b, :c, 1, 2], pr.call(1,2) + assert_equal [1, :b, :c, 2, 3], pr.call(1,2,3) + assert_equal [1, 2, :c, 3, 4], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5,6) + + assert_equal [:a, :b, :c, nil, nil], pr.call([]) + assert_equal [:a, :b, :c, 1, nil], pr.call([1]) + assert_equal [:a, :b, :c, 1, 2], pr.call([1,2]) + assert_equal [1, :b, :c, 2, 3], pr.call([1,2,3]) + assert_equal [1, 2, :c, 3, 4], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_pos_opt_rest + pr = proc {|a,b,c=:c,*d| + [a,b,c,d] + } + assert_equal [nil, nil, :c, []], pr.call() + assert_equal [1, nil, :c, []], pr.call(1) + assert_equal [1, 2, :c, []], pr.call(1,2) + assert_equal [1, 2, 3, []], pr.call(1,2,3) + assert_equal [1, 2, 3, [4]], pr.call(1,2,3,4) + assert_equal [1, 2, 3, [4, 5]], pr.call(1,2,3,4,5) + + assert_equal [nil, nil, :c, []], pr.call([]) + assert_equal [1, nil, :c, []], pr.call([1]) + assert_equal [1, 2, :c, []], pr.call([1,2]) + assert_equal [1, 2, 3, []], pr.call([1,2,3]) + assert_equal [1, 2, 3, [4]], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, [4, 5]], pr.call([1,2,3,4,5]) + end + + def test_proc_args_opt_rest + pr = proc {|a=:a,b=:b,c=:c,*d| + [a,b,c,d] + } + assert_equal [:a, :b, :c, []], pr.call() + assert_equal [1, :b, :c, []], pr.call(1) + assert_equal [1, 2, :c, []], pr.call(1,2) + assert_equal [1, 2, 3, []], pr.call(1,2,3) + assert_equal [1, 2, 3, [4]], pr.call(1,2,3,4) + assert_equal [1, 2, 3, [4, 5]], pr.call(1,2,3,4,5) + + assert_equal [:a, :b, :c, []], pr.call([]) + assert_equal [1, :b, :c, []], pr.call([1]) + assert_equal [1, 2, :c, []], pr.call([1,2]) + assert_equal [1, 2, 3, []], pr.call([1,2,3]) + assert_equal [1, 2, 3, [4]], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, [4, 5]], pr.call([1,2,3,4,5]) + end + + def test_proc_args_pos_opt_rest_post + pr = proc {|a,b,c=:c,*d,e| + [a,b,c,d,e] + } + assert_equal [nil, nil, :c, [], nil], pr.call() + assert_equal [1, nil, :c, [], nil], pr.call(1) + assert_equal [1, 2, :c, [], nil], pr.call(1,2) + assert_equal [1, 2, :c, [], 3], pr.call(1,2,3) + assert_equal [1, 2, 3, [], 4], pr.call(1,2,3,4) + assert_equal [1, 2, 3, [4], 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, [4,5], 6], pr.call(1,2,3,4,5,6) + + assert_equal [nil, nil, :c, [], nil], pr.call([]) + assert_equal [1, nil, :c, [], nil], pr.call([1]) + assert_equal [1, 2, :c, [], nil], pr.call([1,2]) + assert_equal [1, 2, :c, [], 3], pr.call([1,2,3]) + assert_equal [1, 2, 3, [], 4], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, [4], 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3, [4,5], 6], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_opt_rest_post + pr = proc {|a=:a,b=:b,c=:c,*d,e| + [a,b,c,d,e] + } + assert_equal [:a, :b, :c, [], nil], pr.call() + assert_equal [:a, :b, :c, [], 1], pr.call(1) + assert_equal [1, :b, :c, [], 2], pr.call(1,2) + assert_equal [1, 2, :c, [], 3], pr.call(1,2,3) + assert_equal [1, 2, 3, [], 4], pr.call(1,2,3,4) + assert_equal [1, 2, 3, [4], 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, [4,5], 6], pr.call(1,2,3,4,5,6) + + assert_equal [:a, :b, :c, [], nil], pr.call([]) + assert_equal [:a, :b, :c, [], 1], pr.call([1]) + assert_equal [1, :b, :c, [], 2], pr.call([1,2]) + assert_equal [1, 2, :c, [], 3], pr.call([1,2,3]) + assert_equal [1, 2, 3, [], 4], pr.call([1,2,3,4]) + assert_equal [1, 2, 3, [4], 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, 3, [4,5], 6], pr.call([1,2,3,4,5,6]) + end + + def test_proc_args_pos_block + pr = proc {|a,b,&c| + [a, b, c.class, c&&c.call(:x)] + } + assert_equal [nil, nil, NilClass, nil], pr.call() + assert_equal [1, nil, NilClass, nil], pr.call(1) + assert_equal [1, 2, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, NilClass, nil], pr.call(1,2,3,4) + + assert_equal [nil, nil, NilClass, nil], pr.call([]) + assert_equal [1, nil, NilClass, nil], pr.call([1]) + assert_equal [1, 2, NilClass, nil], pr.call([1,2]) + assert_equal [1, 2, NilClass, nil], pr.call([1,2,3]) + assert_equal [1, 2, NilClass, nil], pr.call([1,2,3,4]) + + assert_equal [nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + + assert_equal [nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + end + + def test_proc_args_pos_rest_block + pr = proc {|a,b,*c,&d| + [a, b, c, d.class, d&&d.call(:x)] + } + assert_equal [nil, nil, [], NilClass, nil], pr.call() + assert_equal [1, nil, [], NilClass, nil], pr.call(1) + assert_equal [1, 2, [], NilClass, nil], pr.call(1,2) + assert_equal [1, 2, [3], NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, [3,4], NilClass, nil], pr.call(1,2,3,4) + + assert_equal [nil, nil, [], Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, [], Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, [], Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, [3], Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, [3,4], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + + assert_equal [nil, nil, [], Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, [], Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, [], Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, [3], Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, [3,4], Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + end + + def test_proc_args_rest_block + pr = proc {|*c,&d| + [c, d.class, d&&d.call(:x)] + } + assert_equal [[], NilClass, nil], pr.call() + assert_equal [[1], NilClass, nil], pr.call(1) + assert_equal [[1, 2], NilClass, nil], pr.call(1,2) + + assert_equal [[], Proc, :proc], (pr.call(){ :proc }) + assert_equal [[1], Proc, :proc], (pr.call(1){ :proc }) + assert_equal [[1, 2], Proc, :proc], (pr.call(1, 2){ :proc }) + + assert_equal [[], Proc, :x], (pr.call(){|x| x}) + assert_equal [[1], Proc, :x], (pr.call(1){|x| x}) + assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x}) + end + + def test_proc_args_pos_rest_post_block + pr = proc {|a,b,*c,d,e,&f| + [a, b, c, d, e, f.class, f&&f.call(:x)] + } + assert_equal [nil, nil, [], nil, nil, NilClass, nil], pr.call() + assert_equal [1, nil, [], nil, nil, NilClass, nil], pr.call(1) + assert_equal [1, 2, [], nil, nil, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, [], 3, nil, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, [], 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, [3], 4, 5, NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, [3,4], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6) + + assert_equal [nil, nil, [], nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, [], nil, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, [], nil, nil, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, [], 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, [3], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, [3,4], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + + assert_equal [nil, nil, [], nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, [], nil, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, [], nil, nil, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, [], 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, [3], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, [3,4], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + end + + def test_proc_args_rest_post_block + pr = proc {|*c,d,e,&f| + [c, d, e, f.class, f&&f.call(:x)] + } + assert_equal [[], nil, nil, NilClass, nil], pr.call() + assert_equal [[], 1, nil, NilClass, nil], pr.call(1) + assert_equal [[], 1, 2, NilClass, nil], pr.call(1,2) + assert_equal [[1], 2, 3, NilClass, nil], pr.call(1,2,3) + assert_equal [[1, 2], 3, 4, NilClass, nil], pr.call(1,2,3,4) + + assert_equal [[], nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [[], 1, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [[], 1, 2, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [[1], 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [[1, 2], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + + assert_equal [[], nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [[], 1, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [[], 1, 2, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [[1], 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [[1, 2], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + end + + def test_proc_args_pos_opt_block + pr = proc {|a,b,c=:c,d=:d,&e| + [a, b, c, d, e.class, e&&e.call(:x)] + } + assert_equal [nil, nil, :c, :d, NilClass, nil], pr.call() + assert_equal [1, nil, :c, :d, NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, 3, :d, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4,5) + + assert_equal [nil, nil, :c, :d, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, :c, :d, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, 3, :d, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + + assert_equal [nil, nil, :c, :d, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, :c, :d, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, 3, :d, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + end + + def test_proc_args_opt_block + pr = proc {|a=:a,b=:b,c=:c,d=:d,&e| + [a, b, c, d, e.class, e&&e.call(:x)] + } + assert_equal [:a, :b, :c, :d, NilClass, nil], pr.call() + assert_equal [1, :b, :c, :d, NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, 3, :d, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4,5) + + assert_equal [:a, :b, :c, :d, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, :b, :c, :d, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, 3, :d, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + + assert_equal [:a, :b, :c, :d, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, :b, :c, :d, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, 3, :d, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + end + + def test_proc_args_pos_opt_post_block + pr = proc {|a,b,c=:c,d=:d,e,f,&g| + [a, b, c, d, e, f, g.class, g&&g.call(:x)] + } + assert_equal [nil, nil, :c, :d, nil, nil, NilClass, nil], pr.call() + assert_equal [1, nil, :c, :d, nil, nil, NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, nil, nil, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, :c, :d, 3, nil, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, :c, :d, 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, :d, 4, 5, NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6,7) + + assert_equal [nil, nil, :c, :d, nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, :c, :d, nil, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, nil, nil, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, :c, :d, 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, :c, :d, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, :d, 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc }) + + assert_equal [nil, nil, :c, :d, nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, :c, :d, nil, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, nil, nil, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, :c, :d, 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, :c, :d, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, :d, 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x}) + end + + def test_proc_args_opt_post_block + pr = proc {|a=:a,b=:b,c=:c,d=:d,e,f,&g| + [a, b, c, d, e, f, g.class, g&&g.call(:x)] + } + assert_equal [:a, :b, :c, :d, nil, nil, NilClass, nil], pr.call() + assert_equal [:a, :b, :c, :d, 1, nil, NilClass, nil], pr.call(1) + assert_equal [:a, :b, :c, :d, 1, 2, NilClass, nil], pr.call(1,2) + assert_equal [1, :b, :c, :d, 2, 3, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, :c, :d, 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, :d, 4, 5, NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6,7) + + assert_equal [:a, :b, :c, :d, nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [:a, :b, :c, :d, 1, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [:a, :b, :c, :d, 1, 2, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, :b, :c, :d, 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, :c, :d, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, :d, 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc }) + + assert_equal [:a, :b, :c, :d, nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [:a, :b, :c, :d, 1, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [:a, :b, :c, :d, 1, 2, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, :b, :c, :d, 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, :c, :d, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, :d, 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x}) + end + + def test_proc_args_pos_opt_rest_block + pr = proc {|a,b,c=:c,d=:d,*e,&f| + [a, b, c, d, e, f.class, f&&f.call(:x)] + } + assert_equal [nil, nil, :c, :d, [], NilClass, nil], pr.call() + assert_equal [1, nil, :c, :d, [], NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, [], NilClass, nil], pr.call(1,2) + assert_equal [1, 2, 3, :d, [], NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, 3, 4, [], NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, [5], NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, [5,6], NilClass, nil], pr.call(1,2,3,4,5,6) + + assert_equal [nil, nil, :c, :d, [], Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, :c, :d, [], Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, [], Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, 3, :d, [], Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, 3, 4, [], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, 4, [5], Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, [5,6], Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + + assert_equal [nil, nil, :c, :d, [], Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, :c, :d, [], Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, [], Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, 3, :d, [], Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, 3, 4, [], Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, 4, [5], Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, [5,6], Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + end + + def test_proc_args_opt_rest_block + pr = proc {|a=:a,b=:b,c=:c,d=:d,*e,&f| + [a, b, c, d, e, f.class, f&&f.call(:x)] + } + assert_equal [:a, :b, :c, :d, [], NilClass, nil], pr.call() + assert_equal [1, :b, :c, :d, [], NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, [], NilClass, nil], pr.call(1,2) + assert_equal [1, 2, 3, :d, [], NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, 3, 4, [], NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, 4, [5], NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, [5,6], NilClass, nil], pr.call(1,2,3,4,5,6) + + assert_equal [:a, :b, :c, :d, [], Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, :b, :c, :d, [], Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, [], Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, 3, :d, [], Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, 3, 4, [], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, 4, [5], Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, [5,6], Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + + assert_equal [:a, :b, :c, :d, [], Proc, :x], (pr.call(){|x| x}) + assert_equal [1, :b, :c, :d, [], Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, [], Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, 3, :d, [], Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, 3, 4, [], Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, 4, [5], Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, [5,6], Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + end + + def test_proc_args_pos_opt_rest_post_block + pr = proc {|a,b,c=:c,d=:d,*e,f,g,&h| + [a, b, c, d, e, f, g, h.class, h&&h.call(:x)] + } + assert_equal [nil, nil, :c, :d, [], nil, nil, NilClass, nil], pr.call() + assert_equal [1, nil, :c, :d, [], nil, nil, NilClass, nil], pr.call(1) + assert_equal [1, 2, :c, :d, [], nil, nil, NilClass, nil], pr.call(1,2) + assert_equal [1, 2, :c, :d, [], 3, nil, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, :c, :d, [], 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, :d, [], 4, 5, NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, [], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, 3, 4, [5], 6, 7, NilClass, nil], pr.call(1,2,3,4,5,6,7) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, NilClass, nil], pr.call(1,2,3,4,5,6,7,8) + + assert_equal [nil, nil, :c, :d, [], nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, :c, :d, [], nil, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, :c, :d, [], nil, nil, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, :c, :d, [], 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc }) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){ :proc }) + + assert_equal [nil, nil, :c, :d, [], nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, :c, :d, [], nil, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, :c, :d, [], nil, nil, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, :c, :d, [], 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x}) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){|x| x}) + end + + def test_proc_args_opt_rest_post_block + pr = proc {|a=:a,b=:b,c=:c,d=:d,*e,f,g,&h| + [a, b, c, d, e, f, g, h.class, h&&h.call(:x)] + } + assert_equal [:a, :b, :c, :d, [], nil, nil, NilClass, nil], pr.call() + assert_equal [:a, :b, :c, :d, [], 1, nil, NilClass, nil], pr.call(1) + assert_equal [:a, :b, :c, :d, [], 1, 2, NilClass, nil], pr.call(1,2) + assert_equal [1, :b, :c, :d, [], 2, 3, NilClass, nil], pr.call(1,2,3) + assert_equal [1, 2, :c, :d, [], 3, 4, NilClass, nil], pr.call(1,2,3,4) + assert_equal [1, 2, 3, :d, [], 4, 5, NilClass, nil], pr.call(1,2,3,4,5) + assert_equal [1, 2, 3, 4, [], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, 3, 4, [5], 6, 7, NilClass, nil], pr.call(1,2,3,4,5,6,7) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, NilClass, nil], pr.call(1,2,3,4,5,6,7,8) + + assert_equal [:a, :b, :c, :d, [], nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [:a, :b, :c, :d, [], 1, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [:a, :b, :c, :d, [], 1, 2, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, :b, :c, :d, [], 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc }) + assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc }) + assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc }) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){ :proc }) + + assert_equal [:a, :b, :c, :d, [], nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [:a, :b, :c, :d, [], 1, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [:a, :b, :c, :d, [], 1, 2, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, :b, :c, :d, [], 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) + assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x}) + assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x}) + assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x}) + assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){|x| x}) + end + + def test_proc_args_pos_unleashed + r = proc {|a,b=1,*c,d,e| + [a,b,c,d,e] + }.call(1,2,3,4,5) + assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]") + end + + def test_parameters + assert_equal([], proc {}.parameters) + assert_equal([], proc {||}.parameters) + assert_equal([[:opt, :a]], proc {|a|}.parameters) + assert_equal([[:opt, :a], [:opt, :b]], proc {|a, b|}.parameters) + assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters) + assert_equal([[:opt, :a], [:opt, :b]], proc {|a, b=:b|}.parameters) + assert_equal([[:rest, :a]], proc {|*a|}.parameters) + assert_equal([[:opt, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters) + assert_equal([[:opt, :a], [:rest, :b], [:opt, :c]], proc {|a, *b, c|}.parameters) + assert_equal([[:opt, :a], [:rest, :b], [:opt, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters) + assert_equal([[:opt, :a], [:opt, :b], [:rest, :c], [:opt, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters) + assert_equal([[:opt, nil], [:block, :b]], proc {|(a), &b|a}.parameters) + assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) + + assert_equal([[:req]], method(:putc).parameters) + assert_equal([[:rest]], method(:p).parameters) + end + + def pm0() end + def pm1(a) end + def pm2(a, b) end + def pmo1(a = :a, &b) end + def pmo2(a, b = :b) end + def pmo3(*a) end + def pmo4(a, *b, &c) end + def pmo5(a, *b, c) end + def pmo6(a, *b, c, &d) end + def pmo7(a, b = :b, *c, d, &e) end + def pma1((a), &b) a; end + def pmk1(**) end + def pmk2(**o) nil && o end + def pmk3(a, **o) nil && o end + def pmk4(a = nil, **o) nil && o end + def pmk5(a, b = nil, **o) nil && o end + def pmk6(a, b = nil, c, **o) nil && o end + def pmk7(a, b = nil, *c, d, **o) nil && o end + + + def test_bound_parameters + assert_equal([], method(:pm0).to_proc.parameters) + assert_equal([[:req, :a]], method(:pm1).to_proc.parameters) + assert_equal([[:req, :a], [:req, :b]], method(:pm2).to_proc.parameters) + assert_equal([[:opt, :a], [:block, :b]], method(:pmo1).to_proc.parameters) + assert_equal([[:req, :a], [:opt, :b]], method(:pmo2).to_proc.parameters) + assert_equal([[:rest, :a]], method(:pmo3).to_proc.parameters) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).to_proc.parameters) + assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).to_proc.parameters) + 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, :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) + assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:pmk5).to_proc.parameters) + assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:pmk6).to_proc.parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).to_proc.parameters) + + assert_equal([], "".method(:upcase).to_proc.parameters) + assert_equal([[:rest]], "".method(:gsub).to_proc.parameters) + assert_equal([[:rest]], proc {}.curry.parameters) + end + + def test_to_s + assert_match(/^#<Proc:0x\h+@#{ Regexp.quote(__FILE__) }:\d+>$/, proc {}.to_s) + assert_match(/^#<Proc:0x\h+@#{ Regexp.quote(__FILE__) }:\d+ \(lambda\)>$/, lambda {}.to_s) + assert_match(/^#<Proc:0x\h+ \(lambda\)>$/, method(:p).to_proc.to_s) + x = proc {} + x.taint + assert_predicate(x.to_s, :tainted?) + end + + @@line_of_source_location_test = __LINE__ + 1 + def source_location_test a=1, + b=2 + end + + def test_source_location + file, lineno = method(:source_location_test).source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427') + end + + @@line_of_attr_reader_source_location_test = __LINE__ + 3 + @@line_of_attr_writer_source_location_test = __LINE__ + 3 + @@line_of_attr_accessor_source_location_test = __LINE__ + 3 + attr_reader :attr_reader_source_location_test + attr_writer :attr_writer_source_location_test + attr_accessor :attr_accessor_source_location_test + + def test_attr_source_location + file, lineno = method(:attr_reader_source_location_test).source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(@@line_of_attr_reader_source_location_test, lineno) + + file, lineno = method(:attr_writer_source_location_test=).source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(@@line_of_attr_writer_source_location_test, lineno) + + file, lineno = method(:attr_accessor_source_location_test).source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(@@line_of_attr_accessor_source_location_test, lineno) + + file, lineno = method(:attr_accessor_source_location_test=).source_location + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(@@line_of_attr_accessor_source_location_test, lineno) + end + + def block_source_location_test(*args, &block) + block.source_location + end + + def test_block_source_location + exp_lineno = __LINE__ + 3 + file, lineno = block_source_location_test(1, + 2, + 3) do + end + assert_match(/^#{ Regexp.quote(__FILE__) }$/, file) + assert_equal(exp_lineno, lineno) + end + + def test_splat_without_respond_to + def (obj = Object.new).respond_to?(m,*); false end + [obj].each do |a, b| + assert_equal([obj, nil], [a, b], '[ruby-core:24139]') + end + end + + def test_curry_with_trace + # bug3751 = '[ruby-core:31871]' + set_trace_func(proc {}) + test_curry + ensure + set_trace_func(nil) + end + + def test_block_propagation + bug3792 = '[ruby-core:32075]' + c = Class.new do + def foo + yield + end + end + + o = c.new + f = :foo.to_proc + assert_nothing_raised(LocalJumpError, bug3792) { + assert_equal('bar', f.(o) {'bar'}, bug3792) + } + assert_nothing_raised(LocalJumpError, bug3792) { + assert_equal('zot', o.method(:foo).to_proc.() {'zot'}, bug3792) + } + end + + def test_overridden_lambda + bug8345 = '[ruby-core:54687] [Bug #8345]' + assert_normal_exit('def lambda; end; method(:puts).to_proc', bug8345) + end + + def test_overridden_proc + bug8345 = '[ruby-core:54688] [Bug #8345]' + assert_normal_exit('def proc; end; ->{}.curry', bug8345) + end + + def get_binding if: 1, case: 2, when: 3, begin: 4, end: 5 + a ||= 0 + binding + end + + def test_local_variables + b = get_binding + assert_equal(%i'if case when begin end a', b.local_variables) + a = tap {|;a, b| break binding.local_variables} + assert_equal(%i[a b], a.sort) + end + + def test_local_variables_nested + b = tap {break binding} + assert_equal(%i[b], b.local_variables, '[ruby-dev:48351] [Bug #10001]') + end + + def local_variables_of(bind) + this_should_not_be_in_bind = 2 + bind.local_variables + end + + def test_local_variables_in_other_context + feature8773 = '[Feature #8773]' + assert_equal([:feature8773], local_variables_of(binding), feature8773) + end + + def test_local_variable_get + b = get_binding + assert_equal(0, b.local_variable_get(:a)) + assert_raise(NameError){ b.local_variable_get(:b) } + + # access keyword named local variables + assert_equal(1, b.local_variable_get(:if)) + assert_equal(2, b.local_variable_get(:case)) + assert_equal(3, b.local_variable_get(:when)) + assert_equal(4, b.local_variable_get(:begin)) + assert_equal(5, b.local_variable_get(:end)) + end + + def test_local_variable_set + b = get_binding + b.local_variable_set(:a, 10) + b.local_variable_set(:b, 20) + assert_equal(10, b.local_variable_get(:a)) + assert_equal(20, b.local_variable_get(:b)) + assert_equal(10, b.eval("a")) + assert_equal(20, b.eval("b")) + end + + def test_local_variable_defined? + b = get_binding + assert_equal(true, b.local_variable_defined?(:a)) + assert_equal(false, b.local_variable_defined?(:b)) + end + + def test_binding_receiver + feature8779 = '[ruby-dev:47613] [Feature #8779]' + + assert_same(self, binding.receiver, feature8779) + + obj = Object.new + def obj.b; binding; end + assert_same(obj, obj.b.receiver, feature8779) + end +end diff --git a/jni/ruby/test/ruby/test_process.rb b/jni/ruby/test/ruby/test_process.rb new file mode 100644 index 0000000..8847f6b --- /dev/null +++ b/jni/ruby/test/ruby/test_process.rb @@ -0,0 +1,2023 @@ +require 'test/unit' +require 'tempfile' +require 'timeout' +require 'io/wait' +require 'rbconfig' + +class TestProcess < Test::Unit::TestCase + RUBY = EnvUtil.rubybin + + def setup + Process.waitall + end + + def teardown + Process.waitall + end + + def windows? + self.class.windows? + end + def self.windows? + return /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + end + + def write_file(filename, content) + File.open(filename, "w") {|f| + f << content + } + end + + def with_tmpchdir + Dir.mktmpdir {|d| + d = File.realpath(d) + Dir.chdir(d) { + yield d + } + } + end + + def run_in_child(str) # should be called in a temporary directory + write_file("test-script", str) + Process.wait spawn(RUBY, "test-script") + $? + end + + def test_rlimit_availability + begin + Process.getrlimit(nil) + rescue NotImplementedError + assert_raise(NotImplementedError) { Process.setrlimit } + rescue TypeError + assert_raise(ArgumentError) { Process.setrlimit } + end + end + + def rlimit_exist? + Process.getrlimit(nil) + rescue NotImplementedError + return false + rescue TypeError + return true + end + + def test_rlimit_nofile + return unless rlimit_exist? + with_tmpchdir { + write_file 's', <<-"End" + # Too small RLIMIT_NOFILE, such as zero, causes problems. + # [OpenBSD] Setting to zero freezes this test. + # [GNU/Linux] EINVAL on poll(). EINVAL on ruby's internal poll() ruby with "[ASYNC BUG] thread_timer: select". + pipes = IO.pipe + limit = pipes.map {|io| io.fileno }.min + result = 1 + begin + Process.setrlimit(Process::RLIMIT_NOFILE, limit) + rescue Errno::EINVAL + result = 0 + end + if result == 1 + begin + IO.pipe + rescue Errno::EMFILE + result = 0 + end + end + exit result + End + pid = spawn RUBY, "s" + Process.wait pid + assert_equal(0, $?.to_i, "#{$?}") + } + end + + def test_rlimit_name + return unless rlimit_exist? + [ + :AS, "AS", + :CORE, "CORE", + :CPU, "CPU", + :DATA, "DATA", + :FSIZE, "FSIZE", + :MEMLOCK, "MEMLOCK", + :MSGQUEUE, "MSGQUEUE", + :NICE, "NICE", + :NOFILE, "NOFILE", + :NPROC, "NPROC", + :RSS, "RSS", + :RTPRIO, "RTPRIO", + :RTTIME, "RTTIME", + :SBSIZE, "SBSIZE", + :SIGPENDING, "SIGPENDING", + :STACK, "STACK", + ].each {|name| + if Process.const_defined? "RLIMIT_#{name}" + assert_nothing_raised { Process.getrlimit(name) } + else + assert_raise(ArgumentError) { Process.getrlimit(name) } + end + } + assert_raise(ArgumentError) { Process.getrlimit(:FOO) } + assert_raise(ArgumentError) { Process.getrlimit("FOO") } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.getrlimit("\u{30eb 30d3 30fc}") } + end + + def test_rlimit_value + return unless rlimit_exist? + assert_raise(ArgumentError) { Process.setrlimit(:FOO, 0) } + assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit("\u{30eb 30d3 30fc}", 0) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit(:CORE, "\u{30eb 30d3 30fc}") } + with_tmpchdir do + s = run_in_child(<<-'End') + cur, max = Process.getrlimit(:NOFILE) + Process.setrlimit(:NOFILE, [max-10, cur].min) + begin + Process.setrlimit(:NOFILE, :INFINITY) + rescue Errno::EPERM + exit false + end + End + assert_not_predicate(s, :success?) + s = run_in_child(<<-'End') + cur, max = Process.getrlimit(:NOFILE) + Process.setrlimit(:NOFILE, [max-10, cur].min) + begin + Process.setrlimit(:NOFILE, "INFINITY") + rescue Errno::EPERM + exit false + end + End + assert_not_predicate(s, :success?) + end + end + + TRUECOMMAND = [RUBY, '-e', ''] + + def test_execopts_opts + assert_nothing_raised { + Process.wait Process.spawn(*TRUECOMMAND, {}) + } + assert_raise(ArgumentError) { + Process.wait Process.spawn(*TRUECOMMAND, :foo => 100) + } + assert_raise(ArgumentError) { + Process.wait Process.spawn(*TRUECOMMAND, Process => 100) + } + end + + def test_execopts_pgroup + skip "system(:pgroup) is not supported" if windows? + assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) } + + io = IO.popen([RUBY, "-e", "print Process.getpgrp"]) + assert_equal(Process.getpgrp.to_s, io.read) + io.close + + io = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true]) + assert_equal(io.pid.to_s, io.read) + io.close + + assert_raise(ArgumentError) { system(*TRUECOMMAND, :pgroup=>-1) } + assert_raise(Errno::EPERM) { Process.wait spawn(*TRUECOMMAND, :pgroup=>2) } + + io1 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true]) + io2 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>io1.pid]) + assert_equal(io1.pid.to_s, io1.read) + assert_equal(io1.pid.to_s, io2.read) + Process.wait io1.pid + Process.wait io2.pid + io1.close + io2.close + end + + def test_execopts_rlimit + return unless rlimit_exist? + assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_foo=>0) } + assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_NOFILE=>0) } + assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[]) } + assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[1,2,3]) } + + max = Process.getrlimit(:CORE).last + + n = max + IO.popen([RUBY, "-e", + "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io| + assert_equal("[#{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) + } + + n = max + IO.popen([RUBY, "-e", + "p Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io| + assert_equal("[#{n}, #{n}]", io.read.chomp) + } + + m, n = 0, max + IO.popen([RUBY, "-e", + "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| + assert_equal("[#{m}, #{n}]", io.read.chomp) + } + + m, n = 0, 0 + IO.popen([RUBY, "-e", + "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| + assert_equal("[#{m}, #{n}]", io.read.chomp) + } + + n = max + IO.popen([RUBY, "-e", + "p Process.getrlimit(:CORE), Process.getrlimit(:CPU)", + :rlimit_core=>n, :rlimit_cpu=>3600]) {|io| + assert_equal("[#{n}, #{n}]\n[3600, 3600]", io.read.chomp) + } + end + + MANDATORY_ENVS = %w[RUBYLIB] + case RbConfig::CONFIG['target_os'] + when /linux/ + MANDATORY_ENVS << 'LD_PRELOAD' + when /mswin|mingw/ + MANDATORY_ENVS.concat(%w[HOME USER TMPDIR]) + when /darwin/ + MANDATORY_ENVS.concat(ENV.keys.grep(/\A__CF_/)) + end + if e = RbConfig::CONFIG['LIBPATHENV'] + MANDATORY_ENVS << e + end + PREENVARG = ['-e', "%w[#{MANDATORY_ENVS.join(' ')}].each{|e|ENV.delete(e)}"] + ENVARG = ['-e', 'ENV.each {|k,v| puts "#{k}=#{v}" }'] + ENVCOMMAND = [RUBY].concat(PREENVARG).concat(ENVARG) + + def test_execopts_env + assert_raise(ArgumentError) { + system({"F=O"=>"BAR"}, *TRUECOMMAND) + } + + with_tmpchdir {|d| + prog = "#{d}/notexist" + e = assert_raise(Errno::ENOENT) { + Process.wait Process.spawn({"FOO"=>"BAR"}, prog) + } + assert_equal(prog, e.message.sub(/.* - /, '')) + e = assert_raise(Errno::ENOENT) { + Process.wait Process.spawn({"FOO"=>"BAR"}, [prog, "blar"]) + } + assert_equal(prog, e.message.sub(/.* - /, '')) + } + h = {} + cmd = [h, RUBY] + (ENV.keys + MANDATORY_ENVS).each do |k| + case k + when /\APATH\z/i + when *MANDATORY_ENVS + cmd << '-e' << "ENV.delete('#{k}')" + else + h[k] = nil + end + end + cmd << '-e' << 'puts ENV.keys.map{|e|e.upcase}' + IO.popen(cmd) {|io| + assert_equal("PATH\n", io.read) + } + + IO.popen([{"FOO"=>"BAR"}, *ENVCOMMAND]) {|io| + assert_match(/^FOO=BAR$/, io.read) + } + + with_tmpchdir {|d| + system({"fofo"=>"haha"}, *ENVCOMMAND, STDOUT=>"out") + assert_match(/^fofo=haha$/, File.read("out").chomp) + } + + old = ENV["hmm"] + begin + ENV["hmm"] = "fufu" + IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=fufu$/, io.read) } + IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) } + IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) } + ENV["hmm"] = "" + IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=$/, io.read) } + IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) } + IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) } + ENV["hmm"] = nil + IO.popen(ENVCOMMAND) {|io| assert_not_match(/^hmm=/, io.read) } + IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) } + IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) } + ensure + ENV["hmm"] = old + end + end + + def _test_execopts_env_popen(cmd) + message = cmd.inspect + IO.popen({"FOO"=>"BAR"}, cmd) {|io| + assert_equal('FOO=BAR', io.read[/^FOO=.*/], message) + } + + old = ENV["hmm"] + begin + ENV["hmm"] = "fufu" + IO.popen(cmd) {|io| assert_match(/^hmm=fufu$/, io.read, message)} + IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)} + IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)} + ENV["hmm"] = "" + IO.popen(cmd) {|io| assert_match(/^hmm=$/, io.read, message)} + IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)} + IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)} + ENV["hmm"] = nil + IO.popen(cmd) {|io| assert_not_match(/^hmm=/, io.read, message)} + IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)} + IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)} + ensure + ENV["hmm"] = old + end + end + + def test_execopts_env_popen_vector + _test_execopts_env_popen(ENVCOMMAND) + end + + def test_execopts_env_popen_string + with_tmpchdir do |d| + open('test-script', 'w') do |f| + ENVCOMMAND.each_with_index do |cmd, i| + next if i.zero? or cmd == "-e" + f.puts cmd + end + end + _test_execopts_env_popen("#{RUBY} test-script") + end + end + + def test_execopts_preserve_env_on_exec_failure + with_tmpchdir {|d| + write_file 's', <<-"End" + ENV["mgg"] = nil + prog = "./nonexistent" + begin + Process.exec({"mgg" => "mggoo"}, [prog, prog]) + rescue Errno::ENOENT + end + open('out', 'w') {|f| + f.print ENV["mgg"].inspect + } + End + system(RUBY, 's') + assert_equal(nil.inspect, File.read('out'), + "[ruby-core:44093] [ruby-trunk - Bug #6249]") + } + end + + def test_execopts_env_single_word + with_tmpchdir {|d| + open("test_execopts_env_single_word.rb", "w") {|f| + f.puts "print ENV['hgga']" + } + system({"hgga"=>"ugu"}, RUBY, + :in => 'test_execopts_env_single_word.rb', + :out => 'test_execopts_env_single_word.out') + assert_equal('ugu', File.read('test_execopts_env_single_word.out')) + } + end + + def test_execopts_unsetenv_others + h = {} + MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e} + IO.popen([h, *ENVCOMMAND, :unsetenv_others=>true]) {|io| + assert_equal("", io.read) + } + IO.popen([h.merge("A"=>"B"), *ENVCOMMAND, :unsetenv_others=>true]) {|io| + assert_equal("A=B\n", io.read) + } + end + + PWD = [RUBY, '-e', 'puts Dir.pwd'] + + def test_execopts_chdir + with_tmpchdir {|d| + IO.popen([*PWD, :chdir => d]) {|io| + assert_equal(d, io.read.chomp) + } + assert_raise(Errno::ENOENT) { + Process.wait Process.spawn(*PWD, :chdir => "d/notexist") + } + } + end + + def test_execopts_open_chdir + with_tmpchdir {|d| + Dir.mkdir "foo" + system(*PWD, :chdir => "foo", :out => "open_chdir_test") + assert_file.exist?("open_chdir_test") + assert_file.not_exist?("foo/open_chdir_test") + assert_equal("#{d}/foo", File.read("open_chdir_test").chomp) + } + end + + UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask'] + + def test_execopts_umask + skip "umask is not supported" if windows? + IO.popen([*UMASK, :umask => 0]) {|io| + assert_equal("0000", io.read.chomp) + } + IO.popen([*UMASK, :umask => 0777]) {|io| + assert_equal("0777", io.read.chomp) + } + end + + def with_pipe + begin + r, w = IO.pipe + yield r, w + ensure + r.close unless r.closed? + w.close unless w.closed? + end + end + + def with_pipes(n) + ary = [] + begin + n.times { + ary << IO.pipe + } + yield ary + ensure + ary.each {|r, w| + r.close unless r.closed? + w.close unless w.closed? + } + end + end + + ECHO = lambda {|arg| [RUBY, '-e', "puts #{arg.dump}; STDOUT.flush"] } + SORT = [RUBY, '-e', "puts ARGF.readlines.sort"] + CAT = [RUBY, '-e', "IO.copy_stream STDIN, STDOUT"] + + def test_execopts_redirect_fd + with_tmpchdir {|d| + Process.wait Process.spawn(*ECHO["a"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]) + assert_equal("a", File.read("out").chomp) + if windows? + # currently telling to child the file modes is not supported. + open("out", "a") {|f| f.write "0\n"} + else + Process.wait Process.spawn(*ECHO["0"], STDOUT=>["out", File::WRONLY|File::CREAT|File::APPEND, 0644]) + assert_equal("a\n0\n", File.read("out")) + end + Process.wait Process.spawn(*SORT, STDIN=>["out", File::RDONLY, 0644], + STDOUT=>["out2", File::WRONLY|File::CREAT|File::TRUNC, 0644]) + assert_equal("0\na\n", File.read("out2")) + Process.wait Process.spawn(*ECHO["b"], [STDOUT, STDERR]=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]) + assert_equal("b", File.read("out").chomp) + # problem occur with valgrind + #Process.wait Process.spawn(*ECHO["a"], STDOUT=>:close, STDERR=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]) + #p File.read("out") + #assert_not_empty(File.read("out")) # error message such as "-e:1:in `flush': Bad file descriptor (Errno::EBADF)" + Process.wait Process.spawn(*ECHO["c"], STDERR=>STDOUT, STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]) + assert_equal("c", File.read("out").chomp) + File.open("out", "w") {|f| + Process.wait Process.spawn(*ECHO["d"], STDOUT=>f) + assert_equal("d", File.read("out").chomp) + } + opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]} + opts.merge(3=>STDOUT, 4=>STDOUT, 5=>STDOUT, 6=>STDOUT, 7=>STDOUT) unless windows? + Process.wait Process.spawn(*ECHO["e"], opts) + assert_equal("e", File.read("out").chomp) + opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]} + opts.merge(3=>0, 4=>:in, 5=>STDIN, 6=>1, 7=>:out, 8=>STDOUT, 9=>2, 10=>:err, 11=>STDERR) unless windows? + Process.wait Process.spawn(*ECHO["ee"], opts) + assert_equal("ee", File.read("out").chomp) + unless windows? + # passing non-stdio fds is not supported on Windows + File.open("out", "w") {|f| + h = {STDOUT=>f, f=>STDOUT} + 3.upto(30) {|i| h[i] = STDOUT if f.fileno != i } + Process.wait Process.spawn(*ECHO["f"], h) + assert_equal("f", File.read("out").chomp) + } + end + assert_raise(ArgumentError) { + Process.wait Process.spawn(*ECHO["f"], 1=>Process) + } + assert_raise(ArgumentError) { + Process.wait Process.spawn(*ECHO["f"], [Process]=>1) + } + assert_raise(ArgumentError) { + Process.wait Process.spawn(*ECHO["f"], [1, STDOUT]=>2) + } + assert_raise(ArgumentError) { + Process.wait Process.spawn(*ECHO["f"], -1=>2) + } + Process.wait Process.spawn(*ECHO["hhh\nggg\n"], STDOUT=>"out") + assert_equal("hhh\nggg\n", File.read("out")) + Process.wait Process.spawn(*SORT, STDIN=>"out", STDOUT=>"out2") + assert_equal("ggg\nhhh\n", File.read("out2")) + + unless windows? + # passing non-stdio fds is not supported on Windows + assert_raise(Errno::ENOENT) { + Process.wait Process.spawn("non-existing-command", (3..60).to_a=>["err", File::WRONLY|File::CREAT]) + } + assert_equal("", File.read("err")) + end + + system(*ECHO["bb\naa\n"], STDOUT=>["out", "w"]) + assert_equal("bb\naa\n", File.read("out")) + system(*SORT, STDIN=>["out"], STDOUT=>"out2") + assert_equal("aa\nbb\n", File.read("out2")) + } + end + + def test_execopts_redirect_pipe + with_pipe {|r1, w1| + with_pipe {|r2, w2| + opts = {STDIN=>r1, STDOUT=>w2} + opts.merge(w1=>:close, r2=>:close) unless windows? + pid = spawn(*SORT, opts) + r1.close + w2.close + w1.puts "c" + w1.puts "a" + w1.puts "b" + w1.close + assert_equal("a\nb\nc\n", r2.read) + r2.close + Process.wait(pid) + } + } + + unless windows? + # passing non-stdio fds is not supported on Windows + with_pipes(5) {|pipes| + ios = pipes.flatten + h = {} + ios.length.times {|i| h[ios[i]] = ios[(i-1)%ios.length] } + h2 = h.invert + _rios = pipes.map {|r, w| r } + wios = pipes.map {|r, w| w } + child_wfds = wios.map {|w| h2[w].fileno } + pid = spawn(RUBY, "-e", + "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h) + pipes.each {|r, w| + assert_equal("#{h2[w].fileno}\n", r.gets) + } + Process.wait pid; + } + + with_pipes(5) {|pipes| + ios = pipes.flatten + h = {} + ios.length.times {|i| h[ios[i]] = ios[(i+1)%ios.length] } + h2 = h.invert + _rios = pipes.map {|r, w| r } + wios = pipes.map {|r, w| w } + child_wfds = wios.map {|w| h2[w].fileno } + pid = spawn(RUBY, "-e", + "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h) + pipes.each {|r, w| + assert_equal("#{h2[w].fileno}\n", r.gets) + } + Process.wait pid + } + + closed_fd = nil + with_pipes(5) {|pipes| + io = pipes.last.last + closed_fd = io.fileno + } + assert_raise(Errno::EBADF) { Process.wait spawn(*TRUECOMMAND, closed_fd=>closed_fd) } + + with_pipe {|r, w| + if w.respond_to?(:"close_on_exec=") + w.close_on_exec = true + pid = spawn(RUBY, "-e", "IO.new(#{w.fileno}, 'w').print 'a'", w=>w) + w.close + assert_equal("a", r.read) + Process.wait pid + end + } + end + end + + def test_execopts_redirect_symbol + with_tmpchdir {|d| + system(*ECHO["funya"], :out=>"out") + assert_equal("funya\n", File.read("out")) + system(RUBY, '-e', 'STDOUT.reopen(STDERR); puts "henya"', :err=>"out") + assert_equal("henya\n", File.read("out")) + IO.popen([*CAT, :in=>"out"]) {|io| + assert_equal("henya\n", io.read) + } + } + end + + def test_execopts_redirect_nonascii_path + bug9946 = '[ruby-core:63185] [Bug #9946]' + with_tmpchdir {|d| + path = "t-\u{30c6 30b9 30c8 f6}.txt" + system(*ECHO["a"], out: path) + assert_file.for(bug9946).exist?(path) + assert_equal("a\n", File.read(path), bug9946) + } + end + + def test_execopts_redirect_to_out_and_err + with_tmpchdir {|d| + ret = system(RUBY, "-e", 'STDERR.print "e"; STDOUT.print "o"', [:out, :err] => "foo") + assert_equal(true, ret) + assert_equal("eo", File.read("foo")) + ret = system(RUBY, "-e", 'STDERR.print "E"; STDOUT.print "O"', [:err, :out] => "bar") + assert_equal(true, ret) + assert_equal("EO", File.read("bar")) + } + end + + def test_execopts_redirect_dup2_child + with_tmpchdir {|d| + Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", + STDOUT=>"out", STDERR=>[:child, STDOUT]) + assert_equal("errout", File.read("out")) + + Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", + 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? + Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", + STDOUT=>"out", + STDERR=>[:child, 3], + 3=>[:child, 4], + 4=>[:child, STDOUT] + ) + assert_equal("errout", File.read("out")) + + IO.popen([RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>[:child, STDOUT]]) {|io| + assert_equal("errout", io.read) + } + + assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT]) } + assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 3]) } + assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 5], 5=>[:child, 3]) } + assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3]) } + } + end + + def test_execopts_exec + with_tmpchdir {|d| + write_file("s", 'exec "echo aaa", STDOUT=>"foo"') + pid = spawn RUBY, 's' + Process.wait pid + assert_equal("aaa\n", File.read("foo")) + } + end + + def test_execopts_popen + with_tmpchdir {|d| + IO.popen("#{RUBY} -e 'puts :foo'") {|io| assert_equal("foo\n", io.read) } + assert_raise(Errno::ENOENT) { IO.popen(["echo bar"]) {} } # assuming "echo bar" command not exist. + IO.popen(ECHO["baz"]) {|io| assert_equal("baz\n", io.read) } + assert_raise(ArgumentError) { + IO.popen([*ECHO["qux"], STDOUT=>STDOUT]) {|io| } + } + IO.popen([*ECHO["hoge"], STDERR=>STDOUT]) {|io| + assert_equal("hoge\n", io.read) + } + assert_raise(ArgumentError) { + IO.popen([*ECHO["fuga"], STDOUT=>"out"]) {|io| } + } + skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + with_pipe {|r, w| + IO.popen([RUBY, '-e', 'IO.new(3, "w").puts("a"); puts "b"', 3=>w]) {|io| + assert_equal("b\n", io.read) + } + w.close + assert_equal("a\n", r.read) + } + IO.popen([RUBY, '-e', "IO.new(9, 'w').puts(:b)", + 9=>["out2", File::WRONLY|File::CREAT|File::TRUNC]]) {|io| + assert_equal("", io.read) + } + assert_equal("b\n", File.read("out2")) + } + end + + def test_popen_fork + IO.popen("-") {|io| + if !io + puts "fooo" + else + assert_equal("fooo\n", io.read) + end + } + rescue NotImplementedError + end + + def test_fd_inheritance + skip "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 + assert_equal("ba\n", r.read) + } + with_pipe {|r, w| + Process.wait spawn(RUBY, '-e', + 'IO.new(ARGV[0].to_i, "w").puts("bi") rescue nil', + w.fileno.to_s) + w.close + assert_equal("", r.read) + } + with_pipe {|r, w| + with_tmpchdir {|d| + write_file("s", <<-"End") + exec(#{RUBY.dump}, '-e', + 'IO.new(ARGV[0].to_i, "w").puts("bu") rescue nil', + #{w.fileno.to_s.dump}, :close_others=>false) + End + w.close_on_exec = false + Process.wait spawn(RUBY, "s", :close_others=>false) + w.close + assert_equal("bu\n", r.read) + } + } + with_pipe {|r, w| + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')"]) + begin + w.close + errmsg = io.read + assert_equal("", r.read) + assert_not_equal("", errmsg) + ensure + io.close + end + } + with_pipe {|r, w| + errmsg = `#{RUBY} -e "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts(123)"` + w.close + assert_equal("", r.read) + assert_not_equal("", errmsg) + } + end + + def test_execopts_close_others + skip "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) + w.close + assert_equal("", r.read) + assert_not_equal("", File.read("err")) + File.unlink("err") + } + with_pipe {|r, w| + Process.wait spawn(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mi")', w.fileno.to_s, :close_others=>true) + w.close + assert_equal("", r.read) + assert_not_equal("", File.read("err")) + File.unlink("err") + } + with_pipe {|r, w| + w.close_on_exec = false + Process.wait spawn(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts("bi")', w.fileno.to_s, :close_others=>false) + w.close + assert_equal("bi\n", r.read) + } + with_pipe {|r, w| + write_file("s", <<-"End") + exec(#{RUBY.dump}, '-e', + 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mu")', + #{w.fileno.to_s.dump}, + :close_others=>true) + End + Process.wait spawn(RUBY, "s", :close_others=>false) + w.close + assert_equal("", r.read) + assert_not_equal("", File.read("err")) + File.unlink("err") + } + with_pipe {|r, w| + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')", :close_others=>true]) + begin + w.close + errmsg = io.read + assert_equal("", r.read) + assert_not_equal("", errmsg) + ensure + io.close + end + } + with_pipe {|r, w| + w.close_on_exec = false + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>false]) + begin + w.close + errmsg = io.read + assert_equal("mo\n", r.read) + assert_equal("", errmsg) + ensure + io.close + end + } + with_pipe {|r, w| + w.close_on_exec = false + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>nil]) + begin + w.close + errmsg = io.read + assert_equal("mo\n", r.read) + assert_equal("", errmsg) + ensure + io.close + end + } + + } + end + + def test_execopts_redirect_self + begin + with_pipe {|r, w| + w << "haha\n" + w.close + r.close_on_exec = true + IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}, 'r').read", r.fileno=>r.fileno, :close_others=>false]) {|io| + assert_equal("haha\n", io.read) + } + } + rescue NotImplementedError + skip "IO#close_on_exec= is not supported" + end + end + + def test_execopts_redirect_tempfile + bug6269 = '[ruby-core:44181]' + Tempfile.create("execopts") do |tmp| + pid = assert_nothing_raised(ArgumentError, bug6269) do + break spawn(RUBY, "-e", "print $$", out: tmp) + end + Process.wait(pid) + tmp.rewind + assert_equal(pid.to_s, tmp.read) + end + end + + def test_execopts_duplex_io + IO.popen("#{RUBY} -e ''", "r+") {|duplex| + assert_raise(ArgumentError) { system("#{RUBY} -e ''", duplex=>STDOUT) } + assert_raise(ArgumentError) { system("#{RUBY} -e ''", STDOUT=>duplex) } + } + end + + def test_execopts_modification + h = {} + Process.wait spawn(*TRUECOMMAND, h) + assert_equal({}, h) + + h = {} + system(*TRUECOMMAND, h) + assert_equal({}, h) + + h = {} + io = IO.popen([*TRUECOMMAND, h]) + io.close + assert_equal({}, h) + end + + def test_system_noshell + str = "echo non existing command name which contains spaces" + assert_nil(system([str, str])) + end + + def test_spawn_noshell + str = "echo non existing command name which contains spaces" + assert_raise(Errno::ENOENT) { spawn([str, str]) } + end + + def test_popen_noshell + str = "echo non existing command name which contains spaces" + assert_raise(Errno::ENOENT) { IO.popen([str, str]) } + end + + def test_exec_noshell + with_tmpchdir {|d| + write_file("s", <<-"End") + str = "echo non existing command name which contains spaces" + STDERR.reopen(STDOUT) + begin + exec [str, str] + rescue Errno::ENOENT + print "Errno::ENOENT success" + end + End + r = IO.popen([RUBY, "s", :close_others=>false], "r") {|f| f.read} + assert_equal("Errno::ENOENT success", r) + } + end + + def test_system_wordsplit + with_tmpchdir {|d| + write_file("script", <<-'End') + File.open("result", "w") {|t| t << "haha pid=#{$$} ppid=#{Process.ppid}" } + exit 5 + End + str = "#{RUBY} script" + ret = system(str) + status = $? + assert_equal(false, ret) + assert_predicate(status, :exited?) + assert_equal(5, status.exitstatus) + assert_equal("haha pid=#{status.pid} ppid=#{$$}", File.read("result")) + } + end + + def test_spawn_wordsplit + with_tmpchdir {|d| + write_file("script", <<-'End') + File.open("result", "w") {|t| t << "hihi pid=#{$$} ppid=#{Process.ppid}" } + exit 6 + End + str = "#{RUBY} script" + pid = spawn(str) + Process.wait pid + status = $? + assert_equal(pid, status.pid) + assert_predicate(status, :exited?) + assert_equal(6, status.exitstatus) + assert_equal("hihi pid=#{status.pid} ppid=#{$$}", File.read("result")) + } + end + + def test_popen_wordsplit + with_tmpchdir {|d| + write_file("script", <<-'End') + print "fufu pid=#{$$} ppid=#{Process.ppid}" + exit 7 + End + str = "#{RUBY} script" + io = IO.popen(str) + pid = io.pid + result = io.read + io.close + status = $? + assert_equal(pid, status.pid) + assert_predicate(status, :exited?) + assert_equal(7, status.exitstatus) + assert_equal("fufu pid=#{status.pid} ppid=#{$$}", result) + } + end + + def test_popen_wordsplit_beginning_and_trailing_spaces + with_tmpchdir {|d| + write_file("script", <<-'End') + print "fufumm pid=#{$$} ppid=#{Process.ppid}" + exit 7 + End + str = " #{RUBY} script " + io = IO.popen(str) + pid = io.pid + result = io.read + io.close + status = $? + assert_equal(pid, status.pid) + assert_predicate(status, :exited?) + assert_equal(7, status.exitstatus) + assert_equal("fufumm pid=#{status.pid} ppid=#{$$}", result) + } + end + + def test_exec_wordsplit + with_tmpchdir {|d| + write_file("script", <<-'End') + File.open("result", "w") {|t| + if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + t << "hehe ppid=#{Process.ppid}" + else + t << "hehe pid=#{$$} ppid=#{Process.ppid}" + end + } + exit 6 + End + write_file("s", <<-"End") + ruby = #{RUBY.dump} + exec "\#{ruby} script" + End + pid = spawn(RUBY, "s") + Process.wait pid + status = $? + assert_equal(pid, status.pid) + assert_predicate(status, :exited?) + assert_equal(6, status.exitstatus) + if windows? + expected = "hehe ppid=#{status.pid}" + else + expected = "hehe pid=#{status.pid} ppid=#{$$}" + end + assert_equal(expected, File.read("result")) + } + end + + def test_system_shell + with_tmpchdir {|d| + write_file("script1", <<-'End') + File.open("result1", "w") {|t| t << "taka pid=#{$$} ppid=#{Process.ppid}" } + exit 7 + End + write_file("script2", <<-'End') + File.open("result2", "w") {|t| t << "taki pid=#{$$} ppid=#{Process.ppid}" } + exit 8 + End + ret = system("#{RUBY} script1 || #{RUBY} script2") + status = $? + assert_equal(false, ret) + assert_predicate(status, :exited?) + result1 = File.read("result1") + result2 = File.read("result2") + assert_match(/\Ataka pid=\d+ ppid=\d+\z/, result1) + assert_match(/\Ataki pid=\d+ ppid=\d+\z/, result2) + assert_not_equal(result1[/\d+/].to_i, status.pid) + + if windows? + Dir.mkdir(path = "path with space") + write_file(bat = path + "/bat test.bat", "@echo %1>out") + system(bat, "foo 'bar'") + assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]') + system(%[#{bat.dump} "foo 'bar'"]) + assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]') + end + } + end + + def test_spawn_shell + with_tmpchdir {|d| + write_file("script1", <<-'End') + File.open("result1", "w") {|t| t << "taku pid=#{$$} ppid=#{Process.ppid}" } + exit 7 + End + write_file("script2", <<-'End') + File.open("result2", "w") {|t| t << "take pid=#{$$} ppid=#{Process.ppid}" } + exit 8 + End + pid = spawn("#{RUBY} script1 || #{RUBY} script2") + Process.wait pid + status = $? + assert_predicate(status, :exited?) + assert_not_predicate(status, :success?) + result1 = File.read("result1") + result2 = File.read("result2") + assert_match(/\Ataku pid=\d+ ppid=\d+\z/, result1) + assert_match(/\Atake pid=\d+ ppid=\d+\z/, result2) + assert_not_equal(result1[/\d+/].to_i, status.pid) + + if windows? + Dir.mkdir(path = "path with space") + write_file(bat = path + "/bat test.bat", "@echo %1>out") + pid = spawn(bat, "foo 'bar'") + Process.wait pid + status = $? + assert_predicate(status, :exited?) + assert_predicate(status, :success?) + assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]') + pid = spawn(%[#{bat.dump} "foo 'bar'"]) + Process.wait pid + status = $? + assert_predicate(status, :exited?) + assert_predicate(status, :success?) + assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]') + end + } + end + + def test_popen_shell + with_tmpchdir {|d| + write_file("script1", <<-'End') + puts "tako pid=#{$$} ppid=#{Process.ppid}" + exit 7 + End + write_file("script2", <<-'End') + puts "tika pid=#{$$} ppid=#{Process.ppid}" + exit 8 + End + io = IO.popen("#{RUBY} script1 || #{RUBY} script2") + result = io.read + io.close + status = $? + assert_predicate(status, :exited?) + assert_not_predicate(status, :success?) + assert_match(/\Atako pid=\d+ ppid=\d+\ntika pid=\d+ ppid=\d+\n\z/, result) + assert_not_equal(result[/\d+/].to_i, status.pid) + + if windows? + Dir.mkdir(path = "path with space") + write_file(bat = path + "/bat test.bat", "@echo %1") + r = IO.popen([bat, "foo 'bar'"]) {|f| f.read} + assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]') + r = IO.popen(%[#{bat.dump} "foo 'bar'"]) {|f| f.read} + assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]') + end + } + end + + def test_exec_shell + with_tmpchdir {|d| + write_file("script1", <<-'End') + File.open("result1", "w") {|t| t << "tiki pid=#{$$} ppid=#{Process.ppid}" } + exit 7 + End + write_file("script2", <<-'End') + File.open("result2", "w") {|t| t << "tiku pid=#{$$} ppid=#{Process.ppid}" } + exit 8 + End + write_file("s", <<-"End") + ruby = #{RUBY.dump} + exec("\#{ruby} script1 || \#{ruby} script2") + End + pid = spawn RUBY, "s" + Process.wait pid + status = $? + assert_predicate(status, :exited?) + assert_not_predicate(status, :success?) + result1 = File.read("result1") + result2 = File.read("result2") + assert_match(/\Atiki pid=\d+ ppid=\d+\z/, result1) + assert_match(/\Atiku pid=\d+ ppid=\d+\z/, result2) + assert_not_equal(result1[/\d+/].to_i, status.pid) + } + end + + def test_argv0 + with_tmpchdir {|d| + assert_equal(false, system([RUBY, "asdfg"], "-e", "exit false")) + assert_equal(true, system([RUBY, "zxcvb"], "-e", "exit true")) + + Process.wait spawn([RUBY, "poiu"], "-e", "exit 4") + assert_equal(4, $?.exitstatus) + + assert_equal("1", IO.popen([[RUBY, "qwerty"], "-e", "print 1"]) {|f| f.read }) + + write_file("s", <<-"End") + exec([#{RUBY.dump}, "lkjh"], "-e", "exit 5") + End + pid = spawn RUBY, "s" + Process.wait pid + assert_equal(5, $?.exitstatus) + } + end + + def with_stdin(filename) + open(filename) {|f| + begin + old = STDIN.dup + begin + STDIN.reopen(filename) + yield + ensure + STDIN.reopen(old) + end + ensure + old.close + end + } + end + + def test_argv0_noarg + with_tmpchdir {|d| + open("t", "w") {|f| f.print "exit true" } + open("f", "w") {|f| f.print "exit false" } + + with_stdin("t") { assert_equal(true, system([RUBY, "qaz"])) } + with_stdin("f") { assert_equal(false, system([RUBY, "wsx"])) } + + with_stdin("t") { Process.wait spawn([RUBY, "edc"]) } + assert_predicate($?, :success?) + with_stdin("f") { Process.wait spawn([RUBY, "rfv"]) } + assert_not_predicate($?, :success?) + + with_stdin("t") { IO.popen([[RUBY, "tgb"]]) {|io| assert_equal("", io.read) } } + assert_predicate($?, :success?) + with_stdin("f") { IO.popen([[RUBY, "yhn"]]) {|io| assert_equal("", io.read) } } + assert_not_predicate($?, :success?) + + status = run_in_child "STDIN.reopen('t'); exec([#{RUBY.dump}, 'ujm'])" + assert_predicate(status, :success?) + status = run_in_child "STDIN.reopen('f'); exec([#{RUBY.dump}, 'ik,'])" + assert_not_predicate(status, :success?) + } + end + + def test_status + with_tmpchdir do + s = run_in_child("exit 1") + assert_equal("#<Process::Status: pid #{ s.pid } exit #{ s.exitstatus }>", s.inspect) + + assert_equal(s, s) + assert_equal(s, s.to_i) + + assert_equal(s.to_i & 0x55555555, s & 0x55555555) + assert_equal(s.to_i >> 1, s >> 1) + assert_equal(false, s.stopped?) + assert_equal(nil, s.stopsig) + end + end + + def test_status_kill + return unless Process.respond_to?(:kill) + return unless Signal.list.include?("KILL") + + # assume the system supports signal if SIGQUIT is available + expected = Signal.list.include?("QUIT") ? [false, true, false, nil] : [true, false, false, true] + + with_tmpchdir do + write_file("foo", "Process.kill(:KILL, $$); exit(42)") + system(RUBY, "foo") + s = $? + assert_equal(expected, + [s.exited?, s.signaled?, s.stopped?, s.success?], + "[s.exited?, s.signaled?, s.stopped?, s.success?]") + end + end + + def test_status_quit + return unless Process.respond_to?(:kill) + return unless Signal.list.include?("QUIT") + + with_tmpchdir do + write_file("foo", "puts;STDOUT.flush;sleep 30") + pid = nil + IO.pipe do |r, w| + pid = spawn(RUBY, "foo", out: w) + w.close + th = Thread.new { r.read(1); Process.kill(:SIGQUIT, pid) } + Process.wait(pid) + th.join + end + t = Time.now + s = $? + assert_equal([false, true, false, nil], + [s.exited?, s.signaled?, s.stopped?, s.success?], + "[s.exited?, s.signaled?, s.stopped?, s.success?]") + assert_send( + [["#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig })>", + "#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig }) (core dumped)>"], + :include?, + s.inspect]) + EnvUtil.diagnostic_reports("QUIT", RUBY, pid, t) + end + end + + def test_wait_without_arg + with_tmpchdir do + write_file("foo", "sleep 0.1") + pid = spawn(RUBY, "foo") + assert_equal(pid, Process.wait) + end + end + + def test_wait2 + with_tmpchdir do + write_file("foo", "sleep 0.1") + pid = spawn(RUBY, "foo") + assert_equal([pid, 0], Process.wait2) + end + end + + def test_waitall + with_tmpchdir do + write_file("foo", "sleep 0.1") + ps = (0...3).map { spawn(RUBY, "foo") }.sort + ss = Process.waitall.sort + ps.zip(ss) do |p1, (p2, s)| + assert_equal(p1, p2) + assert_equal(p1, s.pid) + end + end + end + + def test_wait_exception + bug11340 = '[ruby-dev:49176] [Bug #11340]' + t0 = t1 = nil + IO.popen([RUBY, '-e', 'puts;STDOUT.flush;Thread.start{gets;exit};sleep(3)'], 'r+') do |f| + pid = f.pid + f.gets + t0 = Time.now + th = Thread.start(Thread.current) do |main| + Thread.pass until main.stop? + main.raise Interrupt + end + begin + assert_raise(Interrupt) {Process.wait(pid)} + ensure + th.kill.join + end + t1 = Time.now + f.puts + end + assert_operator(t1 - t0, :<, 3, + ->{"#{bug11340}: #{t1-t0} seconds to interrupt Process.wait"}) + end + + def test_abort + with_tmpchdir do + s = run_in_child("abort") + assert_not_equal(0, s.exitstatus) + end + end + + def test_sleep + assert_raise(ArgumentError) { sleep(1, 1) } + end + + def test_getpgid + assert_kind_of(Integer, Process.getpgid(Process.ppid)) + rescue NotImplementedError + end + + def test_getpriority + assert_kind_of(Integer, Process.getpriority(Process::PRIO_PROCESS, $$)) + rescue NameError, NotImplementedError + end + + def test_setpriority + if defined? Process::PRIO_USER + assert_nothing_raised do + pr = Process.getpriority(Process::PRIO_PROCESS, $$) + Process.setpriority(Process::PRIO_PROCESS, $$, pr) + end + end + end + + def test_getuid + assert_kind_of(Integer, Process.uid) + end + + def test_groups + gs = Process.groups + assert_instance_of(Array, gs) + gs.each {|g| assert_kind_of(Integer, g) } + rescue NotImplementedError + end + + def test_maxgroups + assert_kind_of(Integer, Process.maxgroups) + rescue NotImplementedError + end + + def test_geteuid + assert_kind_of(Integer, Process.euid) + end + + def test_seteuid + assert_nothing_raised(TypeError) {Process.euid += 0} + rescue NotImplementedError + end + + def test_seteuid_name + user = ENV["USER"] or return + assert_nothing_raised(TypeError) {Process.euid = user} + rescue NotImplementedError + end + + def test_getegid + assert_kind_of(Integer, Process.egid) + end + + def test_setegid + assert_nothing_raised(TypeError) {Process.egid += 0} + rescue NotImplementedError + end + + def test_uid_re_exchangeable_p + r = Process::UID.re_exchangeable? + assert_include([true, false], r) + end + + def test_gid_re_exchangeable_p + r = Process::GID.re_exchangeable? + assert_include([true, false], r) + end + + def test_uid_sid_available? + r = Process::UID.sid_available? + assert_include([true, false], r) + end + + def test_gid_sid_available? + r = Process::GID.sid_available? + assert_include([true, false], r) + end + + def test_pst_inspect + assert_nothing_raised { Process::Status.allocate.inspect } + end + + def test_wait_and_sigchild + 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" + end + signal_received = [] + Signal.trap(:CHLD) { signal_received << true } + pid = nil + IO.pipe do |r, w| + pid = fork { r.read(1); exit } + Thread.start { raise } + w.puts + end + Process.wait pid + 10.times do + break unless signal_received.empty? + sleep 0.01 + end + assert_equal [true], signal_received, " [ruby-core:19744]" + rescue NotImplementedError, ArgumentError + ensure + begin + Signal.trap(:CHLD, 'DEFAULT') + rescue ArgumentError + end + end + + def test_no_curdir + with_tmpchdir {|d| + Dir.mkdir("vd") + status = nil + Dir.chdir("vd") { + dir = "#{d}/vd" + # OpenSolaris cannot remove the current directory. + system(RUBY, "--disable-gems", "-e", "Dir.chdir '..'; Dir.rmdir #{dir.dump}", err: File::NULL) + system({"RUBYLIB"=>nil}, RUBY, "--disable-gems", "-e", "exit true") + status = $? + } + assert_predicate(status, :success?, "[ruby-dev:38105]") + } + end + + def test_fallback_to_sh + feature = '[ruby-core:32745]' + with_tmpchdir do |d| + open("tmp_script.#{$$}", "w") {|f| f.puts ": ;"; f.chmod(0755)} + assert_not_nil(pid = Process.spawn("./tmp_script.#{$$}"), feature) + wpid, st = Process.waitpid2(pid) + assert_equal([pid, true], [wpid, st.success?], feature) + + open("tmp_script.#{$$}", "w") {|f| f.puts "echo $#: $@"; f.chmod(0755)} + result = IO.popen(["./tmp_script.#{$$}", "a b", "c"]) {|f| f.read} + assert_equal("2: a b c\n", result, feature) + + open("tmp_script.#{$$}", "w") {|f| f.puts "echo $hghg"; f.chmod(0755)} + result = IO.popen([{"hghg" => "mogomogo"}, "./tmp_script.#{$$}", "a b", "c"]) {|f| f.read} + assert_equal("mogomogo\n", result, feature) + + end + end if File.executable?("/bin/sh") + + def test_spawn_too_long_path + bug4314 = '[ruby-core:34842]' + assert_fail_too_long_path(%w"echo", bug4314) + end + + def test_aspawn_too_long_path + bug4315 = '[ruby-core:34833]' + assert_fail_too_long_path(%w"echo |", bug4315) + end + + def assert_fail_too_long_path((cmd, sep), mesg) + sep ||= "" + min = 1_000 / (cmd.size + sep.size) + cmds = Array.new(min, cmd) + exs = [Errno::ENOENT] + exs << Errno::E2BIG if defined?(Errno::E2BIG) + EnvUtil.suppress_warning do + assert_raise(*exs, mesg) do + begin + loop do + Process.spawn(cmds.join(sep), [STDOUT, STDERR]=>File::NULL) + min = [cmds.size, min].max + cmds *= 100 + end + rescue NoMemoryError + size = cmds.size + raise if min >= size - 1 + min = [min, size /= 2].max + cmds[size..-1] = [] + raise if size < 250 + retry + end + end + end + end + + def test_system_sigpipe + return if windows? + + pid = 0 + + with_tmpchdir do + assert_nothing_raised('[ruby-dev:12261]') do + timeout(3) do + pid = spawn('yes | ls') + Process.waitpid pid + end + end + end + ensure + Process.kill(:KILL, pid) if (pid != 0) rescue false + end + + if Process.respond_to?(:daemon) + def test_daemon_default + data = IO.popen("-", "r+") do |f| + break f.read if f + Process.daemon + puts "ng" + end + assert_equal("", data) + end + + def test_daemon_noclose + data = IO.popen("-", "r+") do |f| + break f.read if f + Process.daemon(false, true) + puts "ok", Dir.pwd + end + assert_equal("ok\n/\n", data) + end + + def test_daemon_nochdir_noclose + data = IO.popen("-", "r+") do |f| + break f.read if f + Process.daemon(true, true) + puts "ok", Dir.pwd + end + assert_equal("ok\n#{Dir.pwd}\n", data) + end + + def test_daemon_readwrite + data = IO.popen("-", "r+") do |f| + if f + f.puts "ok?" + break f.read + end + Process.daemon(true, true) + puts STDIN.gets + end + assert_equal("ok?\n", data) + end + + def test_daemon_pid + cpid, dpid = IO.popen("-", "r+") do |f| + break f.pid, Integer(f.read) if f + Process.daemon(false, true) + puts $$ + end + assert_not_equal(cpid, dpid) + end + + if File.directory?("/proc/self/task") && /netbsd[a-z]*[1-6]/ !~ RUBY_PLATFORM + def test_daemon_no_threads + pid, data = IO.popen("-", "r+") do |f| + break f.pid, f.readlines if f + Process.daemon(true, true) + puts Dir.entries("/proc/self/task") - %W[. ..] + end + bug4920 = '[ruby-dev:43873]' + assert_equal(2, data.size, bug4920) + assert_not_include(data.map(&:to_i), pid) + end + else # darwin + def test_daemon_no_threads + data = Timeout.timeout(3) do + IO.popen("-") do |f| + break f.readlines.map(&:chomp) if f + th = Thread.start {sleep 3} + Process.daemon(true, true) + puts Thread.list.size, th.status.inspect + end + end + assert_equal(["1", "false"], data) + end + end + end + + def test_popen_cloexec + return unless defined? Fcntl::FD_CLOEXEC + IO.popen([RUBY, "-e", ""]) {|io| + assert_predicate(io, :close_on_exec?) + } + end + + def test_execopts_new_pgroup + return unless windows? + + assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>true) } + assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>false) } + assert_nothing_raised { spawn(*TRUECOMMAND, :new_pgroup=>true) } + assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} } + end + + def test_execopts_uid + feature6975 = '[ruby-core:47414]' + + [30000, [Process.uid, ENV["USER"]]].each do |uid, user| + if user + assert_nothing_raised(feature6975) do + begin + system(*TRUECOMMAND, uid: user) + rescue Errno::EPERM, NotImplementedError + end + end + end + + assert_nothing_raised(feature6975) do + begin + system(*TRUECOMMAND, uid: uid) + rescue Errno::EPERM, NotImplementedError + end + end + + assert_nothing_raised(feature6975) do + begin + u = IO.popen([RUBY, "-e", "print Process.uid", uid: user||uid], &:read) + assert_equal(uid.to_s, u, feature6975) + rescue Errno::EPERM, NotImplementedError + end + end + end + end + + def test_execopts_gid + skip "Process.groups not implemented on Windows platform" if windows? + feature6975 = '[ruby-core:47414]' + + [30000, *Process.groups.map {|g| g = Etc.getgrgid(g); [g.name, g.gid]}].each do |group, gid| + assert_nothing_raised(feature6975) do + begin + system(*TRUECOMMAND, gid: group) + rescue Errno::EPERM, NotImplementedError + end + end + + gid = "#{gid || group}" + assert_nothing_raised(feature6975) do + begin + g = IO.popen([RUBY, "-e", "print Process.gid", gid: group], &:read) + assert_equal(gid, g, feature6975) + rescue Errno::EPERM, NotImplementedError + end + end + end + end + + def test_sigpipe + system(RUBY, "-e", "") + with_pipe {|r, w| + r.close + assert_raise(Errno::EPIPE) { w.print "a" } + } + end + + def test_sh_comment + IO.popen("echo a # fofoof") {|f| + assert_equal("a\n", f.read) + } + end if File.executable?("/bin/sh") + + def test_sh_env + IO.popen("foofoo=barbar env") {|f| + lines = f.readlines + assert_operator(lines, :include?, "foofoo=barbar\n") + } + end if File.executable?("/bin/sh") + + def test_sh_exec + IO.popen("exec echo exexexec") {|f| + assert_equal("exexexec\n", f.read) + } + end if File.executable?("/bin/sh") + + def test_setsid + return unless Process.respond_to?(:setsid) + return unless Process.respond_to?(:getsid) + # OpenBSD and AIX don't allow Process::getsid(pid) when pid is in + # different session. + return if /openbsd|aix/ =~ RUBY_PLATFORM + + IO.popen([RUBY, "-e", <<EOS]) do|io| + Marshal.dump(Process.getsid, STDOUT) + newsid = Process.setsid + Marshal.dump(newsid, STDOUT) + STDOUT.flush + # getsid() on MacOS X return ESRCH when target process is zombie + # even if it is valid process id. + sleep +EOS + begin + # test Process.getsid() w/o arg + assert_equal(Marshal.load(io), Process.getsid) + + # test Process.setsid return value and Process::getsid(pid) + assert_equal(Marshal.load(io), Process.getsid(io.pid)) + ensure + Process.kill(:KILL, io.pid) rescue nil + Process.wait(io.pid) + end + end + end + + def test_spawn_nonascii + bug1771 = '[ruby-core:24309] [Bug #1771]' + + with_tmpchdir do + [ + "\u{7d05 7389}", + "zuf\u{00E4}llige_\u{017E}lu\u{0165}ou\u{010D}k\u{00FD}_\u{10D2 10D0 10DB 10D4 10DD 10E0 10D4 10D1}_\u{0440 0430 0437 043B 043E 0433 0430}_\u{548C 65B0 52A0 5761 4EE5 53CA 4E1C}", + "c\u{1EE7}a", + ].each do |name| + msg = "#{bug1771} #{name}" + exename = "./#{name}.exe" + FileUtils.cp(ENV["COMSPEC"], exename) + assert_equal(true, system("#{exename} /c exit"), msg) + system("#{exename} /c exit 12") + assert_equal(12, $?.exitstatus, msg) + _, status = Process.wait2(Process.spawn("#{exename} /c exit 42")) + assert_equal(42, status.exitstatus, msg) + assert_equal("ok\n", `#{exename} /c echo ok`, msg) + assert_equal("ok\n", IO.popen("#{exename} /c echo ok", &:read), msg) + assert_equal("ok\n", IO.popen(%W"#{exename} /c echo ok", &:read), msg) + File.binwrite("#{name}.txt", "ok") + assert_equal("ok", `type #{name}.txt`) + end + end + end if windows? + + def test_clock_gettime + t1 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) + t2 = Time.now; t2 = t2.tv_sec * 1000000000 + t2.tv_nsec + t3 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) + assert_operator(t1, :<=, t2) + assert_operator(t2, :<=, t3) + assert_raise(Errno::EINVAL) { Process.clock_gettime(:foo) } + end + + def test_clock_gettime_unit + t0 = Time.now.to_f + [ + [:nanosecond, 1_000_000_000], + [:microsecond, 1_000_000], + [:millisecond, 1_000], + [:second, 1], + [:float_microsecond, 1_000_000.0], + [:float_millisecond, 1_000.0], + [:float_second, 1.0], + [nil, 1.0], + [:foo], + ].each do |unit, num| + unless num + assert_raise(ArgumentError){ Process.clock_gettime(Process::CLOCK_REALTIME, unit) } + next + end + t1 = Process.clock_gettime(Process::CLOCK_REALTIME, unit) + assert_kind_of num.integer? ? Integer : num.class, t1, [unit, num].inspect + assert_in_delta t0, t1/num, 1, [unit, num].inspect + end + end + + def test_clock_gettime_constants + Process.constants.grep(/\ACLOCK_/).each {|n| + c = Process.const_get(n) + begin + t = Process.clock_gettime(c) + rescue Errno::EINVAL + next + end + assert_kind_of(Float, t, "Process.clock_gettime(Process::#{n})") + } + end + + def test_clock_gettime_GETTIMEOFDAY_BASED_CLOCK_REALTIME + n = :GETTIMEOFDAY_BASED_CLOCK_REALTIME + t = Process.clock_gettime(n) + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_TIME_BASED_CLOCK_REALTIME + n = :TIME_BASED_CLOCK_REALTIME + t = Process.clock_gettime(n) + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_TIMES_BASED_CLOCK_MONOTONIC + n = :TIMES_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_gettime(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID + begin + t = Process.clock_gettime(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID + begin + t = Process.clock_gettime(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID + t = Process.clock_gettime(n) + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_gettime_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC + n = :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_gettime(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + + def test_clock_getres + r = Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond) + rescue Errno::EINVAL + else + assert_kind_of(Integer, r) + assert_raise(Errno::EINVAL) { Process.clock_getres(:foo) } + end + + def test_clock_getres_constants + Process.constants.grep(/\ACLOCK_/).each {|n| + c = Process.const_get(n) + begin + t = Process.clock_getres(c) + rescue Errno::EINVAL + next + end + assert_kind_of(Float, t, "Process.clock_getres(Process::#{n})") + } + end + + def test_clock_getres_GETTIMEOFDAY_BASED_CLOCK_REALTIME + n = :GETTIMEOFDAY_BASED_CLOCK_REALTIME + t = Process.clock_getres(n) + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + assert_equal(1000, Process.clock_getres(n, :nanosecond)) + end + + def test_clock_getres_TIME_BASED_CLOCK_REALTIME + n = :TIME_BASED_CLOCK_REALTIME + t = Process.clock_getres(n) + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + assert_equal(1000000000, Process.clock_getres(n, :nanosecond)) + end + + def test_clock_getres_TIMES_BASED_CLOCK_MONOTONIC + n = :TIMES_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_getres(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + f = Process.clock_getres(n, :hertz) + assert_equal(0, f - f.floor) + end + + def test_clock_getres_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID + begin + t = Process.clock_getres(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + assert_equal(1000, Process.clock_getres(n, :nanosecond)) + end + + def test_clock_getres_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID + begin + t = Process.clock_getres(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + f = Process.clock_getres(n, :hertz) + assert_equal(0, f - f.floor) + end + + def test_clock_getres_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID + n = :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID + t = Process.clock_getres(n) + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + f = Process.clock_getres(n, :hertz) + assert_equal(0, f - f.floor) + end + + def test_clock_getres_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC + n = :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_getres(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + end + + def test_deadlock_by_signal_at_forking + assert_separately([], <<-INPUT, timeout: 60) + require 'io/wait' + begin + GC.start # reduce garbage + buf = '' + ruby = EnvUtil.rubybin + er, ew = IO.pipe + unless runner = IO.popen("-".freeze) + er.close + status = true + GC.disable # avoid triggering CoW after forks + begin + $stderr.reopen($stdout) + trap(:QUIT) {} + parent = $$ + 100.times do |i| + pid = fork {Process.kill(:QUIT, parent)} + IO.popen(ruby, 'r+'.freeze){} + Process.wait(pid) + $stdout.puts + $stdout.flush + end + ensure + if $! + ew.puts([Marshal.dump($!)].pack("m0")) + status = false + end + ew.close + exit!(status) + end + end + ew.close + begin + loop do + runner.wait_readable(5) + runner.read_nonblock(100, buf) + end + rescue EOFError => e + _, status = Process.wait2(runner.pid) + rescue IO::WaitReadable => e + Process.kill(:INT, runner.pid) + exc = Marshal.load(er.read.unpack("m")[0]) + if exc.kind_of? Interrupt + # Don't raise Interrupt. It aborts test-all. + flunk "timeout" + else + raise exc + end + end + assert_predicate(status, :success?) + ensure + er.close unless er.closed? + ew.close unless ew.closed? + if runner + begin + Process.kill(:TERM, runner.pid) + sleep 1 + Process.kill(:KILL, runner.pid) + rescue Errno::ESRCH + end + runner.close + end + end + INPUT + end if defined?(fork) + + def test_process_detach + pid = fork {} + th = Process.detach(pid) + assert_equal pid, th.pid + status = th.value + assert status.success?, status.inspect + end if defined?(fork) +end diff --git a/jni/ruby/test/ruby/test_rand.rb b/jni/ruby/test/ruby/test_rand.rb new file mode 100644 index 0000000..d2a1244 --- /dev/null +++ b/jni/ruby/test/ruby/test_rand.rb @@ -0,0 +1,527 @@ +require 'test/unit' + +class TestRand < Test::Unit::TestCase + def assert_random_int(ws, m, init = 0) + srand(init) + rnds = [Random.new(init)] + rnds2 = [rnds[0].dup] + rnds3 = [rnds[0].dup] + ws.each_with_index do |w, i| + w = w.to_i + assert_equal(w, rand(m)) + rnds.each do |rnd| + assert_equal(w, rnd.rand(m)) + end + rnds2.each do |rnd| + r=rnd.rand(i...(m+i)) + assert_equal(w+i, r) + end + rnds3.each do |rnd| + r=rnd.rand(i..(m+i-1)) + assert_equal(w+i, r) + end + rnds << Marshal.load(Marshal.dump(rnds[-1])) + rnds2 << Marshal.load(Marshal.dump(rnds2[-1])) + end + end + + def test_mt + assert_random_int(%w(1067595299 955945823 477289528 4107218783 4228976476), + 0x100000000, 0x00000456_00000345_00000234_00000123) + end + + def test_0x3fffffff + assert_random_int(%w(209652396 398764591 924231285 404868288 441365315), + 0x3fffffff) + end + + def test_0x40000000 + assert_random_int(%w(209652396 398764591 924231285 404868288 441365315), + 0x40000000) + end + + def test_0x40000001 + assert_random_int(%w(209652396 398764591 924231285 441365315 192771779), + 0x40000001) + end + + def test_0xffffffff + assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963), + 0xffffffff) + end + + def test_0x100000000 + assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963), + 0x100000000) + end + + def test_0x100000001 + assert_random_int(%w(2546248239 1277901399 243580376 1171049868 2051556033), + 0x100000001) + end + + def test_rand_0x100000000 + assert_random_int(%w(4119812344 3870378946 80324654 4294967296 410016213), + 0x100000001, 311702798) + end + + def test_0x1000000000000 + assert_random_int(%w(11736396900911 + 183025067478208 + 197104029029115 + 130583529618791 + 180361239846611), + 0x1000000000000) + end + + def test_0x1000000000001 + assert_random_int(%w(187121911899765 + 197104029029115 + 180361239846611 + 236336749852452 + 208739549485656), + 0x1000000000001) + end + + def test_0x3fffffffffffffff + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 3203365596207111891), + 0x3fffffffffffffff) + end + + def test_0x4000000000000000 + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 3203365596207111891), + 0x4000000000000000) + end + + def test_0x4000000000000001 + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 2279347887019741461), + 0x4000000000000001) + end + + def test_0x10000000000 + ws = %w(455570294424 1073054410371 790795084744 2445173525 1088503892627) + assert_random_int(ws, 0x10000000000, 3) + end + + def test_0x10000 + ws = %w(2732 43567 42613 52416 45891) + assert_random_int(ws, 0x10000) + end + + def test_types + srand(0) + rnd = Random.new(0) + assert_equal(44, rand(100.0)) + assert_equal(44, rnd.rand(100)) + assert_equal(1245085576965981900420779258691, rand((2**100).to_f)) + assert_equal(1245085576965981900420779258691, rnd.rand(2**100)) + assert_equal(914679880601515615685077935113, rand(-(2**100).to_f)) + + srand(0) + rnd = Random.new(0) + assert_equal(997707939797331598305742933184, rand(2**100)) + assert_equal(997707939797331598305742933184, rnd.rand(2**100)) + assert_in_delta(0.602763376071644, rand((2**100).coerce(0).first), + 0.000000000000001) + assert_raise(ArgumentError) {rnd.rand((2**100).coerce(0).first)} + + srand(0) + rnd = Random.new(0) + assert_in_delta(0.548813503927325, rand(nil), + 0.000000000000001) + assert_in_delta(0.548813503927325, rnd.rand(), + 0.000000000000001) + srand(0) + rnd = Random.new(0) + o = Object.new + def o.to_int; 100; end + assert_equal(44, rand(o)) + assert_equal(44, rnd.rand(o)) + assert_equal(47, rand(o)) + assert_equal(47, rnd.rand(o)) + assert_equal(64, rand(o)) + assert_equal(64, rnd.rand(o)) + end + + def test_srand + srand + assert_kind_of(Integer, rand(2)) + assert_kind_of(Integer, Random.new.rand(2)) + + srand(2**100) + rnd = Random.new(2**100) + %w(3258412053).each {|w| + assert_equal(w.to_i, rand(0x100000000)) + assert_equal(w.to_i, rnd.rand(0x100000000)) + } + end + + def test_shuffle + srand(0) + result = [*1..5].shuffle + assert_equal([*1..5], result.sort) + assert_equal(result, [*1..5].shuffle(random: Random.new(0))) + end + + def test_big_seed + assert_random_int(%w(2757555016), 0x100000000, 2**1000000-1) + end + + def test_random_gc + r = Random.new(0) + %w(2357136044 2546248239 3071714933).each do |w| + assert_equal(w.to_i, r.rand(0x100000000)) + end + GC.start + %w(3626093760 2588848963 3684848379).each do |w| + assert_equal(w.to_i, r.rand(0x100000000)) + end + end + + def test_random_type_error + assert_raise(TypeError) { Random.new(Object.new) } + assert_raise(TypeError) { Random.new(0).rand(Object.new) } + end + + def test_random_argument_error + r = Random.new(0) + assert_raise(ArgumentError) { r.rand(0, 0) } + assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1) } + assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1.0) } + assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(0) } + assert_equal(0, r.rand(1), '[ruby-dev:39166]') + assert_equal(0, r.rand(0...1), '[ruby-dev:39166]') + assert_equal(0, r.rand(0..0), '[ruby-dev:39166]') + assert_equal(0.0, r.rand(0.0..0.0), '[ruby-dev:39166]') + assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0...0) } + assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0..-1) } + assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...0.0) } + assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...-0.1) } + bug3027 = '[ruby-core:29075]' + assert_raise(ArgumentError, bug3027) { r.rand(nil) } + end + + def test_random_seed + assert_equal(0, Random.new(0).seed) + assert_equal(0x100000000, Random.new(0x100000000).seed) + assert_equal(2**100, Random.new(2**100).seed) + end + + def test_random_dup + r1 = Random.new(0) + r2 = r1.dup + %w(2357136044 2546248239 3071714933).each do |w| + assert_equal(w.to_i, r1.rand(0x100000000)) + end + %w(2357136044 2546248239 3071714933).each do |w| + assert_equal(w.to_i, r2.rand(0x100000000)) + end + r2 = r1.dup + %w(3626093760 2588848963 3684848379).each do |w| + assert_equal(w.to_i, r1.rand(0x100000000)) + end + %w(3626093760 2588848963 3684848379).each do |w| + assert_equal(w.to_i, r2.rand(0x100000000)) + end + end + + def test_random_state + state = <<END +3877134065023083674777481835852171977222677629000095857864323111193832400974413 +4782302161934463784850675209112299537259006497924090422596764895633625964527441 +6943943249411681406395713106007661119327771293929504639878577616749110507385924 +0173026285378896836022134086386136835407107422834685854738117043791709411958489 +3504364936306163473541948635570644161010981140452515307286926529085424765299100 +1255453260115310687580777474046203049197643434654645011966794531914127596390825 +0832232869378617194193100828000236737535657699356156021286278281306055217995213 +8911536025132779573429499813926910299964681785069915877910855089314686097947757 +2621451199734871158015842198110309034467412292693435515184023707918034746119728 +8223459645048255809852819129671833854560563104716892857257229121211527031509280 +2390605053896565646658122125171846129817536096211475312518457776328637574563312 +8113489216547503743508184872149896518488714209752552442327273883060730945969461 +6568672445225657265545983966820639165285082194907591432296265618266901318398982 +0560425129536975583916120558652408261759226803976460322062347123360444839683204 +9868507788028894111577023917218846128348302845774997500569465902983227180328307 +3735301552935104196244116381766459468172162284042207680945316590536094294865648 +5953156978630954893391701383648157037914019502853776972615500142898763385846315 +8457790690531675205213829055442306187692107777193071680668153335688203945049935 +3404449910419303330872435985327845889440458370416464132629866593538629877042969 +7589948685901343135964343582727302330074331803900821801076139161904900333497836 +6627028345784450211920229170280462474456504317367706849373957309797251052447898 +8436235456995644876515032202483449807136139063937892187299239634252391529822163 +9187055268750679730919937006195967184206072757082920250075756273182004964087790 +3812024063897424219316687828337007888030994779068081666133751070479581394604974 +6022215489604777611774245181115126041390161592199230774968475944753915533936834 +4740049163514318351045644344358598159463605453475585370226041981040238023241538 +4958436364776113598408428801867643946791659645708540669432995503575075657406359 +8086928867900590554805639837071298576728564946552163206007997000988745940681607 +4542883814997403673656291618517107133421335645430345871041730410669209035640945 +5024601618318371192091626092482640364669969307766919645222516407626038616667754 +5781148898846306894862390724358039251444333889446128074209417936830253204064223 +3424784857908022314095011879203259864909560830176189727132432100010493659154644 +8407326292884826469503093409465946018496358514999175268200846200025235441426140 +7783386235191526371372655894290440356560751680752191224383460972099834655086068 +9989413443881686756951804138910911737670495391762470293978321414964443502180391 +4665982575919524372985773336921990352313629822677022891307943536442258282401255 +5387646898976193134193506239982621725093291970351083631367582570375381334759004 +1784150668048523676387894646666460369896619585113435743180899362844070393586212 +5023920017185866399742380706352739465848708746963693663004068892056705603018655 +8686663087894205699555906146534549176352859823832196938386172810274748624517052 +8356758650653040545267425513047130342286119889879774951060662713807133125543465 +5104086026298674827575216701372513525846650644773241437066782037334367982012148 +7987782004646896468089089826267467005660035604553432197455616078731159778086155 +9443250946037119223468305483694093795324036812927501783593256716590840500905291 +2096608538205270323065573109227029887731553399324547696295234105140157179430410 +4003109602564833086703863221058381556776789018351726488797845637981974580864082 +1630093543020854542240690897858757985640869209737744458407777584279553258261599 +0246922348101147034463235613998979344685018577901996218099622190722307356620796 +5137485271371502385527388080824050288371607602101805675021790116223360483508538 +8832149997794718410946818866375912486788005950091851067237358294899771385995876 +7088239104394332452501033090159333224995108984871426750597513314521294001864578 +2353528356752869732412552685554334966798888534847483030947310518891788722418172 +6008607577773612004956373863580996793809969715725508939568919714424871639667201 +7922255031431159347210833846575355772055570279673262115911154370983086189948124 +4653677615895887099814174914248255026619941911735341818489822197472499295786997 +7728418516719104857455960900092226749725407204388193002835497055305427730656889 +1508308778869166073740855838213112709306743479676740893150000714099064468263284 +1873435518542972182497755500300784177067568586395485329021157235696300013490087 +2866571034916258390528533374944905429089028336079264760836949419754851422499614 +5732326011260304142074554782259843903215064144396140106592193961703288125005023 +5334375212799817540775536847622032852415253966587517800661605905489339306359573 +2234947905196298436841723673626428243649931398749552780311877734063703985375067 +1239508613417041942487245370152912391885566432830659640677893488723724763120121 +4111855277511356759926232894062814360449757490961653026194107761340614059045172 +1123363102660719217740126157997033682099769790976313166682432732518101889210276 +9574144065390305904944821051736021310524344626348851573631697771556587859836330 +6997324121866564283654784470215100159122764509197570402997911258816526554863326 +9877535269005418736225944874608987238997316999444215865249840762640949599725696 +0773083894168959823152054508672272612355108904098579447774398451678239199426513 +3439507737424049578587487505080347686371029156845461151278198605267053408259090 +3158676794894709281917034995611352710898103415304769654883981727681820369090169 +9295163908214854813365413456264812190842699054830709079275249714169405719140093 +1347572458245530016346604698682269779841803667099480215265926316505737171177810 +9969036572310084022695109125200937135540995157279354438704321290061646592229860 +0156566013602344870223183295508278359111174872740360473845615437106413256386849 +2286259982118315248148847764929974917157683083659364623458927512616369119194574 +2254080 +END + state = state.split.join.to_i + r = Random.new(0) + srand(0) + assert_equal(state, r.instance_eval { state }) + assert_equal(state, Random.instance_eval { state }) + r.rand(0x100) + assert_equal(state, r.instance_eval { state }) + end + + def test_random_left + r = Random.new(0) + assert_equal(1, r.instance_eval { left }) + r.rand(0x100) + assert_equal(624, r.instance_eval { left }) + r.rand(0x100) + assert_equal(623, r.instance_eval { left }) + srand(0) + assert_equal(1, Random.instance_eval { left }) + rand(0x100) + assert_equal(624, Random.instance_eval { left }) + rand(0x100) + assert_equal(623, Random.instance_eval { left }) + end + + def test_random_bytes + assert_random_bytes(Random.new(0)) + end + + def assert_random_bytes(r) + assert_equal("", r.bytes(0)) + assert_equal("\xAC".force_encoding("ASCII-8BIT"), r.bytes(1)) + assert_equal("/\xAA\xC4\x97u\xA6\x16\xB7\xC0\xCC".force_encoding("ASCII-8BIT"), + r.bytes(10)) + end + + def test_random_range + srand(0) + r = Random.new(0) + %w(9 5 8).each {|w| + assert_equal(w.to_i, rand(5..9)) + assert_equal(w.to_i, r.rand(5..9)) + } + %w(-237 731 383).each {|w| + assert_equal(w.to_i, rand(-1000..1000)) + assert_equal(w.to_i, r.rand(-1000..1000)) + } + %w(1267650600228229401496703205382 + 1267650600228229401496703205384 + 1267650600228229401496703205383).each do |w| + assert_equal(w.to_i, rand(2**100+5..2**100+9)) + assert_equal(w.to_i, r.rand(2**100+5..2**100+9)) + end + + v = rand(3.1..4) + assert_instance_of(Float, v, '[ruby-core:24679]') + assert_include(3.1..4, v) + + v = r.rand(3.1..4) + assert_instance_of(Float, v, '[ruby-core:24679]') + assert_include(3.1..4, v) + + now = Time.now + assert_equal(now, rand(now..now)) + assert_equal(now, r.rand(now..now)) + end + + def test_random_float + r = Random.new(0) + assert_in_delta(0.5488135039273248, r.rand, 0.0001) + assert_in_delta(0.7151893663724195, r.rand, 0.0001) + assert_in_delta(0.6027633760716439, r.rand, 0.0001) + assert_in_delta(1.0897663659937937, r.rand(2.0), 0.0001) + assert_in_delta(5.3704626067153264e+29, r.rand((2**100).to_f), 10**25) + + assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(1.0 / 0.0) } + assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(0.0 / 0.0) } + + r = Random.new(0) + assert_in_delta(1.5488135039273248, r.rand(1.0...2.0), 0.0001, '[ruby-core:24655]') + assert_in_delta(1.7151893663724195, r.rand(1.0...2.0), 0.0001, '[ruby-core:24655]') + assert_in_delta(7.027633760716439, r.rand(1.0...11.0), 0.0001, '[ruby-core:24655]') + assert_in_delta(3.0897663659937937, r.rand(2.0...4.0), 0.0001, '[ruby-core:24655]') + + assert_nothing_raised {r.rand(-Float::MAX..Float::MAX)} + end + + def test_random_equal + r = Random.new(0) + assert_equal(r, r) + assert_equal(r, r.dup) + r1 = r.dup + r2 = r.dup + r1.rand(0x100) + assert_not_equal(r1, r2) + r2.rand(0x100) + assert_equal(r1, r2) + end + + def test_fork_shuffle + pid = fork do + (1..10).to_a.shuffle + raise 'default seed is not set' if srand == 0 + end + _, st = Process.waitpid2(pid) + assert_predicate(st, :success?, "#{st.inspect}") + rescue NotImplementedError, ArgumentError + end + + def assert_fork_status(n, mesg, &block) + IO.pipe do |r, w| + (1..n).map do + p1 = fork {w.puts(block.call.to_s)} + _, st = Process.waitpid2(p1) + assert_send([st, :success?], mesg) + r.gets.strip + end + end + end + + def test_rand_reseed_on_fork + GC.start + bug5661 = '[ruby-core:41209]' + + assert_fork_status(1, bug5661) {Random.rand(4)} + r1, r2 = *assert_fork_status(2, bug5661) {Random.rand} + assert_not_equal(r1, r2, bug5661) + + assert_fork_status(1, bug5661) {rand(4)} + r1, r2 = *assert_fork_status(2, bug5661) {rand} + assert_not_equal(r1, r2, bug5661) + + stable = Random.new + assert_fork_status(1, bug5661) {stable.rand(4)} + r1, r2 = *assert_fork_status(2, bug5661) {stable.rand} + assert_equal(r1, r2, bug5661) + rescue NotImplementedError + end + + def test_seed + bug3104 = '[ruby-core:29292]' + rand_1 = Random.new(-1).rand + assert_not_equal(rand_1, Random.new((1 << 31) -1).rand, "#{bug3104} (2)") + assert_not_equal(rand_1, Random.new((1 << 63) -1).rand, "#{bug3104} (2)") + + [-1, -2**10, -2**40].each {|n| + b = (2**64).coerce(n)[0] + r1 = Random.new(n).rand + r2 = Random.new(b).rand + assert_equal(r1, r2) + } + end + + def test_default + r1 = Random::DEFAULT.dup + r2 = Random::DEFAULT.dup + 3.times do + x0 = rand + x1 = r1.rand + x2 = r2.rand + assert_equal(x0, x1) + assert_equal(x0, x2) + end + end + + def test_marshal + bug3656 = '[ruby-core:31622]' + assert_raise(TypeError, bug3656) { + Random.new.__send__(:marshal_load, 0) + } + end + + def test_initialize_frozen + r = Random.new(0) + r.freeze + assert_raise(RuntimeError, '[Bug #6540]') do + r.__send__(:initialize, r) + end + end + + def test_marshal_load_frozen + r = Random.new(0) + d = r.__send__(:marshal_dump) + r.freeze + assert_raise(RuntimeError, '[Bug #6540]') do + r.__send__(:marshal_load, d) + end + end + + def test_random_ulong_limited + def (gen = Object.new).rand(*) 1 end + assert_equal([2], (1..100).map {[1,2,3].sample(random: gen)}.uniq) + + def (gen = Object.new).rand(*) 100 end + assert_raise_with_message(RangeError, /big 100\z/) {[1,2,3].sample(random: gen)} + + bug7903 = '[ruby-dev:47061] [Bug #7903]' + def (gen = Object.new).rand(*) -1 end + assert_raise_with_message(RangeError, /small -1\z/, bug7903) {[1,2,3].sample(random: gen)} + + bug7935 = '[ruby-core:52779] [Bug #7935]' + class << (gen = Object.new) + def rand(limit) @limit = limit; 0 end + attr_reader :limit + end + [1, 2].sample(1, random: gen) + assert_equal(2, gen.limit, bug7935) + end +end diff --git a/jni/ruby/test/ruby/test_range.rb b/jni/ruby/test/ruby/test_range.rb new file mode 100644 index 0000000..852515f --- /dev/null +++ b/jni/ruby/test/ruby/test_range.rb @@ -0,0 +1,583 @@ +require 'test/unit' +require 'delegate' +require 'timeout' +require 'bigdecimal' + +class TestRange < Test::Unit::TestCase + def test_range_string + # XXX: Is this really the test of Range? + assert_equal([], ("a" ... "a").to_a) + assert_equal(["a"], ("a" .. "a").to_a) + assert_equal(["a"], ("a" ... "b").to_a) + assert_equal(["a", "b"], ("a" .. "b").to_a) + end + + def test_range_numeric_string + assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]") + assert_equal(["6", "7"], ("6"..."8").to_a) + assert_equal(["9", "10"], ("9".."10").to_a) + assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]") + assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a) + assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a) + end + + def test_range_symbol + assert_equal([:a, :b], (:a .. :b).to_a) + end + + def test_evaluation_order + arr = [1,2] + r = (arr.shift)..(arr.shift) + assert_equal(1..2, r, "[ruby-dev:26383]") + end + + class DuckRange + def initialize(b,e,excl=false) + @begin = b + @end = e + @excl = excl + end + attr_reader :begin, :end + + def exclude_end? + @excl + end + end + + def test_duckrange + assert_equal("bc", "abcd"[DuckRange.new(1,2)]) + end + + def test_min + assert_equal(1, (1..2).min) + assert_equal(nil, (2..1).min) + assert_equal(1, (1...2).min) + + assert_equal(1.0, (1.0..2.0).min) + assert_equal(nil, (2.0..1.0).min) + assert_equal(1, (1.0...2.0).min) + + assert_equal(0, (0..0).min) + assert_equal(nil, (0...0).min) + + assert_equal([0,1,2], (0..10).min(3)) + assert_equal([0,1], (0..1).min(3)) + end + + def test_max + assert_equal(2, (1..2).max) + assert_equal(nil, (2..1).max) + assert_equal(1, (1...2).max) + + assert_equal(2.0, (1.0..2.0).max) + assert_equal(nil, (2.0..1.0).max) + assert_raise(TypeError) { (1.0...2.0).max } + assert_raise(TypeError) { (1...1.5).max } + assert_raise(TypeError) { (1.5...2).max } + + assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max) + + assert_equal(0, (0..0).max) + assert_equal(nil, (0...0).max) + + assert_equal([10,9,8], (0..10).max(3)) + assert_equal([9,8,7], (0...10).max(3)) + end + + def test_initialize_twice + r = eval("1..2") + assert_raise(NameError) { r.instance_eval { initialize 3, 4 } } + assert_raise(NameError) { r.instance_eval { initialize_copy 3..4 } } + end + + def test_uninitialized_range + r = Range.allocate + s = Marshal.dump(r) + r = Marshal.load(s) + assert_nothing_raised { r.instance_eval { initialize 5, 6} } + end + + def test_bad_value + assert_raise(ArgumentError) { (1 .. :a) } + end + + def test_exclude_end + assert_not_predicate(0..1, :exclude_end?) + assert_predicate(0...1, :exclude_end?) + end + + def test_eq + r = (0..1) + assert_equal(r, r) + assert_equal(r, (0..1)) + assert_not_equal(r, 0) + assert_not_equal(r, (1..2)) + assert_not_equal(r, (0..2)) + assert_not_equal(r, (0...1)) + subclass = Class.new(Range) + assert_equal(r, subclass.new(0,1)) + end + + def test_eql + r = (0..1) + assert_operator(r, :eql?, r) + assert_operator(r, :eql?, 0..1) + assert_not_operator(r, :eql?, 0) + assert_not_operator(r, :eql?, 1..2) + assert_not_operator(r, :eql?, 0..2) + assert_not_operator(r, :eql?, 0...1) + subclass = Class.new(Range) + assert_operator(r, :eql?, subclass.new(0,1)) + end + + def test_hash + assert_kind_of(Fixnum, (0..1).hash) + end + + def test_step + a = [] + (0..10).step {|x| a << x } + assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a) + + a = [] + (0..10).step(2) {|x| a << x } + assert_equal([0, 2, 4, 6, 8, 10], a) + + assert_raise(ArgumentError) { (0..10).step(-1) { } } + assert_raise(ArgumentError) { (0..10).step(0) { } } + + a = [] + ("a" .. "z").step(2) {|x| a << x } + assert_equal(%w(a c e g i k m o q s u w y), a) + + a = [] + ("a" .. "z").step(2**32) {|x| a << x } + assert_equal(["a"], a) + + a = [] + (2**32-1 .. 2**32+1).step(2) {|x| a << x } + assert_equal([4294967295, 4294967297], a) + zero = (2**32).coerce(0).first + assert_raise(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } } + + o1 = Object.new + o2 = Object.new + def o1.<=>(x); -1; end + def o2.<=>(x); 0; end + assert_raise(TypeError) { (o1..o2).step(1) { } } + + class << o1; self; end.class_eval do + define_method(:succ) { o2 } + end + a = [] + (o1..o2).step(1) {|x| a << x } + assert_equal([o1, o2], a) + + a = [] + (o1...o2).step(1) {|x| a << x } + assert_equal([o1], a) + + assert_nothing_raised("[ruby-dev:34557]") { (0..2).step(0.5) {|x| } } + + a = [] + (0..2).step(0.5) {|x| a << x } + assert_equal([0, 0.5, 1.0, 1.5, 2.0], a) + + a = [] + (0x40000000..0x40000002).step(0.5) {|x| a << x } + assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a) + + o = Object.new + def o.to_int() 1 end + assert_nothing_raised("[ruby-dev:34558]") { (0..2).step(o) {|x| } } + end + + def test_step_ruby_core_35753 + assert_equal(6, (1...6.3).step.to_a.size) + assert_equal(5, (1.1...6).step.to_a.size) + assert_equal(5, (1...6).step(1.1).to_a.size) + assert_equal(3, (1.0...5.4).step(1.5).to_a.size) + assert_equal(3, (1.0...5.5).step(1.5).to_a.size) + assert_equal(4, (1.0...5.6).step(1.5).to_a.size) + end + + def test_each + a = [] + (0..10).each {|x| a << x } + assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a) + + o1 = Object.new + o2 = Object.new + def o1.setcmp(v) @cmpresult = v end + o1.setcmp(-1) + def o1.<=>(x); @cmpresult; end + def o2.setcmp(v) @cmpresult = v end + o2.setcmp(0) + def o2.<=>(x); @cmpresult; end + class << o1; self; end.class_eval do + define_method(:succ) { o2 } + end + + r1 = (o1..o2) + r2 = (o1...o2) + + a = [] + r1.each {|x| a << x } + assert_equal([o1, o2], a) + + a = [] + r2.each {|x| a << x } + assert_equal([o1], a) + + o2.setcmp(1) + + a = [] + r1.each {|x| a << x } + assert_equal([o1], a) + + o2.setcmp(nil) + + a = [] + r1.each {|x| a << x } + assert_equal([o1], a) + + o1.setcmp(nil) + + a = [] + r2.each {|x| a << x } + assert_equal([], a) + end + + def test_begin_end + assert_equal(0, (0..1).begin) + assert_equal(1, (0..1).end) + end + + def test_first_last + assert_equal([0, 1, 2], (0..10).first(3)) + assert_equal([8, 9, 10], (0..10).last(3)) + assert_equal(0, (0..10).first) + assert_equal(10, (0..10).last) + assert_equal("a", ("a".."c").first) + assert_equal("c", ("a".."c").last) + assert_equal(0, (2..0).last) + + assert_equal([0, 1, 2], (0...10).first(3)) + assert_equal([7, 8, 9], (0...10).last(3)) + assert_equal(0, (0...10).first) + assert_equal("a", ("a"..."c").first) + end + + def test_to_s + assert_equal("0..1", (0..1).to_s) + assert_equal("0...1", (0...1).to_s) + end + + def test_inspect + assert_equal("0..1", (0..1).inspect) + assert_equal("0...1", (0...1).inspect) + end + + def test_eqq + assert_operator(0..10, :===, 5) + assert_not_operator(0..10, :===, 11) + end + + def test_eqq_time + bug11113 = '[ruby-core:69052] [Bug #11113]' + t = Time.now + assert_nothing_raised(TypeError, bug11113) { + assert_operator(t..(t+10), :===, t+5) + } + end + + def test_include + assert_include("a".."z", "c") + assert_not_include("a".."z", "5") + assert_include("a"..."z", "y") + assert_not_include("a"..."z", "z") + assert_not_include("a".."z", "cc") + assert_include(0...10, 5) + end + + def test_cover + assert_operator("a".."z", :cover?, "c") + assert_not_operator("a".."z", :cover?, "5") + assert_operator("a"..."z", :cover?, "y") + assert_not_operator("a"..."z", :cover?, "z") + assert_operator("a".."z", :cover?, "cc") + end + + def test_beg_len + o = Object.new + assert_raise(TypeError) { [][o] } + class << o; attr_accessor :begin end + o.begin = -10 + assert_raise(TypeError) { [][o] } + class << o; attr_accessor :end end + o.end = 0 + assert_raise(NoMethodError) { [][o] } + def o.exclude_end=(v) @exclude_end = v end + def o.exclude_end?() @exclude_end end + o.exclude_end = false + assert_nil([0][o]) + assert_raise(RangeError) { [0][o] = 1 } + o.begin = 10 + o.end = 10 + assert_nil([0][o]) + o.begin = 0 + assert_equal([0], [0][o]) + o.begin = 2 + o.end = 0 + assert_equal([], [0, 1, 2][o]) + end + + class CyclicRange < Range + def <=>(other); true; end + end + def test_cyclic_range_inspect + o = CyclicRange.allocate + o.instance_eval { initialize(o, 1) } + assert_equal("(... .. ...)..1", o.inspect) + end + + def test_comparison_when_recursive + x = CyclicRange.allocate; x.send(:initialize, x, 1) + y = CyclicRange.allocate; y.send(:initialize, y, 1) + Timeout.timeout(1) { + assert_equal x, y + assert_operator x, :eql?, y + } + + z = CyclicRange.allocate; z.send(:initialize, z, :another) + Timeout.timeout(1) { + assert_not_equal x, z + assert_not_operator x, :eql?, z + } + + x = CyclicRange.allocate + y = CyclicRange.allocate + x.send(:initialize, y, 1) + y.send(:initialize, x, 1) + Timeout.timeout(1) { + assert_equal x, y + assert_operator x, :eql?, y + } + + x = CyclicRange.allocate + z = CyclicRange.allocate + x.send(:initialize, z, 1) + z.send(:initialize, x, :other) + Timeout.timeout(1) { + assert_not_equal x, z + assert_not_operator x, :eql?, z + } + end + + def test_size + assert_equal 42, (1..42).size + assert_equal 41, (1...42).size + assert_equal 6, (1...6.3).size + assert_equal 5, (1.1...6).size + assert_equal 42, (1..42).each.size + end + + def test_bsearch_typechecks_return_values + assert_raise(TypeError) do + (1..42).bsearch{ "not ok" } + end + assert_equal (1..42).bsearch{}, (1..42).bsearch{false} + end + + def test_bsearch_with_no_block + enum = (42...666).bsearch + assert_nil enum.size + assert_equal 200, enum.each{|x| x >= 200 } + end + + def test_bsearch_for_other_numerics + assert_raise(TypeError) { + (Rational(-1,2)..Rational(9,4)).bsearch + } + assert_raise(TypeError) { + (BigDecimal('0.5')..BigDecimal('2.25')).bsearch + } + end + + def test_bsearch_for_fixnum + ary = [3, 4, 7, 9, 12] + assert_equal(0, (0...ary.size).bsearch {|i| ary[i] >= 2 }) + assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 4 }) + assert_equal(2, (0...ary.size).bsearch {|i| ary[i] >= 6 }) + assert_equal(3, (0...ary.size).bsearch {|i| ary[i] >= 8 }) + assert_equal(4, (0...ary.size).bsearch {|i| ary[i] >= 10 }) + assert_equal(nil, (0...ary.size).bsearch {|i| ary[i] >= 100 }) + assert_equal(0, (0...ary.size).bsearch {|i| true }) + assert_equal(nil, (0...ary.size).bsearch {|i| false }) + + ary = [0, 100, 100, 100, 200] + assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 100 }) + end + + def test_bsearch_for_float + inf = Float::INFINITY + assert_in_delta(10.0, (0.0...100.0).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + assert_in_delta(10.0, (0.0...inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + assert_in_delta(-10.0, (-inf..100.0).bsearch {|x| x >= 0 || Math.log(-x / 10) < 0 }, 0.0001) + assert_in_delta(10.0, (-inf..inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + assert_equal(nil, (-inf..5).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + + assert_in_delta(10.0, (-inf.. 10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + assert_equal(nil, (-inf...10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001) + + assert_equal(nil, (-inf..inf).bsearch { false }) + assert_equal(-inf, (-inf..inf).bsearch { true }) + + assert_equal(inf, (0..inf).bsearch {|x| x == inf }) + assert_equal(nil, (0...inf).bsearch {|x| x == inf }) + + v = (-inf..0).bsearch {|x| x != -inf } + assert_operator(-Float::MAX, :>=, v) + assert_operator(-inf, :<, v) + + v = (0.0..1.0).bsearch {|x| x > 0 } # the nearest positive value to 0.0 + assert_in_delta(0, v, 0.0001) + assert_operator(0, :<, v) + assert_equal(0.0, (-1.0..0.0).bsearch {|x| x >= 0 }) + assert_equal(nil, (-1.0...0.0).bsearch {|x| x >= 0 }) + + v = (0..Float::MAX).bsearch {|x| x >= Float::MAX } + assert_in_delta(Float::MAX, v) + assert_equal(nil, v.infinite?) + + v = (0..inf).bsearch {|x| x >= Float::MAX } + assert_in_delta(Float::MAX, v) + assert_equal(nil, v.infinite?) + + v = (-Float::MAX..0).bsearch {|x| x > -Float::MAX } + assert_operator(-Float::MAX, :<, v) + assert_equal(nil, v.infinite?) + + v = (-inf..0).bsearch {|x| x >= -Float::MAX } + assert_in_delta(-Float::MAX, v) + assert_equal(nil, v.infinite?) + + v = (-inf..0).bsearch {|x| x > -Float::MAX } + assert_operator(-Float::MAX, :<, v) + assert_equal(nil, v.infinite?) + + assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 }) + assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x }) + end + + def check_bsearch_values(range, search) + from, to = range.begin, range.end + cmp = range.exclude_end? ? :< : :<= + + # (0) trivial test + r = Range.new(to, from, range.exclude_end?).bsearch do |x| + fail "#{to}, #{from}, #{range.exclude_end?}, #{x}" + end + assert_equal nil, r + + r = (to...to).bsearch do + fail + end + assert_equal nil, r + + # prepare for others + yielded = [] + r = range.bsearch do |val| + yielded << val + val >= search + end + + # (1) log test + max = case from + when Float then 65 + when Integer then Math.log(to-from+(range.exclude_end? ? 0 : 1), 2).to_i + 1 + end + assert_operator yielded.size, :<=, max + + # (2) coverage test + expect = if search < from + from + elsif search.send(cmp, to) + search + else + nil + end + assert_equal expect, r + + # (3) uniqueness test + assert_equal nil, yielded.uniq! + + # (4) end of range test + case + when range.exclude_end? + assert_not_include yielded, to + assert_not_equal r, to + when search >= to + assert_include yielded, to + assert_equal search == to ? to : nil, r + end + + # start of range test + if search <= from + assert_include yielded, from + assert_equal from, r + end + + # (5) out of range test + yielded.each do |val| + assert_operator from, :<=, val + assert_send [val, cmp, to] + end + end + + def test_range_bsearch_for_floats + ints = [-1 << 100, -123456789, -42, -1, 0, 1, 42, 123456789, 1 << 100] + floats = [-Float::INFINITY, -Float::MAX, -42.0, -4.2, -Float::EPSILON, -Float::MIN, 0.0, Float::MIN, Float::EPSILON, Math::PI, 4.2, 42.0, Float::MAX, Float::INFINITY] + + [ints, floats].each do |values| + values.combination(2).to_a.product(values).each do |(from, to), search| + check_bsearch_values(from..to, search) + check_bsearch_values(from...to, search) + end + end + end + + def test_bsearch_for_bignum + bignum = 2**100 + ary = [3, 4, 7, 9, 12] + assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 2 }) + assert_equal(bignum + 1, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 4 }) + assert_equal(bignum + 2, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 6 }) + assert_equal(bignum + 3, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 8 }) + assert_equal(bignum + 4, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 10 }) + assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 }) + assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true }) + assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false }) + + assert_raise(TypeError) { ("a".."z").bsearch {} } + end + + def test_bsearch_with_mathn + assert_separately ['-r', 'mathn'], %q{ + msg = '[ruby-core:25740]' + answer = (1..(1 << 100)).bsearch{|x| + assert_predicate(x, :integer?, msg) + x >= 42 + } + assert_equal(42, answer, msg) + }, ignore_stderr: true + end + + def test_each_no_blockarg + a = "a" + def a.upto(x, e, &b) + super {|y| b.call(y) {|z| assert(false)}} + end + (a.."c").each {|x, &b| assert_nil(b)} + end +end diff --git a/jni/ruby/test/ruby/test_rational.rb b/jni/ruby/test/ruby/test_rational.rb new file mode 100644 index 0000000..ae4a2c6 --- /dev/null +++ b/jni/ruby/test/ruby/test_rational.rb @@ -0,0 +1,927 @@ +require 'test/unit' + +class RationalSub < Rational; end + +class Rational_Test < Test::Unit::TestCase + + def test_ratsub + c = RationalSub.__send__(:convert, 1) + + assert_kind_of(Numeric, c) + + assert_instance_of(RationalSub, c) + + c2 = c + 1 + assert_instance_of(RationalSub, c2) + c2 = c - 1 + assert_instance_of(RationalSub, c2) + + c3 = c - c2 + assert_instance_of(RationalSub, c3) + + s = Marshal.dump(c) + c5 = Marshal.load(s) + assert_equal(c, c5) + assert_instance_of(RationalSub, c5) + + c1 = Rational(1) + assert_equal(c1.hash, c.hash, '[ruby-dev:38850]') + assert_equal([true, true], [c.eql?(c1), c1.eql?(c)]) + end + + def test_eql_p + c = Rational(0) + c2 = Rational(0) + c3 = Rational(1) + + assert_equal(true, c.eql?(c2)) + assert_equal(false, c.eql?(c3)) + + assert_equal(false, c.eql?(0)) + end + + def test_hash + assert_instance_of(Fixnum, Rational(1,2).hash) + + h = {} + h[Rational(0)] = 0 + h[Rational(1,1)] = 1 + h[Rational(2,1)] = 2 + h[Rational(3,1)] = 3 + + assert_equal(4, h.size) + assert_equal(2, h[Rational(2,1)]) + + h[Rational(0,1)] = 9 + assert_equal(4, h.size) + end + + def test_freeze + c = Rational(1) + c.freeze + assert_equal(true, c.frozen?) + assert_instance_of(String, c.to_s) + end + + def test_conv + c = Rational(0,1) + assert_equal(Rational(0,1), c) + + c = Rational(2**32, 2**32) + assert_equal(Rational(2**32,2**32), c) + assert_equal([1,1], [c.numerator,c.denominator]) + + c = Rational(-2**32, 2**32) + assert_equal(Rational(-2**32,2**32), c) + assert_equal([-1,1], [c.numerator,c.denominator]) + + c = Rational(2**32, -2**32) + assert_equal(Rational(2**32,-2**32), c) + assert_equal([-1,1], [c.numerator,c.denominator]) + + c = Rational(-2**32, -2**32) + assert_equal(Rational(-2**32,-2**32), c) + assert_equal([1,1], [c.numerator,c.denominator]) + + c = Rational(Rational(1,2),2) + assert_equal(Rational(1,4), c) + + c = Rational(2,Rational(1,2)) + assert_equal(Rational(4), c) + + c = Rational(Rational(1,2),Rational(1,2)) + assert_equal(Rational(1), c) + + c = Rational(Complex(1,2),2) + assert_equal(Complex(Rational(1,2),1), c) + + c = Rational(2,Complex(1,2)) + assert_equal(Complex(Rational(2,5),Rational(-4,5)), c) + + c = Rational(Complex(1,2),Complex(1,2)) + assert_equal(Rational(1), c) + + assert_equal(Rational(3),Rational(3)) + assert_equal(Rational(1),Rational(3,3)) + assert_equal(3.3.to_r,Rational(3.3)) + assert_equal(1,Rational(3.3,3.3)) + assert_equal(Rational(3),Rational('3')) + assert_equal(Rational(1),Rational('3.0','3.0')) + assert_equal(Rational(1),Rational('3/3','3/3')) + assert_raise(TypeError){Rational(nil)} + assert_raise(ArgumentError){Rational('')} + assert_raise(TypeError){Rational(Object.new)} + assert_raise(ArgumentError){Rational()} + assert_raise(ArgumentError){Rational(1,2,3)} + + if (0.0/0).nan? + assert_raise(FloatDomainError){Rational(0.0/0)} + end + if (1.0/0).infinite? + assert_raise(FloatDomainError){Rational(1.0/0)} + end + end + + def test_attr + c = Rational(4) + + assert_equal(4, c.numerator) + assert_equal(1, c.denominator) + + c = Rational(4,5) + + assert_equal(4, c.numerator) + assert_equal(5, c.denominator) + + c = Rational(4) + + assert_equal(4, c.numerator) + assert_equal(1, c.denominator) + + c = Rational(4,5) + + assert_equal(4, c.numerator) + assert_equal(5, c.denominator) + + c = Rational(4) + + assert_equal(4, c.numerator) + assert_equal(1, c.denominator) + + c = Rational(4,5) + + assert_equal(4, c.numerator) + assert_equal(5, c.denominator) + end + + def test_attr2 + c = Rational(1) + + assert_equal(false, c.integer?) + assert_equal(true, c.real?) + + assert_equal(true, Rational(0).zero?) + assert_equal(true, Rational(0,1).zero?) + assert_equal(false, Rational(1,1).zero?) + + assert_equal(nil, Rational(0).nonzero?) + assert_equal(nil, Rational(0,1).nonzero?) + assert_equal(Rational(1,1), Rational(1,1).nonzero?) + end + + def test_uplus + assert_equal(Rational(1), +Rational(1)) + assert_equal(Rational(-1), +Rational(-1)) + assert_equal(Rational(1,1), +Rational(1,1)) + assert_equal(Rational(-1,1), +Rational(-1,1)) + assert_equal(Rational(-1,1), +Rational(1,-1)) + assert_equal(Rational(1,1), +Rational(-1,-1)) + end + + def test_negate + assert_equal(Rational(-1), -Rational(1)) + assert_equal(Rational(1), -Rational(-1)) + assert_equal(Rational(-1,1), -Rational(1,1)) + assert_equal(Rational(1,1), -Rational(-1,1)) + assert_equal(Rational(1,1), -Rational(1,-1)) + assert_equal(Rational(-1,1), -Rational(-1,-1)) + end + + def test_add + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(Rational(7,6), c + c2) + + assert_equal(Rational(5,2), c + 2) + assert_equal(2.5, c + 2.0) + end + + def test_sub + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(Rational(-1,6), c - c2) + + assert_equal(Rational(-3,2), c - 2) + assert_equal(-1.5, c - 2.0) + end + + def test_mul + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(Rational(1,3), c * c2) + + assert_equal(Rational(1,1), c * 2) + assert_equal(1.0, c * 2.0) + end + + def test_div + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(Rational(3,4), c / c2) + + assert_equal(Rational(1,4), c / 2) + assert_equal(0.25, c / 2.0) + + assert_raise(ZeroDivisionError){Rational(1, 3) / 0} + assert_raise(ZeroDivisionError){Rational(1, 3) / Rational(0)} + + assert_equal(0, Rational(1, 3) / Float::INFINITY) + assert_predicate(Rational(1, 3) / 0.0, :infinite?, '[ruby-core:31626]') + end + + def assert_eql(exp, act, *args) + unless Array === exp + exp = [exp] + end + unless Array === act + act = [act] + end + exp.zip(act).each do |e, a| + na = [e, a] + args + assert_equal(*na) + na = [e.class, a] + args + assert_instance_of(*na) + end + end + + def test_idiv + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql(0, c.div(c2)) + assert_eql(0, c.div(2)) + assert_eql(0, c.div(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal(2, c.div(c2)) + assert_equal(-3, c.div(-c2)) + assert_equal(-3, (-c).div(c2)) + assert_equal(2, (-c).div(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal(1, c.div(c2)) + assert_equal(-2, c.div(-c2)) + assert_equal(-2, (-c).div(c2)) + assert_equal(1, (-c).div(-c2)) + + c = Rational(11) + c2 = Rational(3) + + assert_equal(3, c.div(c2)) + assert_equal(-4, c.div(-c2)) + assert_equal(-4, (-c).div(c2)) + assert_equal(3, (-c).div(-c2)) + end + + def test_modulo + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql(Rational(1,2), c.modulo(c2)) + assert_eql(Rational(1,2), c.modulo(2)) + assert_eql(0.5, c.modulo(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal(Rational(21,100), c.modulo(c2)) + assert_equal(Rational(-119,100), c.modulo(-c2)) + assert_equal(Rational(119,100), (-c).modulo(c2)) + assert_equal(Rational(-21,100), (-c).modulo(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal(Rational(101,100), c.modulo(c2)) + assert_equal(Rational(-99,100), c.modulo(-c2)) + assert_equal(Rational(99,100), (-c).modulo(c2)) + assert_equal(Rational(-101,100), (-c).modulo(-c2)) + + c = Rational(11) + c2 = Rational(3) + + assert_equal(2, c.modulo(c2)) + assert_equal(-1, c.modulo(-c2)) + assert_equal(1, (-c).modulo(c2)) + assert_equal(-2, (-c).modulo(-c2)) + end + + def test_divmod + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql([0, Rational(1,2)], c.divmod(c2)) + assert_eql([0, Rational(1,2)], c.divmod(2)) + assert_eql([0, 0.5], c.divmod(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal([2, Rational(21,100)], c.divmod(c2)) + assert_equal([-3, Rational(-119,100)], c.divmod(-c2)) + assert_equal([-3, Rational(119,100)], (-c).divmod(c2)) + assert_equal([2, Rational(-21,100)], (-c).divmod(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal([1, Rational(101,100)], c.divmod(c2)) + assert_equal([-2, Rational(-99,100)], c.divmod(-c2)) + assert_equal([-2, Rational(99,100)], (-c).divmod(c2)) + assert_equal([1, Rational(-101,100)], (-c).divmod(-c2)) + + c = Rational(11) + c2 = Rational(3) + + assert_equal([3,2], c.divmod(c2)) + assert_equal([-4,-1], c.divmod(-c2)) + assert_equal([-4,1], (-c).divmod(c2)) + assert_equal([3,-2], (-c).divmod(-c2)) + end + + def test_remainder + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql(Rational(1,2), c.remainder(c2)) + assert_eql(Rational(1,2), c.remainder(2)) + assert_eql(0.5, c.remainder(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal(Rational(21,100), c.remainder(c2)) + assert_equal(Rational(21,100), c.remainder(-c2)) + assert_equal(Rational(-21,100), (-c).remainder(c2)) + assert_equal(Rational(-21,100), (-c).remainder(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal(Rational(101,100), c.remainder(c2)) + assert_equal(Rational(101,100), c.remainder(-c2)) + assert_equal(Rational(-101,100), (-c).remainder(c2)) + assert_equal(Rational(-101,100), (-c).remainder(-c2)) + + c = Rational(11) + c2 = Rational(3) + + assert_equal(2, c.remainder(c2)) + assert_equal(2, c.remainder(-c2)) + assert_equal(-2, (-c).remainder(c2)) + assert_equal(-2, (-c).remainder(-c2)) + end + + def test_quo + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(Rational(3,4), c.quo(c2)) + + assert_equal(Rational(1,4), c.quo(2)) + assert_equal(0.25, c.quo(2.0)) + end + + def test_fdiv + c = Rational(1,2) + c2 = Rational(2,3) + + assert_equal(0.75, c.fdiv(c2)) + + assert_equal(0.25, c.fdiv(2)) + assert_equal(0.25, c.fdiv(2.0)) + assert_equal(0, c.fdiv(Float::INFINITY)) + assert_predicate(c.fdiv(0), :infinite?, '[ruby-core:31626]') + end + + def test_expt + c = Rational(1,2) + c2 = Rational(2,3) + + r = c ** c2 + assert_in_delta(0.6299, r, 0.001) + + assert_equal(Rational(1,4), c ** 2) + assert_equal(Rational(4), c ** -2) + assert_equal(Rational(1,4), (-c) ** 2) + assert_equal(Rational(4), (-c) ** -2) + + assert_equal(0.25, c ** 2.0) + assert_equal(4.0, c ** -2.0) + + assert_equal(Rational(1,4), c ** Rational(2)) + assert_equal(Rational(4), c ** Rational(-2)) + + assert_equal(Rational(1), 0 ** Rational(0)) + assert_equal(Rational(1), Rational(0) ** 0) + assert_equal(Rational(1), Rational(0) ** Rational(0)) + + # p ** p + x = 2 ** Rational(2) + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(2) ** 2 + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(2) ** Rational(2) + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + # -p ** p + x = (-2) ** Rational(2) + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(-2) ** 2 + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(-2) ** Rational(2) + assert_equal(Rational(4), x) + assert_instance_of(Rational, x) + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + # p ** -p + x = 2 ** Rational(-2) + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + x = Rational(2) ** -2 + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + x = Rational(2) ** Rational(-2) + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + # -p ** -p + x = (-2) ** Rational(-2) + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + x = Rational(-2) ** -2 + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + x = Rational(-2) ** Rational(-2) + assert_equal(Rational(1,4), x) + assert_instance_of(Rational, x) + assert_equal(1, x.numerator) + assert_equal(4, x.denominator) + + assert_raise(ZeroDivisionError){0 ** -1} + end + + def test_cmp + assert_equal(-1, Rational(-1) <=> Rational(0)) + assert_equal(0, Rational(0) <=> Rational(0)) + assert_equal(+1, Rational(+1) <=> Rational(0)) + + assert_equal(-1, Rational(-1) <=> 0) + assert_equal(0, Rational(0) <=> 0) + assert_equal(+1, Rational(+1) <=> 0) + + assert_equal(-1, Rational(-1) <=> 0.0) + assert_equal(0, Rational(0) <=> 0.0) + assert_equal(+1, Rational(+1) <=> 0.0) + + assert_equal(-1, Rational(1,2) <=> Rational(2,3)) + assert_equal(0, Rational(2,3) <=> Rational(2,3)) + assert_equal(+1, Rational(2,3) <=> Rational(1,2)) + + f = 2**30-1 + b = 2**30 + + assert_equal(0, Rational(f) <=> Rational(f)) + assert_equal(-1, Rational(f) <=> Rational(b)) + assert_equal(+1, Rational(b) <=> Rational(f)) + assert_equal(0, Rational(b) <=> Rational(b)) + + assert_equal(-1, Rational(f-1) <=> Rational(f)) + assert_equal(+1, Rational(f) <=> Rational(f-1)) + assert_equal(-1, Rational(b-1) <=> Rational(b)) + assert_equal(+1, Rational(b) <=> Rational(b-1)) + + assert_equal(false, Rational(0) < Rational(0)) + assert_equal(true, Rational(0) <= Rational(0)) + assert_equal(true, Rational(0) >= Rational(0)) + assert_equal(false, Rational(0) > Rational(0)) + + assert_equal(nil, Rational(0) <=> nil) + assert_equal(nil, Rational(0) <=> 'foo') + end + + def test_eqeq + assert_equal(Rational(1,1), Rational(1)) + assert_equal(Rational(-1,1), Rational(-1)) + + assert_equal(false, Rational(2,1) == Rational(1)) + assert_equal(true, Rational(2,1) != Rational(1)) + assert_equal(false, Rational(1) == nil) + assert_equal(false, Rational(1) == '') + end + + def test_coerce + assert_equal([Rational(2),Rational(1)], Rational(1).coerce(2)) + assert_equal([Rational(2.2),Rational(1)], Rational(1).coerce(2.2)) + assert_equal([Rational(2),Rational(1)], Rational(1).coerce(Rational(2))) + + assert_nothing_raised(TypeError, '[Bug #5020] [ruby-devl:44088]') do + Rational(1,2).coerce(Complex(1,1)) + end + end + + class ObjectX + def + (x) Rational(1) end + alias - + + alias * + + alias / + + alias quo + + alias div + + alias % + + alias remainder + + alias ** + + def coerce(x) [x, Rational(1)] end + end + + def test_coerce2 + x = ObjectX.new + %w(+ - * / quo div % remainder **).each do |op| + assert_kind_of(Numeric, Rational(1).__send__(op, x)) + end + end + + def test_math + assert_equal(Rational(1,2), Rational(1,2).abs) + assert_equal(Rational(1,2), Rational(-1,2).abs) + assert_equal(Rational(1,2), Rational(1,2).magnitude) + assert_equal(Rational(1,2), Rational(-1,2).magnitude) + + assert_equal(1, Rational(1,2).numerator) + assert_equal(2, Rational(1,2).denominator) + end + + def test_trunc + [[Rational(13, 5), [ 2, 3, 2, 3]], # 2.6 + [Rational(5, 2), [ 2, 3, 2, 3]], # 2.5 + [Rational(12, 5), [ 2, 3, 2, 2]], # 2.4 + [Rational(-12,5), [-3, -2, -2, -2]], # -2.4 + [Rational(-5, 2), [-3, -2, -2, -3]], # -2.5 + [Rational(-13, 5), [-3, -2, -2, -3]], # -2.6 + ].each do |i, a| + assert_equal(a[0], i.floor) + assert_equal(a[1], i.ceil) + assert_equal(a[2], i.truncate) + assert_equal(a[3], i.round) + end + end + + def test_to_s + c = Rational(1,2) + + assert_instance_of(String, c.to_s) + assert_equal('1/2', c.to_s) + + assert_equal('0/1', Rational(0,2).to_s) + assert_equal('0/1', Rational(0,-2).to_s) + assert_equal('1/2', Rational(1,2).to_s) + assert_equal('-1/2', Rational(-1,2).to_s) + assert_equal('1/2', Rational(-1,-2).to_s) + assert_equal('-1/2', Rational(1,-2).to_s) + assert_equal('1/2', Rational(-1,-2).to_s) + end + + def test_inspect + c = Rational(1,2) + + assert_instance_of(String, c.inspect) + assert_equal('(1/2)', c.inspect) + end + + def test_marshal + c = Rational(1,2) + c.instance_eval{@ivar = 9} + + s = Marshal.dump(c) + c2 = Marshal.load(s) + assert_equal(c, c2) + assert_equal(9, c2.instance_variable_get(:@ivar)) + assert_instance_of(Rational, c2) + + assert_raise(ZeroDivisionError){ + Marshal.load("\x04\bU:\rRational[\ai\x06i\x05") + } + + bug3656 = '[ruby-core:31622]' + c = Rational(1,2) + c.freeze + assert_predicate(c, :frozen?) + result = c.marshal_load([2,3]) rescue :fail + assert_equal(:fail, result, bug3656) + end + + def test_marshal_compatibility + bug6625 = '[ruby-core:45775]' + dump = "\x04\x08o:\x0dRational\x07:\x11@denominatori\x07:\x0f@numeratori\x06" + assert_nothing_raised(bug6625) do + assert_equal(Rational(1, 2), Marshal.load(dump), bug6625) + end + end + + def test_parse + assert_equal(Rational(5), '5'.to_r) + assert_equal(Rational(-5), '-5'.to_r) + assert_equal(Rational(5,3), '5/3'.to_r) + assert_equal(Rational(-5,3), '-5/3'.to_r) + + assert_equal(Rational(5), '5.0'.to_r) + assert_equal(Rational(-5), '-5.0'.to_r) + assert_equal(Rational(5,3), '5.0/3'.to_r) + assert_equal(Rational(-5,3), '-5.0/3'.to_r) + + assert_equal(Rational(5), '5e0'.to_r) + assert_equal(Rational(-5), '-5e0'.to_r) + assert_equal(Rational(5,3), '5e0/3'.to_r) + assert_equal(Rational(-5,3), '-5e0/3'.to_r) + + assert_equal(Rational(5e1), '5e1'.to_r) + assert_equal(Rational(-5e2), '-5e2'.to_r) + assert_equal(Rational(5e3,3), '5e003/3'.to_r) + assert_equal(Rational(-5e4,3), '-5e004/3'.to_r) + + assert_equal(Rational(33,100), '.33'.to_r) + assert_equal(Rational(33,100), '0.33'.to_r) + assert_equal(Rational(-33,100), '-.33'.to_r) + assert_equal(Rational(-33,100), '-0.33'.to_r) + assert_equal(Rational(-33,100), '-0.3_3'.to_r) + + assert_equal(Rational(1,2), '5e-1'.to_r) + assert_equal(Rational(50), '5e+1'.to_r) + assert_equal(Rational(1,2), '5.0e-1'.to_r) + assert_equal(Rational(50), '5.0e+1'.to_r) + assert_equal(Rational(50), '5e1'.to_r) + assert_equal(Rational(50), '5E1'.to_r) + assert_equal(Rational(500), '5e2'.to_r) + assert_equal(Rational(5000), '5e3'.to_r) + assert_equal(Rational(500000000000), '5e1_1'.to_r) + + assert_equal(Rational(5), Rational('5')) + assert_equal(Rational(-5), Rational('-5')) + assert_equal(Rational(5,3), Rational('5/3')) + assert_equal(Rational(-5,3), Rational('-5/3')) + + assert_equal(Rational(5), Rational('5.0')) + assert_equal(Rational(-5), Rational('-5.0')) + assert_equal(Rational(5,3), Rational('5.0/3')) + assert_equal(Rational(-5,3), Rational('-5.0/3')) + + assert_equal(Rational(5), Rational('5e0')) + assert_equal(Rational(-5), Rational('-5e0')) + assert_equal(Rational(5,3), Rational('5e0/3')) + assert_equal(Rational(-5,3), Rational('-5e0/3')) + + assert_equal(Rational(5e1), Rational('5e1')) + assert_equal(Rational(-5e2), Rational('-5e2')) + assert_equal(Rational(5e3,3), Rational('5e003/3')) + assert_equal(Rational(-5e4,3), Rational('-5e004/3')) + + assert_equal(Rational(33,100), Rational('.33')) + assert_equal(Rational(33,100), Rational('0.33')) + assert_equal(Rational(-33,100), Rational('-.33')) + assert_equal(Rational(-33,100), Rational('-0.33')) + assert_equal(Rational(-33,100), Rational('-0.3_3')) + + assert_equal(Rational(1,2), Rational('5e-1')) + assert_equal(Rational(50), Rational('5e+1')) + assert_equal(Rational(1,2), Rational('5.0e-1')) + assert_equal(Rational(50), Rational('5.0e+1')) + assert_equal(Rational(50), Rational('5e1')) + assert_equal(Rational(50), Rational('5E1')) + assert_equal(Rational(500), Rational('5e2')) + assert_equal(Rational(5000), Rational('5e3')) + assert_equal(Rational(500000000000), Rational('5e1_1')) + + assert_equal(Rational(0), ''.to_r) + assert_equal(Rational(0), ' '.to_r) + assert_equal(Rational(5), "\f\n\r\t\v5\0".to_r) + assert_equal(Rational(0), '_'.to_r) + assert_equal(Rational(0), '_5'.to_r) + assert_equal(Rational(5), '5_'.to_r) + assert_equal(Rational(5), '5x'.to_r) + assert_equal(Rational(5), '5/_3'.to_r) + assert_equal(Rational(5,3), '5/3_'.to_r) + assert_equal(Rational(5,3), '5/3.3'.to_r) + assert_equal(Rational(5,3), '5/3x'.to_r) + assert_raise(ArgumentError){ Rational('')} + assert_raise(ArgumentError){ Rational('_')} + assert_raise(ArgumentError){ Rational("\f\n\r\t\v5\0")} + assert_raise(ArgumentError){ Rational('_5')} + assert_raise(ArgumentError){ Rational('5_')} + assert_raise(ArgumentError){ Rational('5x')} + assert_raise(ArgumentError){ Rational('5/_3')} + assert_raise(ArgumentError){ Rational('5/3_')} + assert_raise(ArgumentError){ Rational('5/3.3')} + assert_raise(ArgumentError){ Rational('5/3x')} + end + + def test_to_i + assert_equal(1, Rational(3,2).to_i) + assert_equal(1, Integer(Rational(3,2))) + end + + def test_to_f + assert_equal(1.5, Rational(3,2).to_f) + assert_equal(1.5, Float(Rational(3,2))) + end + + def test_to_c + assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c) + assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2))) + end + + def test_to_r + c = nil.to_r + assert_equal([0,1], [c.numerator, c.denominator]) + + c = 0.to_r + assert_equal([0,1], [c.numerator, c.denominator]) + + c = 1.to_r + assert_equal([1,1], [c.numerator, c.denominator]) + + c = 1.1.to_r + assert_equal([2476979795053773, 2251799813685248], + [c.numerator, c.denominator]) + + c = Rational(1,2).to_r + assert_equal([1,2], [c.numerator, c.denominator]) + + assert_raise(RangeError){Complex(1,2).to_r} + + if (0.0/0).nan? + assert_raise(FloatDomainError){(0.0/0).to_r} + end + if (1.0/0).infinite? + assert_raise(FloatDomainError){(1.0/0).to_r} + end + end + + def test_rationalize + c = nil.rationalize + assert_equal([0,1], [c.numerator, c.denominator]) + + c = 0.rationalize + assert_equal([0,1], [c.numerator, c.denominator]) + + c = 1.rationalize + assert_equal([1,1], [c.numerator, c.denominator]) + + c = 1.1.rationalize + assert_equal([11, 10], [c.numerator, c.denominator]) + + c = Rational(1,2).rationalize + assert_equal([1,2], [c.numerator, c.denominator]) + + assert_equal(nil.rationalize(Rational(1,10)), Rational(0)) + assert_equal(0.rationalize(Rational(1,10)), Rational(0)) + assert_equal(10.rationalize(Rational(1,10)), Rational(10)) + + r = 0.3333 + assert_equal(r.rationalize, Rational(3333, 10000)) + assert_equal(r.rationalize(Rational(1,10)), Rational(1,3)) + assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3)) + + r = Rational(5404319552844595,18014398509481984) + assert_equal(r.rationalize, r) + assert_equal(r.rationalize(Rational(1,10)), Rational(1,3)) + assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3)) + + r = -0.3333 + assert_equal(r.rationalize, Rational(-3333, 10000)) + assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3)) + assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3)) + + r = Rational(-5404319552844595,18014398509481984) + assert_equal(r.rationalize, r) + assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3)) + assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3)) + + assert_raise(RangeError){Complex(1,2).rationalize} + + if (0.0/0).nan? + assert_raise(FloatDomainError){(0.0/0).rationalize} + end + if (1.0/0).infinite? + assert_raise(FloatDomainError){(1.0/0).rationalize} + end + end + + def test_gcdlcm + assert_equal(7, 91.gcd(-49)) + assert_equal(5, 5.gcd(0)) + assert_equal(5, 0.gcd(5)) + assert_equal(70, 14.lcm(35)) + assert_equal(0, 5.lcm(0)) + assert_equal(0, 0.lcm(5)) + assert_equal([5,0], 0.gcdlcm(5)) + assert_equal([5,0], 5.gcdlcm(0)) + + assert_equal(1, 1073741827.gcd(1073741789)) + assert_equal(1152921470247108503, 1073741827.lcm(1073741789)) + + assert_equal(1, 1073741789.gcd(1073741827)) + assert_equal(1152921470247108503, 1073741789.lcm(1073741827)) + end + + def test_supp + assert_equal(true, 1.real?) + assert_equal(true, 1.1.real?) + + assert_equal(1, 1.numerator) + assert_equal(9, 9.numerator) + assert_equal(1, 1.denominator) + assert_equal(1, 9.denominator) + + assert_equal(1.0, 1.0.numerator) + assert_equal(9.0, 9.0.numerator) + assert_equal(1.0, 1.0.denominator) + assert_equal(1.0, 9.0.denominator) + + assert_equal(Rational(1,2), 1.quo(2)) + assert_equal(Rational(5000000000), 10000000000.quo(2)) + assert_equal(0.5, 1.0.quo(2)) + assert_equal(Rational(1,4), Rational(1,2).quo(2)) + assert_equal(0, Rational(1,2).quo(Float::INFINITY)) + assert_predicate(Rational(1,2).quo(0.0), :infinite?, '[ruby-core:31626]') + + assert_equal(0.5, 1.fdiv(2)) + assert_equal(5000000000.0, 10000000000.fdiv(2)) + assert_equal(0.5, 1.0.fdiv(2)) + assert_equal(0.25, Rational(1,2).fdiv(2)) + end + + def test_ruby19 + assert_raise(NoMethodError){ Rational.new(1) } + assert_raise(NoMethodError){ Rational.new!(1) } + end + + def test_fixed_bug + n = Float::MAX.to_i * 2 + assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]') + end + + def test_power_of_1_and_minus_1 + bug5715 = '[ruby-core:41498]' + big = 1 << 66 + one = Rational( 1, 1) + assert_eql one, one ** -big , bug5715 + assert_eql one, (-one) ** -big , bug5715 + assert_eql -one, (-one) ** -(big+1) , bug5715 + assert_equal Complex, ((-one) ** Rational(1,3)).class + end + + def test_power_of_0 + bug5713 = '[ruby-core:41494]' + big = 1 << 66 + zero = Rational(0, 1) + assert_eql zero, zero ** big + assert_eql zero, zero ** Rational(2, 3) + assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** -big } + assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** Rational(-2,3) } + end + + def test_known_bug + end + +end diff --git a/jni/ruby/test/ruby/test_rational2.rb b/jni/ruby/test/ruby/test_rational2.rb new file mode 100644 index 0000000..3b6a985 --- /dev/null +++ b/jni/ruby/test/ruby/test_rational2.rb @@ -0,0 +1,1386 @@ +require 'test/unit' + +class Rational_Test2 < Test::Unit::TestCase + + def test_kumi + assert_equal(Rational(1, 1), +Rational(1, 1)) + assert_equal(Rational(-1, 1), -Rational(1, 1)) + assert_equal(Rational(2, 1), + Rational(1, 1) + Rational(1, 1)) + assert_equal(Rational(0, 1), + Rational(1, 1) - Rational(1, 1)) + assert_equal(Rational(1, 1), + Rational(1, 1) * Rational(1, 1)) + assert_equal(Rational(1, 1), + Rational(1, 1) / Rational(1, 1)) + assert_equal(Rational(3, 1), + Rational(1, 1) + Rational(2, 1)) + assert_equal(Rational(-1, 1), + Rational(1, 1) - Rational(2, 1)) + assert_equal(Rational(2, 1), + Rational(1, 1) * Rational(2, 1)) + assert_equal(Rational(1, 2), + Rational(1, 1) / Rational(2, 1)) + assert_equal(Rational(4, 1), + Rational(1, 1) + Rational(3, 1)) + assert_equal(Rational(-2, 1), + Rational(1, 1) - Rational(3, 1)) + assert_equal(Rational(3, 1), + Rational(1, 1) * Rational(3, 1)) + assert_equal(Rational(1, 3), + Rational(1, 1) / Rational(3, 1)) + assert_equal(Rational(1073741790, 1), + Rational(1, 1) + Rational(1073741789, 1)) + assert_equal(Rational(-1073741788, 1), + Rational(1, 1) - Rational(1073741789, 1)) + assert_equal(Rational(1073741789, 1), + Rational(1, 1) * Rational(1073741789, 1)) + assert_equal(Rational(1, 1073741789), + Rational(1, 1) / Rational(1073741789, 1)) + assert_equal(Rational(1073741828, 1), + Rational(1, 1) + Rational(1073741827, 1)) + assert_equal(Rational(-1073741826, 1), + Rational(1, 1) - Rational(1073741827, 1)) + assert_equal(Rational(1073741827, 1), + Rational(1, 1) * Rational(1073741827, 1)) + assert_equal(Rational(1, 1073741827), + Rational(1, 1) / Rational(1073741827, 1)) + assert_equal(Rational(5, 3), + Rational(1, 1) + Rational(2, 3)) + assert_equal(Rational(1, 3), + Rational(1, 1) - Rational(2, 3)) + assert_equal(Rational(2, 3), + Rational(1, 1) * Rational(2, 3)) + assert_equal(Rational(3, 2), + Rational(1, 1) / Rational(2, 3)) + assert_equal(Rational(5, 2), + Rational(1, 1) + Rational(3, 2)) + assert_equal(Rational(-1, 2), + Rational(1, 1) - Rational(3, 2)) + assert_equal(Rational(3, 2), + Rational(1, 1) * Rational(3, 2)) + assert_equal(Rational(2, 3), + Rational(1, 1) / Rational(3, 2)) + assert_equal(Rational(1073741792, 1073741789), + Rational(1, 1) + Rational(3, 1073741789)) + assert_equal(Rational(1073741786, 1073741789), + Rational(1, 1) - Rational(3, 1073741789)) + assert_equal(Rational(3, 1073741789), + Rational(1, 1) * Rational(3, 1073741789)) + assert_equal(Rational(1073741789, 3), + Rational(1, 1) / Rational(3, 1073741789)) + assert_equal(Rational(1073741792, 3), + Rational(1, 1) + Rational(1073741789, 3)) + assert_equal(Rational(-1073741786, 3), + Rational(1, 1) - Rational(1073741789, 3)) + assert_equal(Rational(1073741789, 3), + Rational(1, 1) * Rational(1073741789, 3)) + assert_equal(Rational(3, 1073741789), + Rational(1, 1) / Rational(1073741789, 3)) + assert_equal(Rational(1073741830, 1073741827), + Rational(1, 1) + Rational(3, 1073741827)) + assert_equal(Rational(1073741824, 1073741827), + Rational(1, 1) - Rational(3, 1073741827)) + assert_equal(Rational(3, 1073741827), + Rational(1, 1) * Rational(3, 1073741827)) + assert_equal(Rational(1073741827, 3), + Rational(1, 1) / Rational(3, 1073741827)) + assert_equal(Rational(1073741830, 3), + Rational(1, 1) + Rational(1073741827, 3)) + assert_equal(Rational(-1073741824, 3), + Rational(1, 1) - Rational(1073741827, 3)) + assert_equal(Rational(1073741827, 3), + Rational(1, 1) * Rational(1073741827, 3)) + assert_equal(Rational(3, 1073741827), + Rational(1, 1) / Rational(1073741827, 3)) + assert_equal(Rational(2147483616, 1073741827), + Rational(1, 1) + Rational(1073741789, 1073741827)) + assert_equal(Rational(38, 1073741827), + Rational(1, 1) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1, 1) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1, 1) / Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483616, 1073741789), + Rational(1, 1) + Rational(1073741827, 1073741789)) + assert_equal(Rational(-38, 1073741789), + Rational(1, 1) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1, 1) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1, 1) / Rational(1073741827, 1073741789)) + assert_equal(Rational(2, 1), +Rational(2, 1)) + assert_equal(Rational(-2, 1), -Rational(2, 1)) + assert_equal(Rational(3, 1), + Rational(2, 1) + Rational(1, 1)) + assert_equal(Rational(1, 1), + Rational(2, 1) - Rational(1, 1)) + assert_equal(Rational(2, 1), + Rational(2, 1) * Rational(1, 1)) + assert_equal(Rational(2, 1), + Rational(2, 1) / Rational(1, 1)) + assert_equal(Rational(4, 1), + Rational(2, 1) + Rational(2, 1)) + assert_equal(Rational(0, 1), + Rational(2, 1) - Rational(2, 1)) + assert_equal(Rational(4, 1), + Rational(2, 1) * Rational(2, 1)) + assert_equal(Rational(1, 1), + Rational(2, 1) / Rational(2, 1)) + assert_equal(Rational(5, 1), + Rational(2, 1) + Rational(3, 1)) + assert_equal(Rational(-1, 1), + Rational(2, 1) - Rational(3, 1)) + assert_equal(Rational(6, 1), + Rational(2, 1) * Rational(3, 1)) + assert_equal(Rational(2, 3), + Rational(2, 1) / Rational(3, 1)) + assert_equal(Rational(1073741791, 1), + Rational(2, 1) + Rational(1073741789, 1)) + assert_equal(Rational(-1073741787, 1), + Rational(2, 1) - Rational(1073741789, 1)) + assert_equal(Rational(2147483578, 1), + Rational(2, 1) * Rational(1073741789, 1)) + assert_equal(Rational(2, 1073741789), + Rational(2, 1) / Rational(1073741789, 1)) + assert_equal(Rational(1073741829, 1), + Rational(2, 1) + Rational(1073741827, 1)) + assert_equal(Rational(-1073741825, 1), + Rational(2, 1) - Rational(1073741827, 1)) + assert_equal(Rational(2147483654, 1), + Rational(2, 1) * Rational(1073741827, 1)) + assert_equal(Rational(2, 1073741827), + Rational(2, 1) / Rational(1073741827, 1)) + assert_equal(Rational(8, 3), + Rational(2, 1) + Rational(2, 3)) + assert_equal(Rational(4, 3), + Rational(2, 1) - Rational(2, 3)) + assert_equal(Rational(4, 3), + Rational(2, 1) * Rational(2, 3)) + assert_equal(Rational(3, 1), + Rational(2, 1) / Rational(2, 3)) + assert_equal(Rational(7, 2), + Rational(2, 1) + Rational(3, 2)) + assert_equal(Rational(1, 2), + Rational(2, 1) - Rational(3, 2)) + assert_equal(Rational(3, 1), + Rational(2, 1) * Rational(3, 2)) + assert_equal(Rational(4, 3), + Rational(2, 1) / Rational(3, 2)) + assert_equal(Rational(2147483581, 1073741789), + Rational(2, 1) + Rational(3, 1073741789)) + assert_equal(Rational(2147483575, 1073741789), + Rational(2, 1) - Rational(3, 1073741789)) + assert_equal(Rational(6, 1073741789), + Rational(2, 1) * Rational(3, 1073741789)) + assert_equal(Rational(2147483578, 3), + Rational(2, 1) / Rational(3, 1073741789)) + assert_equal(Rational(1073741795, 3), + Rational(2, 1) + Rational(1073741789, 3)) + assert_equal(Rational(-1073741783, 3), + Rational(2, 1) - Rational(1073741789, 3)) + assert_equal(Rational(2147483578, 3), + Rational(2, 1) * Rational(1073741789, 3)) + assert_equal(Rational(6, 1073741789), + Rational(2, 1) / Rational(1073741789, 3)) + assert_equal(Rational(2147483657, 1073741827), + Rational(2, 1) + Rational(3, 1073741827)) + assert_equal(Rational(2147483651, 1073741827), + Rational(2, 1) - Rational(3, 1073741827)) + assert_equal(Rational(6, 1073741827), + Rational(2, 1) * Rational(3, 1073741827)) + assert_equal(Rational(2147483654, 3), + Rational(2, 1) / Rational(3, 1073741827)) + assert_equal(Rational(1073741833, 3), + Rational(2, 1) + Rational(1073741827, 3)) + assert_equal(Rational(-1073741821, 3), + Rational(2, 1) - Rational(1073741827, 3)) + assert_equal(Rational(2147483654, 3), + Rational(2, 1) * Rational(1073741827, 3)) + assert_equal(Rational(6, 1073741827), + Rational(2, 1) / Rational(1073741827, 3)) + assert_equal(Rational(3221225443, 1073741827), + Rational(2, 1) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741865, 1073741827), + Rational(2, 1) - Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483578, 1073741827), + Rational(2, 1) * Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483654, 1073741789), + Rational(2, 1) / Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225405, 1073741789), + Rational(2, 1) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741751, 1073741789), + Rational(2, 1) - Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483654, 1073741789), + Rational(2, 1) * Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483578, 1073741827), + Rational(2, 1) / Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 1), +Rational(3, 1)) + assert_equal(Rational(-3, 1), -Rational(3, 1)) + assert_equal(Rational(4, 1), + Rational(3, 1) + Rational(1, 1)) + assert_equal(Rational(2, 1), + Rational(3, 1) - Rational(1, 1)) + assert_equal(Rational(3, 1), + Rational(3, 1) * Rational(1, 1)) + assert_equal(Rational(3, 1), + Rational(3, 1) / Rational(1, 1)) + assert_equal(Rational(5, 1), + Rational(3, 1) + Rational(2, 1)) + assert_equal(Rational(1, 1), + Rational(3, 1) - Rational(2, 1)) + assert_equal(Rational(6, 1), + Rational(3, 1) * Rational(2, 1)) + assert_equal(Rational(3, 2), + Rational(3, 1) / Rational(2, 1)) + assert_equal(Rational(6, 1), + Rational(3, 1) + Rational(3, 1)) + assert_equal(Rational(0, 1), + Rational(3, 1) - Rational(3, 1)) + assert_equal(Rational(9, 1), + Rational(3, 1) * Rational(3, 1)) + assert_equal(Rational(1, 1), + Rational(3, 1) / Rational(3, 1)) + assert_equal(Rational(1073741792, 1), + Rational(3, 1) + Rational(1073741789, 1)) + assert_equal(Rational(-1073741786, 1), + Rational(3, 1) - Rational(1073741789, 1)) + assert_equal(Rational(3221225367, 1), + Rational(3, 1) * Rational(1073741789, 1)) + assert_equal(Rational(3, 1073741789), + Rational(3, 1) / Rational(1073741789, 1)) + assert_equal(Rational(1073741830, 1), + Rational(3, 1) + Rational(1073741827, 1)) + assert_equal(Rational(-1073741824, 1), + Rational(3, 1) - Rational(1073741827, 1)) + assert_equal(Rational(3221225481, 1), + Rational(3, 1) * Rational(1073741827, 1)) + assert_equal(Rational(3, 1073741827), + Rational(3, 1) / Rational(1073741827, 1)) + assert_equal(Rational(11, 3), + Rational(3, 1) + Rational(2, 3)) + assert_equal(Rational(7, 3), + Rational(3, 1) - Rational(2, 3)) + assert_equal(Rational(2, 1), + Rational(3, 1) * Rational(2, 3)) + assert_equal(Rational(9, 2), + Rational(3, 1) / Rational(2, 3)) + assert_equal(Rational(9, 2), + Rational(3, 1) + Rational(3, 2)) + assert_equal(Rational(3, 2), + Rational(3, 1) - Rational(3, 2)) + assert_equal(Rational(9, 2), + Rational(3, 1) * Rational(3, 2)) + assert_equal(Rational(2, 1), + Rational(3, 1) / Rational(3, 2)) + assert_equal(Rational(3221225370, 1073741789), + Rational(3, 1) + Rational(3, 1073741789)) + assert_equal(Rational(3221225364, 1073741789), + Rational(3, 1) - Rational(3, 1073741789)) + assert_equal(Rational(9, 1073741789), + Rational(3, 1) * Rational(3, 1073741789)) + assert_equal(Rational(1073741789, 1), + Rational(3, 1) / Rational(3, 1073741789)) + assert_equal(Rational(1073741798, 3), + Rational(3, 1) + Rational(1073741789, 3)) + assert_equal(Rational(-1073741780, 3), + Rational(3, 1) - Rational(1073741789, 3)) + assert_equal(Rational(1073741789, 1), + Rational(3, 1) * Rational(1073741789, 3)) + assert_equal(Rational(9, 1073741789), + Rational(3, 1) / Rational(1073741789, 3)) + assert_equal(Rational(3221225484, 1073741827), + Rational(3, 1) + Rational(3, 1073741827)) + assert_equal(Rational(3221225478, 1073741827), + Rational(3, 1) - Rational(3, 1073741827)) + assert_equal(Rational(9, 1073741827), + Rational(3, 1) * Rational(3, 1073741827)) + assert_equal(Rational(1073741827, 1), + Rational(3, 1) / Rational(3, 1073741827)) + assert_equal(Rational(1073741836, 3), + Rational(3, 1) + Rational(1073741827, 3)) + assert_equal(Rational(-1073741818, 3), + Rational(3, 1) - Rational(1073741827, 3)) + assert_equal(Rational(1073741827, 1), + Rational(3, 1) * Rational(1073741827, 3)) + assert_equal(Rational(9, 1073741827), + Rational(3, 1) / Rational(1073741827, 3)) + assert_equal(Rational(4294967270, 1073741827), + Rational(3, 1) + Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483692, 1073741827), + Rational(3, 1) - Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225367, 1073741827), + Rational(3, 1) * Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225481, 1073741789), + Rational(3, 1) / Rational(1073741789, 1073741827)) + assert_equal(Rational(4294967194, 1073741789), + Rational(3, 1) + Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483540, 1073741789), + Rational(3, 1) - Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225481, 1073741789), + Rational(3, 1) * Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225367, 1073741827), + Rational(3, 1) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 1), +Rational(1073741789, 1)) + assert_equal(Rational(-1073741789, 1), -Rational(1073741789, 1)) + assert_equal(Rational(1073741790, 1), + Rational(1073741789, 1) + Rational(1, 1)) + assert_equal(Rational(1073741788, 1), + Rational(1073741789, 1) - Rational(1, 1)) + assert_equal(Rational(1073741789, 1), + Rational(1073741789, 1) * Rational(1, 1)) + assert_equal(Rational(1073741789, 1), + Rational(1073741789, 1) / Rational(1, 1)) + assert_equal(Rational(1073741791, 1), + Rational(1073741789, 1) + Rational(2, 1)) + assert_equal(Rational(1073741787, 1), + Rational(1073741789, 1) - Rational(2, 1)) + assert_equal(Rational(2147483578, 1), + Rational(1073741789, 1) * Rational(2, 1)) + assert_equal(Rational(1073741789, 2), + Rational(1073741789, 1) / Rational(2, 1)) + assert_equal(Rational(1073741792, 1), + Rational(1073741789, 1) + Rational(3, 1)) + assert_equal(Rational(1073741786, 1), + Rational(1073741789, 1) - Rational(3, 1)) + assert_equal(Rational(3221225367, 1), + Rational(1073741789, 1) * Rational(3, 1)) + assert_equal(Rational(1073741789, 3), + Rational(1073741789, 1) / Rational(3, 1)) + assert_equal(Rational(2147483578, 1), + Rational(1073741789, 1) + Rational(1073741789, 1)) + assert_equal(Rational(0, 1), + Rational(1073741789, 1) - Rational(1073741789, 1)) + assert_equal(Rational(1152921429444920521, 1), + Rational(1073741789, 1) * Rational(1073741789, 1)) + assert_equal(Rational(1, 1), + Rational(1073741789, 1) / Rational(1073741789, 1)) + assert_equal(Rational(2147483616, 1), + Rational(1073741789, 1) + Rational(1073741827, 1)) + assert_equal(Rational(-38, 1), + Rational(1073741789, 1) - Rational(1073741827, 1)) + assert_equal(Rational(1152921470247108503, 1), + Rational(1073741789, 1) * Rational(1073741827, 1)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1073741789, 1) / Rational(1073741827, 1)) + assert_equal(Rational(3221225369, 3), + Rational(1073741789, 1) + Rational(2, 3)) + assert_equal(Rational(3221225365, 3), + Rational(1073741789, 1) - Rational(2, 3)) + assert_equal(Rational(2147483578, 3), + Rational(1073741789, 1) * Rational(2, 3)) + assert_equal(Rational(3221225367, 2), + Rational(1073741789, 1) / Rational(2, 3)) + assert_equal(Rational(2147483581, 2), + Rational(1073741789, 1) + Rational(3, 2)) + assert_equal(Rational(2147483575, 2), + Rational(1073741789, 1) - Rational(3, 2)) + assert_equal(Rational(3221225367, 2), + Rational(1073741789, 1) * Rational(3, 2)) + assert_equal(Rational(2147483578, 3), + Rational(1073741789, 1) / Rational(3, 2)) + assert_equal(Rational(1152921429444920524, 1073741789), + Rational(1073741789, 1) + Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920518, 1073741789), + Rational(1073741789, 1) - Rational(3, 1073741789)) + assert_equal(Rational(3, 1), + Rational(1073741789, 1) * Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920521, 3), + Rational(1073741789, 1) / Rational(3, 1073741789)) + assert_equal(Rational(4294967156, 3), + Rational(1073741789, 1) + Rational(1073741789, 3)) + assert_equal(Rational(2147483578, 3), + Rational(1073741789, 1) - Rational(1073741789, 3)) + assert_equal(Rational(1152921429444920521, 3), + Rational(1073741789, 1) * Rational(1073741789, 3)) + assert_equal(Rational(3, 1), + Rational(1073741789, 1) / Rational(1073741789, 3)) + assert_equal(Rational(1152921470247108506, 1073741827), + Rational(1073741789, 1) + Rational(3, 1073741827)) + assert_equal(Rational(1152921470247108500, 1073741827), + Rational(1073741789, 1) - Rational(3, 1073741827)) + assert_equal(Rational(3221225367, 1073741827), + Rational(1073741789, 1) * Rational(3, 1073741827)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741789, 1) / Rational(3, 1073741827)) + assert_equal(Rational(4294967194, 3), + Rational(1073741789, 1) + Rational(1073741827, 3)) + assert_equal(Rational(2147483540, 3), + Rational(1073741789, 1) - Rational(1073741827, 3)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741789, 1) * Rational(1073741827, 3)) + assert_equal(Rational(3221225367, 1073741827), + Rational(1073741789, 1) / Rational(1073741827, 3)) + assert_equal(Rational(1152921471320850292, 1073741827), + Rational(1073741789, 1) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921469173366714, 1073741827), + Rational(1073741789, 1) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921429444920521, 1073741827), + Rational(1073741789, 1) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741827, 1), + Rational(1073741789, 1) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921430518662348, 1073741789), + Rational(1073741789, 1) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921428371178694, 1073741789), + Rational(1073741789, 1) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 1), + Rational(1073741789, 1) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921429444920521, 1073741827), + Rational(1073741789, 1) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 1), +Rational(1073741827, 1)) + assert_equal(Rational(-1073741827, 1), -Rational(1073741827, 1)) + assert_equal(Rational(1073741828, 1), + Rational(1073741827, 1) + Rational(1, 1)) + assert_equal(Rational(1073741826, 1), + Rational(1073741827, 1) - Rational(1, 1)) + assert_equal(Rational(1073741827, 1), + Rational(1073741827, 1) * Rational(1, 1)) + assert_equal(Rational(1073741827, 1), + Rational(1073741827, 1) / Rational(1, 1)) + assert_equal(Rational(1073741829, 1), + Rational(1073741827, 1) + Rational(2, 1)) + assert_equal(Rational(1073741825, 1), + Rational(1073741827, 1) - Rational(2, 1)) + assert_equal(Rational(2147483654, 1), + Rational(1073741827, 1) * Rational(2, 1)) + assert_equal(Rational(1073741827, 2), + Rational(1073741827, 1) / Rational(2, 1)) + assert_equal(Rational(1073741830, 1), + Rational(1073741827, 1) + Rational(3, 1)) + assert_equal(Rational(1073741824, 1), + Rational(1073741827, 1) - Rational(3, 1)) + assert_equal(Rational(3221225481, 1), + Rational(1073741827, 1) * Rational(3, 1)) + assert_equal(Rational(1073741827, 3), + Rational(1073741827, 1) / Rational(3, 1)) + assert_equal(Rational(2147483616, 1), + Rational(1073741827, 1) + Rational(1073741789, 1)) + assert_equal(Rational(38, 1), + Rational(1073741827, 1) - Rational(1073741789, 1)) + assert_equal(Rational(1152921470247108503, 1), + Rational(1073741827, 1) * Rational(1073741789, 1)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1073741827, 1) / Rational(1073741789, 1)) + assert_equal(Rational(2147483654, 1), + Rational(1073741827, 1) + Rational(1073741827, 1)) + assert_equal(Rational(0, 1), + Rational(1073741827, 1) - Rational(1073741827, 1)) + assert_equal(Rational(1152921511049297929, 1), + Rational(1073741827, 1) * Rational(1073741827, 1)) + assert_equal(Rational(1, 1), + Rational(1073741827, 1) / Rational(1073741827, 1)) + assert_equal(Rational(3221225483, 3), + Rational(1073741827, 1) + Rational(2, 3)) + assert_equal(Rational(3221225479, 3), + Rational(1073741827, 1) - Rational(2, 3)) + assert_equal(Rational(2147483654, 3), + Rational(1073741827, 1) * Rational(2, 3)) + assert_equal(Rational(3221225481, 2), + Rational(1073741827, 1) / Rational(2, 3)) + assert_equal(Rational(2147483657, 2), + Rational(1073741827, 1) + Rational(3, 2)) + assert_equal(Rational(2147483651, 2), + Rational(1073741827, 1) - Rational(3, 2)) + assert_equal(Rational(3221225481, 2), + Rational(1073741827, 1) * Rational(3, 2)) + assert_equal(Rational(2147483654, 3), + Rational(1073741827, 1) / Rational(3, 2)) + assert_equal(Rational(1152921470247108506, 1073741789), + Rational(1073741827, 1) + Rational(3, 1073741789)) + assert_equal(Rational(1152921470247108500, 1073741789), + Rational(1073741827, 1) - Rational(3, 1073741789)) + assert_equal(Rational(3221225481, 1073741789), + Rational(1073741827, 1) * Rational(3, 1073741789)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741827, 1) / Rational(3, 1073741789)) + assert_equal(Rational(4294967270, 3), + Rational(1073741827, 1) + Rational(1073741789, 3)) + assert_equal(Rational(2147483692, 3), + Rational(1073741827, 1) - Rational(1073741789, 3)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741827, 1) * Rational(1073741789, 3)) + assert_equal(Rational(3221225481, 1073741789), + Rational(1073741827, 1) / Rational(1073741789, 3)) + assert_equal(Rational(1152921511049297932, 1073741827), + Rational(1073741827, 1) + Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297926, 1073741827), + Rational(1073741827, 1) - Rational(3, 1073741827)) + assert_equal(Rational(3, 1), + Rational(1073741827, 1) * Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297929, 3), + Rational(1073741827, 1) / Rational(3, 1073741827)) + assert_equal(Rational(4294967308, 3), + Rational(1073741827, 1) + Rational(1073741827, 3)) + assert_equal(Rational(2147483654, 3), + Rational(1073741827, 1) - Rational(1073741827, 3)) + assert_equal(Rational(1152921511049297929, 3), + Rational(1073741827, 1) * Rational(1073741827, 3)) + assert_equal(Rational(3, 1), + Rational(1073741827, 1) / Rational(1073741827, 3)) + assert_equal(Rational(1152921512123039718, 1073741827), + Rational(1073741827, 1) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921509975556140, 1073741827), + Rational(1073741827, 1) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741789, 1), + Rational(1073741827, 1) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921511049297929, 1073741789), + Rational(1073741827, 1) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921471320850330, 1073741789), + Rational(1073741827, 1) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921469173366676, 1073741789), + Rational(1073741827, 1) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921511049297929, 1073741789), + Rational(1073741827, 1) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 1), + Rational(1073741827, 1) / Rational(1073741827, 1073741789)) + assert_equal(Rational(2, 3), +Rational(2, 3)) + assert_equal(Rational(-2, 3), -Rational(2, 3)) + assert_equal(Rational(5, 3), + Rational(2, 3) + Rational(1, 1)) + assert_equal(Rational(-1, 3), + Rational(2, 3) - Rational(1, 1)) + assert_equal(Rational(2, 3), + Rational(2, 3) * Rational(1, 1)) + assert_equal(Rational(2, 3), + Rational(2, 3) / Rational(1, 1)) + assert_equal(Rational(8, 3), + Rational(2, 3) + Rational(2, 1)) + assert_equal(Rational(-4, 3), + Rational(2, 3) - Rational(2, 1)) + assert_equal(Rational(4, 3), + Rational(2, 3) * Rational(2, 1)) + assert_equal(Rational(1, 3), + Rational(2, 3) / Rational(2, 1)) + assert_equal(Rational(11, 3), + Rational(2, 3) + Rational(3, 1)) + assert_equal(Rational(-7, 3), + Rational(2, 3) - Rational(3, 1)) + assert_equal(Rational(2, 1), + Rational(2, 3) * Rational(3, 1)) + assert_equal(Rational(2, 9), + Rational(2, 3) / Rational(3, 1)) + assert_equal(Rational(3221225369, 3), + Rational(2, 3) + Rational(1073741789, 1)) + assert_equal(Rational(-3221225365, 3), + Rational(2, 3) - Rational(1073741789, 1)) + assert_equal(Rational(2147483578, 3), + Rational(2, 3) * Rational(1073741789, 1)) + assert_equal(Rational(2, 3221225367), + Rational(2, 3) / Rational(1073741789, 1)) + assert_equal(Rational(3221225483, 3), + Rational(2, 3) + Rational(1073741827, 1)) + assert_equal(Rational(-3221225479, 3), + Rational(2, 3) - Rational(1073741827, 1)) + assert_equal(Rational(2147483654, 3), + Rational(2, 3) * Rational(1073741827, 1)) + assert_equal(Rational(2, 3221225481), + Rational(2, 3) / Rational(1073741827, 1)) + assert_equal(Rational(4, 3), + Rational(2, 3) + Rational(2, 3)) + assert_equal(Rational(0, 1), + Rational(2, 3) - Rational(2, 3)) + assert_equal(Rational(4, 9), + Rational(2, 3) * Rational(2, 3)) + assert_equal(Rational(1, 1), + Rational(2, 3) / Rational(2, 3)) + assert_equal(Rational(13, 6), + Rational(2, 3) + Rational(3, 2)) + assert_equal(Rational(-5, 6), + Rational(2, 3) - Rational(3, 2)) + assert_equal(Rational(1, 1), + Rational(2, 3) * Rational(3, 2)) + assert_equal(Rational(4, 9), + Rational(2, 3) / Rational(3, 2)) + assert_equal(Rational(2147483587, 3221225367), + Rational(2, 3) + Rational(3, 1073741789)) + assert_equal(Rational(2147483569, 3221225367), + Rational(2, 3) - Rational(3, 1073741789)) + assert_equal(Rational(2, 1073741789), + Rational(2, 3) * Rational(3, 1073741789)) + assert_equal(Rational(2147483578, 9), + Rational(2, 3) / Rational(3, 1073741789)) + assert_equal(Rational(1073741791, 3), + Rational(2, 3) + Rational(1073741789, 3)) + assert_equal(Rational(-357913929, 1), + Rational(2, 3) - Rational(1073741789, 3)) + assert_equal(Rational(2147483578, 9), + Rational(2, 3) * Rational(1073741789, 3)) + assert_equal(Rational(2, 1073741789), + Rational(2, 3) / Rational(1073741789, 3)) + assert_equal(Rational(2147483663, 3221225481), + Rational(2, 3) + Rational(3, 1073741827)) + assert_equal(Rational(2147483645, 3221225481), + Rational(2, 3) - Rational(3, 1073741827)) + assert_equal(Rational(2, 1073741827), + Rational(2, 3) * Rational(3, 1073741827)) + assert_equal(Rational(2147483654, 9), + Rational(2, 3) / Rational(3, 1073741827)) + assert_equal(Rational(357913943, 1), + Rational(2, 3) + Rational(1073741827, 3)) + assert_equal(Rational(-1073741825, 3), + Rational(2, 3) - Rational(1073741827, 3)) + assert_equal(Rational(2147483654, 9), + Rational(2, 3) * Rational(1073741827, 3)) + assert_equal(Rational(2, 1073741827), + Rational(2, 3) / Rational(1073741827, 3)) + assert_equal(Rational(5368709021, 3221225481), + Rational(2, 3) + Rational(1073741789, 1073741827)) + assert_equal(Rational(-1073741713, 3221225481), + Rational(2, 3) - Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483578, 3221225481), + Rational(2, 3) * Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483654, 3221225367), + Rational(2, 3) / Rational(1073741789, 1073741827)) + assert_equal(Rational(5368709059, 3221225367), + Rational(2, 3) + Rational(1073741827, 1073741789)) + assert_equal(Rational(-1073741903, 3221225367), + Rational(2, 3) - Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483654, 3221225367), + Rational(2, 3) * Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483578, 3221225481), + Rational(2, 3) / Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 2), +Rational(3, 2)) + assert_equal(Rational(-3, 2), -Rational(3, 2)) + assert_equal(Rational(5, 2), + Rational(3, 2) + Rational(1, 1)) + assert_equal(Rational(1, 2), + Rational(3, 2) - Rational(1, 1)) + assert_equal(Rational(3, 2), + Rational(3, 2) * Rational(1, 1)) + assert_equal(Rational(3, 2), + Rational(3, 2) / Rational(1, 1)) + assert_equal(Rational(7, 2), + Rational(3, 2) + Rational(2, 1)) + assert_equal(Rational(-1, 2), + Rational(3, 2) - Rational(2, 1)) + assert_equal(Rational(3, 1), + Rational(3, 2) * Rational(2, 1)) + assert_equal(Rational(3, 4), + Rational(3, 2) / Rational(2, 1)) + assert_equal(Rational(9, 2), + Rational(3, 2) + Rational(3, 1)) + assert_equal(Rational(-3, 2), + Rational(3, 2) - Rational(3, 1)) + assert_equal(Rational(9, 2), + Rational(3, 2) * Rational(3, 1)) + assert_equal(Rational(1, 2), + Rational(3, 2) / Rational(3, 1)) + assert_equal(Rational(2147483581, 2), + Rational(3, 2) + Rational(1073741789, 1)) + assert_equal(Rational(-2147483575, 2), + Rational(3, 2) - Rational(1073741789, 1)) + assert_equal(Rational(3221225367, 2), + Rational(3, 2) * Rational(1073741789, 1)) + assert_equal(Rational(3, 2147483578), + Rational(3, 2) / Rational(1073741789, 1)) + assert_equal(Rational(2147483657, 2), + Rational(3, 2) + Rational(1073741827, 1)) + assert_equal(Rational(-2147483651, 2), + Rational(3, 2) - Rational(1073741827, 1)) + assert_equal(Rational(3221225481, 2), + Rational(3, 2) * Rational(1073741827, 1)) + assert_equal(Rational(3, 2147483654), + Rational(3, 2) / Rational(1073741827, 1)) + assert_equal(Rational(13, 6), + Rational(3, 2) + Rational(2, 3)) + assert_equal(Rational(5, 6), + Rational(3, 2) - Rational(2, 3)) + assert_equal(Rational(1, 1), + Rational(3, 2) * Rational(2, 3)) + assert_equal(Rational(9, 4), + Rational(3, 2) / Rational(2, 3)) + assert_equal(Rational(3, 1), + Rational(3, 2) + Rational(3, 2)) + assert_equal(Rational(0, 1), + Rational(3, 2) - Rational(3, 2)) + assert_equal(Rational(9, 4), + Rational(3, 2) * Rational(3, 2)) + assert_equal(Rational(1, 1), + Rational(3, 2) / Rational(3, 2)) + assert_equal(Rational(3221225373, 2147483578), + Rational(3, 2) + Rational(3, 1073741789)) + assert_equal(Rational(3221225361, 2147483578), + Rational(3, 2) - Rational(3, 1073741789)) + assert_equal(Rational(9, 2147483578), + Rational(3, 2) * Rational(3, 1073741789)) + assert_equal(Rational(1073741789, 2), + Rational(3, 2) / Rational(3, 1073741789)) + assert_equal(Rational(2147483587, 6), + Rational(3, 2) + Rational(1073741789, 3)) + assert_equal(Rational(-2147483569, 6), + Rational(3, 2) - Rational(1073741789, 3)) + assert_equal(Rational(1073741789, 2), + Rational(3, 2) * Rational(1073741789, 3)) + assert_equal(Rational(9, 2147483578), + Rational(3, 2) / Rational(1073741789, 3)) + assert_equal(Rational(3221225487, 2147483654), + Rational(3, 2) + Rational(3, 1073741827)) + assert_equal(Rational(3221225475, 2147483654), + Rational(3, 2) - Rational(3, 1073741827)) + assert_equal(Rational(9, 2147483654), + Rational(3, 2) * Rational(3, 1073741827)) + assert_equal(Rational(1073741827, 2), + Rational(3, 2) / Rational(3, 1073741827)) + assert_equal(Rational(2147483663, 6), + Rational(3, 2) + Rational(1073741827, 3)) + assert_equal(Rational(-2147483645, 6), + Rational(3, 2) - Rational(1073741827, 3)) + assert_equal(Rational(1073741827, 2), + Rational(3, 2) * Rational(1073741827, 3)) + assert_equal(Rational(9, 2147483654), + Rational(3, 2) / Rational(1073741827, 3)) + assert_equal(Rational(5368709059, 2147483654), + Rational(3, 2) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741903, 2147483654), + Rational(3, 2) - Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225367, 2147483654), + Rational(3, 2) * Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225481, 2147483578), + Rational(3, 2) / Rational(1073741789, 1073741827)) + assert_equal(Rational(5368709021, 2147483578), + Rational(3, 2) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741713, 2147483578), + Rational(3, 2) - Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225481, 2147483578), + Rational(3, 2) * Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225367, 2147483654), + Rational(3, 2) / Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 1073741789), +Rational(3, 1073741789)) + assert_equal(Rational(-3, 1073741789), -Rational(3, 1073741789)) + assert_equal(Rational(1073741792, 1073741789), + Rational(3, 1073741789) + Rational(1, 1)) + assert_equal(Rational(-1073741786, 1073741789), + Rational(3, 1073741789) - Rational(1, 1)) + assert_equal(Rational(3, 1073741789), + Rational(3, 1073741789) * Rational(1, 1)) + assert_equal(Rational(3, 1073741789), + Rational(3, 1073741789) / Rational(1, 1)) + assert_equal(Rational(2147483581, 1073741789), + Rational(3, 1073741789) + Rational(2, 1)) + assert_equal(Rational(-2147483575, 1073741789), + Rational(3, 1073741789) - Rational(2, 1)) + assert_equal(Rational(6, 1073741789), + Rational(3, 1073741789) * Rational(2, 1)) + assert_equal(Rational(3, 2147483578), + Rational(3, 1073741789) / Rational(2, 1)) + assert_equal(Rational(3221225370, 1073741789), + Rational(3, 1073741789) + Rational(3, 1)) + assert_equal(Rational(-3221225364, 1073741789), + Rational(3, 1073741789) - Rational(3, 1)) + assert_equal(Rational(9, 1073741789), + Rational(3, 1073741789) * Rational(3, 1)) + assert_equal(Rational(1, 1073741789), + Rational(3, 1073741789) / Rational(3, 1)) + assert_equal(Rational(1152921429444920524, 1073741789), + Rational(3, 1073741789) + Rational(1073741789, 1)) + assert_equal(Rational(-1152921429444920518, 1073741789), + Rational(3, 1073741789) - Rational(1073741789, 1)) + assert_equal(Rational(3, 1), + Rational(3, 1073741789) * Rational(1073741789, 1)) + assert_equal(Rational(3, 1152921429444920521), + Rational(3, 1073741789) / Rational(1073741789, 1)) + assert_equal(Rational(1152921470247108506, 1073741789), + Rational(3, 1073741789) + Rational(1073741827, 1)) + assert_equal(Rational(-1152921470247108500, 1073741789), + Rational(3, 1073741789) - Rational(1073741827, 1)) + assert_equal(Rational(3221225481, 1073741789), + Rational(3, 1073741789) * Rational(1073741827, 1)) + assert_equal(Rational(3, 1152921470247108503), + Rational(3, 1073741789) / Rational(1073741827, 1)) + assert_equal(Rational(2147483587, 3221225367), + Rational(3, 1073741789) + Rational(2, 3)) + assert_equal(Rational(-2147483569, 3221225367), + Rational(3, 1073741789) - Rational(2, 3)) + assert_equal(Rational(2, 1073741789), + Rational(3, 1073741789) * Rational(2, 3)) + assert_equal(Rational(9, 2147483578), + Rational(3, 1073741789) / Rational(2, 3)) + assert_equal(Rational(3221225373, 2147483578), + Rational(3, 1073741789) + Rational(3, 2)) + assert_equal(Rational(-3221225361, 2147483578), + Rational(3, 1073741789) - Rational(3, 2)) + assert_equal(Rational(9, 2147483578), + Rational(3, 1073741789) * Rational(3, 2)) + assert_equal(Rational(2, 1073741789), + Rational(3, 1073741789) / Rational(3, 2)) + assert_equal(Rational(6, 1073741789), + Rational(3, 1073741789) + Rational(3, 1073741789)) + assert_equal(Rational(0, 1), + Rational(3, 1073741789) - Rational(3, 1073741789)) + assert_equal(Rational(9, 1152921429444920521), + Rational(3, 1073741789) * Rational(3, 1073741789)) + assert_equal(Rational(1, 1), + Rational(3, 1073741789) / Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920530, 3221225367), + Rational(3, 1073741789) + Rational(1073741789, 3)) + assert_equal(Rational(-1152921429444920512, 3221225367), + Rational(3, 1073741789) - Rational(1073741789, 3)) + assert_equal(Rational(1, 1), + Rational(3, 1073741789) * Rational(1073741789, 3)) + assert_equal(Rational(9, 1152921429444920521), + Rational(3, 1073741789) / Rational(1073741789, 3)) + assert_equal(Rational(6442450848, 1152921470247108503), + Rational(3, 1073741789) + Rational(3, 1073741827)) + assert_equal(Rational(114, 1152921470247108503), + Rational(3, 1073741789) - Rational(3, 1073741827)) + assert_equal(Rational(9, 1152921470247108503), + Rational(3, 1073741789) * Rational(3, 1073741827)) + assert_equal(Rational(1073741827, 1073741789), + Rational(3, 1073741789) / Rational(3, 1073741827)) + assert_equal(Rational(1152921470247108512, 3221225367), + Rational(3, 1073741789) + Rational(1073741827, 3)) + assert_equal(Rational(-1152921470247108494, 3221225367), + Rational(3, 1073741789) - Rational(1073741827, 3)) + assert_equal(Rational(1073741827, 1073741789), + Rational(3, 1073741789) * Rational(1073741827, 3)) + assert_equal(Rational(9, 1152921470247108503), + Rational(3, 1073741789) / Rational(1073741827, 3)) + assert_equal(Rational(1152921432666146002, 1152921470247108503), + Rational(3, 1073741789) + Rational(1073741789, 1073741827)) + assert_equal(Rational(-1152921426223695040, 1152921470247108503), + Rational(3, 1073741789) - Rational(1073741789, 1073741827)) + assert_equal(Rational(3, 1073741827), + Rational(3, 1073741789) * Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225481, 1152921429444920521), + Rational(3, 1073741789) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741830, 1073741789), + Rational(3, 1073741789) + Rational(1073741827, 1073741789)) + assert_equal(Rational(-1073741824, 1073741789), + Rational(3, 1073741789) - Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225481, 1152921429444920521), + Rational(3, 1073741789) * Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 1073741827), + Rational(3, 1073741789) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 3), +Rational(1073741789, 3)) + assert_equal(Rational(-1073741789, 3), -Rational(1073741789, 3)) + assert_equal(Rational(1073741792, 3), + Rational(1073741789, 3) + Rational(1, 1)) + assert_equal(Rational(1073741786, 3), + Rational(1073741789, 3) - Rational(1, 1)) + assert_equal(Rational(1073741789, 3), + Rational(1073741789, 3) * Rational(1, 1)) + assert_equal(Rational(1073741789, 3), + Rational(1073741789, 3) / Rational(1, 1)) + assert_equal(Rational(1073741795, 3), + Rational(1073741789, 3) + Rational(2, 1)) + assert_equal(Rational(1073741783, 3), + Rational(1073741789, 3) - Rational(2, 1)) + assert_equal(Rational(2147483578, 3), + Rational(1073741789, 3) * Rational(2, 1)) + assert_equal(Rational(1073741789, 6), + Rational(1073741789, 3) / Rational(2, 1)) + assert_equal(Rational(1073741798, 3), + Rational(1073741789, 3) + Rational(3, 1)) + assert_equal(Rational(1073741780, 3), + Rational(1073741789, 3) - Rational(3, 1)) + assert_equal(Rational(1073741789, 1), + Rational(1073741789, 3) * Rational(3, 1)) + assert_equal(Rational(1073741789, 9), + Rational(1073741789, 3) / Rational(3, 1)) + assert_equal(Rational(4294967156, 3), + Rational(1073741789, 3) + Rational(1073741789, 1)) + assert_equal(Rational(-2147483578, 3), + Rational(1073741789, 3) - Rational(1073741789, 1)) + assert_equal(Rational(1152921429444920521, 3), + Rational(1073741789, 3) * Rational(1073741789, 1)) + assert_equal(Rational(1, 3), + Rational(1073741789, 3) / Rational(1073741789, 1)) + assert_equal(Rational(4294967270, 3), + Rational(1073741789, 3) + Rational(1073741827, 1)) + assert_equal(Rational(-2147483692, 3), + Rational(1073741789, 3) - Rational(1073741827, 1)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741789, 3) * Rational(1073741827, 1)) + assert_equal(Rational(1073741789, 3221225481), + Rational(1073741789, 3) / Rational(1073741827, 1)) + assert_equal(Rational(1073741791, 3), + Rational(1073741789, 3) + Rational(2, 3)) + assert_equal(Rational(357913929, 1), + Rational(1073741789, 3) - Rational(2, 3)) + assert_equal(Rational(2147483578, 9), + Rational(1073741789, 3) * Rational(2, 3)) + assert_equal(Rational(1073741789, 2), + Rational(1073741789, 3) / Rational(2, 3)) + assert_equal(Rational(2147483587, 6), + Rational(1073741789, 3) + Rational(3, 2)) + assert_equal(Rational(2147483569, 6), + Rational(1073741789, 3) - Rational(3, 2)) + assert_equal(Rational(1073741789, 2), + Rational(1073741789, 3) * Rational(3, 2)) + assert_equal(Rational(2147483578, 9), + Rational(1073741789, 3) / Rational(3, 2)) + assert_equal(Rational(1152921429444920530, 3221225367), + Rational(1073741789, 3) + Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920512, 3221225367), + Rational(1073741789, 3) - Rational(3, 1073741789)) + assert_equal(Rational(1, 1), + Rational(1073741789, 3) * Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920521, 9), + Rational(1073741789, 3) / Rational(3, 1073741789)) + assert_equal(Rational(2147483578, 3), + Rational(1073741789, 3) + Rational(1073741789, 3)) + assert_equal(Rational(0, 1), + Rational(1073741789, 3) - Rational(1073741789, 3)) + assert_equal(Rational(1152921429444920521, 9), + Rational(1073741789, 3) * Rational(1073741789, 3)) + assert_equal(Rational(1, 1), + Rational(1073741789, 3) / Rational(1073741789, 3)) + assert_equal(Rational(1152921470247108512, 3221225481), + Rational(1073741789, 3) + Rational(3, 1073741827)) + assert_equal(Rational(1152921470247108494, 3221225481), + Rational(1073741789, 3) - Rational(3, 1073741827)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1073741789, 3) * Rational(3, 1073741827)) + assert_equal(Rational(1152921470247108503, 9), + Rational(1073741789, 3) / Rational(3, 1073741827)) + assert_equal(Rational(715827872, 1), + Rational(1073741789, 3) + Rational(1073741827, 3)) + assert_equal(Rational(-38, 3), + Rational(1073741789, 3) - Rational(1073741827, 3)) + assert_equal(Rational(1152921470247108503, 9), + Rational(1073741789, 3) * Rational(1073741827, 3)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1073741789, 3) / Rational(1073741827, 3)) + assert_equal(Rational(1152921473468333870, 3221225481), + Rational(1073741789, 3) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921467025883136, 3221225481), + Rational(1073741789, 3) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921429444920521, 3221225481), + Rational(1073741789, 3) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741827, 3), + Rational(1073741789, 3) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921432666146002, 3221225367), + Rational(1073741789, 3) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921426223695040, 3221225367), + Rational(1073741789, 3) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 3), + Rational(1073741789, 3) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921429444920521, 3221225481), + Rational(1073741789, 3) / Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 1073741827), +Rational(3, 1073741827)) + assert_equal(Rational(-3, 1073741827), -Rational(3, 1073741827)) + assert_equal(Rational(1073741830, 1073741827), + Rational(3, 1073741827) + Rational(1, 1)) + assert_equal(Rational(-1073741824, 1073741827), + Rational(3, 1073741827) - Rational(1, 1)) + assert_equal(Rational(3, 1073741827), + Rational(3, 1073741827) * Rational(1, 1)) + assert_equal(Rational(3, 1073741827), + Rational(3, 1073741827) / Rational(1, 1)) + assert_equal(Rational(2147483657, 1073741827), + Rational(3, 1073741827) + Rational(2, 1)) + assert_equal(Rational(-2147483651, 1073741827), + Rational(3, 1073741827) - Rational(2, 1)) + assert_equal(Rational(6, 1073741827), + Rational(3, 1073741827) * Rational(2, 1)) + assert_equal(Rational(3, 2147483654), + Rational(3, 1073741827) / Rational(2, 1)) + assert_equal(Rational(3221225484, 1073741827), + Rational(3, 1073741827) + Rational(3, 1)) + assert_equal(Rational(-3221225478, 1073741827), + Rational(3, 1073741827) - Rational(3, 1)) + assert_equal(Rational(9, 1073741827), + Rational(3, 1073741827) * Rational(3, 1)) + assert_equal(Rational(1, 1073741827), + Rational(3, 1073741827) / Rational(3, 1)) + assert_equal(Rational(1152921470247108506, 1073741827), + Rational(3, 1073741827) + Rational(1073741789, 1)) + assert_equal(Rational(-1152921470247108500, 1073741827), + Rational(3, 1073741827) - Rational(1073741789, 1)) + assert_equal(Rational(3221225367, 1073741827), + Rational(3, 1073741827) * Rational(1073741789, 1)) + assert_equal(Rational(3, 1152921470247108503), + Rational(3, 1073741827) / Rational(1073741789, 1)) + assert_equal(Rational(1152921511049297932, 1073741827), + Rational(3, 1073741827) + Rational(1073741827, 1)) + assert_equal(Rational(-1152921511049297926, 1073741827), + Rational(3, 1073741827) - Rational(1073741827, 1)) + assert_equal(Rational(3, 1), + Rational(3, 1073741827) * Rational(1073741827, 1)) + assert_equal(Rational(3, 1152921511049297929), + Rational(3, 1073741827) / Rational(1073741827, 1)) + assert_equal(Rational(2147483663, 3221225481), + Rational(3, 1073741827) + Rational(2, 3)) + assert_equal(Rational(-2147483645, 3221225481), + Rational(3, 1073741827) - Rational(2, 3)) + assert_equal(Rational(2, 1073741827), + Rational(3, 1073741827) * Rational(2, 3)) + assert_equal(Rational(9, 2147483654), + Rational(3, 1073741827) / Rational(2, 3)) + assert_equal(Rational(3221225487, 2147483654), + Rational(3, 1073741827) + Rational(3, 2)) + assert_equal(Rational(-3221225475, 2147483654), + Rational(3, 1073741827) - Rational(3, 2)) + assert_equal(Rational(9, 2147483654), + Rational(3, 1073741827) * Rational(3, 2)) + assert_equal(Rational(2, 1073741827), + Rational(3, 1073741827) / Rational(3, 2)) + assert_equal(Rational(6442450848, 1152921470247108503), + Rational(3, 1073741827) + Rational(3, 1073741789)) + assert_equal(Rational(-114, 1152921470247108503), + Rational(3, 1073741827) - Rational(3, 1073741789)) + assert_equal(Rational(9, 1152921470247108503), + Rational(3, 1073741827) * Rational(3, 1073741789)) + assert_equal(Rational(1073741789, 1073741827), + Rational(3, 1073741827) / Rational(3, 1073741789)) + assert_equal(Rational(1152921470247108512, 3221225481), + Rational(3, 1073741827) + Rational(1073741789, 3)) + assert_equal(Rational(-1152921470247108494, 3221225481), + Rational(3, 1073741827) - Rational(1073741789, 3)) + assert_equal(Rational(1073741789, 1073741827), + Rational(3, 1073741827) * Rational(1073741789, 3)) + assert_equal(Rational(9, 1152921470247108503), + Rational(3, 1073741827) / Rational(1073741789, 3)) + assert_equal(Rational(6, 1073741827), + Rational(3, 1073741827) + Rational(3, 1073741827)) + assert_equal(Rational(0, 1), + Rational(3, 1073741827) - Rational(3, 1073741827)) + assert_equal(Rational(9, 1152921511049297929), + Rational(3, 1073741827) * Rational(3, 1073741827)) + assert_equal(Rational(1, 1), + Rational(3, 1073741827) / Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297938, 3221225481), + Rational(3, 1073741827) + Rational(1073741827, 3)) + assert_equal(Rational(-1152921511049297920, 3221225481), + Rational(3, 1073741827) - Rational(1073741827, 3)) + assert_equal(Rational(1, 1), + Rational(3, 1073741827) * Rational(1073741827, 3)) + assert_equal(Rational(9, 1152921511049297929), + Rational(3, 1073741827) / Rational(1073741827, 3)) + assert_equal(Rational(1073741792, 1073741827), + Rational(3, 1073741827) + Rational(1073741789, 1073741827)) + assert_equal(Rational(-1073741786, 1073741827), + Rational(3, 1073741827) - Rational(1073741789, 1073741827)) + assert_equal(Rational(3221225367, 1152921511049297929), + Rational(3, 1073741827) * Rational(1073741789, 1073741827)) + assert_equal(Rational(3, 1073741789), + Rational(3, 1073741827) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921514270523296, 1152921470247108503), + Rational(3, 1073741827) + Rational(1073741827, 1073741789)) + assert_equal(Rational(-1152921507828072562, 1152921470247108503), + Rational(3, 1073741827) - Rational(1073741827, 1073741789)) + assert_equal(Rational(3, 1073741789), + Rational(3, 1073741827) * Rational(1073741827, 1073741789)) + assert_equal(Rational(3221225367, 1152921511049297929), + Rational(3, 1073741827) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 3), +Rational(1073741827, 3)) + assert_equal(Rational(-1073741827, 3), -Rational(1073741827, 3)) + assert_equal(Rational(1073741830, 3), + Rational(1073741827, 3) + Rational(1, 1)) + assert_equal(Rational(1073741824, 3), + Rational(1073741827, 3) - Rational(1, 1)) + assert_equal(Rational(1073741827, 3), + Rational(1073741827, 3) * Rational(1, 1)) + assert_equal(Rational(1073741827, 3), + Rational(1073741827, 3) / Rational(1, 1)) + assert_equal(Rational(1073741833, 3), + Rational(1073741827, 3) + Rational(2, 1)) + assert_equal(Rational(1073741821, 3), + Rational(1073741827, 3) - Rational(2, 1)) + assert_equal(Rational(2147483654, 3), + Rational(1073741827, 3) * Rational(2, 1)) + assert_equal(Rational(1073741827, 6), + Rational(1073741827, 3) / Rational(2, 1)) + assert_equal(Rational(1073741836, 3), + Rational(1073741827, 3) + Rational(3, 1)) + assert_equal(Rational(1073741818, 3), + Rational(1073741827, 3) - Rational(3, 1)) + assert_equal(Rational(1073741827, 1), + Rational(1073741827, 3) * Rational(3, 1)) + assert_equal(Rational(1073741827, 9), + Rational(1073741827, 3) / Rational(3, 1)) + assert_equal(Rational(4294967194, 3), + Rational(1073741827, 3) + Rational(1073741789, 1)) + assert_equal(Rational(-2147483540, 3), + Rational(1073741827, 3) - Rational(1073741789, 1)) + assert_equal(Rational(1152921470247108503, 3), + Rational(1073741827, 3) * Rational(1073741789, 1)) + assert_equal(Rational(1073741827, 3221225367), + Rational(1073741827, 3) / Rational(1073741789, 1)) + assert_equal(Rational(4294967308, 3), + Rational(1073741827, 3) + Rational(1073741827, 1)) + assert_equal(Rational(-2147483654, 3), + Rational(1073741827, 3) - Rational(1073741827, 1)) + assert_equal(Rational(1152921511049297929, 3), + Rational(1073741827, 3) * Rational(1073741827, 1)) + assert_equal(Rational(1, 3), + Rational(1073741827, 3) / Rational(1073741827, 1)) + assert_equal(Rational(357913943, 1), + Rational(1073741827, 3) + Rational(2, 3)) + assert_equal(Rational(1073741825, 3), + Rational(1073741827, 3) - Rational(2, 3)) + assert_equal(Rational(2147483654, 9), + Rational(1073741827, 3) * Rational(2, 3)) + assert_equal(Rational(1073741827, 2), + Rational(1073741827, 3) / Rational(2, 3)) + assert_equal(Rational(2147483663, 6), + Rational(1073741827, 3) + Rational(3, 2)) + assert_equal(Rational(2147483645, 6), + Rational(1073741827, 3) - Rational(3, 2)) + assert_equal(Rational(1073741827, 2), + Rational(1073741827, 3) * Rational(3, 2)) + assert_equal(Rational(2147483654, 9), + Rational(1073741827, 3) / Rational(3, 2)) + assert_equal(Rational(1152921470247108512, 3221225367), + Rational(1073741827, 3) + Rational(3, 1073741789)) + assert_equal(Rational(1152921470247108494, 3221225367), + Rational(1073741827, 3) - Rational(3, 1073741789)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1073741827, 3) * Rational(3, 1073741789)) + assert_equal(Rational(1152921470247108503, 9), + Rational(1073741827, 3) / Rational(3, 1073741789)) + assert_equal(Rational(715827872, 1), + Rational(1073741827, 3) + Rational(1073741789, 3)) + assert_equal(Rational(38, 3), + Rational(1073741827, 3) - Rational(1073741789, 3)) + assert_equal(Rational(1152921470247108503, 9), + Rational(1073741827, 3) * Rational(1073741789, 3)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1073741827, 3) / Rational(1073741789, 3)) + assert_equal(Rational(1152921511049297938, 3221225481), + Rational(1073741827, 3) + Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297920, 3221225481), + Rational(1073741827, 3) - Rational(3, 1073741827)) + assert_equal(Rational(1, 1), + Rational(1073741827, 3) * Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297929, 9), + Rational(1073741827, 3) / Rational(3, 1073741827)) + assert_equal(Rational(2147483654, 3), + Rational(1073741827, 3) + Rational(1073741827, 3)) + assert_equal(Rational(0, 1), + Rational(1073741827, 3) - Rational(1073741827, 3)) + assert_equal(Rational(1152921511049297929, 9), + Rational(1073741827, 3) * Rational(1073741827, 3)) + assert_equal(Rational(1, 1), + Rational(1073741827, 3) / Rational(1073741827, 3)) + assert_equal(Rational(1152921514270523296, 3221225481), + Rational(1073741827, 3) + Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921507828072562, 3221225481), + Rational(1073741827, 3) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1073741789, 3), + Rational(1073741827, 3) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921511049297929, 3221225367), + Rational(1073741827, 3) / Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921473468333984, 3221225367), + Rational(1073741827, 3) + Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921467025883022, 3221225367), + Rational(1073741827, 3) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921511049297929, 3221225367), + Rational(1073741827, 3) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 3), + Rational(1073741827, 3) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741789, 1073741827), +Rational(1073741789, 1073741827)) + assert_equal(Rational(-1073741789, 1073741827), -Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483616, 1073741827), + Rational(1073741789, 1073741827) + Rational(1, 1)) + assert_equal(Rational(-38, 1073741827), + Rational(1073741789, 1073741827) - Rational(1, 1)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1073741789, 1073741827) * Rational(1, 1)) + assert_equal(Rational(1073741789, 1073741827), + Rational(1073741789, 1073741827) / Rational(1, 1)) + assert_equal(Rational(3221225443, 1073741827), + Rational(1073741789, 1073741827) + Rational(2, 1)) + assert_equal(Rational(-1073741865, 1073741827), + Rational(1073741789, 1073741827) - Rational(2, 1)) + assert_equal(Rational(2147483578, 1073741827), + Rational(1073741789, 1073741827) * Rational(2, 1)) + assert_equal(Rational(1073741789, 2147483654), + Rational(1073741789, 1073741827) / Rational(2, 1)) + assert_equal(Rational(4294967270, 1073741827), + Rational(1073741789, 1073741827) + Rational(3, 1)) + assert_equal(Rational(-2147483692, 1073741827), + Rational(1073741789, 1073741827) - Rational(3, 1)) + assert_equal(Rational(3221225367, 1073741827), + Rational(1073741789, 1073741827) * Rational(3, 1)) + assert_equal(Rational(1073741789, 3221225481), + Rational(1073741789, 1073741827) / Rational(3, 1)) + assert_equal(Rational(1152921471320850292, 1073741827), + Rational(1073741789, 1073741827) + Rational(1073741789, 1)) + assert_equal(Rational(-1152921469173366714, 1073741827), + Rational(1073741789, 1073741827) - Rational(1073741789, 1)) + assert_equal(Rational(1152921429444920521, 1073741827), + Rational(1073741789, 1073741827) * Rational(1073741789, 1)) + assert_equal(Rational(1, 1073741827), + Rational(1073741789, 1073741827) / Rational(1073741789, 1)) + assert_equal(Rational(1152921512123039718, 1073741827), + Rational(1073741789, 1073741827) + Rational(1073741827, 1)) + assert_equal(Rational(-1152921509975556140, 1073741827), + Rational(1073741789, 1073741827) - Rational(1073741827, 1)) + assert_equal(Rational(1073741789, 1), + Rational(1073741789, 1073741827) * Rational(1073741827, 1)) + assert_equal(Rational(1073741789, 1152921511049297929), + Rational(1073741789, 1073741827) / Rational(1073741827, 1)) + assert_equal(Rational(5368709021, 3221225481), + Rational(1073741789, 1073741827) + Rational(2, 3)) + assert_equal(Rational(1073741713, 3221225481), + Rational(1073741789, 1073741827) - Rational(2, 3)) + assert_equal(Rational(2147483578, 3221225481), + Rational(1073741789, 1073741827) * Rational(2, 3)) + assert_equal(Rational(3221225367, 2147483654), + Rational(1073741789, 1073741827) / Rational(2, 3)) + assert_equal(Rational(5368709059, 2147483654), + Rational(1073741789, 1073741827) + Rational(3, 2)) + assert_equal(Rational(-1073741903, 2147483654), + Rational(1073741789, 1073741827) - Rational(3, 2)) + assert_equal(Rational(3221225367, 2147483654), + Rational(1073741789, 1073741827) * Rational(3, 2)) + assert_equal(Rational(2147483578, 3221225481), + Rational(1073741789, 1073741827) / Rational(3, 2)) + assert_equal(Rational(1152921432666146002, 1152921470247108503), + Rational(1073741789, 1073741827) + Rational(3, 1073741789)) + assert_equal(Rational(1152921426223695040, 1152921470247108503), + Rational(1073741789, 1073741827) - Rational(3, 1073741789)) + assert_equal(Rational(3, 1073741827), + Rational(1073741789, 1073741827) * Rational(3, 1073741789)) + assert_equal(Rational(1152921429444920521, 3221225481), + Rational(1073741789, 1073741827) / Rational(3, 1073741789)) + assert_equal(Rational(1152921473468333870, 3221225481), + Rational(1073741789, 1073741827) + Rational(1073741789, 3)) + assert_equal(Rational(-1152921467025883136, 3221225481), + Rational(1073741789, 1073741827) - Rational(1073741789, 3)) + assert_equal(Rational(1152921429444920521, 3221225481), + Rational(1073741789, 1073741827) * Rational(1073741789, 3)) + assert_equal(Rational(3, 1073741827), + Rational(1073741789, 1073741827) / Rational(1073741789, 3)) + assert_equal(Rational(1073741792, 1073741827), + Rational(1073741789, 1073741827) + Rational(3, 1073741827)) + assert_equal(Rational(1073741786, 1073741827), + Rational(1073741789, 1073741827) - Rational(3, 1073741827)) + assert_equal(Rational(3221225367, 1152921511049297929), + Rational(1073741789, 1073741827) * Rational(3, 1073741827)) + assert_equal(Rational(1073741789, 3), + Rational(1073741789, 1073741827) / Rational(3, 1073741827)) + assert_equal(Rational(1152921514270523296, 3221225481), + Rational(1073741789, 1073741827) + Rational(1073741827, 3)) + assert_equal(Rational(-1152921507828072562, 3221225481), + Rational(1073741789, 1073741827) - Rational(1073741827, 3)) + assert_equal(Rational(1073741789, 3), + Rational(1073741789, 1073741827) * Rational(1073741827, 3)) + assert_equal(Rational(3221225367, 1152921511049297929), + Rational(1073741789, 1073741827) / Rational(1073741827, 3)) + assert_equal(Rational(2147483578, 1073741827), + Rational(1073741789, 1073741827) + Rational(1073741789, 1073741827)) + assert_equal(Rational(0, 1), + Rational(1073741789, 1073741827) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921429444920521, 1152921511049297929), + Rational(1073741789, 1073741827) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1, 1), + Rational(1073741789, 1073741827) / Rational(1073741789, 1073741827)) + assert_equal(Rational(2305842940494218450, 1152921470247108503), + Rational(1073741789, 1073741827) + Rational(1073741827, 1073741789)) + assert_equal(Rational(-81604377408, 1152921470247108503), + Rational(1073741789, 1073741827) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1, 1), + Rational(1073741789, 1073741827) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921429444920521, 1152921511049297929), + Rational(1073741789, 1073741827) / Rational(1073741827, 1073741789)) + assert_equal(Rational(1073741827, 1073741789), +Rational(1073741827, 1073741789)) + assert_equal(Rational(-1073741827, 1073741789), -Rational(1073741827, 1073741789)) + assert_equal(Rational(2147483616, 1073741789), + Rational(1073741827, 1073741789) + Rational(1, 1)) + assert_equal(Rational(38, 1073741789), + Rational(1073741827, 1073741789) - Rational(1, 1)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1073741827, 1073741789) * Rational(1, 1)) + assert_equal(Rational(1073741827, 1073741789), + Rational(1073741827, 1073741789) / Rational(1, 1)) + assert_equal(Rational(3221225405, 1073741789), + Rational(1073741827, 1073741789) + Rational(2, 1)) + assert_equal(Rational(-1073741751, 1073741789), + Rational(1073741827, 1073741789) - Rational(2, 1)) + assert_equal(Rational(2147483654, 1073741789), + Rational(1073741827, 1073741789) * Rational(2, 1)) + assert_equal(Rational(1073741827, 2147483578), + Rational(1073741827, 1073741789) / Rational(2, 1)) + assert_equal(Rational(4294967194, 1073741789), + Rational(1073741827, 1073741789) + Rational(3, 1)) + assert_equal(Rational(-2147483540, 1073741789), + Rational(1073741827, 1073741789) - Rational(3, 1)) + assert_equal(Rational(3221225481, 1073741789), + Rational(1073741827, 1073741789) * Rational(3, 1)) + assert_equal(Rational(1073741827, 3221225367), + Rational(1073741827, 1073741789) / Rational(3, 1)) + assert_equal(Rational(1152921430518662348, 1073741789), + Rational(1073741827, 1073741789) + Rational(1073741789, 1)) + assert_equal(Rational(-1152921428371178694, 1073741789), + Rational(1073741827, 1073741789) - Rational(1073741789, 1)) + assert_equal(Rational(1073741827, 1), + Rational(1073741827, 1073741789) * Rational(1073741789, 1)) + assert_equal(Rational(1073741827, 1152921429444920521), + Rational(1073741827, 1073741789) / Rational(1073741789, 1)) + assert_equal(Rational(1152921471320850330, 1073741789), + Rational(1073741827, 1073741789) + Rational(1073741827, 1)) + assert_equal(Rational(-1152921469173366676, 1073741789), + Rational(1073741827, 1073741789) - Rational(1073741827, 1)) + assert_equal(Rational(1152921511049297929, 1073741789), + Rational(1073741827, 1073741789) * Rational(1073741827, 1)) + assert_equal(Rational(1, 1073741789), + Rational(1073741827, 1073741789) / Rational(1073741827, 1)) + assert_equal(Rational(5368709059, 3221225367), + Rational(1073741827, 1073741789) + Rational(2, 3)) + assert_equal(Rational(1073741903, 3221225367), + Rational(1073741827, 1073741789) - Rational(2, 3)) + assert_equal(Rational(2147483654, 3221225367), + Rational(1073741827, 1073741789) * Rational(2, 3)) + assert_equal(Rational(3221225481, 2147483578), + Rational(1073741827, 1073741789) / Rational(2, 3)) + assert_equal(Rational(5368709021, 2147483578), + Rational(1073741827, 1073741789) + Rational(3, 2)) + assert_equal(Rational(-1073741713, 2147483578), + Rational(1073741827, 1073741789) - Rational(3, 2)) + assert_equal(Rational(3221225481, 2147483578), + Rational(1073741827, 1073741789) * Rational(3, 2)) + assert_equal(Rational(2147483654, 3221225367), + Rational(1073741827, 1073741789) / Rational(3, 2)) + assert_equal(Rational(1073741830, 1073741789), + Rational(1073741827, 1073741789) + Rational(3, 1073741789)) + assert_equal(Rational(1073741824, 1073741789), + Rational(1073741827, 1073741789) - Rational(3, 1073741789)) + assert_equal(Rational(3221225481, 1152921429444920521), + Rational(1073741827, 1073741789) * Rational(3, 1073741789)) + assert_equal(Rational(1073741827, 3), + Rational(1073741827, 1073741789) / Rational(3, 1073741789)) + assert_equal(Rational(1152921432666146002, 3221225367), + Rational(1073741827, 1073741789) + Rational(1073741789, 3)) + assert_equal(Rational(-1152921426223695040, 3221225367), + Rational(1073741827, 1073741789) - Rational(1073741789, 3)) + assert_equal(Rational(1073741827, 3), + Rational(1073741827, 1073741789) * Rational(1073741789, 3)) + assert_equal(Rational(3221225481, 1152921429444920521), + Rational(1073741827, 1073741789) / Rational(1073741789, 3)) + assert_equal(Rational(1152921514270523296, 1152921470247108503), + Rational(1073741827, 1073741789) + Rational(3, 1073741827)) + assert_equal(Rational(1152921507828072562, 1152921470247108503), + Rational(1073741827, 1073741789) - Rational(3, 1073741827)) + assert_equal(Rational(3, 1073741789), + Rational(1073741827, 1073741789) * Rational(3, 1073741827)) + assert_equal(Rational(1152921511049297929, 3221225367), + Rational(1073741827, 1073741789) / Rational(3, 1073741827)) + assert_equal(Rational(1152921473468333984, 3221225367), + Rational(1073741827, 1073741789) + Rational(1073741827, 3)) + assert_equal(Rational(-1152921467025883022, 3221225367), + Rational(1073741827, 1073741789) - Rational(1073741827, 3)) + assert_equal(Rational(1152921511049297929, 3221225367), + Rational(1073741827, 1073741789) * Rational(1073741827, 3)) + assert_equal(Rational(3, 1073741789), + Rational(1073741827, 1073741789) / Rational(1073741827, 3)) + assert_equal(Rational(2305842940494218450, 1152921470247108503), + Rational(1073741827, 1073741789) + Rational(1073741789, 1073741827)) + assert_equal(Rational(81604377408, 1152921470247108503), + Rational(1073741827, 1073741789) - Rational(1073741789, 1073741827)) + assert_equal(Rational(1, 1), + Rational(1073741827, 1073741789) * Rational(1073741789, 1073741827)) + assert_equal(Rational(1152921511049297929, 1152921429444920521), + Rational(1073741827, 1073741789) / Rational(1073741789, 1073741827)) + assert_equal(Rational(2147483654, 1073741789), + Rational(1073741827, 1073741789) + Rational(1073741827, 1073741789)) + assert_equal(Rational(0, 1), + Rational(1073741827, 1073741789) - Rational(1073741827, 1073741789)) + assert_equal(Rational(1152921511049297929, 1152921429444920521), + Rational(1073741827, 1073741789) * Rational(1073741827, 1073741789)) + assert_equal(Rational(1, 1), + Rational(1073741827, 1073741789) / Rational(1073741827, 1073741789)) + end + +end diff --git a/jni/ruby/test/ruby/test_readpartial.rb b/jni/ruby/test/ruby/test_readpartial.rb new file mode 100644 index 0000000..7f2ec65 --- /dev/null +++ b/jni/ruby/test/ruby/test_readpartial.rb @@ -0,0 +1,72 @@ +require 'test/unit' +require 'timeout' +require 'fcntl' + +class TestReadPartial < Test::Unit::TestCase + def make_pipe + r, w = IO.pipe + r.binmode + w.binmode + begin + yield r, w + ensure + r.close unless r.closed? + w.close unless w.closed? + end + end + + def pipe + make_pipe {|r, w| + yield r, w + } + return unless defined?(Fcntl::F_SETFL) + return unless defined?(Fcntl::F_GETFL) + return unless defined?(Fcntl::O_NONBLOCK) + make_pipe {|r, w| + r.fcntl(Fcntl::F_SETFL, r.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) + yield r, w + } + end + + def test_length_zero + pipe {|r, w| + assert_equal('', r.readpartial(0)) + } + end + + def test_closed_pipe + pipe {|r, w| + w << 'abc' + w.close + assert_equal('ab', r.readpartial(2)) + assert_equal('c', r.readpartial(2)) + assert_raise(EOFError) { r.readpartial(2) } + assert_raise(EOFError) { r.readpartial(2) } + } + end + + def test_open_pipe + pipe {|r, w| + w << 'abc' + assert_equal('ab', r.readpartial(2)) + assert_equal('c', r.readpartial(2)) + assert_raise(Timeout::Error) { + timeout(0.1) { r.readpartial(2) } + } + } + end + + def test_with_stdio + pipe {|r, w| + w << "abc\ndef\n" + assert_equal("abc\n", r.gets) + w << "ghi\n" + assert_equal("de", r.readpartial(2)) + assert_equal("f\n", r.readpartial(4096)) + assert_equal("ghi\n", r.readpartial(4096)) + assert_raise(Timeout::Error) { + timeout(0.1) { r.readpartial(2) } + } + } + end +end diff --git a/jni/ruby/test/ruby/test_refinement.rb b/jni/ruby/test/ruby/test_refinement.rb new file mode 100644 index 0000000..557dc38 --- /dev/null +++ b/jni/ruby/test/ruby/test_refinement.rb @@ -0,0 +1,1450 @@ +require 'test/unit' + +# to supress warnings for future calls of Module#refine +EnvUtil.suppress_warning do + Module.new { + refine(Object) {} + } +end + +class TestRefinement < Test::Unit::TestCase + class Foo + def x + return "Foo#x" + end + + def y + return "Foo#y" + end + + def a + return "Foo#a" + end + + def call_x + return x + end + end + + module FooExt + refine Foo do + def x + return "FooExt#x" + end + + def y + return "FooExt#y " + super + end + + def z + return "FooExt#z" + end + + def a + return "FooExt#a" + end + end + end + + module FooExt2 + refine Foo do + def x + return "FooExt2#x" + end + + def y + return "FooExt2#y " + super + end + + def z + return "FooExt2#z" + end + end + end + + class FooSub < Foo + def x + return "FooSub#x" + end + + def y + return "FooSub#y " + super + end + end + + eval <<-EOF, TOPLEVEL_BINDING + using TestRefinement::FooExt + + class TestRefinement::FooExtClient + def self.invoke_x_on(foo) + return foo.x + end + + def self.invoke_y_on(foo) + return foo.y + end + + def self.invoke_z_on(foo) + return foo.z + end + + def self.send_z_on(foo) + return foo.send(:z) + end + + def self.method_z(foo) + return foo.method(:z) + end + + def self.invoke_call_x_on(foo) + return foo.call_x + end + end + EOF + + eval <<-EOF, TOPLEVEL_BINDING + using TestRefinement::FooExt + using TestRefinement::FooExt2 + + class TestRefinement::FooExtClient2 + def self.invoke_y_on(foo) + return foo.y + end + + def self.invoke_a_on(foo) + return foo.a + end + end + EOF + + def test_override + foo = Foo.new + assert_equal("Foo#x", foo.x) + assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo)) + assert_equal("Foo#x", foo.x) + end + + def test_super + foo = Foo.new + assert_equal("Foo#y", foo.y) + assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo)) + assert_equal("Foo#y", foo.y) + end + + def test_super_not_chained + foo = Foo.new + assert_equal("Foo#y", foo.y) + assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo)) + assert_equal("Foo#y", foo.y) + end + + def test_using_same_class_refinements + foo = Foo.new + assert_equal("Foo#a", foo.a) + assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo)) + assert_equal("Foo#a", foo.a) + end + + def test_new_method + foo = Foo.new + assert_raise(NoMethodError) { foo.z } + assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo)) + assert_raise(NoMethodError) { foo.z } + end + + module RespondTo + class Super + def foo + end + end + + class Sub < Super + end + + module M + refine Sub do + def foo + end + end + end + end + + def test_send_should_not_use_refinements + foo = Foo.new + assert_raise(NoMethodError) { foo.send(:z) } + assert_raise(NoMethodError) { FooExtClient.send_z_on(foo) } + assert_raise(NoMethodError) { foo.send(:z) } + + assert_equal(true, RespondTo::Sub.new.respond_to?(:foo)) + end + + def test_method_should_not_use_refinements + foo = Foo.new + assert_raise(NameError) { foo.method(:z) } + assert_raise(NameError) { FooExtClient.method_z(foo) } + assert_raise(NameError) { foo.method(:z) } + end + + def test_no_local_rebinding + foo = Foo.new + assert_equal("Foo#x", foo.call_x) + assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo)) + assert_equal("Foo#x", foo.call_x) + end + + def test_subclass_is_prior + sub = FooSub.new + assert_equal("FooSub#x", sub.x) + assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub)) + assert_equal("FooSub#x", sub.x) + end + + def test_super_in_subclass + sub = FooSub.new + assert_equal("FooSub#y Foo#y", sub.y) + # not "FooSub#y FooExt#y Foo#y" + assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub)) + assert_equal("FooSub#y Foo#y", sub.y) + end + + def test_new_method_on_subclass + sub = FooSub.new + assert_raise(NoMethodError) { sub.z } + assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub)) + assert_raise(NoMethodError) { sub.z } + end + + def test_module_eval + foo = Foo.new + assert_equal("Foo#x", foo.x) + assert_equal("Foo#x", FooExt.module_eval { foo.x }) + assert_equal("Foo#x", FooExt.module_eval("foo.x")) + assert_equal("Foo#x", foo.x) + end + + def test_instance_eval_without_refinement + foo = Foo.new + ext_client = FooExtClient.new + assert_equal("Foo#x", foo.x) + assert_equal("Foo#x", ext_client.instance_eval { foo.x }) + assert_equal("Foo#x", foo.x) + end + + module FixnumSlashExt + refine Fixnum do + def /(other) quo(other) end + end + end + + def test_override_builtin_method + assert_equal(0, 1 / 2) + assert_equal(Rational(1, 2), eval_using(FixnumSlashExt, "1 / 2")) + assert_equal(0, 1 / 2) + end + + module FixnumPlusExt + refine Fixnum do + def self.method_added(*args); end + def +(other) "overridden" end + end + end + + def test_override_builtin_method_with_method_added + assert_equal(3, 1 + 2) + assert_equal("overridden", eval_using(FixnumPlusExt, "1 + 2")) + assert_equal(3, 1 + 2) + end + + def test_return_value_of_refine + mod = nil + result = nil + Module.new { + result = refine(Object) { + mod = self + } + } + assert_equal mod, result + end + + module RefineSameClass + REFINEMENT1 = refine(Fixnum) { + def foo; return "foo" end + } + REFINEMENT2 = refine(Fixnum) { + def bar; return "bar" end + } + REFINEMENT3 = refine(String) { + def baz; return "baz" end + } + end + + def test_refine_same_class_twice + assert_equal("foo", eval_using(RefineSameClass, "1.foo")) + assert_equal("bar", eval_using(RefineSameClass, "1.bar")) + assert_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT2) + assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3) + end + + module FixnumFooExt + refine Fixnum do + def foo; "foo"; end + end + end + + def test_respond_to_should_not_use_refinements + assert_equal(false, 1.respond_to?(:foo)) + assert_equal(false, eval_using(FixnumFooExt, "1.respond_to?(:foo)")) + end + + module StringCmpExt + refine String do + def <=>(other) return 0 end + end + end + + module ArrayEachExt + refine Array do + def each + super do |i| + yield 2 * i + end + end + end + end + + def test_builtin_method_no_local_rebinding + assert_equal(false, eval_using(StringCmpExt, '"1" >= "2"')) + assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min")) + end + + module RefinePrependedClass + module M1 + def foo + super << :m1 + end + end + + class C + prepend M1 + + def foo + [:c] + end + end + + module M2 + refine C do + def foo + super << :m2 + end + end + end + end + + def test_refine_prepended_class + x = eval_using(RefinePrependedClass::M2, + "TestRefinement::RefinePrependedClass::C.new.foo") + assert_equal([:c, :m1, :m2], x) + end + + def test_refine_module + m1 = Module.new + assert_raise(TypeError) do + Module.new { + refine m1 do + def foo + :m2 + end + end + } + end + end + + def test_refine_neither_class_nor_module + assert_raise(TypeError) do + Module.new { + refine Object.new do + end + } + end + assert_raise(TypeError) do + Module.new { + refine 123 do + end + } + end + assert_raise(TypeError) do + Module.new { + refine "foo" do + end + } + end + end + + def test_refine_in_class + assert_raise(NoMethodError) do + Class.new { + refine Fixnum do + def foo + "c" + end + end + } + end + end + + def test_main_using + assert_in_out_err([], <<-INPUT, %w(:C :M), []) + class C + def foo + :C + end + end + + module M + refine C do + def foo + :M + end + end + end + + c = C.new + p c.foo + using M + p c.foo + INPUT + end + + def test_main_using_is_private + assert_raise(NoMethodError) do + eval("self.using Module.new", TOPLEVEL_BINDING) + end + end + + def test_no_kernel_using + assert_raise(NoMethodError) do + using Module.new + end + end + + class UsingClass + end + + def test_module_using_class + assert_raise(TypeError) do + eval("using TestRefinement::UsingClass", TOPLEVEL_BINDING) + end + end + + def test_refine_without_block + c1 = Class.new + assert_raise_with_message(ArgumentError, "no block given") { + Module.new do + refine c1 + end + } + end + + module Inspect + module M + Fixnum = refine(Fixnum) {} + end + end + + def test_inspect + assert_equal("#<refinement:Fixnum@TestRefinement::Inspect::M>", + Inspect::M::Fixnum.inspect) + end + + def test_using_method_cache + assert_in_out_err([], <<-INPUT, %w(:M1 :M2), []) + class C + def foo + "original" + end + end + + module M1 + refine C do + def foo + :M1 + end + end + end + + module M2 + refine C do + def foo + :M2 + end + end + end + + c = C.new + using M1 + p c.foo + using M2 + p c.foo + INPUT + end + + module RedefineRefinedMethod + class C + def foo + "original" + end + end + + module M + refine C do + def foo + "refined" + end + end + end + + class C + def foo + "redefined" + end + end + end + + def test_redefine_refined_method + x = eval_using(RedefineRefinedMethod::M, + "TestRefinement::RedefineRefinedMethod::C.new.foo") + assert_equal("refined", x) + end + + module StringExt + refine String do + def foo + "foo" + end + end + end + + module RefineScoping + refine String do + def foo + "foo" + end + + def RefineScoping.call_in_refine_block + "".foo + end + end + + def self.call_outside_refine_block + "".foo + end + end + + def test_refine_scoping + assert_equal("foo", RefineScoping.call_in_refine_block) + assert_raise(NoMethodError) do + RefineScoping.call_outside_refine_block + end + end + + module StringRecursiveLength + refine String do + def recursive_length + if empty? + 0 + else + self[1..-1].recursive_length + 1 + end + end + end + end + + def test_refine_recursion + x = eval_using(StringRecursiveLength, "'foo'.recursive_length") + assert_equal(3, x) + end + + module ToJSON + refine Integer do + def to_json; to_s; end + end + + refine Array do + def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end + end + + refine Hash do + def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end + end + end + + def test_refine_mutual_recursion + x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json") + assert_equal('[{"1":2},{"3":4}]', x) + end + + def test_refine_with_proc + assert_raise(ArgumentError) do + Module.new { + refine(String, &Proc.new {}) + } + end + end + + def test_using_in_module + assert_raise(RuntimeError) do + eval(<<-EOF, TOPLEVEL_BINDING) + $main = self + module M + end + module M2 + $main.send(:using, M) + end + EOF + end + end + + def test_using_in_method + assert_raise(RuntimeError) do + eval(<<-EOF, TOPLEVEL_BINDING) + $main = self + module M + end + def call_using_in_method + $main.send(:using, M) + end + call_using_in_method + EOF + end + 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 + include Mixin + + def baz + return super << " M#baz" + end + end + end + end + + eval <<-EOF, TOPLEVEL_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 + prepend Mixin + + def baz + return super << " M#baz" + end + end + end + end + + eval <<-EOF, TOPLEVEL_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 self.invoke_baz_on(x) + x.baz + 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 + + module PrependAfterRefine + class C + def foo + "original" + end + end + + module M + refine C do + def foo + "refined" + end + + def bar + "refined" + end + end + end + + module Mixin + def foo + "mixin" + end + + def bar + "mixin" + end + end + + class C + prepend Mixin + end + end + + def test_prepend_after_refine + x = eval_using(PrependAfterRefine::M, + "TestRefinement::PrependAfterRefine::C.new.foo") + assert_equal("refined", x) + assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo) + y = eval_using(PrependAfterRefine::M, + "TestRefinement::PrependAfterRefine::C.new.bar") + assert_equal("refined", y) + assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar) + end + + module SuperInBlock + class C + def foo(*args) + [:foo, *args] + end + end + + module R + refine C do + def foo(*args) + tap do + return super(:ref, *args) + end + end + end + end + end + + def test_super_in_block + bug7925 = '[ruby-core:52750] [Bug #7925]' + x = eval_using(SuperInBlock::R, + "TestRefinement:: SuperInBlock::C.new.foo(#{bug7925.dump})") + assert_equal([:foo, :ref, bug7925], x, bug7925) + end + + module ModuleUsing + using FooExt + + def self.invoke_x_on(foo) + return foo.x + end + + def self.invoke_y_on(foo) + return foo.y + end + + def self.invoke_z_on(foo) + return foo.z + end + + def self.send_z_on(foo) + return foo.send(:z) + end + + def self.method_z(foo) + return foo.method(:z) + end + + def self.invoke_call_x_on(foo) + return foo.call_x + end + end + + def test_module_using + foo = Foo.new + assert_equal("Foo#x", foo.x) + assert_equal("Foo#y", foo.y) + assert_raise(NoMethodError) { foo.z } + assert_equal("FooExt#x", ModuleUsing.invoke_x_on(foo)) + assert_equal("FooExt#y Foo#y", ModuleUsing.invoke_y_on(foo)) + assert_equal("FooExt#z", ModuleUsing.invoke_z_on(foo)) + assert_equal("Foo#x", foo.x) + assert_equal("Foo#y", foo.y) + assert_raise(NoMethodError) { foo.z } + end + + def test_module_using_in_method + assert_raise(RuntimeError) do + Module.new.send(:using, FooExt) + end + end + + def test_module_using_invalid_self + assert_raise(RuntimeError) do + eval <<-EOF, TOPLEVEL_BINDING + module TestRefinement::TestModuleUsingInvalidSelf + Module.new.send(:using, TestRefinement::FooExt) + end + EOF + end + end + + class Bar + end + + module BarExt + refine Bar do + def x + return "BarExt#x" + end + end + end + + module FooBarExt + include FooExt + include BarExt + end + + module FooBarExtClient + using FooBarExt + + def self.invoke_x_on(foo) + return foo.x + end + end + + def test_module_inclusion + foo = Foo.new + assert_equal("FooExt#x", FooBarExtClient.invoke_x_on(foo)) + bar = Bar.new + assert_equal("BarExt#x", FooBarExtClient.invoke_x_on(bar)) + end + + module FooFoo2Ext + include FooExt + include FooExt2 + end + + module FooFoo2ExtClient + using FooFoo2Ext + + def self.invoke_x_on(foo) + return foo.x + end + + def self.invoke_y_on(foo) + return foo.y + end + end + + def test_module_inclusion2 + foo = Foo.new + assert_equal("FooExt2#x", FooFoo2ExtClient.invoke_x_on(foo)) + assert_equal("FooExt2#y Foo#y", FooFoo2ExtClient.invoke_y_on(foo)) + end + + def test_eval_scoping + assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "HELLO WORLD"], []) + module M + refine String do + def upcase + reverse + end + end + end + + puts "hello world".upcase + puts eval(%{using M; "hello world".upcase}) + puts "hello world".upcase + INPUT + end + + def test_eval_with_binding_scoping + assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "HELLO WORLD"], []) + module M + refine String do + def upcase + reverse + end + end + end + + puts "hello world".upcase + puts eval(%{using M; "hello world".upcase}, TOPLEVEL_BINDING) + puts eval(%{"hello world".upcase}, TOPLEVEL_BINDING) + INPUT + end + + def test_case_dispatch_is_aware_of_refinements + assert_in_out_err([], <<-RUBY, ["refinement used"], []) + module RefineSymbol + refine Symbol do + def ===(other) + true + end + end + end + + using RefineSymbol + + case :a + when :b + puts "refinement used" + else + puts "refinement not used" + end + RUBY + end + + def test_refine_after_using + assert_separately([], <<-"end;") + bug8880 = '[ruby-core:57079] [Bug #8880]' + module Test + refine(String) do + end + end + using Test + def t + 'Refinements are broken!'.chop! + end + t + module Test + refine(String) do + def chop! + self.sub!(/broken/, 'fine') + end + end + end + assert_equal('Refinements are fine!', t, bug8880) + end; + end + + def test_instance_methods + bug8881 = '[ruby-core:57080] [Bug #8881]' + assert_not_include(Foo.instance_methods(false), :z, bug8881) + assert_not_include(FooSub.instance_methods(true), :z, bug8881) + end + + def test_method_defined + assert_not_send([Foo, :method_defined?, :z]) + assert_not_send([FooSub, :method_defined?, :z]) + end + + def test_undef_refined_method + bug8966 = '[ruby-core:57466] [Bug #8966]' + + assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966) + module Foo + refine Object do + def foo + puts "foo" + end + end + end + + using Foo + + class Object + begin + undef foo + rescue Exception => e + p e.class + end + end + INPUT + + assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966) + module Foo + refine Object do + def foo + puts "foo" + end + end + end + + # without `using Foo' + + class Object + begin + undef foo + rescue Exception => e + p e.class + end + end + INPUT + end + + def test_refine_undefed_method_and_call + assert_in_out_err([], <<-INPUT, ["NoMethodError"], []) + class Foo + def foo + end + + undef foo + end + + module FooExt + refine Foo do + def foo + end + end + end + + begin + Foo.new.foo + rescue => e + p e.class + end + INPUT + end + + def test_refine_undefed_method_and_send + assert_in_out_err([], <<-INPUT, ["NoMethodError"], []) + class Foo + def foo + end + + undef foo + end + + module FooExt + refine Foo do + def foo + end + end + end + + begin + Foo.new.send(:foo) + rescue => e + p e.class + end + INPUT + end + + def test_adding_private_method + bug9452 = '[ruby-core:60111] [Bug #9452]' + + assert_in_out_err([], <<-INPUT, ["Success!", "NoMethodError"], [], bug9452) + module R + refine Object do + def m + puts "Success!" + end + + private(:m) + end + end + + using R + + m + 42.m rescue p($!.class) + INPUT + end + + def test_making_private_method_public + bug9452 = '[ruby-core:60111] [Bug #9452]' + + assert_in_out_err([], <<-INPUT, ["Success!", "Success!"], [], bug9452) + class Object + private + def m + end + end + + module R + refine Object do + def m + puts "Success!" + end + end + end + + using R + m + 42.m + INPUT + end + + def test_refine_basic_object + assert_separately([], <<-"end;") + bug10106 = '[ruby-core:64166] [Bug #10106]' + module RefinementBug + refine BasicObject do + def foo + 1 + end + end + end + + assert_raise(NoMethodError, bug10106) {Object.new.foo} + end; + + assert_separately([], <<-"end;") + bug10707 = '[ruby-core:67389] [Bug #10707]' + module RefinementBug + refine BasicObject do + def foo + end + end + end + + assert(methods, bug10707) + assert_raise(NameError, bug10707) {method(:foo)} + end; + end + + def test_change_refined_new_method_visibility + assert_separately([], <<-"end;") + bug10706 = '[ruby-core:67387] [Bug #10706]' + module RefinementBug + refine Object do + def foo + end + end + end + + assert_raise(NameError, bug10706) {private(:foo)} + end; + end + + def test_alias_refined_method + assert_separately([], <<-"end;") + bug10731 = '[ruby-core:67523] [Bug #10731]' + + class C + end + + module RefinementBug + refine C do + def foo + end + + def bar + end + end + end + + assert_raise(NameError, bug10731) do + class C + alias foo bar + end + end + end; + end + + def test_singleton_method_should_not_use_refinements + assert_separately([], <<-"end;") + bug10744 = '[ruby-core:67603] [Bug #10744]' + + class C + end + + module RefinementBug + refine C.singleton_class do + def foo + end + end + end + + assert_raise(NameError, bug10744) { C.singleton_method(:foo) } + end; + end + + def test_refined_method_defined + assert_separately([], <<-"end;") + bug10753 = '[ruby-core:67656] [Bug #10753]' + + c = Class.new do + def refined_public; end + def refined_protected; end + def refined_private; end + + public :refined_public + protected :refined_protected + private :refined_private + end + + m = Module.new do + refine(c) do + def refined_public; end + def refined_protected; end + def refined_private; end + + public :refined_public + protected :refined_protected + private :refined_private + end + end + + using m + + assert_equal(true, c.public_method_defined?(:refined_public), bug10753) + assert_equal(false, c.public_method_defined?(:refined_protected), bug10753) + assert_equal(false, c.public_method_defined?(:refined_private), bug10753) + + assert_equal(false, c.protected_method_defined?(:refined_public), bug10753) + assert_equal(true, c.protected_method_defined?(:refined_protected), bug10753) + assert_equal(false, c.protected_method_defined?(:refined_private), bug10753) + + assert_equal(false, c.private_method_defined?(:refined_public), bug10753) + assert_equal(false, c.private_method_defined?(:refined_protected), bug10753) + assert_equal(true, c.private_method_defined?(:refined_private), bug10753) + end; + end + + def test_undefined_refined_method_defined + assert_separately([], <<-"end;") + bug10753 = '[ruby-core:67656] [Bug #10753]' + + c = Class.new + + m = Module.new do + refine(c) do + def undefined_refined_public; end + def undefined_refined_protected; end + def undefined_refined_private; end + public :undefined_refined_public + protected :undefined_refined_protected + private :undefined_refined_private + end + end + + using m + + assert_equal(false, c.public_method_defined?(:undefined_refined_public), bug10753) + assert_equal(false, c.public_method_defined?(:undefined_refined_protected), bug10753) + assert_equal(false, c.public_method_defined?(:undefined_refined_private), bug10753) + + assert_equal(false, c.protected_method_defined?(:undefined_refined_public), bug10753) + assert_equal(false, c.protected_method_defined?(:undefined_refined_protected), bug10753) + assert_equal(false, c.protected_method_defined?(:undefined_refined_private), bug10753) + + assert_equal(false, c.private_method_defined?(:undefined_refined_public), bug10753) + assert_equal(false, c.private_method_defined?(:undefined_refined_protected), bug10753) + assert_equal(false, c.private_method_defined?(:undefined_refined_private), bug10753) + end; + end + + def test_remove_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + def foo + "C#foo" + end + end + + module RefinementBug + refine C do + def foo + "RefinementBug#foo" + end + end + end + + using RefinementBug + + class C + remove_method :foo + end + + assert_equal("RefinementBug#foo", C.new.foo, bug10765) + end; + end + + def test_remove_undefined_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + end + + module RefinementBug + refine C do + def foo + end + end + end + + using RefinementBug + + assert_raise(NameError, bug10765) { + class C + remove_method :foo + end + } + end; + end + + module NotIncludeSuperclassMethod + class X + def foo + end + end + + class Y < X + end + + module Bar + refine Y do + def foo + end + end + end + end + + def test_instance_methods_not_include_superclass_method + bug10826 = '[ruby-dev:48854] [Bug #10826]' + assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false), + :foo, bug10826) + assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true), + :foo, bug10826) + end + + def test_call_refined_method_in_duplicate_module + bug10885 = '[ruby-dev:48878]' + assert_in_out_err([], <<-INPUT, [], [], bug10885) + module M + refine Object do + def raise + # do nothing + end + end + + class << self + using M + def m0 + raise + end + end + + using M + def M.m1 + raise + end + end + + M.dup.m0 + M.dup.m1 + INPUT + end + + def test_check_funcall_undefined + bug11117 = '[ruby-core:69064] [Bug #11117]' + + x = Class.new + Module.new do + refine x do + def to_regexp + // + end + end + end + + assert_nothing_raised(NoMethodError, bug11117) { + assert_nil(Regexp.try_convert(x.new)) + } + end + + def test_funcall_inherited + bug11117 = '[ruby-core:69064] [Bug #11117]' + + Module.new {refine(Dir) {def to_s; end}} + x = Class.new(Dir).allocate + assert_nothing_raised(NoMethodError, bug11117) { + x.inspect + } + end + + private + + def eval_using(mod, s) + eval("using #{mod}; #{s}", TOPLEVEL_BINDING) + end +end diff --git a/jni/ruby/test/ruby/test_regexp.rb b/jni/ruby/test/ruby/test_regexp.rb new file mode 100644 index 0000000..cef21b9 --- /dev/null +++ b/jni/ruby/test/ruby/test_regexp.rb @@ -0,0 +1,1102 @@ +# coding: US-ASCII +require 'test/unit' + +class TestRegexp < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def test_has_NOENCODING + assert Regexp::NOENCODING + re = //n + assert_equal Regexp::NOENCODING, re.options + end + + def test_ruby_dev_999 + assert_match(/(?<=a).*b/, "aab") + assert_match(/(?<=\u3042).*b/, "\u3042ab") + end + + def test_ruby_core_27247 + assert_match(/(a){2}z/, "aaz") + end + + def test_ruby_dev_24643 + assert_nothing_raised("[ruby-dev:24643]") { + /(?:(?:[a]*[a])?b)*a*$/ =~ "aabaaca" + } + end + + def test_ruby_talk_116455 + assert_match(/^(\w{2,}).* ([A-Za-z\xa2\xc0-\xff]{2,}?)$/n, "Hallo Welt") + end + + def test_ruby_dev_24887 + assert_equal("a".gsub(/a\Z/, ""), "") + end + + def test_yoshidam_net_20041111_1 + s = "[\xC2\xA0-\xC3\xBE]" + assert_match(Regexp.new(s, nil, "u"), "\xC3\xBE") + end + + def test_yoshidam_net_20041111_2 + assert_raise(RegexpError) do + s = "[\xFF-\xFF]".force_encoding("utf-8") + Regexp.new(s, nil, "u") + end + end + + def test_ruby_dev_31309 + assert_equal('Ruby', 'Ruby'.sub(/[^a-z]/i, '-')) + end + + def test_assert_normal_exit + # moved from knownbug. It caused core. + Regexp.union("a", "a") + end + + def test_to_s + assert_equal '(?-mix:\x00)', Regexp.new("\0").to_s + + str = "abcd\u3042" + [:UTF_16BE, :UTF_16LE, :UTF_32BE, :UTF_32LE].each do |es| + enc = Encoding.const_get(es) + rs = Regexp.new(str.encode(enc)).to_s + assert_equal("(?-mix:abcd\u3042)".encode(enc), rs) + assert_equal(enc, rs.encoding) + end + end + + def test_union + assert_equal :ok, begin + Regexp.union( + "a", + Regexp.new("\xc2\xa1".force_encoding("euc-jp")), + Regexp.new("\xc2\xa1".force_encoding("utf-8"))) + :ng + rescue ArgumentError + :ok + end + end + + def test_word_boundary + assert_match(/\u3042\b /, "\u3042 ") + assert_not_match(/\u3042\ba/, "\u3042a") + end + + def test_named_capture + m = /&(?<foo>.*?);/.match("aaa & yyy") + assert_equal("amp", m["foo"]) + assert_equal("amp", m[:foo]) + assert_equal(5, m.begin(:foo)) + assert_equal(8, m.end(:foo)) + assert_equal([5,8], m.offset(:foo)) + + assert_equal("aaa [amp] yyy", + "aaa & yyy".sub(/&(?<foo>.*?);/, '[\k<foo>]')) + + assert_equal('#<MatchData "& y" foo:"amp">', + /&(?<foo>.*?); (y)/.match("aaa & yyy").inspect) + assert_equal('#<MatchData "& y" 1:"amp" 2:"y">', + /&(.*?); (y)/.match("aaa & yyy").inspect) + assert_equal('#<MatchData "& y" foo:"amp" bar:"y">', + /&(?<foo>.*?); (?<bar>y)/.match("aaa & yyy").inspect) + assert_equal('#<MatchData "& y" foo:"amp" foo:"y">', + /&(?<foo>.*?); (?<foo>y)/.match("aaa & yyy").inspect) + + /(?<id>[A-Za-z_]+)/ =~ "!abc" + assert_equal("abc", Regexp.last_match(:id)) + + /a/ =~ "b" # doesn't match. + assert_equal(nil, Regexp.last_match) + assert_equal(nil, Regexp.last_match(1)) + assert_equal(nil, Regexp.last_match(:foo)) + + assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.names) + assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.names) + assert_equal([], /(.)(.)/.names) + + assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.match("ab").names) + assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.match("ab").names) + assert_equal([], /(.)(.)/.match("ab").names) + + assert_equal({"foo"=>[1], "bar"=>[2]}, + /(?<foo>.)(?<bar>.)/.named_captures) + assert_equal({"foo"=>[1, 2]}, + /(?<foo>.)(?<foo>.)/.named_captures) + assert_equal({}, /(.)(.)/.named_captures) + + assert_equal("a[b]c", "abc".sub(/(?<x>[bc])/, "[\\k<x>]")) + + assert_equal("o", "foo"[/(?<bar>o)/, "bar"]) + + s = "foo" + s[/(?<bar>o)/, "bar"] = "baz" + assert_equal("fbazo", s) + end + + def test_named_capture_with_nul + bug9902 = '[ruby-dev:48275] [Bug #9902]' + + m = /(?<a>.*)/.match("foo") + assert_raise(IndexError, bug9902) {m["a\0foo"]} + assert_raise(IndexError, bug9902) {m["a\0foo".to_sym]} + + m = Regexp.new("(?<foo\0bar>.*)").match("xxx") + assert_raise(IndexError, bug9902) {m["foo"]} + assert_raise(IndexError, bug9902) {m["foo".to_sym]} + assert_nothing_raised(IndexError, bug9902) { + assert_equal("xxx", m["foo\0bar"], bug9902) + assert_equal("xxx", m["foo\0bar".to_sym], bug9902) + } + end + + def test_named_capture_nonascii + bug9903 = '[ruby-dev:48278] [Bug #9903]' + + key = "\xb1\xb2".force_encoding(Encoding::EUC_JP) + m = /(?<#{key}>.*)/.match("xxx") + assert_equal("xxx", m[key]) + assert_raise(IndexError, bug9903) {m[key.dup.force_encoding(Encoding::Shift_JIS)]} + end + + def test_assign_named_capture + assert_equal("a", eval('/(?<foo>.)/ =~ "a"; foo')) + assert_equal("a", eval('foo = 1; /(?<foo>.)/ =~ "a"; foo')) + assert_equal("a", eval('1.times {|foo| /(?<foo>.)/ =~ "a"; break foo }')) + assert_nothing_raised { eval('/(?<Foo>.)/ =~ "a"') } + assert_nil(eval('/(?<Foo>.)/ =~ "a"; defined? Foo')) + end + + def test_assign_named_capture_to_reserved_word + /(?<nil>.)/ =~ "a" + assert_not_include(local_variables, :nil, "[ruby-dev:32675]") + end + + def test_match_regexp + r = /./ + m = r.match("a") + assert_equal(r, m.regexp) + re = /foo/ + assert_equal(re, re.match("foo").regexp) + end + + def test_source + bug5484 = '[ruby-core:40364]' + assert_equal('', //.source) + assert_equal('\:', /\:/.source, bug5484) + assert_equal(':', %r:\::.source, bug5484) + end + + def test_source_escaped + expected, result = "$*+.?^|".each_char.map {|c| + [ + ["\\#{c}", "\\#{c}", 1], + begin + re = eval("%r#{c}\\#{c}#{c}", nil, __FILE__, __LINE__) + t = eval("/\\#{c}/", nil, __FILE__, __LINE__).source + rescue SyntaxError => e + [e, t, nil] + else + [re.source, t, re =~ "a#{c}a"] + end + ] + }.transpose + assert_equal(expected, result) + end + + def test_source_escaped_paren + bug7610 = '[ruby-core:51088] [Bug #7610]' + bug8133 = '[ruby-core:53578] [Bug #8133]' + [ + ["(", ")", bug7610], ["[", "]", bug8133], + ["{", "}", bug8133], ["<", ">", bug8133], + ].each do |lparen, rparen, bug| + s = "\\#{lparen}a\\#{rparen}" + assert_equal(/#{s}/, eval("%r#{lparen}#{s}#{rparen}"), bug) + end + end + + def test_source_unescaped + expected, result = "!\"#%&',-/:;=@_`~".each_char.map {|c| + [ + ["#{c}", "\\#{c}", 1], + begin + re = eval("%r#{c}\\#{c}#{c}", nil, __FILE__, __LINE__) + t = eval("%r{\\#{c}}", nil, __FILE__, __LINE__).source + rescue SyntaxError => e + [e, t, nil] + else + [re.source, t, re =~ "a#{c}a"] + end + ] + }.transpose + assert_equal(expected, result) + end + + def test_inspect + assert_equal('//', //.inspect) + assert_equal('//i', //i.inspect) + assert_equal('/\//i', /\//i.inspect) + assert_equal('/\//i', %r"#{'/'}"i.inspect) + assert_equal('/\/x/i', /\/x/i.inspect) + assert_equal('/\x00/i', /#{"\0"}/i.inspect) + assert_equal("/\n/i", /#{"\n"}/i.inspect) + s = [0xf1, 0xf2, 0xf3].pack("C*") + assert_equal('/\/\xF1\xF2\xF3/i', /\/#{s}/i.inspect) + end + + def test_char_to_option + assert_equal("BAR", "FOOBARBAZ"[/b../i]) + assert_equal("bar", "foobarbaz"[/ b . . /x]) + assert_equal("bar\n", "foo\nbar\nbaz"[/b.../m]) + assert_raise(SyntaxError) { eval('//z') } + end + + def test_char_to_option_kcode + assert_equal("bar", "foobarbaz"[/b../s]) + assert_equal("bar", "foobarbaz"[/b../e]) + assert_equal("bar", "foobarbaz"[/b../u]) + end + + def test_to_s2 + assert_equal('(?-mix:foo)', /(?:foo)/.to_s) + assert_equal('(?m-ix:foo)', /(?:foo)/m.to_s) + assert_equal('(?mi-x:foo)', /(?:foo)/mi.to_s) + assert_equal('(?mix:foo)', /(?:foo)/mix.to_s) + assert_equal('(?m-ix:foo)', /(?m-ix:foo)/.to_s) + assert_equal('(?mi-x:foo)', /(?mi-x:foo)/.to_s) + assert_equal('(?mix:foo)', /(?mix:foo)/.to_s) + assert_equal('(?mix:)', /(?mix)/.to_s) + assert_equal('(?-mix:(?mix:foo) )', /(?mix:foo) /.to_s) + end + + def test_casefold_p + assert_equal(false, /a/.casefold?) + assert_equal(true, /a/i.casefold?) + assert_equal(false, /(?i:a)/.casefold?) + end + + def test_options + assert_equal(Regexp::IGNORECASE, /a/i.options) + assert_equal(Regexp::EXTENDED, /a/x.options) + assert_equal(Regexp::MULTILINE, /a/m.options) + end + + def test_match_init_copy + m = /foo/.match("foo") + assert_equal(/foo/, m.dup.regexp) + assert_raise(TypeError) do + m.instance_eval { initialize_copy(nil) } + end + assert_equal([0, 3], m.offset(0)) + assert_equal(/foo/, m.dup.regexp) + end + + def test_match_size + m = /(.)(.)(\d+)(\d)/.match("THX1138.") + assert_equal(5, m.size) + end + + def test_match_offset_begin_end + m = /(?<x>b..)/.match("foobarbaz") + assert_equal([3, 6], m.offset("x")) + assert_equal(3, m.begin("x")) + assert_equal(6, m.end("x")) + assert_raise(IndexError) { m.offset("y") } + assert_raise(IndexError) { m.offset(2) } + assert_raise(IndexError) { m.begin(2) } + assert_raise(IndexError) { m.end(2) } + + m = /(?<x>q..)?/.match("foobarbaz") + assert_equal([nil, nil], m.offset("x")) + assert_equal(nil, m.begin("x")) + assert_equal(nil, m.end("x")) + + m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044") + assert_equal([1, 2], m.offset(1)) + assert_equal([nil, nil], m.offset(2)) + assert_equal([2, 3], m.offset(3)) + end + + def test_match_to_s + m = /(?<x>b..)/.match("foobarbaz") + assert_equal("bar", m.to_s) + end + + def test_match_pre_post + m = /(?<x>b..)/.match("foobarbaz") + assert_equal("foo", m.pre_match) + assert_equal("baz", m.post_match) + end + + def test_match_array + m = /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal(["foobarbaz", "foo", "bar", "baz", nil], m.to_a) + end + + def test_match_captures + m = /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal(["foo", "bar", "baz", nil], m.captures) + end + + def test_match_aref + m = /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal("foo", m[1]) + assert_equal(["foo", "bar", "baz"], m[1..3]) + assert_nil(m[5]) + assert_raise(IndexError) { m[:foo] } + end + + def test_match_values_at + m = /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal(["foo", "bar", "baz"], m.values_at(1, 2, 3)) + end + + def test_match_string + m = /(?<x>b..)/.match("foobarbaz") + assert_equal("foobarbaz", m.string) + end + + def test_match_inspect + m = /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect) + end + + def test_initialize + assert_raise(ArgumentError) { Regexp.new } + assert_equal(/foo/, Regexp.new(/foo/, Regexp::IGNORECASE)) + + assert_equal(Encoding.find("US-ASCII"), Regexp.new("b..", nil, "n").encoding) + assert_equal("bar", "foobarbaz"[Regexp.new("b..", nil, "n")]) + assert_equal(//n, Regexp.new("", nil, "n")) + + arg_encoding_none = 32 # ARG_ENCODING_NONE is implementation defined value + assert_equal(arg_encoding_none, Regexp.new("", nil, "n").options) + assert_equal(arg_encoding_none, Regexp.new("", nil, "N").options) + + assert_raise(RegexpError) { Regexp.new(")(") } + end + + def test_unescape + assert_raise(ArgumentError) { s = '\\'; /#{ s }/ } + assert_equal(/\xFF/n, /#{ s="\\xFF" }/n) + assert_equal(/\177/, (s = '\177'; /#{ s }/)) + assert_raise(ArgumentError) { s = '\u'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u{ ffffffff }'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u{ ffffff }'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u{ ffff X }'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u{ }'; /#{ s }/ } + assert_equal("b", "abc"[(s = '\u{0062}'; /#{ s }/)]) + assert_equal("b", "abc"[(s = '\u0062'; /#{ s }/)]) + assert_raise(ArgumentError) { s = '\u0'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u000X'; /#{ s }/ } + assert_raise(ArgumentError) { s = "\xff" + '\u3042'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\u3042' + [0xff].pack("C"); /#{ s }/ } + assert_raise(SyntaxError) { s = ''; eval(%q(/\u#{ s }/)) } + + assert_equal(/a/, eval(%q(s="\u0061";/#{s}/n))) + assert_raise(RegexpError) { s = "\u3042"; eval(%q(/#{s}/n)) } + assert_raise(RegexpError) { s = "\u0061"; eval(%q(/\u3042#{s}/n)) } + assert_raise(RegexpError) { s1=[0xff].pack("C"); s2="\u3042"; eval(%q(/#{s1}#{s2}/)); [s1, s2] } + + assert_raise(ArgumentError) { s = '\x'; /#{ s }/ } + + assert_equal("\xe1", [0x00, 0xe1, 0xff].pack("C*")[/\M-a/]) + assert_equal("\xdc", [0x00, 0xdc, 0xff].pack("C*")[/\M-\\/]) + assert_equal("\x8a", [0x00, 0x8a, 0xff].pack("C*")[/\M-\n/]) + assert_equal("\x89", [0x00, 0x89, 0xff].pack("C*")[/\M-\t/]) + assert_equal("\x8d", [0x00, 0x8d, 0xff].pack("C*")[/\M-\r/]) + assert_equal("\x8c", [0x00, 0x8c, 0xff].pack("C*")[/\M-\f/]) + assert_equal("\x8b", [0x00, 0x8b, 0xff].pack("C*")[/\M-\v/]) + assert_equal("\x87", [0x00, 0x87, 0xff].pack("C*")[/\M-\a/]) + assert_equal("\x9b", [0x00, 0x9b, 0xff].pack("C*")[/\M-\e/]) + assert_equal("\x01", [0x00, 0x01, 0xff].pack("C*")[/\C-a/]) + + assert_raise(ArgumentError) { s = '\M'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\M-\M-a'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\M-\\'; /#{ s }/ } + + assert_raise(ArgumentError) { s = '\C'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\c'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\C-\C-a'; /#{ s }/ } + + assert_raise(ArgumentError) { s = '\M-\z'; /#{ s }/ } + assert_raise(ArgumentError) { s = '\M-\777'; /#{ s }/ } + + assert_equal("\u3042\u3042", "\u3042\u3042"[(s = "\u3042" + %q(\xe3\x81\x82); /#{s}/)]) + assert_raise(ArgumentError) { s = "\u3042" + %q(\xe3); /#{s}/ } + assert_raise(ArgumentError) { s = "\u3042" + %q(\xe3\xe3); /#{s}/ } + assert_raise(ArgumentError) { s = '\u3042' + [0xff].pack("C"); /#{s}/ } + + assert_raise(SyntaxError) { eval("/\u3042/n") } + + s = ".........." + 5.times { s.sub!(".", "") } + assert_equal(".....", s) + end + + def test_equal + bug5484 = '[ruby-core:40364]' + assert_equal(/abc/, /abc/) + assert_not_equal(/abc/, /abc/m) + assert_not_equal(/abc/, /abd/) + assert_equal(/\/foo/, Regexp.new('/foo'), bug5484) + end + + def test_match + assert_nil(//.match(nil)) + assert_equal("abc", /.../.match(:abc)[0]) + assert_raise(TypeError) { /.../.match(Object.new)[0] } + assert_equal("bc", /../.match('abc', 1)[0]) + assert_equal("bc", /../.match('abc', -2)[0]) + assert_nil(/../.match("abc", -4)) + assert_nil(/../.match("abc", 4)) + assert_equal('\x', /../n.match("\u3042" + '\x', 1)[0]) + + r = nil + /.../.match("abc") {|m| r = m[0] } + assert_equal("abc", r) + + $_ = "abc"; assert_equal(1, ~/bc/) + $_ = "abc"; assert_nil(~/d/) + $_ = nil; assert_nil(~/./) + end + + def test_eqq + assert_equal(false, /../ === nil) + end + + def test_quote + assert_equal("\xff", Regexp.quote([0xff].pack("C"))) + assert_equal("\\ ", Regexp.quote("\ ")) + assert_equal("\\t", Regexp.quote("\t")) + assert_equal("\\n", Regexp.quote("\n")) + assert_equal("\\r", Regexp.quote("\r")) + assert_equal("\\f", Regexp.quote("\f")) + assert_equal("\\v", Regexp.quote("\v")) + assert_equal("\u3042\\t", Regexp.quote("\u3042\t")) + assert_equal("\\t\xff", Regexp.quote("\t" + [0xff].pack("C"))) + end + + def test_try_convert + assert_equal(/re/, Regexp.try_convert(/re/)) + assert_nil(Regexp.try_convert("re")) + + o = Object.new + assert_nil(Regexp.try_convert(o)) + def o.to_regexp() /foo/ end + assert_equal(/foo/, Regexp.try_convert(o)) + end + + def test_union2 + assert_equal(/(?!)/, Regexp.union) + assert_equal(/foo/, Regexp.union(/foo/)) + assert_equal(/foo/, Regexp.union([/foo/])) + assert_equal(/\t/, Regexp.union("\t")) + assert_equal(/(?-mix:\u3042)|(?-mix:\u3042)/, Regexp.union(/\u3042/, /\u3042/)) + assert_equal("\u3041", "\u3041"[Regexp.union(/\u3042/, "\u3041")]) + end + + def test_dup + assert_equal(//, //.dup) + assert_raise(TypeError) { //.instance_eval { initialize_copy(nil) } } + end + + def test_regsub + assert_equal("fooXXXbaz", "foobarbaz".sub!(/bar/, "XXX")) + s = [0xff].pack("C") + assert_equal(s, "X".sub!(/./, s)) + assert_equal('\\' + s, "X".sub!(/./, '\\' + s)) + assert_equal('\k', "foo".sub!(/.../, '\k')) + assert_raise(RuntimeError) { "foo".sub!(/(?<x>o)/, '\k<x') } + assert_equal('foo[bar]baz', "foobarbaz".sub!(/(b..)/, '[\0]')) + assert_equal('foo[foo]baz', "foobarbaz".sub!(/(b..)/, '[\`]')) + assert_equal('foo[baz]baz', "foobarbaz".sub!(/(b..)/, '[\\\']')) + assert_equal('foo[r]baz', "foobarbaz".sub!(/(b)(.)(.)/, '[\+]')) + assert_equal('foo[\\]baz', "foobarbaz".sub!(/(b..)/, '[\\\\]')) + assert_equal('foo[\z]baz', "foobarbaz".sub!(/(b..)/, '[\z]')) + end + + def test_regsub_K + bug8856 = '[ruby-dev:47694] [Bug #8856]' + result = "foobarbazquux/foobarbazquux".gsub(/foo\Kbar/, "") + assert_equal('foobazquux/foobazquux', result, bug8856) + end + + def test_KCODE + assert_nil($KCODE) + assert_nothing_raised { $KCODE = nil } + assert_equal(false, $=) + assert_nothing_raised { $= = nil } + end + + def test_match_setter + /foo/ =~ "foo" + m = $~ + /bar/ =~ "bar" + $~ = m + assert_equal("foo", $&) + end + + def test_match_without_regexp + bug10877 = '[ruby-core:68209] [Bug #10877]' + "abc".sub("a", "") + assert_raise_with_message(IndexError, /foo/, bug10877) {$~["foo"]} + key = "\u{3042}" + [Encoding::UTF_8, Encoding::Shift_JIS, Encoding::EUC_JP].each do |enc| + idx = key.encode(enc) + EnvUtil.with_default_external(enc) do + assert_raise_with_message(IndexError, /#{idx}/, bug10877) {$~[idx]} + end + end + end + + def test_last_match + /(...)(...)(...)(...)?/.match("foobarbaz") + assert_equal("foobarbaz", Regexp.last_match(0)) + assert_equal("foo", Regexp.last_match(1)) + assert_nil(Regexp.last_match(5)) + assert_nil(Regexp.last_match(-1)) + end + + def test_getter + alias $__REGEXP_TEST_LASTMATCH__ $& + alias $__REGEXP_TEST_PREMATCH__ $` + alias $__REGEXP_TEST_POSTMATCH__ $' + alias $__REGEXP_TEST_LASTPARENMATCH__ $+ + /(b)(.)(.)/.match("foobarbaz") + assert_equal("bar", $__REGEXP_TEST_LASTMATCH__) + assert_equal("foo", $__REGEXP_TEST_PREMATCH__) + assert_equal("baz", $__REGEXP_TEST_POSTMATCH__) + assert_equal("r", $__REGEXP_TEST_LASTPARENMATCH__) + + /(...)(...)(...)/.match("foobarbaz") + assert_equal("baz", $+) + end + + def test_rindex_regexp + assert_equal(3, "foobarbaz\u3042".rindex(/b../n, 5)) + end + + def test_taint + m = Thread.new do + "foo"[/foo/] + $SAFE = 3 + /foo/.match("foo") + end.value + assert_predicate(m, :tainted?) + assert_nothing_raised('[ruby-core:26137]') { + m = proc {$SAFE = 3; %r"#{ }"o}.call + } + assert_predicate(m, :tainted?) + end + + def assert_regexp(re, ss, fs = [], msg = nil) + re = Regexp.new(re) unless re.is_a?(Regexp) + ss = [ss] unless ss.is_a?(Array) + ss.each do |e, s| + s ||= e + assert_match(re, s, msg) + m = re.match(s) + assert_equal(e, m[0], msg) + end + fs = [fs] unless fs.is_a?(Array) + fs.each {|s| assert_no_match(re, s, msg) } + end + alias check assert_regexp + + def assert_fail(re) + assert_raise(RegexpError) { %r"#{ re }" } + end + alias failcheck assert_fail + + def test_parse + check(/\*\+\?\{\}\|\(\)\<\>\`\'/, "*+?{}|()<>`'") + check(/\A\w\W\z/, %w(a. b!), %w(.. ab)) + check(/\A.\b.\b.\B.\B.\z/, %w(a.aaa .a...), %w(aaaaa .....)) + check(/\A\s\S\z/, [' a', "\n."], [' ', "\n\n", 'a ']) + check(/\A\d\D\z/, '0a', %w(00 aa)) + check(/\A\h\H\z/, %w(0g ag BH), %w(a0 af GG)) + check(/\Afoo\Z\s\z/, "foo\n", ["foo", "foo\nbar"]) + assert_equal(%w(a b c), "abc def".scan(/\G\w/)) + check(/\A\u3042\z/, "\u3042", ["", "\u3043", "a"]) + check(/\A(..)\1\z/, %w(abab ....), %w(abba aba)) + failcheck('\1') + check(/\A\80\z/, "80", ["\100", ""]) + check(/\A\77\z/, "?") + check(/\A\78\z/, "\7" + '8', ["\100", ""]) + check(eval('/\A\Qfoo\E\z/'), "QfooE") + check(/\Aa++\z/, "aaa") + check('\Ax]\z', "x]") + check(/x#foo/x, "x", "#foo") + check(/\Ax#foo#{ "\n" }x\z/x, "xx", ["x", "x#foo\nx"]) + check(/\A\p{Alpha}\z/, ["a", "z"], [".", "", ".."]) + check(/\A\p{^Alpha}\z/, [".", "!"], ["!a", ""]) + check(/\A\n\z/, "\n") + check(/\A\t\z/, "\t") + check(/\A\r\z/, "\r") + check(/\A\f\z/, "\f") + check(/\A\a\z/, "\007") + check(/\A\e\z/, "\033") + check(/\A\v\z/, "\v") + failcheck('(') + failcheck('(?foo)') + failcheck('/\p{foobarbazqux}/') + failcheck('/\p{foobarbazqux' + 'a' * 1000 + '}/') + failcheck('/[1-\w]/') + end + + def test_exec + check(/A*B/, %w(B AB AAB AAAB), %w(A)) + check(/\w*!/, %w(! a! ab! abc!), %w(abc)) + check(/\w*\W/, %w(! a" ab# abc$), %w(abc)) + check(/\w*\w/, %w(z az abz abcz), %w(!)) + check(/[a-z]*\w/, %w(z az abz abcz), %w(!)) + check(/[a-z]*\W/, %w(! a" ab# abc$), %w(A)) + check(/((a|bb|ccc|dddd)(1|22|333|4444))/i, %w(a1 bb1 a22), %w(a2 b1)) + check(/\u0080/, (1..4).map {|i| ["\u0080", "\u0080" * i] }, ["\u0081"]) + check(/\u0080\u0080/, (2..4).map {|i| ["\u0080" * 2, "\u0080" * i] }, ["\u0081"]) + check(/\u0080\u0080\u0080/, (3..4).map {|i| ["\u0080" * 3, "\u0080" * i] }, ["\u0081"]) + check(/\u0080\u0080\u0080\u0080/, (4..4).map {|i| ["\u0080" * 4, "\u0080" * i] }, ["\u0081"]) + check(/[^\u3042\u3043\u3044]/, %W(a b \u0080 \u3041 \u3045), %W(\u3042 \u3043 \u3044)) + check(/a.+/m, %W(a\u0080 a\u0080\u0080 a\u0080\u0080\u0080), %W(a)) + check(/a.+z/m, %W(a\u0080z a\u0080\u0080z a\u0080\u0080\u0080z), %W(az)) + check(/abc\B.\Bxyz/, %w(abcXxyz abc0xyz), %w(abc|xyz abc-xyz)) + check(/\Bxyz/, [%w(xyz abcXxyz), %w(xyz abc0xyz)], %w(abc xyz abc-xyz)) + check(/abc\B/, [%w(abc abcXxyz), %w(abc abc0xyz)], %w(abc xyz abc-xyz)) + failcheck('(?<foo>abc)\1') + check(/^(A+|B+)(?>\g<1>)*[BC]$/, %w(AC BC ABC BAC AABBC), %w(AABB)) + check(/^(A+|B(?>\g<1>)*)[AC]$/, %w(AAAC BBBAAAAC), %w(BBBAAA)) + check(/^()(?>\g<1>)*$/, "", "a") + check(/^(?>(?=a)(#{ "a" * 1000 }|))++$/, ["a" * 1000, "a" * 2000, "a" * 3000], ["", "a" * 500, "b" * 1000]) + check(eval('/^(?:a?)?$/'), ["", "a"], ["aa"]) + check(eval('/^(?:a+)?$/'), ["", "a", "aa"], ["ab"]) + check(/^(?:a?)+?$/, ["", "a", "aa"], ["ab"]) + check(/^a??[ab]/, [["a", "a"], ["a", "aa"], ["b", "b"], ["a", "ab"]], ["c"]) + check(/^(?:a*){3,5}$/, ["", "a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa"], ["b"]) + check(/^(?:a+){3,5}$/, ["aaa", "aaaa", "aaaaa", "aaaaaa"], ["", "a", "aa", "b"]) + end + + def test_parse_look_behind + check(/(?<=A)B(?=C)/, [%w(B ABC)], %w(aBC ABc aBc)) + check(/(?<!A)B(?!C)/, [%w(B aBc)], %w(ABC aBC ABc)) + failcheck('(?<=.*)') + failcheck('(?<!.*)') + check(/(?<=A|B.)C/, [%w(C AC), %w(C BXC)], %w(C BC)) + check(/(?<!A|B.)C/, [%w(C C), %w(C BC)], %w(AC BXC)) + + assert_not_match(/(?<!aa|b)c/i, "Aac") + assert_not_match(/(?<!b|aa)c/i, "Aac") + end + + def test_parse_kg + check(/\A(.)(.)\k<1>(.)\z/, %w(abac abab ....), %w(abcd aaba xxx)) + check(/\A(.)(.)\k<-1>(.)\z/, %w(abbc abba ....), %w(abcd aaba xxx)) + check(/\A(?<n>.)(?<x>\g<n>){0}(?<y>\k<n+0>){0}\g<x>\g<y>\z/, "aba", "abb") + check(/\A(?<n>.)(?<x>\g<n>){0}(?<y>\k<n+1>){0}\g<x>\g<y>\z/, "abb", "aba") + check(/\A(?<x>..)\k<x>\z/, %w(abab ....), %w(abac abba xxx)) + check(/\A(.)(..)\g<-1>\z/, "abcde", %w(.... ......)) + failcheck('\k<x>') + failcheck('\k<') + failcheck('\k<>') + failcheck('\k<.>') + failcheck('\k<x.>') + failcheck('\k<1.>') + failcheck('\k<x') + failcheck('\k<x+') + failcheck('()\k<-2>') + failcheck('()\g<-2>') + check(/\A(?<x>.)(?<x>.)\k<x>\z/, %w(aba abb), %w(abc .. ....)) + check(/\A(?<x>.)(?<x>.)\k<x>\z/i, %w(aba ABa abb ABb), %w(abc .. ....)) + check('\k\g', "kg") + failcheck('(.\g<1>)') + failcheck('(.\g<2>)') + failcheck('(?=\g<1>)') + failcheck('((?=\g<1>))') + failcheck('(\g<1>|.)') + failcheck('(.|\g<1>)') + check(/(!)(?<=(a)|\g<1>)/, ["!"], %w(a)) + check(/^(a|b\g<1>c)$/, %w(a bac bbacc bbbaccc), %w(bbac bacc)) + check(/^(a|b\g<2>c)(B\g<1>C){0}$/, %w(a bBaCc bBbBaCcCc bBbBbBaCcCcCc), %w(bBbBaCcC BbBaCcCc)) + check(/\A(?<n>.|X\g<n>)(?<x>\g<n>){0}(?<y>\k<n+0>){0}\g<x>\g<y>\z/, "XXaXbXXa", %w(XXabXa abb)) + check(/\A(?<n>.|X\g<n>)(?<x>\g<n>){0}(?<y>\k<n+1>){0}\g<x>\g<y>\z/, "XaXXbXXb", %w(aXXbXb aba)) + failcheck('(?<x>)(?<x>)(\g<x>)') + check(/^(?<x>foo)(bar)\k<x>/, %w(foobarfoo), %w(foobar barfoo)) + check(/^(?<a>f)(?<a>o)(?<a>o)(?<a>b)(?<a>a)(?<a>r)(?<a>b)(?<a>a)(?<a>z)\k<a>{9}$/, %w(foobarbazfoobarbaz foobarbazbazbarfoo foobarbazzabraboof), %w(foobar barfoo)) + end + + def test_parse_curly_brace + check(/\A{/, ["{", ["{", "{x"]]) + check(/\A{ /, ["{ ", ["{ ", "{ x"]]) + check(/\A{,}\z/, "{,}") + check(/\A{}\z/, "{}") + check(/\Aa{0}+\z/, "", %w(a aa aab)) + check(/\Aa{1}+\z/, %w(a aa), ["", "aab"]) + check(/\Aa{1,2}b{1,2}\z/, %w(ab aab abb aabb), ["", "aaabb", "abbb"]) + check(/(?!x){0,1}/, [ ['', 'ab'], ['', ''] ]) + check(/c\z{0,1}/, [ ['c', 'abc'], ['c', 'cab']], ['abd']) + check(/\A{0,1}a/, [ ['a', 'abc'], ['a', '____abc']], ['bcd']) + failcheck('.{100001}') + failcheck('.{0,100001}') + failcheck('.{1,0}') + failcheck('{0}') + end + + def test_parse_comment + check(/\A(?#foo\)bar)\z/, "", "a") + failcheck('(?#') + end + + def test_char_type + check(/\u3042\d/, ["\u30421", "\u30422"]) + + # CClassTable cache test + assert_match(/\u3042\d/, "\u30421") + assert_match(/\u3042\d/, "\u30422") + end + + def test_char_class + failcheck('[]') + failcheck('[x') + check('\A[]]\z', "]", "") + check('\A[]\.]+\z', %w(] . ]..]), ["", "["]) + check(/\A[\u3042]\z/, "\u3042", "\u3042aa") + check(/\A[\u3042\x61]+\z/, ["aa\u3042aa", "\u3042\u3042", "a"], ["", "b"]) + check(/\A[\u3042\x61\x62]+\z/, "abab\u3042abab\u3042") + check(/\A[abc]+\z/, "abcba", ["", "ada"]) + check(/\A[\w][\W]\z/, %w(a. b!), %w(.. ab)) + check(/\A[\s][\S]\z/, [' a', "\n."], [' ', "\n\n", 'a ']) + check(/\A[\d][\D]\z/, '0a', %w(00 aa)) + check(/\A[\h][\H]\z/, %w(0g ag BH), %w(a0 af GG)) + check(/\A[\p{Alpha}]\z/, ["a", "z"], [".", "", ".."]) + check(/\A[\p{^Alpha}]\z/, [".", "!"], ["!a", ""]) + check(/\A[\xff]\z/, "\xff", ["", "\xfe"]) + check(/\A[\80]+\z/, "8008", ["\\80", "\100", "\1000"]) + check(/\A[\77]+\z/, "???") + check(/\A[\78]+\z/, "\788\7") + check(/\A[\0]\z/, "\0") + check(/\A[[:0]]\z/, [":", "0"], ["", ":0"]) + check(/\A[0-]\z/, ["0", "-"], "0-") + check('\A[a-&&\w]\z', "a", "-") + check('\A[--0]\z', ["-", "/", "0"], ["", "1"]) + check('\A[\'--0]\z', %w(* + \( \) 0 ,), ["", ".", "1"]) + check(/\A[a-b-]\z/, %w(a b -), ["", "c"]) + check('\A[a-b-&&\w]\z', %w(a b), ["", "-"]) + check('\A[a-b-&&\W]\z', "-", ["", "a", "b"]) + check('\A[a-c-e]\z', %w(a b c e -), %w(d)) + check(/\A[a-f&&[^b-c]&&[^e]]\z/, %w(a d f), %w(b c e g 0)) + check(/\A[[^b-c]&&[^e]&&a-f]\z/, %w(a d f), %w(b c e g 0)) + check(/\A[\n\r\t]\z/, ["\n", "\r", "\t"]) + failcheck('[9-1]') + + assert_match(/\A\d+\z/, "0123456789") + assert_no_match(/\d/, "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19") + assert_match(/\A\w+\z/, "09azAZ_") + assert_no_match(/\w/, "\uff10\uff19\uff41\uff5a\uff21\uff3a") + assert_match(/\A\s+\z/, "\r\n\v\f\r\s") + assert_no_match(/\s/, "\u0085") + end + + def test_posix_bracket + check(/\A[[:alpha:]0]\z/, %w(0 a), %w(1 .)) + check(eval('/\A[[:^alpha:]0]\z/'), %w(0 1 .), "a") + check(eval('/\A[[:alpha\:]]\z/'), %w(a l p h a :), %w(b 0 1 .)) + check(eval('/\A[[:alpha:foo]0]\z/'), %w(0 a), %w(1 .)) + check(/\A[[:xdigit:]&&[:alpha:]]\z/, "a", %w(g 0)) + check('\A[[:abcdefghijklmnopqrstu:]]+\z', "[]") + failcheck('[[:alpha') + failcheck('[[:alpha:') + failcheck('[[:alp:]]') + + assert_match(/\A[[:digit:]]+\z/, "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19") + assert_match(/\A[[:alnum:]]+\z/, "\uff10\uff19\uff41\uff5a\uff21\uff3a") + assert_match(/\A[[:space:]]+\z/, "\r\n\v\f\r\s\u0085") + assert_match(/\A[[:ascii:]]+\z/, "\x00\x7F") + assert_no_match(/[[:ascii:]]/, "\x80\xFF") + end + + def test_backward + assert_equal(3, "foobar".rindex(/b.r/i)) + assert_equal(nil, "foovar".rindex(/b.r/i)) + assert_equal(3, ("foo" + "bar" * 1000).rindex(/#{"bar"*1000}/)) + assert_equal(4, ("foo\nbar\nbaz\n").rindex(/bar/i)) + end + + def test_uninitialized + assert_raise(TypeError) { Regexp.allocate.hash } + assert_raise(TypeError) { Regexp.allocate.eql? Regexp.allocate } + assert_raise(TypeError) { Regexp.allocate == Regexp.allocate } + assert_raise(TypeError) { Regexp.allocate =~ "" } + assert_equal(false, Regexp.allocate === Regexp.allocate) + assert_nil(~Regexp.allocate) + assert_raise(TypeError) { Regexp.allocate.match("") } + assert_raise(TypeError) { Regexp.allocate.to_s } + assert_match(/^#<Regexp:.*>$/, Regexp.allocate.inspect) + assert_raise(TypeError) { Regexp.allocate.source } + assert_raise(TypeError) { Regexp.allocate.casefold? } + assert_raise(TypeError) { Regexp.allocate.options } + assert_equal(Encoding.find("ASCII-8BIT"), Regexp.allocate.encoding) + assert_equal(false, Regexp.allocate.fixed_encoding?) + assert_raise(TypeError) { Regexp.allocate.names } + assert_raise(TypeError) { Regexp.allocate.named_captures } + + assert_raise(TypeError) { MatchData.allocate.regexp } + assert_raise(TypeError) { MatchData.allocate.names } + assert_raise(TypeError) { MatchData.allocate.size } + assert_raise(TypeError) { MatchData.allocate.length } + assert_raise(TypeError) { MatchData.allocate.offset(0) } + assert_raise(TypeError) { MatchData.allocate.begin(0) } + assert_raise(TypeError) { MatchData.allocate.end(0) } + assert_raise(TypeError) { MatchData.allocate.to_a } + assert_raise(TypeError) { MatchData.allocate[:foo] } + assert_raise(TypeError) { MatchData.allocate.captures } + assert_raise(TypeError) { MatchData.allocate.values_at } + assert_raise(TypeError) { MatchData.allocate.pre_match } + assert_raise(TypeError) { MatchData.allocate.post_match } + assert_raise(TypeError) { MatchData.allocate.to_s } + assert_match(/^#<MatchData:.*>$/, MatchData.allocate.inspect) + assert_raise(TypeError) { MatchData.allocate.string } + $~ = MatchData.allocate + assert_raise(TypeError) { $& } + assert_raise(TypeError) { $` } + assert_raise(TypeError) { $' } + assert_raise(TypeError) { $+ } + end + + def test_unicode + assert_match(/^\u3042{0}\p{Any}$/, "a") + assert_match(/^\u3042{0}\p{Any}$/, "\u3041") + assert_match(/^\u3042{0}\p{Any}$/, "\0") + assert_match(/^\p{Lo}{4}$/u, "\u3401\u4E01\u{20001}\u{2A701}") + assert_no_match(/^\u3042{0}\p{Any}$/, "\0\0") + assert_no_match(/^\u3042{0}\p{Any}$/, "") + assert_raise(SyntaxError) { eval('/^\u3042{0}\p{' + "\u3042" + '}$/') } + assert_raise(SyntaxError) { eval('/^\u3042{0}\p{' + 'a' * 1000 + '}$/') } + assert_raise(SyntaxError) { eval('/^\u3042{0}\p{foobarbazqux}$/') } + assert_match(/^(\uff21)(a)\1\2$/i, "\uff21A\uff41a") + assert_no_match(/^(\uff21)\1$/i, "\uff21A") + assert_no_match(/^(\uff41)\1$/i, "\uff41a") + assert_match(/^\u00df$/i, "\u00df") + assert_match(/^\u00df$/i, "ss") + #assert_match(/^(\u00df)\1$/i, "\u00dfss") # this must be bug... + assert_match(/^\u00df{2}$/i, "\u00dfss") + assert_match(/^\u00c5$/i, "\u00c5") + assert_match(/^\u00c5$/i, "\u00e5") + assert_match(/^\u00c5$/i, "\u212b") + assert_match(/^(\u00c5)\1\1$/i, "\u00c5\u00e5\u212b") + assert_match(/^\u0149$/i, "\u0149") + assert_match(/^\u0149$/i, "\u02bcn") + #assert_match(/^(\u0149)\1$/i, "\u0149\u02bcn") # this must be bug... + assert_match(/^\u0149{2}$/i, "\u0149\u02bcn") + assert_match(/^\u0390$/i, "\u0390") + assert_match(/^\u0390$/i, "\u03b9\u0308\u0301") + #assert_match(/^(\u0390)\1$/i, "\u0390\u03b9\u0308\u0301") # this must be bug... + assert_match(/^\u0390{2}$/i, "\u0390\u03b9\u0308\u0301") + assert_match(/^\ufb05$/i, "\ufb05") + assert_match(/^\ufb05$/i, "\ufb06") + assert_match(/^\ufb05$/i, "st") + #assert_match(/^(\ufb05)\1\1$/i, "\ufb05\ufb06st") # this must be bug... + assert_match(/^\ufb05{3}$/i, "\ufb05\ufb06st") + assert_match(/^\u03b9\u0308\u0301$/i, "\u0390") + end + + def test_unicode_age + assert_match(/^\p{Age=6.0}$/u, "\u261c") + assert_match(/^\p{Age=1.1}$/u, "\u261c") + assert_no_match(/^\P{age=6.0}$/u, "\u261c") + + assert_match(/^\p{age=6.0}$/u, "\u31f6") + assert_match(/^\p{age=3.2}$/u, "\u31f6") + assert_no_match(/^\p{age=3.1}$/u, "\u31f6") + assert_no_match(/^\p{age=3.0}$/u, "\u31f6") + assert_no_match(/^\p{age=1.1}$/u, "\u31f6") + + assert_match(/^\p{age=6.0}$/u, "\u2754") + assert_no_match(/^\p{age=5.0}$/u, "\u2754") + assert_no_match(/^\p{age=4.0}$/u, "\u2754") + assert_no_match(/^\p{age=3.0}$/u, "\u2754") + assert_no_match(/^\p{age=2.0}$/u, "\u2754") + assert_no_match(/^\p{age=1.1}$/u, "\u2754") + end + + MatchData_A = eval("class MatchData_\u{3042} < MatchData; self; end") + + def test_matchdata + a = "haystack".match(/hay/) + b = "haystack".match(/hay/) + assert_equal(a, b, '[ruby-core:24748]') + h = {a => 42} + assert_equal(42, h[b], '[ruby-core:24748]') + assert_match(/#<TestRegexp::MatchData_\u{3042}:/, MatchData_A.allocate.inspect) + end + + def test_regexp_poped + assert_nothing_raised { eval("a = 1; /\#{ a }/; a") } + assert_nothing_raised { eval("a = 1; /\#{ a }/o; a") } + end + + def test_invalid_fragment + bug2547 = '[ruby-core:27374]' + assert_raise(SyntaxError, bug2547) {eval('/#{"\\\\"}y/')} + end + + def test_dup_warn + assert_warning(/duplicated/) { Regexp.new('[\u3042\u3043\u3042]') } + assert_warning(/duplicated/) { Regexp.new('[\u3042\u3043\u3043]') } + assert_warning(/\A\z/) { Regexp.new('[\u3042\u3044\u3043]') } + assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3043]') } + assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3044]') } + assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3043-\u3044]') } + assert_warning(/duplicated/) { Regexp.new('[\u3042\u3045\u3042-\u3043]') } + assert_warning(/duplicated/) { Regexp.new('[\u3042\u3045\u3044-\u3045]') } + assert_warning(/\A\z/) { Regexp.new('[\u3042\u3046\u3044]') } + assert_warning(/duplicated/) { Regexp.new('[\u1000-\u2000\u3042-\u3046\u3044]') } + assert_warning(/duplicated/) { Regexp.new('[\u3044\u3041-\u3047]') } + assert_warning(/duplicated/) { Regexp.new('[\u3042\u3044\u3046\u3041-\u3047]') } + + bug7471 = '[ruby-core:50344]' + assert_warning('', bug7471) { Regexp.new('[\D]') =~ "\u3042" } + + bug8151 = '[ruby-core:53649]' + assert_warning(/\A\z/, bug8151) { Regexp.new('(?:[\u{33}])').to_s } + end + + def test_property_warn + assert_in_out_err('-w', 'x=/\p%s/', [], %r"warning: invalid Unicode Property \\p: /\\p%s/") + end + + def test_invalid_escape_error + bug3539 = '[ruby-core:31048]' + error = assert_raise(SyntaxError) {eval('/\x/', nil, bug3539)} + assert_match(/invalid hex escape/, error.message) + assert_equal(1, error.message.scan(/.*invalid .*escape.*/i).size, bug3539) + end + + def test_raw_hyphen_and_tk_char_type_after_range + bug6853 = '[ruby-core:47115]' + # use Regexp.new instead of literal to ignore a parser warning. + check(Regexp.new('[0-1-\\s]'), [' ', '-'], ['2', 'a'], bug6853) + end + + def test_error_message_on_failed_conversion + bug7539 = '[ruby-core:50733]' + assert_equal false, /x/=== 42 + assert_raise_with_message(TypeError, 'no implicit conversion of Fixnum into String', bug7539) { + Regexp.quote(42) + } + end + + def test_conditional_expression + bug8583 = '[ruby-dev:47480] [Bug #8583]' + + conds = {"xy"=>true, "yx"=>true, "xx"=>false, "yy"=>false} + assert_match_each(/\A((x)|(y))(?(2)y|x)\z/, conds, bug8583) + assert_match_each(/\A((?<x>x)|(?<y>y))(?(<x>)y|x)\z/, conds, bug8583) + end + + def test_options_in_look_behind + assert_nothing_raised { + assert_match_at("(?<=(?i)ab)cd", "ABcd", [[2,4]]) + assert_match_at("(?<=(?i:ab))cd", "ABcd", [[2,4]]) + assert_match_at("(?<!(?i)ab)cd", "aacd", [[2,4]]) + assert_match_at("(?<!(?i:ab))cd", "aacd", [[2,4]]) + + assert_not_match("(?<=(?i)ab)cd", "ABCD") + assert_not_match("(?<=(?i:ab))cd", "ABCD") + assert_not_match("(?<!(?i)ab)cd", "ABcd") + assert_not_match("(?<!(?i:ab))cd", "ABcd") + } + end + + def test_once + pr1 = proc{|i| /#{i}/o} + assert_equal(/0/, pr1.call(0)) + assert_equal(/0/, pr1.call(1)) + assert_equal(/0/, pr1.call(2)) + end + + def test_once_recursive + pr2 = proc{|i| + if i > 0 + /#{pr2.call(i-1).to_s}#{i}/ + else + // + end + } + assert_equal(/(?-mix:(?-mix:(?-mix:)1)2)3/, pr2.call(3)) + end + + def test_once_multithread + m = Mutex.new + pr3 = proc{|i| + /#{m.unlock; sleep 0.5; i}/o + } + ary = [] + n = 0 + th1 = Thread.new{m.lock; ary << pr3.call(n+=1)} + th2 = Thread.new{m.lock; ary << pr3.call(n+=1)} + th1.join; th2.join + assert_equal([/1/, /1/], ary) + end + + def test_once_escape + pr4 = proc{|i| + catch(:xyzzy){ + /#{throw :xyzzy, i}/o =~ "" + :ng + } + } + assert_equal(0, pr4.call(0)) + assert_equal(1, pr4.call(1)) + end + + def test_eq_tilde_can_be_overridden + assert_separately([], <<-RUBY) + class Regexp + undef =~ + def =~(str) + "foo" + end + end + + assert_equal("foo", // =~ "") + RUBY + 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) + + match = re.match(str) + + assert_not_nil match, message(msg) { + "Expected #{re.inspect} to match #{str.inspect}" + } + + if match + actual_positions = (0...match.size).map { |i| + [match.begin(i), match.end(i)] + } + + assert_equal positions, actual_positions, message(msg) { + "Expected #{re.inspect} to match #{str.inspect} at: #{positions.inspect}" + } + end + end + + def assert_match_each(re, conds, msg = nil) + errs = conds.select {|str, match| match ^ (re =~ str)} + msg = message(msg) { + "Expected #{re.inspect} to\n" + + errs.map {|str, match| "\t#{'not ' unless match}match #{str.inspect}"}.join(",\n") + } + assert_empty(errs, msg) + end +end diff --git a/jni/ruby/test/ruby/test_require.rb b/jni/ruby/test/ruby/test_require.rb new file mode 100644 index 0000000..33aea60 --- /dev/null +++ b/jni/ruby/test/ruby/test_require.rb @@ -0,0 +1,704 @@ +require 'test/unit' + +require 'tempfile' +require 'tmpdir' + +class TestRequire < Test::Unit::TestCase + def test_load_error_path + filename = "should_not_exist" + error = assert_raise(LoadError) do + require filename + end + assert_equal filename, error.path + end + + def test_require_invalid_shared_object + Tempfile.create(["test_ruby_test_require", ".so"]) {|t| + t.puts "dummy" + t.close + + assert_separately([], <<-INPUT) + $:.replace([IO::NULL]) + assert_raise(LoadError) do + require \"#{ t.path }\" + end + INPUT + } + end + + def test_require_too_long_filename + assert_separately(["RUBYOPT"=>nil], <<-INPUT) + $:.replace([IO::NULL]) + assert_raise(LoadError) do + require '#{ "foo/" * 10000 }foo' + end + INPUT + + begin + assert_in_out_err(["-S", "-w", "foo/" * 1024 + "foo"], "") do |r, e| + assert_equal([], r) + assert_operator(2, :<=, e.size) + assert_match(/warning: openpath: pathname too long \(ignored\)/, e.first) + assert_match(/\(LoadError\)/, e.last) + end + rescue Errno::EINVAL + # too long commandline may be blocked by OS. + end + end + + def test_require_nonascii + bug3758 = '[ruby-core:31915]' + ["\u{221e}", "\x82\xa0".force_encoding("cp932")].each do |path| + assert_raise_with_message(LoadError, /#{path}\z/, bug3758) {require path} + end + end + + def test_require_nonascii_path + bug8165 = '[ruby-core:53733] [Bug #8165]' + encoding = 'filesystem' + assert_require_nonascii_path(encoding, bug8165) + end + + def test_require_nonascii_path_utf8 + bug8676 = '[ruby-core:56136] [Bug #8676]' + encoding = Encoding::UTF_8 + return if Encoding.find('filesystem') == encoding + assert_require_nonascii_path(encoding, bug8676) + end + + def test_require_nonascii_path_shift_jis + bug8676 = '[ruby-core:56136] [Bug #8676]' + encoding = Encoding::Shift_JIS + return if Encoding.find('filesystem') == encoding + assert_require_nonascii_path(encoding, bug8676) + end + + case RUBY_PLATFORM + when /cygwin/, /mswin/, /mingw/, /darwin/ + def self.ospath_encoding(path) + Encoding::UTF_8 + end + else + def self.ospath_encoding(path) + path.encoding + end + end + + def assert_require_nonascii_path(encoding, bug) + Dir.mktmpdir {|tmp| + dir = "\u3042" * 5 + begin + require_path = File.join(tmp, dir, 'foo.rb').encode(encoding) + rescue + skip "cannot convert path encoding to #{encoding}" + end + Dir.mkdir(File.dirname(require_path)) + open(require_path, "wb") {|f| f.puts '$:.push __FILE__'} + begin + load_path = $:.dup + features = $".dup + # leave paths for require encoding objects + bug = "#{bug} require #{encoding} path" + require_path = "#{require_path}" + $:.clear + assert_nothing_raised(LoadError, bug) { + assert(require(require_path), bug) + assert_equal(self.class.ospath_encoding(require_path), $:.last.encoding, '[Bug #8753]') + assert(!require(require_path), bug) + } + ensure + $:.replace(load_path) + $".replace(features) + end + } + end + + def test_require_path_home_1 + env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"] + pathname_too_long = /pathname too long \(ignored\).*\(LoadError\)/m + + ENV["RUBYPATH"] = "~" + ENV["HOME"] = "/foo" * 1024 + assert_in_out_err(%w(-S -w test_ruby_test_require), "", [], pathname_too_long) + + ensure + env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH") + env_home ? ENV["HOME"] = env_home : ENV.delete("HOME") + end + + def test_require_path_home_2 + env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"] + pathname_too_long = /pathname too long \(ignored\).*\(LoadError\)/m + + ENV["RUBYPATH"] = "~" + "/foo" * 1024 + ENV["HOME"] = "/foo" + assert_in_out_err(%w(-S -w test_ruby_test_require), "", [], pathname_too_long) + + ensure + env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH") + env_home ? ENV["HOME"] = env_home : ENV.delete("HOME") + end + + def test_require_path_home_3 + env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"] + + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + t.puts "p :ok" + t.close + + ENV["RUBYPATH"] = "~" + ENV["HOME"] = t.path + assert_in_out_err(%w(-S test_ruby_test_require), "", [], /\(LoadError\)/) + + ENV["HOME"], name = File.split(t.path) + assert_in_out_err(["-S", name], "", %w(:ok), []) + } + ensure + env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH") + env_home ? ENV["HOME"] = env_home : ENV.delete("HOME") + end + + def test_require_with_unc + ruby = File.expand_path(EnvUtil.rubybin).sub(/\A(\w):/, '//127.0.0.1/\1$/') + skip "local drive #$1: is not shared" unless File.exist?(ruby) + pid = nil + assert_nothing_raised {pid = spawn(ruby, "-rabbrev", "-e0")} + ret, status = Process.wait2(pid) + assert_equal(pid, ret) + assert_predicate(status, :success?) + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_require_twice + Dir.mktmpdir do |tmp| + req = File.join(tmp, "very_long_file_name.rb") + File.write(req, "p :ok\n") + assert_file.exist?(req) + req[/.rb$/i] = "" + assert_in_out_err(['--disable-gems'], <<-INPUT, %w(:ok), []) + require "#{req}" + require "#{req}" + INPUT + end + end + + def test_define_class + begin + require "socket" + rescue LoadError + return + end + + assert_separately([], <<-INPUT) + BasicSocket = 1 + assert_raise(TypeError) do + require 'socket' + end + INPUT + + assert_separately([], <<-INPUT) + class BasicSocket; end + assert_raise(TypeError) do + require 'socket' + end + INPUT + + assert_separately([], <<-INPUT) + class BasicSocket < IO; end + assert_nothing_raised do + require 'socket' + end + INPUT + end + + def test_define_class_under + begin + require "zlib" + rescue LoadError + return + end + + assert_separately([], <<-INPUT) + module Zlib; end + Zlib::Error = 1 + assert_raise(TypeError) do + require 'zlib' + end + INPUT + + assert_separately([], <<-INPUT) + module Zlib; end + class Zlib::Error; end + assert_raise(NameError) do + require 'zlib' + end + INPUT + + assert_separately([], <<-INPUT) + module Zlib; end + class Zlib::Error < StandardError; end + assert_nothing_raised do + require 'zlib' + end + INPUT + end + + def test_define_module + begin + require "zlib" + rescue LoadError + return + end + + assert_separately([], <<-INPUT) + Zlib = 1 + assert_raise(TypeError) do + require 'zlib' + end + INPUT + end + + def test_define_module_under + begin + require "socket" + rescue LoadError + return + end + + assert_separately([], <<-INPUT) + class BasicSocket < IO; end + class Socket < BasicSocket; end + Socket::Constants = 1 + assert_raise(TypeError) do + require 'socket' + end + INPUT + end + + def test_load + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + t.puts "module Foo; end" + t.puts "at_exit { p :wrap_end }" + t.puts "at_exit { raise 'error in at_exit test' }" + t.puts "p :ok" + t.close + + assert_in_out_err([], <<-INPUT, %w(:ok :end :wrap_end), /error in at_exit test/) + load(#{ t.path.dump }, true) + GC.start + p :end + INPUT + + assert_raise(ArgumentError) { at_exit } + } + end + + def test_load_scope + bug1982 = '[ruby-core:25039] [Bug #1982]' + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + t.puts "Hello = 'hello'" + t.puts "class Foo" + t.puts " p Hello" + t.puts "end" + t.close + + assert_in_out_err([], <<-INPUT, %w("hello"), [], bug1982) + load(#{ t.path.dump }, true) + INPUT + } + end + + def test_load_ospath + bug = '[ruby-list:49994] path in ospath' + base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J) + path = nil + Tempfile.create([base, ".rb"]) do |t| + path = t.path + + assert_raise_with_message(LoadError, /#{base}/) { + load(File.join(File.dirname(path), base)) + } + + t.puts "warn 'ok'" + t.close + assert_include(path, base) + assert_warn("ok\n", bug) { + assert_nothing_raised(LoadError, bug) { + load(path) + } + } + end + end + + def test_tainted_loadpath + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + abs_dir, file = File.split(t.path) + abs_dir = File.expand_path(abs_dir).untaint + + assert_separately([], <<-INPUT) + abs_dir = "#{ abs_dir }" + $: << abs_dir + assert_nothing_raised {require "#{ file }"} + INPUT + + assert_separately([], <<-INPUT) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + assert_nothing_raised {require "#{ file }"} + INPUT + + assert_separately([], <<-INPUT) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + $SAFE = 1 + assert_raise(SecurityError) {require "#{ file }"} + INPUT + + assert_separately([], <<-INPUT) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + $SAFE = 1 + assert_raise(SecurityError) {require "#{ file }"} + INPUT + + assert_separately([], <<-INPUT) + abs_dir = "#{ abs_dir }" + $: << abs_dir << 'elsewhere'.taint + assert_nothing_raised {require "#{ file }"} + INPUT + } + end + + def test_relative + load_path = $:.dup + $:.delete(".") + Dir.mktmpdir do |tmp| + Dir.chdir(tmp) do + Dir.mkdir('x') + File.open('x/t.rb', 'wb') {} + File.open('x/a.rb', 'wb') {|f| f.puts("require_relative('t.rb')")} + assert require('./x/t.rb') + assert !require(File.expand_path('x/t.rb')) + assert_nothing_raised(LoadError) {require('./x/a.rb')} + assert_raise(LoadError) {require('x/t.rb')} + File.unlink(*Dir.glob('x/*')) + Dir.rmdir("#{tmp}/x") + $:.replace(load_path) + load_path = nil + assert(!require('tmpdir')) + end + end + ensure + $:.replace(load_path) if load_path + end + + def test_relative_symlink + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + Dir.mkdir "a" + Dir.mkdir "b" + File.open("a/lib.rb", "w") {|f| f.puts 'puts "a/lib.rb"' } + File.open("b/lib.rb", "w") {|f| f.puts 'puts "b/lib.rb"' } + File.open("a/tst.rb", "w") {|f| f.puts 'require_relative "lib"' } + begin + File.symlink("../a/tst.rb", "b/tst.rb") + result = IO.popen([EnvUtil.rubybin, "b/tst.rb"], &:read) + assert_equal("a/lib.rb\n", result, "[ruby-dev:40040]") + rescue NotImplementedError + skip "File.symlink is not implemented" + end + } + } + end + + def test_frozen_loaded_features + bug3756 = '[ruby-core:31913]' + assert_in_out_err(['-e', '$LOADED_FEATURES.freeze; require "ostruct"'], "", + [], /\$LOADED_FEATURES is frozen; cannot append feature \(RuntimeError\)$/, + bug3756) + end + + def test_race_exception + bug5754 = '[ruby-core:41618]' + path = nil + stderr = $stderr + verbose = $VERBOSE + Tempfile.create(%w"bug5754 .rb") {|tmp| + path = tmp.path + tmp.print %{\ + th = Thread.current + t = th[:t] + scratch = th[:scratch] + + if scratch.empty? + scratch << :pre + Thread.pass until t.stop? + raise RuntimeError + else + scratch << :post + end + } + tmp.close + + class << (output = "") + alias write concat + end + $stderr = output + + start = false + + scratch = [] + t1_res = nil + t2_res = nil + + t1 = Thread.new do + Thread.pass until start + begin + require(path) + rescue RuntimeError + end + + t1_res = require(path) + end + + t2 = Thread.new do + Thread.pass until scratch[0] + t2_res = require(path) + end + + t1[:scratch] = t2[:scratch] = scratch + t1[:t] = t2 + t2[:t] = t1 + + $VERBOSE = true + start = true + + assert_nothing_raised(ThreadError, bug5754) {t1.join} + assert_nothing_raised(ThreadError, bug5754) {t2.join} + + $VERBOSE = false + + assert_equal(true, (t1_res ^ t2_res), bug5754 + " t1:#{t1_res} t2:#{t2_res}") + assert_equal([:pre, :post], scratch, bug5754) + + assert_match(/circular require/, output) + assert_match(/in #{__method__}'$/o, output) + } + ensure + $VERBOSE = verbose + $stderr = stderr + $".delete(path) + end + + def test_loaded_features_encoding + bug6377 = '[ruby-core:44750]' + loadpath = $:.dup + features = $".dup + $".clear + $:.clear + Dir.mktmpdir {|tmp| + $: << tmp + open(File.join(tmp, "foo.rb"), "w") {} + require "foo" + assert_send([Encoding, :compatible?, tmp, $"[0]], bug6377) + } + ensure + $:.replace(loadpath) + $".replace(features) + end + + def test_require_changed_current_dir + bug7158 = '[ruby-core:47970]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + Dir.mkdir("a") + Dir.mkdir("b") + open(File.join("a", "foo.rb"), "w") {} + open(File.join("b", "bar.rb"), "w") {|f| + f.puts "p :ok" + } + assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + $:.replace([IO::NULL]) + $: << "." + Dir.chdir("a") + require "foo" + Dir.chdir("../b") + p :ng unless require "bar" + Dir.chdir("..") + p :ng if require "b/bar" + INPUT + } + } + end + + def test_require_not_modified_load_path + bug7158 = '[ruby-core:47970]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("foo.rb", "w") {} + assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + $:.replace([IO::NULL]) + a = Object.new + def a.to_str + "#{tmp}" + end + $: << a + require "foo" + last_path = $:.pop + p :ok if last_path == a && last_path.class == Object + INPUT + } + } + end + + def test_require_changed_home + bug7158 = '[ruby-core:47970]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("foo.rb", "w") {} + Dir.mkdir("a") + open(File.join("a", "bar.rb"), "w") {} + assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + $:.replace([IO::NULL]) + $: << '~' + ENV['HOME'] = "#{tmp}" + require "foo" + ENV['HOME'] = "#{tmp}/a" + p :ok if require "bar" + INPUT + } + } + end + + def test_require_to_path_redefined_in_load_path + bug7158 = '[ruby-core:47970]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("foo.rb", "w") {} + assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158) + $:.replace([IO::NULL]) + a = Object.new + def a.to_path + "bar" + end + $: << a + begin + require "foo" + p [:ng, $LOAD_PATH, ENV['RUBYLIB']] + rescue LoadError + end + def a.to_path + "#{tmp}" + end + p :ok if require "foo" + INPUT + } + } + end + + def test_require_to_str_redefined_in_load_path + bug7158 = '[ruby-core:47970]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("foo.rb", "w") {} + assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158) + $:.replace([IO::NULL]) + a = Object.new + def a.to_str + "foo" + end + $: << a + begin + require "foo" + p [:ng, $LOAD_PATH, ENV['RUBYLIB']] + rescue LoadError + end + def a.to_str + "#{tmp}" + end + p :ok if require "foo" + INPUT + } + } + end + + def assert_require_with_shared_array_modified(add, del) + bug7383 = '[ruby-core:49518]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("foo.rb", "w") {} + Dir.mkdir("a") + open(File.join("a", "bar.rb"), "w") {} + assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7383) + $:.replace([IO::NULL]) + $:.#{add} "#{tmp}" + $:.#{add} "#{tmp}/a" + require "foo" + $:.#{del} + # Expanded load path cache should be rebuilt. + begin + require "bar" + rescue LoadError + p :ok + end + INPUT + } + } + end + + def test_require_with_array_pop + assert_require_with_shared_array_modified("push", "pop") + end + + def test_require_with_array_shift + assert_require_with_shared_array_modified("unshift", "shift") + end + + def test_require_local_var_on_toplevel + bug7536 = '[ruby-core:50701]' + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + open("bar.rb", "w") {|f| f.puts 'TOPLEVEL_BINDING.eval("lib = 2")' } + assert_in_out_err(%w[-r./bar.rb], <<-INPUT, %w([:lib] 2), [], bug7536) + puts TOPLEVEL_BINDING.eval("local_variables").inspect + puts TOPLEVEL_BINDING.eval("lib").inspect + INPUT + } + } + end + + def test_require_with_loaded_features_pop + bug7530 = '[ruby-core:50645]' + Tempfile.create(%w'bug-7530- .rb') {|script| + script.close + assert_in_out_err([{"RUBYOPT" => nil}, "-", script.path], <<-INPUT, %w(:ok), [], bug7530) + PATH = ARGV.shift + THREADS = 2 + ITERATIONS_PER_THREAD = 1000 + + THREADS.times.map { + Thread.new do + ITERATIONS_PER_THREAD.times do + require PATH + $".pop + end + end + }.each(&:join) + p :ok + INPUT + } + end + + def test_loading_fifo_threading + Tempfile.create(%w'fifo .rb') {|f| + f.close + File.unlink(f.path) + File.mkfifo(f.path) + assert_separately(["-", f.path], <<-END, timeout: 3) + th = Thread.current + Thread.start {begin sleep(0.001) end until th.stop?; th.raise(IOError)} + assert_raise(IOError) {load(ARGV[0])} + END + } + rescue Errno::ENOENT + end unless /mswin|mingw/ =~ RUBY_PLATFORM +end diff --git a/jni/ruby/test/ruby/test_rubyoptions.rb b/jni/ruby/test/ruby/test_rubyoptions.rb new file mode 100644 index 0000000..7cb1248 --- /dev/null +++ b/jni/ruby/test/ruby/test_rubyoptions.rb @@ -0,0 +1,796 @@ +# -*- coding: us-ascii -*- +require 'test/unit' + +require 'tmpdir' +require 'tempfile' + +class TestRubyOptions < Test::Unit::TestCase + def write_file(filename, content) + File.open(filename, "w") {|f| + f << content + } + end + + def with_tmpchdir + Dir.mktmpdir {|d| + d = File.realpath(d) + Dir.chdir(d) { + yield d + } + } + end + + def test_source_file + assert_in_out_err([], "", [], []) + end + + def test_usage + assert_in_out_err(%w(-h)) do |r, e| + assert_operator(r.size, :<=, 24) + longer = r[1..-1].select {|x| x.size > 80} + assert_equal([], longer) + assert_equal([], e) + end + end + + def test_usage_long + assert_in_out_err(%w(--help)) do |r, e| + longer = r[1..-1].select {|x| x.size > 80} + assert_equal([], longer) + assert_equal([], e) + end + end + + def test_option_variables + assert_in_out_err(["-e", 'p [$-p, $-l, $-a]']) do |r, e| + assert_equal(["[false, false, false]"], r) + assert_equal([], e) + end + + assert_in_out_err(%w(-p -l -a -e) + ['p [$-p, $-l, $-a]'], + "foo\nbar\nbaz\n") do |r, e| + assert_equal( + [ '[true, true, true]', 'foo', + '[true, true, true]', 'bar', + '[true, true, true]', 'baz' ], r) + assert_equal([], e) + end + end + + def test_warning + save_rubyopt = ENV['RUBYOPT'] + ENV['RUBYOPT'] = nil + assert_in_out_err(%w(-W0 -e) + ['p $-W'], "", %w(0), []) + assert_in_out_err(%w(-W1 -e) + ['p $-W'], "", %w(1), []) + assert_in_out_err(%w(-Wx -e) + ['p $-W'], "", %w(1), []) + assert_in_out_err(%w(-W -e) + ['p $-W'], "", %w(2), []) + ensure + ENV['RUBYOPT'] = save_rubyopt + end + + def test_safe_level + assert_in_out_err(%w(-T -e) + [""], "", [], + /no -e allowed in tainted mode \(SecurityError\)/) + + assert_in_out_err(%w(-T4 -S foo.rb), "", [], + /no -S allowed in tainted mode \(SecurityError\)/) + end + + def test_debug + assert_in_out_err(["--disable-gems", "-de", "p $DEBUG"], "", %w(true), []) + + assert_in_out_err(["--disable-gems", "--debug", "-e", "p $DEBUG"], + "", %w(true), []) + end + + def test_verbose + assert_in_out_err(["-vve", ""]) do |r, e| + assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev|rc).*? \[#{RUBY_PLATFORM}\]$/, r.join) + assert_equal RUBY_DESCRIPTION, r.join.chomp + assert_equal([], e) + end + + assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), []) + + assert_in_out_err(%w(--verbose), "", [], []) + end + + def test_copyright + assert_in_out_err(%w(--copyright), "", + /^ruby - Copyright \(C\) 1993-\d+ Yukihiro Matsumoto$/, []) + + assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), []) + end + + def test_enable + assert_in_out_err(%w(--enable all -e) + [""], "", [], []) + assert_in_out_err(%w(--enable-all -e) + [""], "", [], []) + assert_in_out_err(%w(--enable=all -e) + [""], "", [], []) + assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [], + /unknown argument for --enable: `foobarbazqux'/) + assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/) + end + + def test_disable + assert_in_out_err(%w(--disable all -e) + [""], "", [], []) + assert_in_out_err(%w(--disable-all -e) + [""], "", [], []) + assert_in_out_err(%w(--disable=all -e) + [""], "", [], []) + assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [], + /unknown argument for --disable: `foobarbazqux'/) + assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/) + end + + def test_kanji + assert_in_out_err(%w(-KU), "p '\u3042'") do |r, e| + assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) + end + line = '-eputs"\xc2\xa1".encoding' + env = {'RUBYOPT' => nil} + assert_in_out_err([env, '-Ke', line], "", ["EUC-JP"], []) + assert_in_out_err([env, '-KE', line], "", ["EUC-JP"], []) + assert_in_out_err([env, '-Ks', line], "", ["Windows-31J"], []) + assert_in_out_err([env, '-KS', line], "", ["Windows-31J"], []) + assert_in_out_err([env, '-Ku', line], "", ["UTF-8"], []) + assert_in_out_err([env, '-KU', line], "", ["UTF-8"], []) + assert_in_out_err([env, '-Kn', line], "", ["ASCII-8BIT"], []) + assert_in_out_err([env, '-KN', line], "", ["ASCII-8BIT"], []) + assert_in_out_err([env, '-wKe', line], "", ["EUC-JP"], /-K/) + end + + def test_version + assert_in_out_err(%w(--version)) do |r, e| + assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev|rc).*? \[#{RUBY_PLATFORM}\]$/, r.join) + assert_equal RUBY_DESCRIPTION, r.join.chomp + assert_equal([], e) + end + end + + def test_eval + assert_in_out_err(%w(-e), "", [], /no code specified for -e \(RuntimeError\)/) + end + + def test_require + require "pp" + assert_in_out_err(%w(-r pp -e) + ["pp 1"], "", %w(1), []) + assert_in_out_err(%w(-rpp -e) + ["pp 1"], "", %w(1), []) + assert_in_out_err(%w(-ep\ 1 -r), "", %w(1), []) + assert_in_out_err(%w(-r), "", [], []) + rescue LoadError + end + + def test_include + d = Dir.tmpdir + assert_in_out_err(["-I" + d, "-e", ""], "", [], []) + assert_in_out_err(["-I", d, "-e", ""], "", [], []) + end + + def test_separator + assert_in_out_err(%w(-000 -e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0baz), []) + + assert_in_out_err(%w(-0141 -e) + ["print gets"], "foo\nbar\0baz", %w(foo ba), []) + + assert_in_out_err(%w(-0e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0), []) + end + + def test_autosplit + assert_in_out_err(%w(-an -F: -e) + ["p $F"], "foo:bar:baz\nqux:quux:quuux\n", + ['["foo", "bar", "baz\n"]', '["qux", "quux", "quuux\n"]'], []) + end + + def test_chdir + assert_in_out_err(%w(-C), "", [], /Can't chdir/) + + assert_in_out_err(%w(-C test_ruby_test_rubyoptions_foobarbazqux), "", [], /Can't chdir/) + + d = Dir.tmpdir + assert_in_out_err(["-C", d, "-e", "puts Dir.pwd"]) do |r, e| + assert_file.identical?(r.join, d) + assert_equal([], e) + end + end + + def test_yydebug + assert_in_out_err(["-ye", ""]) do |r, e| + assert_equal([], r) + assert_not_equal([], e) + end + + assert_in_out_err(%w(--yydebug -e) + [""]) do |r, e| + assert_equal([], r) + assert_not_equal([], e) + end + end + + def test_encoding + assert_in_out_err(%w(--encoding), "", [], /missing argument for --encoding/) + + assert_in_out_err(%w(--encoding test_ruby_test_rubyoptions_foobarbazqux), "", [], + /unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/) + + if /mswin|mingw|aix/ =~ RUBY_PLATFORM && + (str = "\u3042".force_encoding(Encoding.find("locale"))).valid_encoding? + # This result depends on locale because LANG=C doesn't affect locale + # on Windows. + # On AIX, the source encoding of stdin with LANG=C is ISO-8859-1, + # which allows \u3042. + out, err = [str], [] + else + out, err = [], /invalid multibyte char/ + end + assert_in_out_err(%w(-Eutf-8), "puts '\u3042'", out, err) + assert_in_out_err(%w(--encoding utf-8), "puts '\u3042'", out, err) + end + + def test_syntax_check + assert_in_out_err(%w(-c -e a=1+1 -e !a), "", ["Syntax OK"], []) + end + + def test_invalid_option + assert_in_out_err(%w(--foobarbazqux), "", [], /invalid option --foobarbazqux/) + + assert_in_out_err(%W(-\r -e) + [""], "", [], []) + + assert_in_out_err(%W(-\rx), "", [], /invalid option -\\x0D \(-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 + + def test_rubyopt + rubyopt_orig = ENV['RUBYOPT'] + + ENV['RUBYOPT'] = ' - -' + assert_in_out_err([], "", [], []) + + ENV['RUBYOPT'] = '-e "p 1"' + assert_in_out_err([], "", [], /invalid switch in RUBYOPT: -e \(RuntimeError\)/) + + ENV['RUBYOPT'] = '-T1' + assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/) + + ENV['RUBYOPT'] = '-T4' + assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/) + + ENV['RUBYOPT'] = '-Eus-ascii -KN' + assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e| + assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) + assert_equal([], e) + end + + ensure + if rubyopt_orig + ENV['RUBYOPT'] = rubyopt_orig + else + ENV.delete('RUBYOPT') + end + end + + def test_search + rubypath_orig = ENV['RUBYPATH'] + path_orig = ENV['PATH'] + + Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| + t.puts "p 1" + t.close + + @verbose = $VERBOSE + $VERBOSE = nil + + ENV['PATH'] = File.dirname(t.path) + + assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), []) + + ENV['RUBYPATH'] = File.dirname(t.path) + + assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), []) + } + + ensure + if rubypath_orig + ENV['RUBYPATH'] = rubypath_orig + else + ENV.delete('RUBYPATH') + end + if path_orig + ENV['PATH'] = path_orig + else + ENV.delete('PATH') + end + $VERBOSE = @verbose + end + + def test_shebang + assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux\r\np 1\r\n", + [], /: no Ruby script found in input/) + + assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux -foo -bar\r\np 1\r\n", + [], /: no Ruby script found in input/) + + assert_in_out_err([{'RUBYOPT' => nil}], "#!ruby -KU -Eutf-8\r\np \"\u3042\"\r\n") do |r, e| + assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) + assert_equal([], e) + end + + bug4118 = '[ruby-dev:42680]' + assert_in_out_err(%w[], "#!/bin/sh\n""#!shebang\n""#!ruby\n""puts __LINE__\n", + %w[4], [], bug4118) + assert_in_out_err(%w[-x], "#!/bin/sh\n""#!shebang\n""#!ruby\n""puts __LINE__\n", + %w[4], [], bug4118) + end + + def test_sflag + assert_in_out_err(%w(- -abc -def=foo -ghi-jkl -- -xyz), + "#!ruby -s\np [$abc, $def, $ghi_jkl, defined?($xyz)]\n", + ['[true, "foo", true, nil]'], []) + + assert_in_out_err(%w(- -#), "#!ruby -s\n", [], + /invalid name for global variable - -# \(NameError\)/) + + assert_in_out_err(%w(- -#=foo), "#!ruby -s\n", [], + /invalid name for global variable - -# \(NameError\)/) + end + + def test_assignment_in_conditional + Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| + t.puts "if a = 1" + t.puts "end" + t.puts "0.times do" + t.puts " if b = 2" + t.puts " a += b" + t.puts " end" + t.puts "end" + t.flush + warning = ' warning: found = in conditional, should be ==' + err = ["#{t.path}:1:#{warning}", + "#{t.path}:4:#{warning}", + ] + bug2136 = '[ruby-dev:39363]' + assert_in_out_err(["-w", t.path], "", [], err, bug2136) + assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err, bug2136) + + t.rewind + t.truncate(0) + t.puts "if a = ''; end" + t.puts "if a = []; end" + t.puts "if a = [1]; end" + t.puts "if a = [a]; end" + t.puts "if a = {}; end" + t.puts "if a = {1=>2}; end" + t.puts "if a = {3=>a}; end" + t.flush + err = ["#{t.path}:1:#{warning}", + "#{t.path}:2:#{warning}", + "#{t.path}:3:#{warning}", + "#{t.path}:5:#{warning}", + "#{t.path}:6:#{warning}", + ] + feature4299 = '[ruby-dev:43083]' + assert_in_out_err(["-w", t.path], "", [], err, feature4299) + assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err, feature4299) + } + end + + def test_indentation_check + Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| + t.puts "begin" + t.puts " end" + t.flush + err = ["#{t.path}:2: warning: mismatched indentations at 'end' with 'begin' at 1"] + assert_in_out_err(["-w", t.path], "", [], err) + assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err) + + t.rewind + t.puts "# -*- warn-indent: false -*-" + t.puts "begin" + t.puts " end" + t.flush + assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]') + + err = ["#{t.path}:4: warning: mismatched indentations at 'end' with 'begin' at 3"] + t.rewind + t.puts "# -*- warn-indent: false -*-" + t.puts "# -*- warn-indent: true -*-" + t.puts "begin" + t.puts " end" + t.flush + assert_in_out_err(["-w", t.path], "", [], err, '[ruby-core:25442]') + + err = ["#{t.path}:4: warning: mismatched indentations at 'end' with 'begin' at 2"] + t.rewind + t.puts "# -*- warn-indent: true -*-" + t.puts "begin" + t.puts "# -*- warn-indent: false -*-" + t.puts " end" + t.flush + assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]') + } + end + + def test_notfound + notexist = "./notexist.rb" + rubybin = EnvUtil.rubybin.dup + rubybin.gsub!(%r(/), '\\') if /mswin|mingw/ =~ RUBY_PLATFORM + rubybin = Regexp.quote(rubybin) + pat = Regexp.quote(notexist) + bug1573 = '[ruby-core:23717]' + assert_file.not_exist?(notexist) + assert_in_out_err(["-r", notexist, "-ep"], "", [], /.* -- #{pat} \(LoadError\)/, bug1573) + assert_in_out_err([notexist], "", [], /#{rubybin}:.* -- #{pat} \(LoadError\)/, bug1573) + end + + def test_program_name + ruby = EnvUtil.rubybin + IO.popen([ruby, '-e', 'print $0']) {|f| + assert_equal('-e', f.read) + } + IO.popen([ruby, '-'], 'r+') {|f| + f << 'print $0' + f.close_write + assert_equal('-', f.read) + } + Dir.mktmpdir {|d| + n1 = File.join(d, 't1') + open(n1, 'w') {|f| f << 'print $0' } + IO.popen([ruby, n1]) {|f| + assert_equal(n1, f.read) + } + if File.respond_to? :symlink + n2 = File.join(d, 't2') + File.symlink(n1, n2) + IO.popen([ruby, n2]) {|f| + assert_equal(n2, f.read) + } + end + Dir.chdir(d) { + n3 = '-e' + open(n3, 'w') {|f| f << 'print $0' } + IO.popen([ruby, '--', n3]) {|f| + assert_equal(n3, f.read) + } + n4 = '-' + IO.popen([ruby, '--', n4], 'r+') {|f| + f << 'print $0' + f.close_write + assert_equal(n4, f.read) + } + } + } + end + + if /linux|freebsd|netbsd|openbsd|darwin/ =~ RUBY_PLATFORM + PSCMD = EnvUtil.find_executable("ps", "-o", "command", "-p", $$.to_s) {|out| /ruby/=~out} + PSCMD.pop if PSCMD + end + + def test_set_program_name + skip "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") + + pid = spawn(EnvUtil.rubybin, "test-script") + ps = nil + 10.times do + sleep 0.1 + ps = `#{PSCMD.join(' ')} #{pid}` + break if /hello world/ =~ ps + end + assert_match(/hello world/, ps) + Process.kill :KILL, pid + Process.wait(pid) + end + end + + def test_setproctitle + skip "platform dependent feature" unless defined?(PSCMD) and PSCMD + + with_tmpchdir do + write_file("test-script", "$_0 = $0.dup; Process.setproctitle('hello world'); $0 == $_0 or Process.setproctitle('$0 changed!'); sleep 60") + + pid = spawn(EnvUtil.rubybin, "test-script") + ps = nil + 10.times do + sleep 0.1 + ps = `#{PSCMD.join(' ')} #{pid}` + break if /hello world/ =~ ps + end + assert_match(/hello world/, ps) + Process.kill :KILL, pid + Process.wait(pid) + end + end + + module SEGVTest + opts = {} + if /mswin|mingw/ =~ RUBY_PLATFORM + additional = /[\s\w\.\']*/ + else + opts[:rlimit_core] = 0 + additional = nil + end + ExecOptions = opts.freeze + + ExpectedStderrList = [ + %r( + -e:(?:1:)?\s\[BUG\]\sSegmentation\sfault.*\n + )x, + %r( + #{ Regexp.quote(RUBY_DESCRIPTION) }\n\n + )x, + %r( + (?:--\s(?:.+\n)*\n)? + --\sControl\sframe\sinformation\s-+\n + (?:c:.*\n)* + )x, + %r( + (?: + --\sRuby\slevel\sbacktrace\sinformation\s----------------------------------------\n + -e:1:in\s\`<main>\'\n + -e:1:in\s\`kill\'\n + )? + )x, + %r( + (?: + --\sC\slevel\sbacktrace\sinformation\s-------------------------------------------\n + (?:(?:.*\s)?\[0x\h+\]\n)*\n + )? + )x, + :*, + %r( + \[NOTE\]\n + You\smay\shave\sencountered\sa\sbug\sin\sthe\sRuby\sinterpreter\sor\sextension\slibraries.\n + Bug\sreports\sare\swelcome.\n + (?:.*\n)? + For\sdetails:\shttp:\/\/.*\.ruby-lang\.org/.*\n + \n + )x, + ] + ExpectedStderrList << additional if additional + end + + def assert_segv(args, message=nil) + test_stdin = "" + opt = SEGVTest::ExecOptions.dup + + _, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, false, true, **opt) + stderr.force_encoding("ASCII-8BIT") + + if signo = status.termsig + sleep 0.1 + EnvUtil.diagnostic_reports(Signal.signame(signo), EnvUtil.rubybin, status.pid, Time.now) + end + + assert_pattern_list(SEGVTest::ExpectedStderrList, stderr, message) + + status + end + + def test_segv_test + assert_segv(["--disable-gems", "-e", "Process.kill :SEGV, $$"]) + end + + def test_segv_loaded_features + opts = SEGVTest::ExecOptions.dup + + bug7402 = '[ruby-core:49573]' + + status = Dir.mktmpdir("segv_test") do |tmpdir| + assert_in_out_err(['-e', 'class Bogus; def to_str; exit true; end; end', + '-e', '$".clear', + '-e', '$".unshift Bogus.new', + '-e', '(p $"; abort) unless $".size == 1', + '-e', 'Process.kill :SEGV, $$', + '-C', tmpdir, + ], + "", [], //, + nil, + opts) + end + if signo = status.termsig + sleep 0.1 + EnvUtil.diagnostic_reports(Signal.signame(signo), EnvUtil.rubybin, status.pid, Time.now) + end + assert_not_predicate(status, :success?, "segv but success #{bug7402}") + end + + def test_segv_setproctitle + bug7597 = '[ruby-dev:46786]' + Tempfile.create(["test_ruby_test_bug7597", ".rb"]) {|t| + t.write "f" * 100 + t.flush + assert_segv(["--disable-gems", "-e", "$0=ARGV[0]; Process.kill :SEGV, $$", t.path], bug7597) + } + end + + def test_DATA + Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| + t.puts "puts DATA.read.inspect" + t.puts "__END__" + t.puts "foo" + t.puts "bar" + t.puts "baz" + t.flush + assert_in_out_err([t.path], "", %w("foo\\nbar\\nbaz\\n"), []) + } + end + + def test_unused_variable + feature3446 = '[ruby-dev:41620]' + assert_in_out_err(["-we", "a=1"], "", [], [], feature3446) + assert_in_out_err(["-we", "def foo\n a=1\nend"], "", [], ["-e:2: warning: assigned but unused variable - a"], feature3446) + assert_in_out_err(["-we", "def foo\n eval('a=1')\nend"], "", [], [], feature3446) + assert_in_out_err(["-we", "1.times do\n a=1\nend"], "", [], [], feature3446) + assert_in_out_err(["-we", "def foo\n 1.times do\n a=1\n end\nend"], "", [], ["-e:3: warning: assigned but unused variable - a"], feature3446) + assert_in_out_err(["-we", "def foo\n"" 1.times do |a| end\n""end"], "", [], []) + feature6693 = '[ruby-core:46160]' + assert_in_out_err(["-we", "def foo\n _a=1\nend"], "", [], [], feature6693) + bug7408 = '[ruby-core:49659]' + assert_in_out_err(["-we", "def foo\n a=1\n :a\nend"], "", [], ["-e:2: warning: assigned but unused variable - a"], bug7408) + feature7730 = '[ruby-core:51580]' + assert_in_out_err(["-w", "-"], "a=1", [], ["-:1: warning: assigned but unused variable - a"], feature7730) + assert_in_out_err(["-w", "-"], "eval('a=1')", [], [], feature7730) + end + + def test_shadowing_variable + bug4130 = '[ruby-dev:42718]' + assert_in_out_err(["-we", "def foo\n"" a=1\n"" 1.times do |a| end\n"" a\n""end"], + "", [], ["-e:3: warning: shadowing outer local variable - a"], bug4130) + assert_in_out_err(["-we", "def foo\n"" a=1\n"" 1.times do |a| end\n""end"], + "", [], + ["-e:3: warning: shadowing outer local variable - a", + "-e:2: warning: assigned but unused variable - a", + ], bug4130) + feature6693 = '[ruby-core:46160]' + assert_in_out_err(["-we", "def foo\n"" _a=1\n"" 1.times do |_a| end\n""end"], + "", [], [], feature6693) + end + + def test_script_from_stdin + begin + require 'pty' + require 'io/console' + rescue LoadError + return + end + require 'timeout' + result = nil + IO.pipe {|r, w| + begin + PTY.open {|m, s| + s.echo = false + m.print("\C-d") + pid = spawn(EnvUtil.rubybin, :in => s, :out => w) + w.close + assert_nothing_raised('[ruby-dev:37798]') do + result = Timeout.timeout(3) {r.read} + end + Process.wait pid + } + rescue RuntimeError + skip $! + end + } + assert_equal("", result, '[ruby-dev:37798]') + IO.pipe {|r, w| + PTY.open {|m, s| + s.echo = false + pid = spawn(EnvUtil.rubybin, :in => s, :out => w) + w.close + m.print("$stdin.read; p $stdin.gets\n\C-d") + m.print("abc\n\C-d") + m.print("zzz\n") + result = r.read + Process.wait pid + } + } + assert_equal("\"zzz\\n\"\n", result, '[ruby-core:30910]') + end + + def test_unmatching_glob + bug3851 = '[ruby-core:32478]' + a = "a[foo" + Dir.mktmpdir do |dir| + open(File.join(dir, a), "w") {|f| f.puts("p 42")} + assert_in_out_err(["-C", dir, a], "", ["42"], [], bug3851) + File.unlink(File.join(dir, a)) + assert_in_out_err(["-C", dir, a], "", [], /LoadError/, bug3851) + end + end + + if /mswin|mingw/ =~ RUBY_PLATFORM + def test_command_line_glob_nonascii + bug10555 = '[ruby-dev:48752] [Bug #10555]' + name = "\u{3042}.txt" + expected = name.encode("locale") rescue "?.txt" + with_tmpchdir do |dir| + open(name, "w") {} + assert_in_out_err(["-e", "puts ARGV", "?.txt"], "", [expected], [], + bug10555, encoding: "locale") + end + end + + def test_command_line_progname_nonascii + bug10555 = '[ruby-dev:48752] [Bug #10555]' + name = "\u{3042}.rb" + expected = name.encode("locale") rescue "?.rb" + with_tmpchdir do |dir| + open(name, "w") {|f| f.puts "puts File.basename($0)"} + assert_in_out_err([name], "", [expected], [], + bug10555, encoding: "locale") + end + end + + def test_command_line_glob_with_dir + bug10941 = '[ruby-core:68430] [Bug #10941]' + with_tmpchdir do |dir| + Dir.mkdir('test') + assert_in_out_err(["-e", "", "test/*"], "", [], [], bug10941) + end + end + end + + if /mswin|mingw/ =~ RUBY_PLATFORM + Ougai = %W[\u{68ee}O\u{5916}.txt \u{68ee 9d0e 5916}.txt \u{68ee 9dd7 5916}.txt] + def test_command_line_glob_noncodepage + with_tmpchdir do |dir| + Ougai.each {|f| open(f, "w") {}} + assert_in_out_err(["-Eutf-8", "-e", "puts ARGV", "*"], "", Ougai, encoding: "utf-8") + ougai = Ougai.map {|f| f.encode("locale", replace: "?")} + assert_in_out_err(["-e", "puts ARGV", "*.txt"], "", ougai) + end + end + end + + def test_script_is_directory + feature2408 = '[ruby-core:26925]' + assert_in_out_err(%w[.], "", [], /Is a directory -- \./, feature2408) + end + + def test_pflag_gsub + bug7157 = '[ruby-core:47967]' + assert_in_out_err(['-p', '-e', 'gsub(/t.*/){"TEST"}'], %[test], %w[TEST], [], bug7157) + end + + def test_pflag_sub + bug7157 = '[ruby-core:47967]' + assert_in_out_err(['-p', '-e', 'sub(/t.*/){"TEST"}'], %[test], %w[TEST], [], bug7157) + end + + def assert_norun_with_rflag(opt) + bug10435 = "[ruby-dev:48712] [Bug #10435]: should not run with #{opt} option" + stderr = [] + Tempfile.create(%w"bug10435- .rb") do |script| + dir, base = File.split(script.path) + script.puts "abort ':run'" + script.close + opts = ['-C', dir, '-r', "./#{base}", opt] + assert_in_out_err([*opts, '-ep']) do |_, e| + stderr.concat(e) + end + stderr << "---" + assert_in_out_err([*opts, base]) do |_, e| + stderr.concat(e) + end + end + assert_not_include(stderr, ":run", bug10435) + end + + def test_dump_syntax_with_rflag + assert_norun_with_rflag('-c') + assert_norun_with_rflag('--dump=syntax') + end + + def test_dump_yydebug_with_rflag + assert_norun_with_rflag('-y') + assert_norun_with_rflag('--dump=yydebug') + end + + def test_dump_parsetree_with_rflag + assert_norun_with_rflag('--dump=parsetree') + end + + def test_dump_insns_with_rflag + assert_norun_with_rflag('--dump=insns') + end +end diff --git a/jni/ruby/test/ruby/test_rubyvm.rb b/jni/ruby/test/ruby/test_rubyvm.rb new file mode 100644 index 0000000..580f3be --- /dev/null +++ b/jni/ruby/test/ruby/test_rubyvm.rb @@ -0,0 +1,17 @@ +require 'test/unit' + +class TestRubyVM < Test::Unit::TestCase + def test_stat + assert_kind_of Hash, RubyVM.stat + assert_kind_of Fixnum, RubyVM.stat[:global_method_state] + + RubyVM.stat(stat = {}) + assert_not_empty stat + assert_equal stat[:global_method_state], RubyVM.stat(:global_method_state) + end + + def test_stat_unknown + assert_raise(ArgumentError){ RubyVM.stat(:unknown) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {RubyVM.stat(:"\u{30eb 30d3 30fc}")} + end +end diff --git a/jni/ruby/test/ruby/test_settracefunc.rb b/jni/ruby/test/ruby/test_settracefunc.rb new file mode 100644 index 0000000..1dcd2cc --- /dev/null +++ b/jni/ruby/test/ruby/test_settracefunc.rb @@ -0,0 +1,1355 @@ +require 'test/unit' + +class TestSetTraceFunc < Test::Unit::TestCase + def setup + @original_compile_option = RubyVM::InstructionSequence.compile_option + RubyVM::InstructionSequence.compile_option = { + :trace_instruction => true, + :specialized_instruction => false + } + @target_thread = Thread.current + end + + def teardown + set_trace_func(nil) + RubyVM::InstructionSequence.compile_option = @original_compile_option + @target_thread = nil + end + + def target_thread? + Thread.current == @target_thread + end + + def test_c_call + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: x = 1 + 1 + 5: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["c-call", 4, :+, Fixnum], + events.shift) + assert_equal(["c-return", 4, :+, Fixnum], + events.shift) + assert_equal(["line", 5, __method__, self.class], + events.shift) + assert_equal(["c-call", 5, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_call + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: def add(x, y) + 5: x + y + 6: end + 7: x = add(1, 1) + 8: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["c-call", 4, :method_added, self.class], + events.shift) + assert_equal(["c-return", 4, :method_added, self.class], + events.shift) + assert_equal(["line", 7, __method__, self.class], + events.shift) + assert_equal(["call", 4, :add, self.class], + events.shift) + assert_equal(["line", 5, :add, self.class], + events.shift) + assert_equal(["c-call", 5, :+, Fixnum], + events.shift) + assert_equal(["c-return", 5, :+, Fixnum], + events.shift) + assert_equal(["return", 6, :add, self.class], + events.shift) + assert_equal(["line", 8, __method__, self.class], + events.shift) + assert_equal(["c-call", 8, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_class + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: class Foo + 5: def bar + 6: end + 7: end + 8: x = Foo.new.bar + 9: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["c-call", 4, :inherited, Class], + events.shift) + assert_equal(["c-return", 4, :inherited, Class], + events.shift) + assert_equal(["class", 4, nil, nil], + events.shift) + assert_equal(["line", 5, nil, nil], + events.shift) + assert_equal(["c-call", 5, :method_added, Module], + events.shift) + assert_equal(["c-return", 5, :method_added, Module], + events.shift) + assert_equal(["end", 7, nil, nil], + events.shift) + assert_equal(["line", 8, __method__, self.class], + events.shift) + assert_equal(["c-call", 8, :new, Class], + events.shift) + assert_equal(["c-call", 8, :initialize, BasicObject], + events.shift) + assert_equal(["c-return", 8, :initialize, BasicObject], + events.shift) + assert_equal(["c-return", 8, :new, Class], + events.shift) + assert_equal(["call", 5, :bar, Foo], + events.shift) + assert_equal(["return", 6, :bar, Foo], + events.shift) + assert_equal(["line", 9, __method__, self.class], + events.shift) + assert_equal(["c-call", 9, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_return # [ruby-dev:38701] + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: def meth_return(a) + 5: return if a + 6: return + 7: end + 8: meth_return(true) + 9: meth_return(false) + 10: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["c-call", 4, :method_added, self.class], + events.shift) + assert_equal(["c-return", 4, :method_added, self.class], + events.shift) + assert_equal(["line", 8, __method__, self.class], + events.shift) + assert_equal(["call", 4, :meth_return, self.class], + events.shift) + assert_equal(["line", 5, :meth_return, self.class], + events.shift) + assert_equal(["return", 5, :meth_return, self.class], + events.shift) + assert_equal(["line", 9, :test_return, self.class], + events.shift) + assert_equal(["call", 4, :meth_return, self.class], + events.shift) + assert_equal(["line", 5, :meth_return, self.class], + events.shift) + assert_equal(["return", 7, :meth_return, self.class], + events.shift) + assert_equal(["line", 10, :test_return, self.class], + events.shift) + assert_equal(["c-call", 10, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_return2 # [ruby-core:24463] + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: def meth_return2 + 5: a = 5 + 6: return a + 7: end + 8: meth_return2 + 9: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["c-call", 4, :method_added, self.class], + events.shift) + assert_equal(["c-return", 4, :method_added, self.class], + events.shift) + assert_equal(["line", 8, __method__, self.class], + events.shift) + assert_equal(["call", 4, :meth_return2, self.class], + events.shift) + assert_equal(["line", 5, :meth_return2, self.class], + events.shift) + assert_equal(["line", 6, :meth_return2, self.class], + events.shift) + assert_equal(["return", 7, :meth_return2, self.class], + events.shift) + assert_equal(["line", 9, :test_return2, self.class], + events.shift) + assert_equal(["c-call", 9, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_raise + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: begin + 5: raise TypeError, "error" + 6: rescue TypeError + 7: end + 8: set_trace_func(nil) + EOF + assert_equal(["c-return", 1, :set_trace_func, Kernel], + events.shift) + assert_equal(["line", 4, __method__, self.class], + events.shift) + assert_equal(["line", 5, __method__, self.class], + events.shift) + assert_equal(["c-call", 5, :raise, Kernel], + events.shift) + assert_equal(["c-call", 5, :exception, Exception], + events.shift) + assert_equal(["c-call", 5, :initialize, Exception], + events.shift) + assert_equal(["c-return", 5, :initialize, Exception], + events.shift) + assert_equal(["c-return", 5, :exception, Exception], + events.shift) + assert_equal(["c-return", 5, :raise, Kernel], + events.shift) + assert_equal(["c-call", 5, :backtrace, Exception], + events.shift) + assert_equal(["c-return", 5, :backtrace, Exception], + events.shift) + assert_equal(["raise", 5, :test_raise, TestSetTraceFunc], + events.shift) + assert_equal(["c-call", 6, :===, Module], + events.shift) + assert_equal(["c-return", 6, :===, Module], + events.shift) + assert_equal(["line", 8, __method__, self.class], + events.shift) + assert_equal(["c-call", 8, :set_trace_func, Kernel], + events.shift) + assert_equal([], events) + end + + def test_break # [ruby-core:27606] [Bug #2610] + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] if file == name + 3: }) + 4: [1,2,3].any? {|n| n} + 8: set_trace_func(nil) + EOF + + [["c-return", 1, :set_trace_func, Kernel], + ["line", 4, __method__, self.class], + ["c-call", 4, :any?, Array], + ["line", 4, __method__, self.class], + ["c-return", 4, :any?, Array], + ["line", 5, __method__, self.class], + ["c-call", 5, :set_trace_func, Kernel]].each{|e| + assert_equal(e, events.shift) + } + end + + def test_invalid_proc + assert_raise(TypeError) { set_trace_func(1) } + end + + def test_raise_in_trace + set_trace_func proc {raise rescue nil} + assert_equal(42, (raise rescue 42), '[ruby-core:24118]') + end + + def test_thread_trace + events = {:set => [], :add => []} + prc = Proc.new { |event, file, lineno, mid, binding, klass| + events[:set] << [event, lineno, mid, klass, :set] + } + prc = prc # suppress warning + prc2 = Proc.new { |event, file, lineno, mid, binding, klass| + events[:add] << [event, lineno, mid, klass, :add] + } + prc2 = prc2 # suppress warning + + th = Thread.new do + th = Thread.current + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: th.set_trace_func(prc) + 2: th.add_trace_func(prc2) + 3: class ThreadTraceInnerClass + 4: def foo + 5: _x = 1 + 1 + 6: end + 7: end + 8: ThreadTraceInnerClass.new.foo + 9: th.set_trace_func(nil) + EOF + end + th.join + + [["c-return", 1, :set_trace_func, Thread, :set], + ["line", 2, __method__, self.class, :set], + ["c-call", 2, :add_trace_func, Thread, :set]].each do |e| + assert_equal(e, events[:set].shift) + end + + [["c-return", 2, :add_trace_func, Thread], + ["line", 3, __method__, self.class], + ["c-call", 3, :inherited, Class], + ["c-return", 3, :inherited, Class], + ["class", 3, nil, nil], + ["line", 4, nil, nil], + ["c-call", 4, :method_added, Module], + ["c-return", 4, :method_added, Module], + ["end", 7, nil, nil], + ["line", 8, __method__, self.class], + ["c-call", 8, :new, Class], + ["c-call", 8, :initialize, BasicObject], + ["c-return", 8, :initialize, BasicObject], + ["c-return", 8, :new, Class], + ["call", 4, :foo, ThreadTraceInnerClass], + ["line", 5, :foo, ThreadTraceInnerClass], + ["c-call", 5, :+, Fixnum], + ["c-return", 5, :+, Fixnum], + ["return", 6, :foo, ThreadTraceInnerClass], + ["line", 9, __method__, self.class], + ["c-call", 9, :set_trace_func, Thread]].each do |e| + [:set, :add].each do |type| + assert_equal(e + [type], events[type].shift) + end + end + assert_equal([], events[:set]) + assert_equal([], events[:add]) + end + + def test_trace_defined_method + events = [] + name = "#{self.class}\##{__method__}" + eval <<-EOF.gsub(/^.*?: /, ""), nil, name + 1: class FooBar; define_method(:foobar){}; end + 2: fb = FooBar.new + 3: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 4: events << [event, lineno, mid, klass] if file == name + 5: }) + 6: fb.foobar + 7: set_trace_func(nil) + EOF + + [["c-return", 3, :set_trace_func, Kernel], + ["line", 6, __method__, self.class], + ["call", 1, :foobar, FooBar], + ["return", 6, :foobar, FooBar], + ["line", 7, __method__, self.class], + ["c-call", 7, :set_trace_func, Kernel]].each{|e| + assert_equal(e, events.shift) + } + end + + def test_remove_in_trace + bug3921 = '[ruby-dev:42350]' + ok = false + func = lambda{|e, f, l, i, b, k| + set_trace_func(nil) + ok = eval("self", b) + } + + set_trace_func(func) + assert_equal(self, ok, bug3921) + end + + class << self + define_method(:method_added, Module.method(:method_added)) + end + + def trace_by_tracepoint *trace_events + events = [] + trace = nil + xyzzy = nil + _local_var = :outer + raised_exc = nil + method = :trace_by_tracepoint + _get_data = lambda{|tp| + case tp.event + when :return, :c_return + tp.return_value + when :raise + tp.raised_exception + else + :nothing + end + } + _defined_class = lambda{|tp| + klass = tp.defined_class + begin + # If it is singleton method, then return original class + # to make compatible with set_trace_func(). + # This is very ad-hoc hack. I hope I can make more clean test on it. + case klass.inspect + when /Class:TracePoint/; return TracePoint + when /Class:Exception/; return Exception + else klass + end + rescue Exception => e + e + end if klass + } + + trace = nil + begin + eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy' + 1: trace = TracePoint.trace(*trace_events){|tp| next if !target_thread? + 2: events << [tp.event, tp.lineno, tp.path, _defined_class.(tp), tp.method_id, tp.self, tp.binding.eval("_local_var"), _get_data.(tp)] if tp.path == 'xyzzy' + 3: } + 4: 1.times{|;_local_var| _local_var = :inner + 5: tap{} + 6: } + 7: class XYZZY + 8: _local_var = :XYZZY_outer + 9: def foo + 10: _local_var = :XYZZY_foo + 11: bar + 12: end + 13: def bar + 14: _local_var = :XYZZY_bar + 15: tap{} + 16: end + 17: end + 18: xyzzy = XYZZY.new + 19: xyzzy.foo + 20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end + 21: trace.disable + EOF + self.class.class_eval{remove_const(:XYZZY)} + ensure + trace.disable if trace && trace.enabled? + end + + answer_events = [ + # + [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, :outer, trace], + [:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing], + [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], + [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], + [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], + [:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing], + [:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self], + [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], + [: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], + [: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], + [: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], + [: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], + [: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], + [:line, 11, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, :nothing], + [:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], + [:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], + [:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing], + [:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing], + [:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy], + [: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], + [: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], + [:line, 21, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], + [:c_call, 21, "xyzzy", TracePoint, :disable, trace, :outer, :nothing], + ] + + return events, answer_events + end + + def trace_by_set_trace_func + events = [] + trace = nil + trace = trace + xyzzy = nil + xyzzy = xyzzy + _local_var = :outer + 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' + 3: }) + 4: 1.times{|;_local_var| _local_var = :inner + 5: tap{} + 6: } + 7: class XYZZY + 8: _local_var = :XYZZY_outer + 9: def foo + 10: _local_var = :XYZZY_foo + 11: bar + 12: end + 13: def bar + 14: _local_var = :XYZZY_bar + 15: tap{} + 16: end + 17: end + 18: xyzzy = XYZZY.new + 19: xyzzy.foo + 20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end + 21: set_trace_func(nil) + EOF + self.class.class_eval{remove_const(:XYZZY)} + return events + end + + def test_tracepoint + events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise) + + ms = [events1, answer_events].map{|evs| + evs.map{|e| + "#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}" + } + } + + mesg = ms[0].zip(ms[1]).map{|a, b| + if a != b + "#{a} <-> #{b}" + end + }.compact.join("\n") + + answer_events.zip(events1){|answer, event| + assert_equal answer, event, mesg + } + + events2 = trace_by_set_trace_func + events1.zip(events2){|ev1, ev2| + ev2[0] = ev2[0].sub('-', '_').to_sym + assert_equal ev1[0..2], ev2[0..2], ev1.inspect + + # event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var") + assert_equal ev1[3].nil?, ev2[3].nil? # klass + assert_equal ev1[4].nil?, ev2[4].nil? # id + assert_equal ev1[6], ev2[6] # _local_var + } + + [:line, :class, :end, :call, :return, :c_call, :c_return, :raise].each{|event| + events1, answer_events = *trace_by_tracepoint(event) + answer_events.find_all{|e| e[0] == event}.zip(events1){|answer_line, event_line| + assert_equal answer_line, event_line + } + } + end + + def test_tracepoint_object_id + tps = [] + trace = TracePoint.trace(){|tp| + next if !target_thread? + tps << tp + } + tap{} + tap{} + tap{} + trace.disable + + # passed tp is unique, `trace' object which is generated by TracePoint.trace + tps.each{|tp| + assert_equal trace, tp + } + end + + def test_tracepoint_access_from_outside + tp_store = nil + trace = TracePoint.trace(){|tp| + next if !target_thread? + tp_store = tp + } + tap{} + trace.disable + + assert_raise(RuntimeError){tp_store.lineno} + assert_raise(RuntimeError){tp_store.event} + assert_raise(RuntimeError){tp_store.path} + assert_raise(RuntimeError){tp_store.method_id} + assert_raise(RuntimeError){tp_store.defined_class} + assert_raise(RuntimeError){tp_store.binding} + assert_raise(RuntimeError){tp_store.self} + assert_raise(RuntimeError){tp_store.return_value} + assert_raise(RuntimeError){tp_store.raised_exception} + end + + def foo + end + + def test_tracepoint_enable + ary = [] + trace = TracePoint.new(:call){|tp| + next if !target_thread? + ary << tp.method_id + } + foo + trace.enable{ + foo + } + foo + assert_equal([:foo], ary) + + trace = TracePoint.new{} + begin + assert_equal(false, trace.enable) + assert_equal(true, trace.enable) + trace.enable{} + assert_equal(true, trace.enable) + ensure + trace.disable + end + end + + def test_tracepoint_disable + ary = [] + trace = TracePoint.trace(:call){|tp| + next if !target_thread? + ary << tp.method_id + } + foo + trace.disable{ + foo + } + foo + trace.disable + assert_equal([:foo, :foo], ary) + + trace = TracePoint.new{} + trace.enable{ + assert_equal(true, trace.disable) + assert_equal(false, trace.disable) + trace.disable{} + assert_equal(false, trace.disable) + } + end + + def test_tracepoint_enabled + trace = TracePoint.trace(:call){|tp| + # + } + assert_equal(true, trace.enabled?) + trace.disable{ + assert_equal(false, trace.enabled?) + trace.enable{ + assert_equal(true, trace.enabled?) + } + } + trace.disable + assert_equal(false, trace.enabled?) + end + + def method_test_tracepoint_return_value obj + obj + end + + def test_tracepoint_return_value + trace = TracePoint.new(:call, :return){|tp| + next if !target_thread? + next if tp.path != __FILE__ + case tp.event + when :call + assert_raise(RuntimeError) {tp.return_value} + when :return + assert_equal("xyzzy", tp.return_value) + end + } + trace.enable{ + method_test_tracepoint_return_value "xyzzy" + } + end + + class XYZZYException < Exception; end + def method_test_tracepoint_raised_exception err + raise err + end + + def test_tracepoint_raised_exception + trace = TracePoint.new(:call, :return){|tp| + next if !target_thread? + case tp.event + when :call, :return + assert_raise(RuntimeError) { tp.raised_exception } + when :raise + assert_equal(XYZZYError, tp.raised_exception) + end + } + trace.enable{ + begin + method_test_tracepoint_raised_exception XYZZYException + rescue XYZZYException + # ok + else + raise + end + } + end + + def method_for_test_tracepoint_block + yield + end + + def test_tracepoint_block + events = [] + TracePoint.new(:call, :return, :c_call, :b_call, :c_return, :b_return){|tp| + next if !target_thread? + events << [ + tp.event, tp.method_id, tp.defined_class, tp.self.class, + /return/ =~ tp.event ? tp.return_value : nil + ] + }.enable{ + 1.times{ + 3 + } + method_for_test_tracepoint_block{ + 4 + } + } + # pp events + # expected_events = + [[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], + [:c_call, :times, Integer, Fixnum, nil], + [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], + [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3], + [:c_return, :times, Integer, Fixnum, 1], + [:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], + [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], + [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4], + [:return, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4], + [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4] + ].zip(events){|expected, actual| + assert_equal(expected, actual) + } + end + + def test_tracepoint_thread + events = [] + thread_self = nil + created_thread = nil + TracePoint.new(:thread_begin, :thread_end){|tp| + events << [Thread.current, + tp.event, + tp.lineno, #=> 0 + tp.path, #=> nil + tp.binding, #=> nil + tp.defined_class, #=> nil, + tp.self.class # tp.self return creating/ending thread + ] + }.enable{ + created_thread = Thread.new{thread_self = self} + created_thread.join + } + events.reject!{|i| i[0] != created_thread} + assert_equal(self, thread_self) + assert_equal([created_thread, :thread_begin, 0, nil, nil, nil, Thread], events[0]) + assert_equal([created_thread, :thread_end, 0, nil, nil, nil, Thread], events[1]) + assert_equal(2, events.size) + end + + def test_tracepoint_inspect + events = [] + trace = TracePoint.new{|tp| + next if !target_thread? + events << [tp.event, tp.inspect] + } + assert_equal("#<TracePoint:disabled>", trace.inspect) + trace.enable{ + assert_equal("#<TracePoint:enabled>", trace.inspect) + Thread.new{}.join + } + assert_equal("#<TracePoint:disabled>", trace.inspect) + events.each{|(ev, str)| + case ev + when :line + assert_match(/ in /, str) + when :call, :c_call + assert_match(/call \`/, str) # #<TracePoint:c_call `inherited'@../trunk/test.rb:11> + when :return, :c_return + assert_match(/return \`/, str) # #<TracePoint:return `m'@../trunk/test.rb:3> + when /thread/ + assert_match(/\#<Thread:/, str) # #<TracePoint:thread_end of #<Thread:0x87076c0>> + else + assert_match(/\#<TracePoint:/, str) + end + } + end + + def test_tracepoint_exception_at_line + assert_raise(RuntimeError) do + TracePoint.new(:line) { + next if !target_thread? + raise + }.enable { + 1 + } + end + end + + def test_tracepoint_exception_at_return + assert_nothing_raised(Timeout::Error, 'infinite trace') do + assert_normal_exit('def m; end; TracePoint.new(:return) {raise}.enable {m}', '', timeout: 3) + end + end + + def test_tracepoint_with_multithreads + assert_nothing_raised do + TracePoint.new{ + 10.times{ + Thread.pass + } + }.enable do + (1..10).map{ + Thread.new{ + 1000.times{ + } + } + }.each{|th| + th.join + } + end + end + end + + class FOO_ERROR < RuntimeError; end + class BAR_ERROR < RuntimeError; end + def m1_test_trace_point_at_return_when_exception + m2_test_trace_point_at_return_when_exception + end + def m2_test_trace_point_at_return_when_exception + raise BAR_ERROR + end + + def test_trace_point_at_return_when_exception + bug_7624 = '[ruby-core:51128] [ruby-trunk - Bug #7624]' + TracePoint.new{|tp| + next if !target_thread? + if tp.event == :return && + tp.method_id == :m2_test_trace_point_at_return_when_exception + raise FOO_ERROR + end + }.enable do + assert_raise(FOO_ERROR, bug_7624) do + m1_test_trace_point_at_return_when_exception + end + end + + bug_7668 = '[Bug #7668]' + ary = [] + trace = TracePoint.new{|tp| + next if !target_thread? + ary << tp.event + raise + } + begin + trace.enable{ + 1.times{ + raise + } + } + rescue + assert_equal([:b_call, :b_return], ary, bug_7668) + end + end + + def m1_for_test_trace_point_binding_in_ifunc(arg) + arg + nil + rescue + end + + def m2_for_test_trace_point_binding_in_ifunc(arg) + arg.inject(:+) + rescue + end + + def test_trace_point_binding_in_ifunc + bug7774 = '[ruby-dev:46908]' + src = %q{ + tp = TracePoint.new(:raise) do |tp| + tp.binding + end + tp.enable do + obj = Object.new + class << obj + include Enumerable + def each + yield 1 + end + end + %s + end + } + assert_normal_exit src % %q{obj.zip({}) {}}, bug7774 + assert_normal_exit src % %q{ + require 'continuation' + begin + c = nil + obj.sort_by {|x| callcc {|c2| c ||= c2 }; x } + c.call + rescue RuntimeError + end + }, bug7774 + + # TracePoint + tp_b = nil + TracePoint.new(:raise) do |tp| + next if !target_thread? + tp_b = tp.binding + end.enable do + m1_for_test_trace_point_binding_in_ifunc(0) + assert_equal(self, eval('self', tp_b), '[ruby-dev:46960]') + + m2_for_test_trace_point_binding_in_ifunc([0, nil]) + assert_equal(self, eval('self', tp_b), '[ruby-dev:46960]') + end + + # set_trace_func + stf_b = nil + set_trace_func ->(event, file, line, id, binding, klass) do + stf_b = binding if event == 'raise' + end + begin + m1_for_test_trace_point_binding_in_ifunc(0) + assert_equal(self, eval('self', stf_b), '[ruby-dev:46960]') + + m2_for_test_trace_point_binding_in_ifunc([0, nil]) + assert_equal(self, eval('self', stf_b), '[ruby-dev:46960]') + ensure + set_trace_func(nil) + end + end + + def test_trace_point_binding_after_break + bug10689 = '[ruby-dev:48797]' + assert_in_out_err([], <<-INPUT, [], [], bug10689) + class Bug + include Enumerable + + def each + [0].each do + yield + end + end + end + + TracePoint.trace(:c_return) do |tp| + tp.binding + end + + Bug.new.all? { false } + INPUT + end + + def test_tracepoint_b_return_with_next + n = 0 + TracePoint.new(:b_return){ + next if !target_thread? + n += 1 + }.enable{ + 3.times{ + next + } # 3 times b_retun + } # 1 time b_return + + assert_equal 4, n + end + + def test_tracepoint_b_return_with_lambda + n = 0 + TracePoint.new(:b_return){ + next if !target_thread? + n+=1 + }.enable{ + lambda{ + return + }.call # n += 1 #=> 1 + 3.times{ + lambda{ + return # n += 3 #=> 4 + }.call + } # n += 3 #=> 7 + begin + lambda{ + raise + }.call # n += 1 #=> 8 + rescue + # ignore + end # n += 1 #=> 9 + } + + assert_equal 9, n + end + + def test_isolated_raise_in_trace + bug9088 = '[ruby-dev:47793] [Bug #9088]' + assert_ruby_status([], <<-END, bug9088) + set_trace_func proc {raise rescue nil} + 1.times {break} + END + end + + def test_a_call + events = [] + TracePoint.new(:a_call){|tp| + next if !target_thread? + events << tp.event + }.enable{ + 1.times{ + 3 + } + method_for_test_tracepoint_block{ + 4 + } + } + assert_equal([ + :b_call, + :c_call, + :b_call, + :call, + :b_call, + ], events) + end + + def test_a_return + events = [] + TracePoint.new(:a_return){|tp| + next if !target_thread? + events << tp.event + }.enable{ + 1.times{ + 3 + } + method_for_test_tracepoint_block{ + 4 + } + } + assert_equal([ + :b_return, + :c_return, + :b_return, + :return, + :b_return + ], events) + end + + def test_const_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !defined?(MISSING_CONSTANT_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next if !target_thread? + next unless tp.defined_class == Module + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :const_missing || tp.method_id == :rake_original_const_missing + }.enable{ + MISSING_CONSTANT_59398 rescue nil + } + if events.map{|e|e[1]}.include?(:rake_original_const_missing) + assert_equal([ + [:call, :const_missing], + [:c_call, :rake_original_const_missing], + [:c_return, :rake_original_const_missing], + [:return, :const_missing], + ], events, bug59398) + else + assert_equal([ + [:c_call, :const_missing], + [:c_return, :const_missing] + ], events, bug59398) + end + end + + class AliasedRubyMethod + def foo; 1; end; + alias bar foo + end + def test_aliased_ruby_method + events = [] + aliased = AliasedRubyMethod.new + TracePoint.new(:call, :return){|tp| + next if !target_thread? + events << [tp.event, tp.method_id] + }.enable{ + aliased.bar + } + assert_equal([ + [:call, :foo], + [:return, :foo] + ], events, "should use original method name for tracing ruby methods") + end + class AliasedCMethod < Hash + alias original_size size + def size; original_size; end + end + + def test_aliased_c_method + events = [] + aliased = AliasedCMethod.new + TracePoint.new(:call, :return, :c_call, :c_return){|tp| + next if !target_thread? + events << [tp.event, tp.method_id] + }.enable{ + aliased.size + } + assert_equal([ + [:call, :size], + [:c_call, :original_size], + [:c_return, :original_size], + [:return, :size] + ], events, "should use alias method name for tracing c methods") + end + + def test_method_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !respond_to?(:missing_method_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next if !target_thread? + next unless tp.defined_class == BasicObject + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :method_missing + }.enable{ + missing_method_59398 rescue nil + } + assert_equal([ + [:c_call, :method_missing], + [:c_return, :method_missing] + ], events, bug59398) + end + + class C9759 + define_method(:foo){ + raise + } + end + + def test_define_method_on_exception + events = [] + obj = C9759.new + TracePoint.new(:call, :return){|tp| + next unless target_thread? + events << [tp.event, tp.method_id] + }.enable{ + obj.foo rescue nil + } + assert_equal([[:call, :foo], [:return, :foo]], events, 'Bug #9759') + + events = [] + begin + set_trace_func(lambda{|event, file, lineno, mid, binding, klass| + next unless target_thread? + case event + when 'call', 'return' + events << [event, mid] + end + }) + obj.foo rescue nil + set_trace_func(nil) + + assert_equal([['call', :foo], ['return', :foo]], events, 'Bug #9759') + ensure + end + end + + def test_recursive + assert_ruby_status [], %q{ + stack = [] + TracePoint.new(:c_call){|tp| + p 2 + stack << tp.method_id + }.enable{ + p 1 + } + raise if stack != [:p, :hash, :inspect] + }, '[Bug #9940]' + end + + def method_prefix event + case event + when :call, :return + :n + when :c_call, :c_return + :c + when :b_call, :b_return + :b + end + end + + def method_label tp + "#{method_prefix(tp.event)}##{tp.method_id}" + end + + def assert_consistent_call_return message='', check_events: nil + check_events ||= %i(a_call a_return) + call_stack = [] + + TracePoint.new(*check_events){|tp| + next unless target_thread? + + case tp.event.to_s + when /call/ + call_stack << method_label(tp) + when /return/ + frame = call_stack.pop + assert_equal(frame, method_label(tp)) + end + }.enable do + yield + end + + assert_equal true, call_stack.empty? + end + + def method_test_rescue_should_not_cause_b_return + begin + raise + rescue + return + end + end + + def method_test_ensure_should_not_cause_b_return + begin + raise + ensure + return + end + end + + def test_rescue_and_ensure_should_not_cause_b_return + assert_consistent_call_return '[Bug #9957]' do + method_test_rescue_should_not_cause_b_return + begin + method_test_ensure_should_not_cause_b_return + rescue + # ignore + end + end + end + + define_method(:method_test_argument_error_on_bmethod){|correct_key: 1|} + + def test_argument_error_on_bmethod + assert_consistent_call_return '[Bug #9959]' do + begin + method_test_argument_error_on_bmethod(wrong_key: 2) + rescue => e + # ignore + end + end + end + + def test_rb_rescue + assert_consistent_call_return '[Bug #9961]' do + begin + -Numeric.new + rescue => e + # ignore + end + end + end + + def test_b_call_with_redo + assert_consistent_call_return '[Bug #9964]' do + i = 0 + 1.times{ + break if (i+=1) > 10 + redo + } + end + end + + def test_no_duplicate_line_events + lines = [] + dummy = [] + + TracePoint.new(:line){|tp| + next unless target_thread? + lines << tp.lineno + }.enable{ + dummy << (1) + (2) + dummy << (1) + (2) + } + assert_equal [__LINE__ - 3, __LINE__ - 2], lines, 'Bug #10449' + end + + class Bug10724 + def initialize + loop{return} + end + end + + def test_throwing_return_with_finish_frame + target_th = Thread.current + evs = [] + + TracePoint.new(:call, :return){|tp| + return if Thread.current != target_th + evs << tp.event + }.enable{ + a = Bug10724.new + } + + assert_equal([:call, :return], evs) + end +end diff --git a/jni/ruby/test/ruby/test_signal.rb b/jni/ruby/test/ruby/test_signal.rb new file mode 100644 index 0000000..4a59aa6 --- /dev/null +++ b/jni/ruby/test/ruby/test_signal.rb @@ -0,0 +1,294 @@ +require 'test/unit' +require 'timeout' +require 'tempfile' + +class TestSignal < Test::Unit::TestCase + def test_signal + begin + x = 0 + oldtrap = Signal.trap(:INT) {|sig| x = 2 } + Process.kill :INT, Process.pid + 10.times do + break if 2 == x + sleep 0.1 + end + assert_equal 2, x + + Signal.trap(:INT) { raise "Interrupt" } + assert_raise_with_message(RuntimeError, /Interrupt/) { + Process.kill :INT, Process.pid + sleep 0.1 + } + ensure + Signal.trap :INT, oldtrap if oldtrap + end + end if Process.respond_to?(:kill) + + def test_signal_process_group + bug4362 = '[ruby-dev:43169]' + assert_nothing_raised(bug4362) do + pid = Process.spawn(EnvUtil.rubybin, '-e', 'sleep 10', :pgroup => true) + Process.kill(:"-TERM", pid) + Process.waitpid(pid) + assert_equal(true, $?.signaled?) + assert_equal(Signal.list["TERM"], $?.termsig) + end + end if Process.respond_to?(:kill) and + Process.respond_to?(:pgroup) # for mswin32 + + def test_exit_action + if Signal.list[sig = "USR1"] + term = :TERM + else + sig = "INT" + term = :KILL + end + IO.popen([EnvUtil.rubybin, '-e', <<-"End"], 'r+') do |io| + Signal.trap(:#{sig}, "EXIT") + STDOUT.syswrite("a") + Thread.start { sleep(2) } + STDIN.sysread(4096) + End + pid = io.pid + io.sysread(1) + sleep 0.1 + assert_nothing_raised("[ruby-dev:26128]") { + Process.kill(term, pid) + begin + Timeout.timeout(3) { + Process.waitpid pid + } + rescue Timeout::Error + if term + Process.kill(term, pid) + term = (:KILL if term != :KILL) + retry + end + raise + end + } + end + end if Process.respond_to?(:kill) + + def test_invalid_signal_name + assert_raise(ArgumentError) { Process.kill(:XXXXXXXXXX, $$) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.kill("\u{30eb 30d3 30fc}", $$) } + end if Process.respond_to?(:kill) + + def test_signal_exception + assert_raise(ArgumentError) { SignalException.new } + assert_raise(ArgumentError) { SignalException.new(-1) } + assert_raise(ArgumentError) { SignalException.new(:XXXXXXXXXX) } + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { SignalException.new("\u{30eb 30d3 30fc}") } + Signal.list.each do |signm, signo| + next if signm == "EXIT" + assert_equal(SignalException.new(signm).signo, signo) + assert_equal(SignalException.new(signm.to_sym).signo, signo) + assert_equal(SignalException.new(signo).signo, signo) + end + end + + def test_interrupt + assert_raise(Interrupt) { raise Interrupt.new } + end + + def test_signal2 + begin + x = false + oldtrap = Signal.trap(:INT) {|sig| x = true } + GC.start + + assert_raise(ArgumentError) { Process.kill } + + Timeout.timeout(10) do + x = false + Process.kill(SignalException.new(:INT).signo, $$) + sleep(0.01) until x + + x = false + Process.kill("INT", $$) + sleep(0.01) until x + + x = false + Process.kill("SIGINT", $$) + sleep(0.01) until x + + x = false + o = Object.new + def o.to_str; "SIGINT"; end + Process.kill(o, $$) + sleep(0.01) until x + end + + assert_raise(ArgumentError) { Process.kill(Object.new, $$) } + + ensure + Signal.trap(:INT, oldtrap) if oldtrap + end + end if Process.respond_to?(:kill) + + def test_trap + begin + oldtrap = Signal.trap(:INT) {|sig| } + + assert_raise(ArgumentError) { Signal.trap } + + assert_raise(SecurityError) do + s = proc {}.taint + Signal.trap(:INT, s) + end + + # FIXME! + Signal.trap(:INT, nil) + Signal.trap(:INT, "") + Signal.trap(:INT, "SIG_IGN") + Signal.trap(:INT, "IGNORE") + + Signal.trap(:INT, "SIG_DFL") + Signal.trap(:INT, "SYSTEM_DEFAULT") + + Signal.trap(:INT, "EXIT") + + Signal.trap(:INT, "xxxxxx") + Signal.trap(:INT, "xxxx") + + Signal.trap(SignalException.new(:INT).signo, "SIG_DFL") + + assert_raise(ArgumentError) { Signal.trap(-1, "xxxx") } + + o = Object.new + def o.to_str; "SIGINT"; end + Signal.trap(o, "SIG_DFL") + + assert_raise(ArgumentError) { Signal.trap("XXXXXXXXXX", "SIG_DFL") } + + assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Signal.trap("\u{30eb 30d3 30fc}", "SIG_DFL") } + ensure + Signal.trap(:INT, oldtrap) if oldtrap + end + end if Process.respond_to?(:kill) + + %w"KILL STOP".each do |sig| + if Signal.list.key?(sig) + define_method("test_trap_uncatchable_#{sig}") do + assert_raise(Errno::EINVAL, "SIG#{sig} is not allowed to be caught") { Signal.trap(sig) {} } + end + end + end + + def test_sigexit + assert_in_out_err([], 'Signal.trap(:EXIT) {print "OK"}', ["OK"]) + assert_in_out_err([], 'Signal.trap("EXIT") {print "OK"}', ["OK"]) + assert_in_out_err([], 'Signal.trap(:SIGEXIT) {print "OK"}', ["OK"]) + assert_in_out_err([], 'Signal.trap("SIGEXIT") {print "OK"}', ["OK"]) + assert_in_out_err([], 'Signal.trap(0) {print "OK"}', ["OK"]) + end + + def test_kill_immediately_before_termination + Signal.list[sig = "USR1"] or sig = "INT" + assert_in_out_err(["-e", <<-"end;"], "", %w"foo") + Signal.trap(:#{sig}) { STDOUT.syswrite("foo") } + Process.kill :#{sig}, $$ + end; + end if Process.respond_to?(:kill) + + def test_trap_system_default + assert_separately([], <<-End) + trap(:QUIT, "SYSTEM_DEFAULT") + assert_equal("SYSTEM_DEFAULT", trap(:QUIT, "DEFAULT")) + End + end if Signal.list.key?('QUIT') + + def test_reserved_signal + assert_raise(ArgumentError) { + Signal.trap(:SEGV) {} + } + assert_raise(ArgumentError) { + Signal.trap(:BUS) {} + } + assert_raise(ArgumentError) { + Signal.trap(:ILL) {} + } + assert_raise(ArgumentError) { + Signal.trap(:FPE) {} + } + assert_raise(ArgumentError) { + Signal.trap(:VTALRM) {} + } + end + + def test_signame + 10.times do + IO.popen([EnvUtil.rubybin, "-e", <<EOS, :err => File::NULL]) do |child| + Signal.trap("INT") do |signo| + signame = Signal.signame(signo) + Marshal.dump(signame, STDOUT) + STDOUT.flush + exit 0 + end + Process.kill("INT", $$) + sleep 1 # wait signal deliver +EOS + + signame = Marshal.load(child) + assert_equal(signame, "INT") + end + end + end if Process.respond_to?(:kill) + + def test_trap_puts + assert_in_out_err([], <<-INPUT, ["a"*10000], []) + Signal.trap(:INT) { + # for enable internal io mutex + STDOUT.sync = false + # larger than internal io buffer + print "a"*10000 + } + Process.kill :INT, $$ + sleep 0.1 + INPUT + end if Process.respond_to?(:kill) + + def test_hup_me + # [Bug #7951] [ruby-core:52864] + # This is MRI specific spec. ruby has no guarantee + # that signal will be deliverd synchronously. + # This ugly workaround was introduced to don't break + # compatibility against silly example codes. + assert_separately([], <<-RUBY) + trap(:HUP, "DEFAULT") + assert_raise(SignalException) { + Process.kill('HUP', Process.pid) + } + RUBY + bug8137 = '[ruby-dev:47182] [Bug #8137]' + assert_nothing_raised(bug8137) { + Timeout.timeout(1) { + Process.kill(0, Process.pid) + } + } + end if Process.respond_to?(:kill) and Signal.list.key?('HUP') + + def test_ignored_interrupt + bug9820 = '[ruby-dev:48203] [Bug #9820]' + assert_separately(['-', bug9820], <<-'end;') # begin + bug = ARGV.shift + trap(:INT, "IGNORE") + assert_nothing_raised(SignalException, bug) do + Process.kill(:INT, $$) + end + end; + + if trap = Signal.list['TRAP'] + bug9820 = '[ruby-dev:48592] [Bug #9820]' + status = assert_in_out_err(['-e', 'Process.kill(:TRAP, $$)']) + assert_predicate(status, :signaled?, bug9820) + assert_equal(trap, status.termsig, bug9820) + end + + if Signal.list['CONT'] + bug9820 = '[ruby-dev:48606] [Bug #9820]' + assert_ruby_status(['-e', 'Process.kill(:CONT, $$)']) + end + end if Process.respond_to?(:kill) +end diff --git a/jni/ruby/test/ruby/test_sleep.rb b/jni/ruby/test/ruby/test_sleep.rb new file mode 100644 index 0000000..29490a7 --- /dev/null +++ b/jni/ruby/test/ruby/test_sleep.rb @@ -0,0 +1,16 @@ +require 'test/unit' +require 'etc' + +class TestSleep < Test::Unit::TestCase + def test_sleep_5sec + GC.disable + start = Process.clock_gettime(Process::CLOCK_MONOTONIC) + sleep 5 + slept = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start + bottom = 5.0 + assert_operator(slept, :>=, bottom) + assert_operator(slept, :<=, 6.0, "[ruby-core:18015]: longer than expected") + ensure + GC.enable + end +end diff --git a/jni/ruby/test/ruby/test_sprintf.rb b/jni/ruby/test/ruby/test_sprintf.rb new file mode 100644 index 0000000..15c809c --- /dev/null +++ b/jni/ruby/test/ruby/test_sprintf.rb @@ -0,0 +1,412 @@ +require 'test/unit' + +class TestSprintf < Test::Unit::TestCase + def test_positional + assert_equal(" 00001", sprintf("%*1$.*2$3$d", 10, 5, 1)) + end + + def test_binary + assert_equal("0", sprintf("%b", 0)) + assert_equal("1", sprintf("%b", 1)) + assert_equal("10", sprintf("%b", 2)) + assert_equal("..1", sprintf("%b", -1)) + + assert_equal(" 0", sprintf("%4b", 0)) + assert_equal(" 1", sprintf("%4b", 1)) + assert_equal(" 10", sprintf("%4b", 2)) + assert_equal(" ..1", sprintf("%4b", -1)) + + assert_equal("0000", sprintf("%04b", 0)) + assert_equal("0001", sprintf("%04b", 1)) + assert_equal("0010", sprintf("%04b", 2)) + assert_equal("..11", sprintf("%04b", -1)) + + assert_equal("0000", sprintf("%.4b", 0)) + assert_equal("0001", sprintf("%.4b", 1)) + assert_equal("0010", sprintf("%.4b", 2)) + assert_equal("..11", sprintf("%.4b", -1)) + + assert_equal(" 0000", sprintf("%6.4b", 0)) + assert_equal(" 0001", sprintf("%6.4b", 1)) + assert_equal(" 0010", sprintf("%6.4b", 2)) + assert_equal(" ..11", sprintf("%6.4b", -1)) + + assert_equal(" 0", sprintf("%#4b", 0)) + assert_equal(" 0b1", sprintf("%#4b", 1)) + assert_equal("0b10", sprintf("%#4b", 2)) + assert_equal("0b..1", sprintf("%#4b", -1)) + + assert_equal("0000", sprintf("%#04b", 0)) + assert_equal("0b01", sprintf("%#04b", 1)) + assert_equal("0b10", sprintf("%#04b", 2)) + assert_equal("0b..1", sprintf("%#04b", -1)) + + assert_equal("0000", sprintf("%#.4b", 0)) + assert_equal("0b0001", sprintf("%#.4b", 1)) + assert_equal("0b0010", sprintf("%#.4b", 2)) + assert_equal("0b..11", sprintf("%#.4b", -1)) + + assert_equal(" 0000", sprintf("%#6.4b", 0)) + assert_equal("0b0001", sprintf("%#6.4b", 1)) + assert_equal("0b0010", sprintf("%#6.4b", 2)) + assert_equal("0b..11", sprintf("%#6.4b", -1)) + + assert_equal("+0", sprintf("%+b", 0)) + assert_equal("+1", sprintf("%+b", 1)) + assert_equal("+10", sprintf("%+b", 2)) + assert_equal("-1", sprintf("%+b", -1)) + + assert_equal(" +0", sprintf("%+4b", 0)) + assert_equal(" +1", sprintf("%+4b", 1)) + assert_equal(" +10", sprintf("%+4b", 2)) + assert_equal(" -1", sprintf("%+4b", -1)) + + assert_equal("+000", sprintf("%+04b", 0)) + assert_equal("+001", sprintf("%+04b", 1)) + assert_equal("+010", sprintf("%+04b", 2)) + assert_equal("-001", sprintf("%+04b", -1)) + + assert_equal("+0000", sprintf("%+.4b", 0)) + assert_equal("+0001", sprintf("%+.4b", 1)) + assert_equal("+0010", sprintf("%+.4b", 2)) + assert_equal("-0001", sprintf("%+.4b", -1)) + + assert_equal(" +0000", sprintf("%+6.4b", 0)) + assert_equal(" +0001", sprintf("%+6.4b", 1)) + assert_equal(" +0010", sprintf("%+6.4b", 2)) + assert_equal(" -0001", sprintf("%+6.4b", -1)) + end + + def test_nan + nan = 0.0 / 0.0 + assert_equal("NaN", sprintf("%f", nan)) + assert_equal("NaN", sprintf("%-f", nan)) + assert_equal("+NaN", sprintf("%+f", nan)) + + assert_equal(" NaN", sprintf("%8f", nan)) + assert_equal("NaN ", sprintf("%-8f", nan)) + assert_equal(" +NaN", sprintf("%+8f", nan)) + + assert_equal(" NaN", sprintf("%08f", nan)) + assert_equal("NaN ", sprintf("%-08f", nan)) + assert_equal(" +NaN", sprintf("%+08f", nan)) + + assert_equal(" NaN", sprintf("% 8f", nan)) + assert_equal(" NaN ", sprintf("%- 8f", nan)) + assert_equal(" +NaN", sprintf("%+ 8f", nan)) + + assert_equal(" NaN", sprintf("% 08f", nan)) + assert_equal(" NaN ", sprintf("%- 08f", nan)) + assert_equal(" +NaN", sprintf("%+ 08f", nan)) + end + + def test_inf + inf = 1.0 / 0.0 + assert_equal("Inf", sprintf("%f", inf)) + assert_equal("Inf", sprintf("%-f", inf)) + assert_equal("+Inf", sprintf("%+f", inf)) + + assert_equal(" Inf", sprintf("%8f", inf)) + assert_equal("Inf ", sprintf("%-8f", inf)) + assert_equal(" +Inf", sprintf("%+8f", inf)) + + assert_equal(" Inf", sprintf("%08f", inf)) + assert_equal("Inf ", sprintf("%-08f", inf)) + assert_equal(" +Inf", sprintf("%+08f", inf)) + + assert_equal(" Inf", sprintf("% 8f", inf)) + assert_equal(" Inf ", sprintf("%- 8f", inf)) + assert_equal(" +Inf", sprintf("%+ 8f", inf)) + + assert_equal(" Inf", sprintf("% 08f", inf)) + assert_equal(" Inf ", sprintf("%- 08f", inf)) + assert_equal(" +Inf", sprintf("%+ 08f", inf)) + + assert_equal("-Inf", sprintf("%f", -inf)) + assert_equal("-Inf", sprintf("%-f", -inf)) + assert_equal("-Inf", sprintf("%+f", -inf)) + + assert_equal(" -Inf", sprintf("%8f", -inf)) + assert_equal("-Inf ", sprintf("%-8f", -inf)) + assert_equal(" -Inf", sprintf("%+8f", -inf)) + + assert_equal(" -Inf", sprintf("%08f", -inf)) + assert_equal("-Inf ", sprintf("%-08f", -inf)) + assert_equal(" -Inf", sprintf("%+08f", -inf)) + + assert_equal(" -Inf", sprintf("% 8f", -inf)) + assert_equal("-Inf ", sprintf("%- 8f", -inf)) + assert_equal(" -Inf", sprintf("%+ 8f", -inf)) + + assert_equal(" -Inf", sprintf("% 08f", -inf)) + assert_equal("-Inf ", sprintf("%- 08f", -inf)) + assert_equal(" -Inf", sprintf("%+ 08f", -inf)) + assert_equal('..f00000000', + sprintf("%x", -2**32), '[ruby-dev:32351]') + assert_equal("..101111111111111111111111111111111", + sprintf("%b", -2147483649), '[ruby-dev:32365]') + assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]') + end + + def test_rational + assert_match(/\A0\.10+\z/, sprintf("%.60f", 0.1r)) + assert_match(/\A0\.010+\z/, sprintf("%.60f", 0.01r)) + assert_match(/\A0\.0010+\z/, sprintf("%.60f", 0.001r)) + assert_match(/\A0\.3+\z/, sprintf("%.60f", 1/3r)) + assert_match(/\A1\.20+\z/, sprintf("%.60f", 1.2r)) + + 0.upto(9) do |len| + -1.upto(9) do |prec| + ['', '+', '-', ' ', '0', '+0', '-0', ' 0', '+ ', '- ', '+ 0', '- 0'].each do |flags| + fmt = "%#{flags}#{len > 0 ? len : ''}#{prec >= 0 ? ".#{prec}" : ''}f" + [0, 0.1, 0.01, 0.001, 1.001, 100.0, 100.001, 10000000000.0, 0.00000000001, 1/3r, 2/3r, 1.2r, 10r].each do |num| + assert_equal(sprintf(fmt, num.to_f), sprintf(fmt, num.to_r), "sprintf(#{fmt.inspect}, #{num.inspect}.to_r)") + assert_equal(sprintf(fmt, -num.to_f), sprintf(fmt, -num.to_r), "sprintf(#{fmt.inspect}, #{(-num).inspect}.to_r)") if num > 0 + end + end + end + end + end + + def test_hash + options = {:capture=>/\d+/} + assert_equal("with options {:capture=>/\\d+/}", sprintf("with options %p" % options)) + end + + def test_invalid + # Star precision before star width: + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.**d", 5, 10, 1)} + + # Precision before flags and width: + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.5+05d", 5)} + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.5 5d", 5)} + + # Overriding a star width with a numeric one: + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%*1s", 5, 1)} + + # Width before flags: + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%5+0d", 1)} + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%5 0d", 1)} + + # Specifying width multiple times: + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%50+30+20+10+5d", 5)} + assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%50 30 20 10 5d", 5)} + + # Specifying the precision multiple times with negative star arguments: + assert_raise(ArgumentError, "[ruby-core:11570]") {sprintf("%.*.*.*.*f", -1, -1, -1, 5, 1)} + + # Null bytes after percent signs are removed: + assert_equal("%\0x hello", sprintf("%\0x hello"), "[ruby-core:11571]") + + assert_raise(ArgumentError, "[ruby-core:11573]") {sprintf("%.25555555555555555555555555555555555555s", "hello")} + + assert_raise(ArgumentError) { sprintf("%\1", 1) } + assert_raise(ArgumentError) { sprintf("%!", 1) } + assert_raise(ArgumentError) { sprintf("%1$1$d", 1) } + assert_raise(ArgumentError) { sprintf("%0%") } + + assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$*d", 3) } + assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$.*d", 3) } + + verbose, $VERBOSE = $VERBOSE, nil + assert_nothing_raised { sprintf("", 1) } + ensure + $VERBOSE = verbose + end + + def test_float + assert_equal("36893488147419111424", + sprintf("%20.0f", 36893488147419107329.0)) + assert_equal(" Inf", sprintf("% 0e", 1.0/0.0), "moved from btest/knownbug") + assert_equal(" -0.", sprintf("%#10.0f", -0.5), "[ruby-dev:42552]") + # out of spec + #assert_equal("0x1p+2", sprintf('%.0a', Float('0x1.fp+1')), "[ruby-dev:42551]") + #assert_equal("-0x1.0p+2", sprintf('%.1a', Float('-0x1.ffp+1')), "[ruby-dev:42551]") + end + + def test_float_hex + assert_equal("-0x0p+0", sprintf("%a", -0.0)) + assert_equal("0x0p+0", sprintf("%a", 0.0)) + assert_equal("0x1p-1", sprintf("%a", 0.5)) + assert_equal("0x1p+0", sprintf("%a", 1.0)) + assert_equal("0x1p+1", sprintf("%a", 2.0)) + assert_equal("0x1p+10", sprintf("%a", 1024)) + assert_equal("0x1.23456p+789", sprintf("%a", 3.704450999893983e+237)) + assert_equal("0x1p-1074", sprintf("%a", 4.9e-324)) + assert_equal("Inf", sprintf("%e", Float::INFINITY)) + assert_equal("Inf", sprintf("%E", Float::INFINITY)) + assert_equal("NaN", sprintf("%e", Float::NAN)) + assert_equal("NaN", sprintf("%E", Float::NAN)) + + assert_equal(" -0x1p+0", sprintf("%10a", -1)) + assert_equal(" -0x1.8p+0", sprintf("%10a", -1.5)) + assert_equal(" -0x1.4p+0", sprintf("%10a", -1.25)) + assert_equal(" -0x1.2p+0", sprintf("%10a", -1.125)) + assert_equal(" -0x1.1p+0", sprintf("%10a", -1.0625)) + assert_equal("-0x1.08p+0", sprintf("%10a", -1.03125)) + + bug3962 = '[ruby-core:32841]' + assert_equal("-0x0001p+0", sprintf("%010a", -1), bug3962) + assert_equal("-0x01.8p+0", sprintf("%010a", -1.5), bug3962) + assert_equal("-0x01.4p+0", sprintf("%010a", -1.25), bug3962) + assert_equal("-0x01.2p+0", sprintf("%010a", -1.125), bug3962) + assert_equal("-0x01.1p+0", sprintf("%010a", -1.0625), bug3962) + assert_equal("-0x1.08p+0", sprintf("%010a", -1.03125), bug3962) + + bug3964 = '[ruby-core:32848]' + assert_equal("0x000000000000000p+0", sprintf("%020a", 0), bug3964) + assert_equal("0x000000000000001p+0", sprintf("%020a", 1), bug3964) + assert_equal("-0x00000000000001p+0", sprintf("%020a", -1), bug3964) + assert_equal("0x00000000000000.p+0", sprintf("%#020a", 0), bug3964) + + bug3965 = '[ruby-dev:42431]' + assert_equal("0x1.p+0", sprintf("%#.0a", 1), bug3965) + assert_equal("0x00000000000000.p+0", sprintf("%#020a", 0), bug3965) + assert_equal("0x0000.0000000000p+0", sprintf("%#020.10a", 0), bug3965) + + bug3979 = '[ruby-dev:42453]' + assert_equal(" 0x0.000p+0", sprintf("%20.3a", 0), bug3979) + assert_equal(" 0x1.000p+0", sprintf("%20.3a", 1), bug3979) + end + + BSIZ = 120 + + def test_skip + assert_equal(" " * BSIZ + "1", sprintf(" " * BSIZ + "%d", 1)) + end + + def test_char + assert_equal("a", sprintf("%c", 97)) + assert_equal("a", sprintf("%c", ?a)) + assert_raise(ArgumentError) { sprintf("%c", sprintf("%c%c", ?a, ?a)) } + assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%c", ?a)) + assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%-1c", ?a)) + assert_equal(" " * BSIZ + "a", sprintf("%#{ BSIZ + 1 }c", ?a)) + assert_equal("a" + " " * BSIZ, sprintf("%-#{ BSIZ + 1 }c", ?a)) + end + + def test_string + assert_equal("foo", sprintf("%s", "foo")) + assert_equal("fo", sprintf("%.2s", "foo")) + assert_equal(" " * BSIZ, sprintf("%s", " " * BSIZ)) + assert_equal(" " * (BSIZ - 1) + "foo", sprintf("%#{ BSIZ - 1 + 3 }s", "foo")) + assert_equal(" " * BSIZ + "foo", sprintf("%#{ BSIZ + 3 }s", "foo")) + assert_equal("foo" + " " * BSIZ, sprintf("%-#{ BSIZ + 3 }s", "foo")) + end + + def test_integer + assert_equal("01", sprintf("%#o", 1)) + assert_equal("0x1", sprintf("%#x", 1)) + assert_equal("0X1", sprintf("%#X", 1)) + assert_equal("0b1", sprintf("%#b", 1)) + assert_equal("0B1", sprintf("%#B", 1)) + assert_equal("1", sprintf("%d", 1.0)) + assert_equal("4294967296", sprintf("%d", (2**32).to_f)) + assert_equal("-2147483648", sprintf("%d", -(2**31).to_f)) + assert_equal("18446744073709551616", sprintf("%d", (2**64).to_f)) + assert_equal("-9223372036854775808", sprintf("%d", -(2**63).to_f)) + assert_equal("1", sprintf("%d", "1")) + o = Object.new; def o.to_int; 1; end + assert_equal("1", sprintf("%d", o)) + assert_equal("+1", sprintf("%+d", 1)) + assert_equal(" 1", sprintf("% d", 1)) + assert_equal("..f", sprintf("%x", -1)) + assert_equal("..7", sprintf("%o", -1)) + one = (2**32).coerce(1).first + mone = (2**32).coerce(-1).first + assert_equal("+1", sprintf("%+d", one)) + assert_equal(" 1", sprintf("% d", one)) + assert_equal("..f", sprintf("%x", mone)) + assert_equal("..7", sprintf("%o", mone)) + assert_equal(" " * BSIZ + "1", sprintf("%#{ BSIZ + 1 }d", one)) + assert_equal(" " * (BSIZ - 1) + "1", sprintf(" " * (BSIZ - 1) + "%d", 1)) + end + + def test_float2 + inf = 1.0 / 0.0 + assert_equal(" " * BSIZ + "Inf", sprintf("%#{ BSIZ + 3 }.1f", inf)) + assert_equal("+Inf", sprintf("%+-f", inf)) + assert_equal(" " * BSIZ + "1.0", sprintf("%#{ BSIZ + 3 }.1f", 1.0)) + end + + class T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 + end + + def test_star + assert_equal("-1 ", sprintf("%*d", -3, -1)) + assert_raise_with_message(ArgumentError, /width too big/) { + sprintf("%*999999999999999999999999999999999999999999999999999999999999$d", 1) + } + assert_raise_with_message(ArgumentError, /prec too big/) { + sprintf("%.*999999999999999999999999999999999999999999999999999999999999$d", 1) + } + end + + def test_escape + assert_equal("%" * BSIZ, sprintf("%%" * BSIZ)) + end + + def test_rb_sprintf + assert_match(/^#<TestSprintf::T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789:0x[0-9a-f]+>$/, + T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.new.inspect) + end + + def test_negative_hex + s1 = sprintf("%0x", -0x40000000) + s2 = sprintf("%0x", -0x40000001) + b1 = (/\.\./ =~ s1) != nil + b2 = (/\.\./ =~ s2) != nil + assert_equal(b1, b2, "[ruby-dev:33224]") + end + + def test_named_untyped + assert_equal("value", sprintf("%<key>s", :key => "value")) + assert_raise_with_message(ArgumentError, "named<key2> after numbered") {sprintf("%1$<key2>s", :key => "value")} + assert_raise_with_message(ArgumentError, "named<key2> after unnumbered(2)") {sprintf("%s%s%<key2>s", "foo", "bar", :key => "value")} + assert_raise_with_message(ArgumentError, "named<key2> after <key>") {sprintf("%<key><key2>s", :key => "value")} + assert_raise_with_message(KeyError, "key<key> not found") {sprintf("%<key>s", {})} + end + + def test_named_untyped_enc + key = "\u{3012}" + [Encoding::UTF_8, Encoding::EUC_JP].each do |enc| + k = key.encode(enc) + e = assert_raise_with_message(ArgumentError, "named<#{k}> after numbered") {sprintf("%1$<#{k}>s", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named<#{k}> after unnumbered(2)") {sprintf("%s%s%<#{k}>s", "foo", "bar", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named<#{k}> after <key>") {sprintf("%<key><#{k}>s", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named<key> after <#{k}>") {sprintf("%<#{k}><key>s", k.to_sym => "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(KeyError, "key<#{k}> not found") {sprintf("%<#{k}>s", {})} + assert_equal(enc, e.message.encoding) + end + end + + def test_named_typed + assert_equal("value", sprintf("%{key}", :key => "value")) + assert_raise_with_message(ArgumentError, "named{key2} after numbered") {sprintf("%1${key2}", :key => "value")} + assert_raise_with_message(ArgumentError, "named{key2} after unnumbered(2)") {sprintf("%s%s%{key2}", "foo", "bar", :key => "value")} + assert_raise_with_message(ArgumentError, "named{key2} after <key>") {sprintf("%<key>{key2}", :key => "value")} + assert_equal("value{key2}", sprintf("%{key}{key2}", :key => "value")) + assert_raise_with_message(KeyError, "key{key} not found") {sprintf("%{key}", {})} + end + + def test_named_typed_enc + key = "\u{3012}" + [Encoding::UTF_8, Encoding::EUC_JP].each do |enc| + k = key.encode(enc) + e = assert_raise_with_message(ArgumentError, "named{#{k}} after numbered") {sprintf("%1${#{k}}s", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named{#{k}} after unnumbered(2)") {sprintf("%s%s%{#{k}}s", "foo", "bar", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named{#{k}} after <key>") {sprintf("%<key>{#{k}}s", key: "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(ArgumentError, "named{key} after <#{k}>") {sprintf("%<#{k}>{key}s", k.to_sym => "value")} + assert_equal(enc, e.message.encoding) + e = assert_raise_with_message(KeyError, "key{#{k}} not found") {sprintf("%{#{k}}", {})} + assert_equal(enc, e.message.encoding) + end + end +end diff --git a/jni/ruby/test/ruby/test_sprintf_comb.rb b/jni/ruby/test/ruby/test_sprintf_comb.rb new file mode 100644 index 0000000..c58ddf4 --- /dev/null +++ b/jni/ruby/test/ruby/test_sprintf_comb.rb @@ -0,0 +1,553 @@ +require 'test/unit' +require_relative 'allpairs' + +class TestSprintfComb < Test::Unit::TestCase + VS = [ + #-0x1000000000000000000000000000000000000000000000002, + #-0x1000000000000000000000000000000000000000000000001, + #-0x1000000000000000000000000000000000000000000000000, + #-0xffffffffffffffffffffffffffffffffffffffffffffffff, + #-0x1000000000000000000000002, + #-0x1000000000000000000000001, + #-0x1000000000000000000000000, + #-0xffffffffffffffffffffffff, + -0x10000000000000002, + -0x10000000000000001, + -0x10000000000000000, + -0xffffffffffffffff, + -0x4000000000000002, + -0x4000000000000001, + -0x4000000000000000, + -0x3fffffffffffffff, + -0x100000002, + -0x100000001, + -0x100000000, + -0xffffffff, + #-0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001 + -0x80000002, + -0x80000001, + -0x80000000, + -0x7fffffff, + #-0x524b2245, + -0x40000002, + -0x40000001, + -0x40000000, + -0x3fffffff, + #-0x10002, + #-0x10001, + #-0x10000, + #-0xffff, + #-0x8101, # 0x8101 * 0x7f01 = 0x40000001 + #-0x8002, + #-0x8001, + #-0x8000, + #-0x7fff, + #-0x7f01, + #-65, + #-64, + #-63, + #-62, + #-33, + #-32, + #-31, + #-30, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + #30, + #31, + #32, + #33, + #62, + #63, + #64, + #65, + #0x7f01, + #0x7ffe, + #0x7fff, + #0x8000, + #0x8001, + #0x8101, + #0xfffe, + #0xffff, + #0x10000, + #0x10001, + 0x3ffffffe, + 0x3fffffff, + 0x40000000, + 0x40000001, + #0x524b2245, + 0x7ffffffe, + 0x7fffffff, + 0x80000000, + 0x80000001, + #0xc717a08d, + 0xfffffffe, + 0xffffffff, + 0x100000000, + 0x100000001, + 0x3ffffffffffffffe, + 0x3fffffffffffffff, + 0x4000000000000000, + 0x4000000000000001, + 0xfffffffffffffffe, + 0xffffffffffffffff, + 0x10000000000000000, + 0x10000000000000001, + #0xffffffffffffffffffffffff, + #0x1000000000000000000000000, + #0x1000000000000000000000001, + #0xffffffffffffffffffffffffffffffffffffffffffffffff, + #0x1000000000000000000000000000000000000000000000000, + #0x1000000000000000000000000000000000000000000000001 + ] + VS.reverse! + + FLAGS = [['', ' '], ['', '#'], ['', '+'], ['', '-'], ['', '0']] + + def self.combination(*args, &b) + #AllPairs.exhaustive_each(*args, &b) + AllPairs.each(*args, &b) + end + + def emu_int(format, v) + /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format + sp = $1 + hs = $2 + pl = $3 + mi = $4 + zr = $5 + width = $6 + precision = $7 + type = $8 + width = width.to_i if width + precision = precision.to_i if precision + prefix = '' + + zr = nil if precision + + zr = nil if mi && zr + + case type + when 'B' + radix = 2 + digitmap = {0 => '0', 1 => '1'} + complement = !pl && !sp + prefix = '0B' if hs && v != 0 + when 'b' + radix = 2 + digitmap = {0 => '0', 1 => '1'} + complement = !pl && !sp + prefix = '0b' if hs && v != 0 + when 'd' + radix = 10 + digitmap = {} + 10.times {|i| digitmap[i] = i.to_s } + complement = false + when 'o' + radix = 8 + digitmap = {} + 8.times {|i| digitmap[i] = i.to_s } + complement = !pl && !sp + when 'X' + radix = 16 + digitmap = {} + 16.times {|i| digitmap[i] = i.to_s(16).upcase } + complement = !pl && !sp + prefix = '0X' if hs && v != 0 + when 'x' + radix = 16 + digitmap = {} + 16.times {|i| digitmap[i] = i.to_s(16) } + complement = !pl && !sp + prefix = '0x' if hs && v != 0 + else + raise "unexpected type: #{type.inspect}" + end + + digits = [] + abs = v.abs + sign = '' + while 0 < abs + digits << (abs % radix) + abs /= radix + end + + if v < 0 + if complement + digits.map! {|d| radix-1 - d } + carry = 1 + digits.each_index {|i| + digits[i] += carry + carry = 0 + if radix <= digits[i] + digits[i] -= radix + carry = 1 + end + } + if digits.last != radix-1 + digits << (radix-1) + end + sign = '..' + else + sign = '-' + end + else + if pl + sign = '+' + elsif sp + sign = ' ' + end + end + + dlen = digits.length + dlen += 2 if sign == '..' + + if v < 0 && complement + d = radix - 1 + else + d = 0 + end + if precision + if dlen < precision + (precision - dlen).times { + digits << d + } + end + else + if dlen == 0 + digits << d + end + end + if type == 'o' && hs + if digits.empty? || digits.last != d + digits << d + end + end + + digits.reverse! + + str = digits.map {|digit| digitmap[digit] }.join + + pad = '' + nlen = prefix.length + sign.length + str.length + if width && nlen < width + len = width - nlen + if zr + if complement && v < 0 + pad = digitmap[radix-1] * len + else + pad = '0' * len + end + else + pad = ' ' * len + end + end + + if / / =~ pad + if sign == '..' + str = prefix + sign + str + else + str = sign + prefix + str + end + if mi + str = str + pad + else + str = pad + str + end + else + if sign == '..' + str = prefix + sign + pad + str + else + str = sign + prefix + pad + str + end + end + + str + end + + def self.assertions_format_integer(format) + proc { + VS.each {|v| + r = sprintf format, v + e = emu_int format, v + if true + assert_equal(e, r, "sprintf(#{format.dump}, #{v})") + else + if e != r + puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{v})" + end + end + } + } + end + + combination(%w[B b d o X x], + [nil, 0, 5, 20], + ["", ".", ".0", ".8", ".20"], + *FLAGS) {|type, width, precision, sp, hs, pl, mi, zr| + format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}" + define_method("test_format_integer(#{format})", assertions_format_integer(format)) + } + + FLOAT_VALUES = [ + -1e100, + -123456789.0, + -1.0, + -0.0, + 0.0, + 0.01, + 1/3.0, + 2/3.0, + 1.0, + 2.0, + 9.99999999, + 123456789.0, + 1e100, + Float::MAX, + Float::MIN, + Float::EPSILON, + 1+Float::EPSILON, + #1-Float::EPSILON/2, + 10 + Float::EPSILON*10, + 10 - Float::EPSILON*5, + 1.0/0.0, + -1.0/0.0, + 0.0/0.0, + ] + + def split_float10(v) + if v == 0 + if 1/v < 0 + sign = -1 + v = -v + else + sign = 1 + end + else + if v < 0 + sign = -1 + v = -v + else + sign = 1 + end + end + exp = 0 + int = v.floor + v -= int + while v != 0 + v *= 2 + int *= 2 + i = v.floor + v -= i + int += i + exp -= 1 + end + int *= 5 ** (-exp) + [sign, int, exp] + end + + def emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp) + precision = 6 unless precision + if int == 0 + if precision == 0 && !hs + result = "0#{type}+00" + else + result = "0." + "0" * precision + "#{type}+00" + end + else + if int < 10**precision + int *= 10**precision + exp -= precision + end + digits = int.to_s.length + discard = digits - (precision+1) + if discard != 0 + q, r = int.divmod(10**discard) + if r < 10**discard / 2 + int = q + exp += discard + elsif (q+1).to_s.length == q.to_s.length + int = q+1 + exp += discard + else + discard += 1 + q, r = int.divmod(10**discard) + int = q+1 + exp += discard + end + end + ints = int.to_s + frac = ints[1..-1] + result = ints[0,1] + e = exp + frac.length + if precision != 0 || hs + result << "." + if precision != 0 + result << frac + end + end + result << type + if e == 0 + if v.abs < 1 + result << '-00' # glibc 2.7 causes '+00' + else + result << '+00' + end + else + result << sprintf("%+03d", e) + end + result + end + result + end + + def emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp) + precision = 6 unless precision + if int == 0 + if precision == 0 && !hs + result = '0' + else + result = '0.' + '0' * precision + end + else + if -precision < exp + int *= 10 ** (precision+exp) + exp = -precision + end + if exp < -precision + discard = -exp - precision + q, r = int.divmod(10**discard) + if 10**discard / 2 <= r + q += 1 + end + int = q + exp += discard + end + result = int.to_s + if result.length <= precision + result = '0' * (precision+1 - result.length) + result + end + if precision != 0 || hs + if precision == 0 + result << '.' + else + result[-precision,0] = '.' + end + end + end + result + end + + def emu_float(format, v) + /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format + sp = $1 + hs = $2 + pl = $3 + mi = $4 + zr = $5 + width = $6 + precision = $7 + type = $8 + width = width.to_i if width + precision = precision.to_i if precision + + zr = nil if mi && zr + + if v.infinite? + sign = v < 0 ? -1 : 1 + int = :inf + hs = zr = nil + elsif v.nan? + sign = 1 + int = :nan + hs = zr = nil + else + sign, int, exp = split_float10(v) + end + + if sign < 0 + sign = '-' + elsif sign == 0 + sign = '' + elsif pl + sign = '+' + elsif sp + sign = ' ' + else + sign = '' + end + + if v.nan? + result = 'NaN' + elsif v.infinite? + result = 'Inf' + else + case type + when /[eE]/ + result = emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp) + when /f/ + result = emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp) + when /[gG]/ + precision = 6 unless precision + precision = 1 if precision == 0 + r = emu_e(sp, hs, pl, mi, zr, width, precision-1, type.tr('gG', 'eE'), v, sign, int, exp) + /[eE]([+-]\d+)/ =~ r + e = $1.to_i + if e < -4 || precision <= e + result = r + else + result = emu_f(sp, hs, pl, mi, zr, width, precision-1-e, type, sign, int, exp) + end + result.sub!(/\.[0-9]*/) { $&.sub(/\.?0*\z/, '') } if !hs + else + raise "unexpected type: #{type}" + end + end + + pad = '' + if width && sign.length + result.length < width + if zr + pad = '0' * (width - sign.length - result.length) + else + pad = ' ' * (width - sign.length - result.length) + end + end + if mi + sign + result + pad + elsif zr + sign + pad + result + else + pad + sign + result + end + + end + + def self.assertions_format_float(format) + proc { + FLOAT_VALUES.each {|v| + r = sprintf format, v + e = emu_float format, v + if true + assert_equal(e, r, "sprintf(#{format.dump}, #{'%.20g' % v})") + else + if e != r + puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{'%.20g' % v})" + end + end + } + } + end + + combination(%w[e E f g G], + [nil, 0, 5, 20], + ["", ".", ".0", ".8", ".20", ".200", ".9999"], + *FLAGS) {|type, width, precision, sp, hs, pl, mi, zr| + format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}" + define_method("test_format_float(#{format})", assertions_format_float(format)) + } +end diff --git a/jni/ruby/test/ruby/test_string.rb b/jni/ruby/test/ruby/test_string.rb new file mode 100644 index 0000000..4cd6afd --- /dev/null +++ b/jni/ruby/test/ruby/test_string.rb @@ -0,0 +1,2314 @@ +require 'test/unit' + +# use of $= is deprecated after 1.7.1 +def pre_1_7_1 +end + +class TestString < Test::Unit::TestCase + ENUMERATOR_WANTARRAY = RUBY_VERSION >= "3.0.0" + + def initialize(*args) + @cls = String + @aref_re_nth = true + @aref_re_silent = false + @aref_slicebang_silent = true + super + end + + def S(str) + @cls.new(str) + end + + def test_s_new + assert_equal("RUBY", S("RUBY")) + end + + def test_AREF # '[]' + assert_equal("A", S("AooBar")[0]) + assert_equal("B", S("FooBaB")[-1]) + assert_equal(nil, S("FooBar")[6]) + assert_equal(nil, S("FooBar")[-7]) + + assert_equal(S("Foo"), S("FooBar")[0,3]) + assert_equal(S("Bar"), S("FooBar")[-3,3]) + assert_equal(S(""), S("FooBar")[6,2]) + assert_equal(nil, S("FooBar")[-7,10]) + + assert_equal(S("Foo"), S("FooBar")[0..2]) + assert_equal(S("Foo"), S("FooBar")[0...3]) + assert_equal(S("Bar"), S("FooBar")[-3..-1]) + assert_equal(S(""), S("FooBar")[6..2]) + assert_equal(nil, S("FooBar")[-10..-7]) + + assert_equal(S("Foo"), S("FooBar")[/^F../]) + assert_equal(S("Bar"), S("FooBar")[/..r$/]) + assert_equal(nil, S("FooBar")[/xyzzy/]) + assert_equal(nil, S("FooBar")[/plugh/]) + + assert_equal(S("Foo"), S("FooBar")[S("Foo")]) + assert_equal(S("Bar"), S("FooBar")[S("Bar")]) + assert_equal(nil, S("FooBar")[S("xyzzy")]) + assert_equal(nil, S("FooBar")[S("plugh")]) + + if @aref_re_nth + assert_equal(S("Foo"), S("FooBar")[/([A-Z]..)([A-Z]..)/, 1]) + assert_equal(S("Bar"), S("FooBar")[/([A-Z]..)([A-Z]..)/, 2]) + assert_equal(nil, S("FooBar")[/([A-Z]..)([A-Z]..)/, 3]) + assert_equal(S("Bar"), S("FooBar")[/([A-Z]..)([A-Z]..)/, -1]) + assert_equal(S("Foo"), S("FooBar")[/([A-Z]..)([A-Z]..)/, -2]) + assert_equal(nil, S("FooBar")[/([A-Z]..)([A-Z]..)/, -3]) + end + + o = Object.new + def o.to_int; 2; end + assert_equal("o", "foo"[o]) + + assert_raise(ArgumentError) { "foo"[] } + end + + def test_ASET # '[]=' + s = S("FooBar") + s[0] = S('A') + assert_equal(S("AooBar"), s) + + s[-1]= S('B') + assert_equal(S("AooBaB"), s) + assert_raise(IndexError) { s[-7] = S("xyz") } + assert_equal(S("AooBaB"), s) + s[0] = S("ABC") + assert_equal(S("ABCooBaB"), s) + + s = S("FooBar") + s[0,3] = S("A") + assert_equal(S("ABar"),s) + s[0] = S("Foo") + assert_equal(S("FooBar"), s) + s[-3,3] = S("Foo") + assert_equal(S("FooFoo"), s) + assert_raise(IndexError) { s[7,3] = S("Bar") } + assert_raise(IndexError) { s[-7,3] = S("Bar") } + + s = S("FooBar") + s[0..2] = S("A") + assert_equal(S("ABar"), s) + s[1..3] = S("Foo") + assert_equal(S("AFoo"), s) + s[-4..-4] = S("Foo") + assert_equal(S("FooFoo"), s) + assert_raise(RangeError) { s[7..10] = S("Bar") } + assert_raise(RangeError) { s[-7..-10] = S("Bar") } + + s = S("FooBar") + s[/^F../]= S("Bar") + assert_equal(S("BarBar"), s) + s[/..r$/] = S("Foo") + assert_equal(S("BarFoo"), s) + if @aref_re_silent + s[/xyzzy/] = S("None") + assert_equal(S("BarFoo"), s) + else + assert_raise(IndexError) { s[/xyzzy/] = S("None") } + end + if @aref_re_nth + s[/([A-Z]..)([A-Z]..)/, 1] = S("Foo") + assert_equal(S("FooFoo"), s) + s[/([A-Z]..)([A-Z]..)/, 2] = S("Bar") + assert_equal(S("FooBar"), s) + assert_raise(IndexError) { s[/([A-Z]..)([A-Z]..)/, 3] = "None" } + s[/([A-Z]..)([A-Z]..)/, -1] = S("Foo") + assert_equal(S("FooFoo"), s) + s[/([A-Z]..)([A-Z]..)/, -2] = S("Bar") + assert_equal(S("BarFoo"), s) + assert_raise(IndexError) { s[/([A-Z]..)([A-Z]..)/, -3] = "None" } + end + + s = S("FooBar") + s[S("Foo")] = S("Bar") + assert_equal(S("BarBar"), s) + + pre_1_7_1 do + s = S("FooBar") + s[S("Foo")] = S("xyz") + assert_equal(S("xyzBar"), s) + + $= = true + s = S("FooBar") + s[S("FOO")] = S("Bar") + assert_equal(S("BarBar"), s) + s[S("FOO")] = S("xyz") + assert_equal(S("BarBar"), s) + $= = false + end + + s = S("a string") + s[0..s.size] = S("another string") + assert_equal(S("another string"), s) + + o = Object.new + def o.to_int; 2; end + s = "foo" + s[o] = "bar" + assert_equal("fobar", s) + + assert_raise(ArgumentError) { "foo"[1, 2, 3] = "" } + end + + def test_CMP # '<=>' + assert_equal(1, S("abcdef") <=> S("abcde")) + assert_equal(0, S("abcdef") <=> S("abcdef")) + assert_equal(-1, S("abcde") <=> S("abcdef")) + + assert_equal(-1, S("ABCDEF") <=> S("abcdef")) + + pre_1_7_1 do + $= = true + assert_equal(0, S("ABCDEF") <=> S("abcdef")) + $= = false + end + + assert_nil("foo" <=> Object.new) + + o = Object.new + def o.to_str; "bar"; end + assert_equal(1, "foo" <=> o) + + class << o;remove_method :to_str;end + def o.<=>(x); nil; end + assert_nil("foo" <=> o) + + class << o;remove_method :<=>;end + def o.<=>(x); 1; end + assert_equal(-1, "foo" <=> o) + + class << o;remove_method :<=>;end + def o.<=>(x); 2**100; end + assert_equal(-1, "foo" <=> o) + end + + def test_EQUAL # '==' + assert_not_equal(:foo, S("foo")) + assert_equal(S("abcdef"), S("abcdef")) + + pre_1_7_1 do + $= = true + assert_equal(S("CAT"), S('cat')) + assert_equal(S("CaT"), S('cAt')) + $= = false + end + + assert_not_equal(S("CAT"), S('cat')) + assert_not_equal(S("CaT"), S('cAt')) + + o = Object.new + def o.to_str; end + def o.==(x); false; end + assert_equal(false, "foo" == o) + class << o;remove_method :==;end + def o.==(x); true; end + assert_equal(true, "foo" == o) + end + + def test_LSHIFT # '<<' + assert_equal(S("world!"), S("world") << 33) + assert_equal(S("world!"), S("world") << S("!")) + + s = "a" + 10.times {|i| + s << s + assert_equal("a" * (2 << i), s) + } + + s = ["foo"].pack("p") + l = s.size + s << "bar" + assert_equal(l + 3, s.size) + + bug = '[ruby-core:27583]' + assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -3} + assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -2} + assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -1} + assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << 0x81308130} + assert_nothing_raised {S("a".force_encoding(Encoding::GB18030)) << 0x81308130} + end + + def test_MATCH # '=~' + assert_equal(10, S("FeeFieFoo-Fum") =~ /Fum$/) + assert_equal(nil, S("FeeFieFoo-Fum") =~ /FUM$/) + + pre_1_7_1 do + $= = true + assert_equal(10, S("FeeFieFoo-Fum") =~ /FUM$/) + $= = false + end + + o = Object.new + def o.=~(x); x + "bar"; end + assert_equal("foobar", S("foo") =~ o) + + assert_raise(TypeError) { S("foo") =~ "foo" } + end + + def test_MOD # '%' + assert_equal(S("00123"), S("%05d") % 123) + assert_equal(S("123 |00000001"), S("%-5s|%08x") % [123, 1]) + x = S("%3s %-4s%%foo %.0s%5d %#x%c%3.1f %b %x %X %#b %#x %#X") % + [S("hi"), + 123, + S("never seen"), + 456, + 0, + ?A, + 3.0999, + 11, + 171, + 171, + 11, + 171, + 171] + + assert_equal(S(' hi 123 %foo 456 0A3.1 1011 ab AB 0b1011 0xab 0XAB'), x) + end + + def test_MUL # '*' + assert_equal(S("XXX"), S("X") * 3) + assert_equal(S("HOHO"), S("HO") * 2) + end + + def test_PLUS # '+' + assert_equal(S("Yodel"), S("Yo") + S("del")) + end + + def casetest(a, b, rev=false) + msg = proc {"#{a} should#{' not' if rev} match #{b}"} + case a + when b + assert(!rev, msg) + else + assert(rev, msg) + end + end + + def test_VERY_EQUAL # '===' + # assert_equal(true, S("foo") === :foo) + casetest(S("abcdef"), S("abcdef")) + + pre_1_7_1 do + $= = true + casetest(S("CAT"), S('cat')) + casetest(S("CaT"), S('cAt')) + $= = false + end + + casetest(S("CAT"), S('cat'), true) # Reverse the test - we don't want to + casetest(S("CaT"), S('cAt'), true) # find these in the case. + end + + def test_capitalize + assert_equal(S("Hello"), S("hello").capitalize) + assert_equal(S("Hello"), S("hELLO").capitalize) + assert_equal(S("123abc"), S("123ABC").capitalize) + end + + def test_capitalize! + a = S("hello"); a.capitalize! + assert_equal(S("Hello"), a) + + a = S("hELLO"); a.capitalize! + assert_equal(S("Hello"), a) + + a = S("123ABC"); a.capitalize! + assert_equal(S("123abc"), a) + + assert_equal(nil, S("123abc").capitalize!) + assert_equal(S("123abc"), S("123ABC").capitalize!) + assert_equal(S("Abc"), S("ABC").capitalize!) + assert_equal(S("Abc"), S("abc").capitalize!) + assert_equal(nil, S("Abc").capitalize!) + + a = S("hello") + b = a.dup + assert_equal(S("Hello"), a.capitalize!) + assert_equal(S("hello"), b) + + end + + Bug2463 = '[ruby-dev:39856]' + def test_center + assert_equal(S("hello"), S("hello").center(4)) + assert_equal(S(" hello "), S("hello").center(11)) + assert_equal(S("ababaababa"), S("").center(10, "ab"), Bug2463) + assert_equal(S("ababaababab"), S("").center(11, "ab"), Bug2463) + end + + def test_chomp + assert_equal(S("hello"), S("hello").chomp("\n")) + assert_equal(S("hello"), S("hello\n").chomp("\n")) + save = $/ + + $/ = "\n" + + assert_equal(S("hello"), S("hello").chomp) + assert_equal(S("hello"), S("hello\n").chomp) + + $/ = "!" + assert_equal(S("hello"), S("hello").chomp) + assert_equal(S("hello"), S("hello!").chomp) + $/ = save + + assert_equal(S("a").hash, S("a\u0101").chomp(S("\u0101")).hash, '[ruby-core:22414]') + end + + def test_chomp! + a = S("hello") + a.chomp!(S("\n")) + + assert_equal(S("hello"), a) + assert_equal(nil, a.chomp!(S("\n"))) + + a = S("hello\n") + a.chomp!(S("\n")) + assert_equal(S("hello"), a) + save = $/ + + $/ = "\n" + a = S("hello") + a.chomp! + assert_equal(S("hello"), a) + + a = S("hello\n") + a.chomp! + assert_equal(S("hello"), a) + + $/ = "!" + a = S("hello") + a.chomp! + assert_equal(S("hello"), a) + + a="hello!" + a.chomp! + assert_equal(S("hello"), a) + + $/ = save + + a = S("hello\n") + b = a.dup + assert_equal(S("hello"), a.chomp!) + assert_equal(S("hello\n"), b) + + s = "foo\r\n" + s.chomp! + assert_equal("foo", s) + + s = "foo\r" + s.chomp! + assert_equal("foo", s) + + s = "foo\r\n" + s.chomp!("") + assert_equal("foo", s) + + s = "foo\r" + s.chomp!("") + assert_equal("foo\r", s) + + assert_equal(S("a").hash, S("a\u0101").chomp!(S("\u0101")).hash, '[ruby-core:22414]') + end + + def test_chop + assert_equal(S("hell"), S("hello").chop) + assert_equal(S("hello"), S("hello\r\n").chop) + assert_equal(S("hello\n"), S("hello\n\r").chop) + assert_equal(S(""), S("\r\n").chop) + assert_equal(S(""), S("").chop) + assert_equal(S("a").hash, S("a\u00d8").chop.hash) + end + + def test_chop! + a = S("hello").chop! + assert_equal(S("hell"), a) + + a = S("hello\r\n").chop! + assert_equal(S("hello"), a) + + a = S("hello\n\r").chop! + assert_equal(S("hello\n"), a) + + a = S("\r\n").chop! + assert_equal(S(""), a) + + a = S("").chop! + assert_nil(a) + + a = S("a\u00d8") + a.chop! + assert_equal(S("a").hash, a.hash) + + a = S("hello\n") + b = a.dup + assert_equal(S("hello"), a.chop!) + assert_equal(S("hello\n"), b) + end + + def test_clone + for taint in [ false, true ] + for frozen in [ false, true ] + a = S("Cool") + a.taint if taint + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert_not_same(a, b) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + + null = File.exist?("/dev/null") ? "/dev/null" : "NUL" # maybe DOSISH + assert_equal("", File.read(null).clone, '[ruby-dev:32819] reported by Kazuhiro NISHIYAMA') + end + + def test_concat + assert_equal(S("world!"), S("world").concat(33)) + assert_equal(S("world!"), S("world").concat(S('!'))) + + bug7090 = '[ruby-core:47751]' + result = S("").force_encoding(Encoding::UTF_16LE) + result << 0x0300 + expected = S("\u0300".encode(Encoding::UTF_16LE)) + assert_equal(expected, result, bug7090) + assert_raise(TypeError) { 'foo' << :foo } + end + + def test_count + a = S("hello world") + assert_equal(5, a.count(S("lo"))) + assert_equal(2, a.count(S("lo"), S("o"))) + 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_raise(ArgumentError) { "foo".count } + end + + def test_crypt + assert_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("aa"))) + assert_not_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("ab"))) + assert_raise(ArgumentError) {S("mypassword").crypt(S(""))} + assert_raise(ArgumentError) {S("mypassword").crypt(S("\0a"))} + assert_raise(ArgumentError) {S("mypassword").crypt(S("a\0"))} + [Encoding::UTF_16BE, Encoding::UTF_16LE, + Encoding::UTF_32BE, Encoding::UTF_32LE].each do |enc| + assert_raise(ArgumentError) {S("mypassword").crypt(S("aa".encode(enc)))} + assert_raise(ArgumentError) {S("mypassword".encode(enc)).crypt(S("aa"))} + end + end + + def test_delete + assert_equal(S("heo"), S("hello").delete(S("l"), S("lo"))) + assert_equal(S("he"), S("hello").delete(S("lo"))) + 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".tr("\u3041", "a").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")) + + bug6160 = '[ruby-dev:45374]' + assert_equal("", '\\'.delete('\\'), bug6160) + end + + def test_delete! + a = S("hello") + a.delete!(S("l"), S("lo")) + assert_equal(S("heo"), a) + + a = S("hello") + a.delete!(S("lo")) + assert_equal(S("he"), a) + + a = S("hello") + a.delete!(S("aeiou"), S("^e")) + assert_equal(S("hell"), a) + + a = S("hello") + a.delete!(S("ej-m")) + assert_equal(S("ho"), a) + + a = S("hello") + assert_nil(a.delete!(S("z"))) + + a = S("hello") + b = a.dup + a.delete!(S("lo")) + assert_equal(S("he"), a) + assert_equal(S("hello"), b) + + a = S("hello") + a.delete!(S("^el")) + assert_equal(S("ell"), a) + + assert_raise(ArgumentError) { S("foo").delete! } + end + + + def test_downcase + assert_equal(S("hello"), S("helLO").downcase) + assert_equal(S("hello"), S("hello").downcase) + assert_equal(S("hello"), S("HELLO").downcase) + assert_equal(S("abc hello 123"), S("abc HELLO 123").downcase) + end + + def test_downcase! + a = S("helLO") + b = a.dup + assert_equal(S("hello"), a.downcase!) + assert_equal(S("hello"), a) + assert_equal(S("helLO"), b) + + a=S("hello") + assert_nil(a.downcase!) + assert_equal(S("hello"), a) + end + + def test_dump + a= S("Test") << 1 << 2 << 3 << 9 << 13 << 10 + assert_equal(S('"Test\\x01\\x02\\x03\\t\\r\\n"'), a.dump) + end + + def test_dup + for taint in [ false, true ] + for frozen in [ false, true ] + a = S("hello") + a.taint if taint + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert_not_same(a, b) + assert_not_predicate(b, :frozen?) + assert_equal(a.tainted?, b.tainted?) + end + end + end + + def test_each + save = $/ + $/ = "\n" + res=[] + S("hello\nworld").lines.each {|x| res << x} + assert_equal(S("hello\n"), res[0]) + assert_equal(S("world"), res[1]) + + res=[] + S("hello\n\n\nworld").lines(S('')).each {|x| res << x} + assert_equal(S("hello\n\n\n"), res[0]) + assert_equal(S("world"), res[1]) + + $/ = "!" + res=[] + S("hello!world").lines.each {|x| res << x} + assert_equal(S("hello!"), res[0]) + assert_equal(S("world"), res[1]) + $/ = save + end + + def test_each_byte + s = S("ABC") + + res = [] + assert_equal s.object_id, s.each_byte {|x| res << x }.object_id + assert_equal(65, res[0]) + assert_equal(66, res[1]) + assert_equal(67, res[2]) + + assert_equal 65, s.each_byte.next + end + + def test_bytes + s = S("ABC") + assert_equal [65, 66, 67], s.bytes + + if ENUMERATOR_WANTARRAY + assert_warn(/block not used/) { + assert_equal [65, 66, 67], s.bytes {} + } + else + assert_warning(/deprecated/) { + res = [] + assert_equal s.object_id, s.bytes {|x| res << x }.object_id + assert_equal(65, res[0]) + assert_equal(66, res[1]) + assert_equal(67, res[2]) + } + end + end + + def test_each_codepoint + # Single byte optimization + assert_equal 65, S("ABC").each_codepoint.next + + s = S("\u3042\u3044\u3046") + + res = [] + assert_equal s.object_id, s.each_codepoint {|x| res << x }.object_id + assert_equal(0x3042, res[0]) + assert_equal(0x3044, res[1]) + assert_equal(0x3046, res[2]) + + assert_equal 0x3042, s.each_codepoint.next + end + + def test_codepoints + # Single byte optimization + assert_equal [65, 66, 67], S("ABC").codepoints + + s = S("\u3042\u3044\u3046") + assert_equal [0x3042, 0x3044, 0x3046], s.codepoints + + if ENUMERATOR_WANTARRAY + assert_warn(/block not used/) { + assert_equal [0x3042, 0x3044, 0x3046], s.codepoints {} + } + else + assert_warning(/deprecated/) { + res = [] + assert_equal s.object_id, s.codepoints {|x| res << x }.object_id + assert_equal(0x3042, res[0]) + assert_equal(0x3044, res[1]) + assert_equal(0x3046, res[2]) + } + end + end + + def test_each_char + s = S("ABC") + + res = [] + assert_equal s.object_id, s.each_char {|x| res << x }.object_id + assert_equal("A", res[0]) + assert_equal("B", res[1]) + assert_equal("C", res[2]) + + assert_equal "A", S("ABC").each_char.next + end + + def test_chars + s = S("ABC") + assert_equal ["A", "B", "C"], s.chars + + if ENUMERATOR_WANTARRAY + assert_warn(/block not used/) { + assert_equal ["A", "B", "C"], s.chars {} + } + else + assert_warning(/deprecated/) { + res = [] + assert_equal s.object_id, s.chars {|x| res << x }.object_id + assert_equal("A", res[0]) + assert_equal("B", res[1]) + assert_equal("C", res[2]) + } + end + end + + def test_each_line + save = $/ + $/ = "\n" + res=[] + S("hello\nworld").each_line {|x| res << x} + assert_equal(S("hello\n"), res[0]) + assert_equal(S("world"), res[1]) + + res=[] + S("hello\n\n\nworld").each_line(S('')) {|x| res << x} + assert_equal(S("hello\n\n\n"), res[0]) + assert_equal(S("world"), res[1]) + + $/ = "!" + + res=[] + S("hello!world").each_line {|x| res << x} + assert_equal(S("hello!"), res[0]) + assert_equal(S("world"), res[1]) + + $/ = "ab" + + res=[] + S("a").lines.each {|x| res << x} + assert_equal(1, res.size) + assert_equal(S("a"), res[0]) + + $/ = save + + s = nil + "foo\nbar".each_line(nil) {|s2| s = s2 } + assert_equal("foo\nbar", s) + + assert_equal "hello\n", S("hello\nworld").each_line.next + assert_equal "hello\nworld", S("hello\nworld").each_line(nil).next + + bug7646 = "[ruby-dev:46827]" + assert_nothing_raised(bug7646) do + "\n\u0100".each_line("\n") {} + end + end + + def test_lines + s = S("hello\nworld") + assert_equal ["hello\n", "world"], s.lines + assert_equal ["hello\nworld"], s.lines(nil) + + if ENUMERATOR_WANTARRAY + assert_warn(/block not used/) { + assert_equal ["hello\n", "world"], s.lines {} + } + else + assert_warning(/deprecated/) { + res = [] + assert_equal s.object_id, s.lines {|x| res << x }.object_id + assert_equal(S("hello\n"), res[0]) + assert_equal(S("world"), res[1]) + } + end + end + + def test_empty? + assert_empty(S("")) + assert_not_empty(S("not")) + end + + def test_end_with? + assert_send([S("hello"), :end_with?, S("llo")]) + assert_not_send([S("hello"), :end_with?, S("ll")]) + assert_send([S("hello"), :end_with?, S("el"), S("lo")]) + + bug5536 = '[ruby-core:40623]' + assert_raise(TypeError, bug5536) {S("str").end_with? :not_convertible_to_string} + end + + def test_eql? + a = S("hello") + assert_operator(a, :eql?, S("hello")) + assert_operator(a, :eql?, a) + end + + def test_gsub + assert_equal(S("h*ll*"), S("hello").gsub(/[aeiou]/, S('*'))) + assert_equal(S("h<e>ll<o>"), S("hello").gsub(/([aeiou])/, S('<\1>'))) + assert_equal(S("h e l l o "), + S("hello").gsub(/./) { |s| s[0].to_s + S(' ')}) + assert_equal(S("HELL-o"), + S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 }) + assert_equal(S("<>h<>e<>l<>l<>o<>"), S("hello").gsub(S(''), S('<\0>'))) + + a = S("hello") + a.taint + assert_predicate(a.gsub(/./, S('X')), :tainted?) + + assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug") + + assert_raise(ArgumentError) { "foo".gsub } + end + + def test_gsub_encoding + a = S("hello world") + a.force_encoding Encoding::UTF_8 + + b = S("hi") + b.force_encoding Encoding::US_ASCII + + assert_equal Encoding::UTF_8, a.gsub(/hello/, b).encoding + + c = S("everybody") + c.force_encoding Encoding::US_ASCII + + assert_equal Encoding::UTF_8, a.gsub(/world/, c).encoding + + assert_equal S("a\u{e9}apos<"), S("a\u{e9}'<").gsub("'", "apos") + + bug9849 = '[ruby-core:62669] [Bug #9849]' + assert_equal S("\u{3042 3042 3042}!foo!"), S("\u{3042 3042 3042}/foo/").gsub("/", "!"), bug9849 + end + + def test_gsub! + a = S("hello") + b = a.dup + a.gsub!(/[aeiou]/, S('*')) + assert_equal(S("h*ll*"), a) + assert_equal(S("hello"), b) + + a = S("hello") + a.gsub!(/([aeiou])/, S('<\1>')) + assert_equal(S("h<e>ll<o>"), a) + + a = S("hello") + a.gsub!(/./) { |s| s[0].to_s + S(' ')} + assert_equal(S("h e l l o "), a) + + a = S("hello") + a.gsub!(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 } + assert_equal(S("HELL-o"), a) + + r = S('X') + r.taint + a.gsub!(/./, r) + assert_predicate(a, :tainted?) + + a = S("hello") + assert_nil(a.sub!(S('X'), S('Y'))) + 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")) + 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")) + end + + def test_hash + assert_equal(S("hello").hash, S("hello").hash) + assert_not_equal(S("hello").hash, S("helLO").hash) + bug4104 = '[ruby-core:33500]' + assert_not_equal(S("a").hash, S("a\0").hash, bug4104) + bug9172 = '[ruby-core:58658] [Bug #9172]' + assert_not_equal(S("sub-setter").hash, S("discover").hash, bug9172) + end + + def test_hash_random + str = 'abc' + a = [str.hash.to_s] + 3.times { + assert_in_out_err(["-e", "print #{str.dump}.hash"], "") do |r, e| + a += r + assert_equal([], e) + end + } + assert_not_equal([str.hash.to_s], a.uniq) + end + + def test_hex + assert_equal(255, S("0xff").hex) + assert_equal(-255, S("-0xff").hex) + assert_equal(255, S("ff").hex) + assert_equal(-255, S("-ff").hex) + assert_equal(0, S("-ralph").hex) + assert_equal(-15, S("-fred").hex) + assert_equal(15, S("fred").hex) + end + + def test_include? + assert_include(S("foobar"), ?f) + assert_include(S("foobar"), S("foo")) + assert_not_include(S("foobar"), S("baz")) + assert_not_include(S("foobar"), ?z) + end + + def test_index + assert_equal(0, S("hello").index(?h)) + assert_equal(1, S("hello").index(S("ell"))) + assert_equal(2, S("hello").index(/ll./)) + + assert_equal(3, S("hello").index(?l, 3)) + assert_equal(3, S("hello").index(S("l"), 3)) + assert_equal(3, S("hello").index(/l./, 3)) + + assert_nil(S("hello").index(?z, 3)) + assert_nil(S("hello").index(S("z"), 3)) + assert_nil(S("hello").index(/z./, 3)) + + assert_nil(S("hello").index(?z)) + assert_nil(S("hello").index(S("z"))) + assert_nil(S("hello").index(/z./)) + + assert_equal(0, S("").index(S(""))) + assert_equal(0, S("").index(//)) + assert_nil(S("").index(S("hello"))) + assert_nil(S("").index(/hello/)) + assert_equal(0, S("hello").index(S(""))) + assert_equal(0, S("hello").index(//)) + + s = S("long") * 1000 << "x" + assert_nil(s.index(S("y"))) + assert_equal(4 * 1000, s.index(S("x"))) + s << "yx" + assert_equal(4 * 1000, s.index(S("x"))) + assert_equal(4 * 1000, s.index(S("xyx"))) + + o = Object.new + def o.to_str; "bar"; end + assert_equal(3, "foobarbarbaz".index(o)) + assert_raise(TypeError) { "foo".index(Object.new) } + + assert_nil("foo".index(//, -100)) + assert_nil($~) + end + + def test_intern + assert_equal(:koala, S("koala").intern) + assert_not_equal(:koala, S("Koala").intern) + end + + def test_length + assert_equal(0, S("").length) + assert_equal(4, S("1234").length) + assert_equal(6, S("1234\r\n").length) + assert_equal(7, S("\0011234\r\n").length) + end + + def test_ljust + assert_equal(S("hello"), S("hello").ljust(4)) + assert_equal(S("hello "), S("hello").ljust(11)) + assert_equal(S("ababababab"), S("").ljust(10, "ab"), Bug2463) + assert_equal(S("abababababa"), S("").ljust(11, "ab"), Bug2463) + end + + def test_next + assert_equal(S("abd"), S("abc").next) + assert_equal(S("z"), S("y").next) + assert_equal(S("aaa"), S("zz").next) + + assert_equal(S("124"), S("123").next) + assert_equal(S("1000"), S("999").next) + + assert_equal(S("2000aaa"), S("1999zzz").next) + assert_equal(S("AAAAA000"), S("ZZZZ999").next) + + assert_equal(S("*+"), S("**").next) + end + + def test_next! + a = S("abc") + b = a.dup + assert_equal(S("abd"), a.next!) + assert_equal(S("abd"), a) + assert_equal(S("abc"), b) + + a = S("y") + assert_equal(S("z"), a.next!) + assert_equal(S("z"), a) + + a = S("zz") + assert_equal(S("aaa"), a.next!) + assert_equal(S("aaa"), a) + + a = S("123") + assert_equal(S("124"), a.next!) + assert_equal(S("124"), a) + + a = S("999") + assert_equal(S("1000"), a.next!) + assert_equal(S("1000"), a) + + a = S("1999zzz") + assert_equal(S("2000aaa"), a.next!) + assert_equal(S("2000aaa"), a) + + a = S("ZZZZ999") + assert_equal(S("AAAAA000"), a.next!) + assert_equal(S("AAAAA000"), a) + + a = S("**") + assert_equal(S("*+"), a.next!) + assert_equal(S("*+"), a) + end + + def test_oct + assert_equal(255, S("0377").oct) + assert_equal(255, S("377").oct) + assert_equal(-255, S("-0377").oct) + assert_equal(-255, S("-377").oct) + assert_equal(0, S("OO").oct) + assert_equal(24, S("030OO").oct) + end + + def test_replace + a = S("foo") + assert_equal(S("f"), a.replace(S("f"))) + + a = S("foo") + assert_equal(S("foobar"), a.replace(S("foobar"))) + + a = S("foo") + a.taint + b = a.replace(S("xyz")) + assert_equal(S("xyz"), b) + assert_predicate(b, :tainted?) + + s = "foo" * 100 + s2 = ("bar" * 100).dup + s.replace(s2) + assert_equal(s2, s) + + s2 = ["foo"].pack("p") + s.replace(s2) + assert_equal(s2, s) + + fs = "".freeze + assert_raise(RuntimeError) { fs.replace("a") } + assert_raise(RuntimeError) { fs.replace(fs) } + assert_raise(ArgumentError) { fs.replace() } + assert_raise(RuntimeError) { fs.replace(42) } + end + + def test_reverse + assert_equal(S("beta"), S("ateb").reverse) + assert_equal(S("madamImadam"), S("madamImadam").reverse) + + a=S("beta") + assert_equal(S("ateb"), a.reverse) + assert_equal(S("beta"), a) + end + + def test_reverse! + a = S("beta") + b = a.dup + assert_equal(S("ateb"), a.reverse!) + assert_equal(S("ateb"), a) + assert_equal(S("beta"), b) + + assert_equal(S("madamImadam"), S("madamImadam").reverse!) + + a = S("madamImadam") + assert_equal(S("madamImadam"), a.reverse!) # ?? + assert_equal(S("madamImadam"), a) + end + + def test_rindex + assert_equal(3, S("hello").rindex(?l)) + assert_equal(6, S("ell, hello").rindex(S("ell"))) + assert_equal(7, S("ell, hello").rindex(/ll./)) + + assert_equal(3, S("hello,lo").rindex(?l, 3)) + assert_equal(3, S("hello,lo").rindex(S("l"), 3)) + assert_equal(3, S("hello,lo").rindex(/l./, 3)) + + assert_nil(S("hello").rindex(?z, 3)) + assert_nil(S("hello").rindex(S("z"), 3)) + assert_nil(S("hello").rindex(/z./, 3)) + + assert_nil(S("hello").rindex(?z)) + assert_nil(S("hello").rindex(S("z"))) + assert_nil(S("hello").rindex(/z./)) + + o = Object.new + def o.to_str; "bar"; end + assert_equal(6, "foobarbarbaz".rindex(o)) + assert_raise(TypeError) { "foo".rindex(Object.new) } + + assert_nil("foo".rindex(//, -100)) + assert_nil($~) + end + + def test_rjust + assert_equal(S("hello"), S("hello").rjust(4)) + assert_equal(S(" hello"), S("hello").rjust(11)) + assert_equal(S("ababababab"), S("").rjust(10, "ab"), Bug2463) + assert_equal(S("abababababa"), S("").rjust(11, "ab"), Bug2463) + end + + def test_scan + a = S("cruel world") + assert_equal([S("cruel"), S("world")],a.scan(/\w+/)) + assert_equal([S("cru"), S("el "), S("wor")],a.scan(/.../)) + assert_equal([[S("cru")], [S("el ")], [S("wor")]],a.scan(/(...)/)) + + res = [] + a.scan(/\w+/) { |w| res << w } + assert_equal([S("cruel"), S("world") ],res) + + res = [] + a.scan(/.../) { |w| res << w } + assert_equal([S("cru"), S("el "), S("wor")],res) + + res = [] + a.scan(/(...)/) { |w| res << w } + assert_equal([[S("cru")], [S("el ")], [S("wor")]],res) + + a = S("hello") + a.taint + res = [] + a.scan(/./) { |w| res << w } + assert_predicate(res[0], :tainted?, '[ruby-core:33338] #4087') + + /h/ =~ a + a.scan(/x/) + assert_nil($~) + + /h/ =~ a + a.scan('x') + assert_nil($~) + + assert_equal(3, S("hello hello hello").scan("hello".taint).count(&:tainted?)) + end + + def test_size + assert_equal(0, S("").size) + assert_equal(4, S("1234").size) + assert_equal(6, S("1234\r\n").size) + assert_equal(7, S("\0011234\r\n").size) + end + + def test_slice + assert_equal(?A, S("AooBar").slice(0)) + assert_equal(?B, S("FooBaB").slice(-1)) + assert_nil(S("FooBar").slice(6)) + assert_nil(S("FooBar").slice(-7)) + + assert_equal(S("Foo"), S("FooBar").slice(0,3)) + assert_equal(S(S("Bar")), S("FooBar").slice(-3,3)) + assert_nil(S("FooBar").slice(7,2)) # Maybe should be six? + assert_nil(S("FooBar").slice(-7,10)) + + assert_equal(S("Foo"), S("FooBar").slice(0..2)) + assert_equal(S("Bar"), S("FooBar").slice(-3..-1)) + assert_equal(S(""), S("FooBar").slice(6..2)) + assert_nil(S("FooBar").slice(-10..-7)) + + assert_equal(S("Foo"), S("FooBar").slice(/^F../)) + assert_equal(S("Bar"), S("FooBar").slice(/..r$/)) + assert_nil(S("FooBar").slice(/xyzzy/)) + assert_nil(S("FooBar").slice(/plugh/)) + + assert_equal(S("Foo"), S("FooBar").slice(S("Foo"))) + assert_equal(S("Bar"), S("FooBar").slice(S("Bar"))) + assert_nil(S("FooBar").slice(S("xyzzy"))) + assert_nil(S("FooBar").slice(S("plugh"))) + + bug9882 = '[ruby-core:62842] [Bug #9882]' + substr = S("\u{30c6 30b9 30c8 2019}#{bug9882}").slice(4..-1) + assert_equal(S(bug9882).hash, substr.hash, bug9882) + assert_predicate(substr, :ascii_only?, bug9882) + end + + def test_slice! + a = S("AooBar") + b = a.dup + assert_equal(?A, a.slice!(0)) + assert_equal(S("ooBar"), a) + assert_equal(S("AooBar"), b) + + a = S("FooBar") + assert_equal(?r,a.slice!(-1)) + assert_equal(S("FooBa"), a) + + a = S("FooBar") + if @aref_slicebang_silent + assert_nil( a.slice!(6) ) + else + assert_raise(IndexError) { a.slice!(6) } + end + assert_equal(S("FooBar"), a) + + if @aref_slicebang_silent + assert_nil( a.slice!(-7) ) + else + assert_raise(IndexError) { a.slice!(-7) } + end + assert_equal(S("FooBar"), a) + + a = S("FooBar") + assert_equal(S("Foo"), a.slice!(0,3)) + assert_equal(S("Bar"), a) + + a = S("FooBar") + assert_equal(S("Bar"), a.slice!(-3,3)) + assert_equal(S("Foo"), a) + + a=S("FooBar") + if @aref_slicebang_silent + assert_nil(a.slice!(7,2)) # Maybe should be six? + else + assert_raise(IndexError) {a.slice!(7,2)} # Maybe should be six? + end + assert_equal(S("FooBar"), a) + if @aref_slicebang_silent + assert_nil(a.slice!(-7,10)) + else + assert_raise(IndexError) {a.slice!(-7,10)} + end + assert_equal(S("FooBar"), a) + + a=S("FooBar") + assert_equal(S("Foo"), a.slice!(0..2)) + assert_equal(S("Bar"), a) + + a=S("FooBar") + assert_equal(S("Bar"), a.slice!(-3..-1)) + assert_equal(S("Foo"), a) + + a=S("FooBar") + if @aref_slicebang_silent + assert_equal(S(""), a.slice!(6..2)) + else + assert_raise(RangeError) {a.slice!(6..2)} + end + assert_equal(S("FooBar"), a) + if @aref_slicebang_silent + assert_nil(a.slice!(-10..-7)) + else + assert_raise(RangeError) {a.slice!(-10..-7)} + end + assert_equal(S("FooBar"), a) + + a=S("FooBar") + assert_equal(S("Foo"), a.slice!(/^F../)) + assert_equal(S("Bar"), a) + + a=S("FooBar") + assert_equal(S("Bar"), a.slice!(/..r$/)) + assert_equal(S("Foo"), a) + + a=S("FooBar") + if @aref_slicebang_silent + assert_nil(a.slice!(/xyzzy/)) + else + assert_raise(IndexError) {a.slice!(/xyzzy/)} + end + assert_equal(S("FooBar"), a) + if @aref_slicebang_silent + assert_nil(a.slice!(/plugh/)) + else + assert_raise(IndexError) {a.slice!(/plugh/)} + end + assert_equal(S("FooBar"), a) + + a=S("FooBar") + assert_equal(S("Foo"), a.slice!(S("Foo"))) + assert_equal(S("Bar"), a) + + a=S("FooBar") + assert_equal(S("Bar"), a.slice!(S("Bar"))) + assert_equal(S("Foo"), a) + + pre_1_7_1 do + a=S("FooBar") + assert_nil(a.slice!(S("xyzzy"))) + assert_equal(S("FooBar"), a) + assert_nil(a.slice!(S("plugh"))) + assert_equal(S("FooBar"), a) + end + + assert_raise(ArgumentError) { "foo".slice! } + end + + def test_split + assert_nil($;) + assert_equal([S("a"), S("b"), S("c")], S(" a b\t c ").split) + assert_equal([S("a"), S("b"), S("c")], S(" a b\t c ").split(S(" "))) + + assert_equal([S(" a "), S(" b "), S(" c ")], S(" a | b | c ").split(S("|"))) + + assert_equal([S("a"), S("b"), S("c")], S("aXXbXXcXX").split(/X./)) + + assert_equal([S("a"), S("b"), S("c")], S("abc").split(//)) + + assert_equal([S("a|b|c")], S("a|b|c").split(S('|'), 1)) + + assert_equal([S("a"), S("b|c")], S("a|b|c").split(S('|'), 2)) + assert_equal([S("a"), S("b"), S("c")], S("a|b|c").split(S('|'), 3)) + + assert_equal([S("a"), S("b"), S("c"), S("")], S("a|b|c|").split(S('|'), -1)) + assert_equal([S("a"), S("b"), S("c"), S(""), S("")], S("a|b|c||").split(S('|'), -1)) + + 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("[2, 3]", [1,2,3].slice!(1,10000).inspect, "moved from btest/knownbug") + end + + def test_split_encoding + bug6206 = '[ruby-dev:45441]' + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + s = S("a:".force_encoding(enc)) + assert_equal([enc]*2, s.split(":", 2).map(&:encoding), bug6206) + end + end + + def test_split_wchar + bug8642 = '[ruby-core:56036] [Bug #8642]' + [ + Encoding::UTF_16BE, Encoding::UTF_16LE, + Encoding::UTF_32BE, Encoding::UTF_32LE, + ].each do |enc| + s = S("abc,def".encode(enc)) + assert_equal(["abc", "def"].map {|c| c.encode(enc)}, + s.split(",".encode(enc)), + "#{bug8642} in #{enc.name}") + end + end + + def test_split_invalid_sequence + bug10886 = '[ruby-core:68229] [Bug #10886]' + broken = S("\xa1".force_encoding("utf-8")) + assert_raise(ArgumentError, bug10886) { + S("a,b").split(broken) + } + end + + def test_split_invalid_argument + assert_raise(TypeError) { + S("a,b").split(BasicObject.new) + } + end + + def test_squeeze + assert_equal(S("abc"), S("aaabbbbccc").squeeze) + assert_equal(S("aa bb cc"), S("aa bb cc").squeeze(S(" "))) + assert_equal(S("BxTyWz"), S("BxxxTyyyWzzzzz").squeeze(S("a-z"))) + end + + def test_squeeze! + a = S("aaabbbbccc") + b = a.dup + assert_equal(S("abc"), a.squeeze!) + assert_equal(S("abc"), a) + assert_equal(S("aaabbbbccc"), b) + + a = S("aa bb cc") + assert_equal(S("aa bb cc"), a.squeeze!(S(" "))) + assert_equal(S("aa bb cc"), a) + + a = S("BxxxTyyyWzzzzz") + assert_equal(S("BxTyWz"), a.squeeze!(S("a-z"))) + assert_equal(S("BxTyWz"), a) + + a=S("The quick brown fox") + assert_nil(a.squeeze!) + end + + def test_start_with? + assert_send([S("hello"), :start_with?, S("hel")]) + assert_not_send([S("hello"), :start_with?, S("el")]) + assert_send([S("hello"), :start_with?, S("el"), S("he")]) + + bug5536 = '[ruby-core:40623]' + assert_raise(TypeError, bug5536) {S("str").start_with? :not_convertible_to_string} + end + + def test_strip + assert_equal(S("x"), S(" x ").strip) + assert_equal(S("x"), S(" \n\r\t x \t\r\n\n ").strip) + + assert_equal("0b0 ".force_encoding("UTF-16BE"), + "\x00 0b0 ".force_encoding("UTF-16BE").strip) + assert_equal("0\x000b0 ".force_encoding("UTF-16BE"), + "0\x000b0 ".force_encoding("UTF-16BE").strip) + end + + def test_strip! + a = S(" x ") + b = a.dup + assert_equal(S("x") ,a.strip!) + assert_equal(S("x") ,a) + assert_equal(S(" x "), b) + + a = S(" \n\r\t x \t\r\n\n ") + assert_equal(S("x"), a.strip!) + assert_equal(S("x"), a) + + a = S("x") + assert_nil(a.strip!) + assert_equal(S("x") ,a) + end + + def test_sub + assert_equal(S("h*llo"), S("hello").sub(/[aeiou]/, S('*'))) + assert_equal(S("h<e>llo"), S("hello").sub(/([aeiou])/, S('<\1>'))) + assert_equal(S("h ello"), S("hello").sub(/./) { + |s| s[0].to_s + S(' ')}) + assert_equal(S("HELL-o"), S("hello").sub(/(hell)(.)/) { + |s| $1.upcase + S('-') + $2 + }) + assert_equal(S("h<e>llo"), S("hello").sub('e', S('<\0>'))) + + assert_equal(S("a\\aba"), S("ababa").sub(/b/, '\\')) + assert_equal(S("ab\\aba"), S("ababa").sub(/(b)/, '\1\\')) + assert_equal(S("ababa"), S("ababa").sub(/(b)/, '\1')) + assert_equal(S("ababa"), S("ababa").sub(/(b)/, '\\1')) + assert_equal(S("a\\1aba"), S("ababa").sub(/(b)/, '\\\1')) + assert_equal(S("a\\1aba"), S("ababa").sub(/(b)/, '\\\\1')) + assert_equal(S("a\\baba"), S("ababa").sub(/(b)/, '\\\\\1')) + + assert_equal(S("a--ababababababababab"), + S("abababababababababab").sub(/(b)/, '-\9-')) + assert_equal(S("1-b-0"), + S("1b2b3b4b5b6b7b8b9b0"). + sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\9-')) + assert_equal(S("1-b-0"), + S("1b2b3b4b5b6b7b8b9b0"). + sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\\9-')) + assert_equal(S("1-\\9-0"), + S("1b2b3b4b5b6b7b8b9b0"). + sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\\\9-')) + assert_equal(S("k"), + S("1a2b3c4d5e6f7g8h9iAjBk"). + sub(/.(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.)/, '\+')) + + assert_equal(S("ab\\aba"), S("ababa").sub(/b/, '\&\\')) + assert_equal(S("ababa"), S("ababa").sub(/b/, '\&')) + assert_equal(S("ababa"), S("ababa").sub(/b/, '\\&')) + assert_equal(S("a\\&aba"), S("ababa").sub(/b/, '\\\&')) + assert_equal(S("a\\&aba"), S("ababa").sub(/b/, '\\\\&')) + assert_equal(S("a\\baba"), S("ababa").sub(/b/, '\\\\\&')) + + a = S("hello") + a.taint + x = a.sub(/./, S('X')) + assert_predicate(x, :tainted?) + + o = Object.new + def o.to_str; "bar"; end + assert_equal("fooBARbaz", "foobarbaz".sub(o, "BAR")) + + assert_raise(TypeError) { "foo".sub(Object.new, "") } + + assert_raise(ArgumentError) { "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_equal(S("Abc"), S("abc").sub("a", "A")) + m = nil + assert_equal(S("Abc"), S("abc").sub("a") {m = $~; "A"}) + assert_equal(S("a"), m[0]) + assert_equal(/a/, m.regexp) + end + + def test_sub! + a = S("hello") + b = a.dup + a.sub!(/[aeiou]/, S('*')) + assert_equal(S("h*llo"), a) + assert_equal(S("hello"), b) + + a = S("hello") + a.sub!(/([aeiou])/, S('<\1>')) + assert_equal(S("h<e>llo"), a) + + a = S("hello") + a.sub!(/./) { |s| s[0].to_s + S(' ')} + assert_equal(S("h ello"), a) + + a = S("hello") + a.sub!(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 } + assert_equal(S("HELL-o"), a) + + a=S("hello") + assert_nil(a.sub!(/X/, S('Y'))) + + r = S('X') + r.taint + a.sub!(/./, r) + assert_predicate(a, :tainted?) + end + + def test_succ + assert_equal(S("abd"), S("abc").succ) + assert_equal(S("z"), S("y").succ) + assert_equal(S("aaa"), S("zz").succ) + + assert_equal(S("124"), S("123").succ) + assert_equal(S("1000"), S("999").succ) + assert_equal(S("2.000"), S("1.999").succ) + + assert_equal(S("No.10"), S("No.9").succ) + assert_equal(S("2000aaa"), S("1999zzz").succ) + 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) + end + + def test_succ! + a = S("abc") + b = a.dup + assert_equal(S("abd"), a.succ!) + assert_equal(S("abd"), a) + assert_equal(S("abc"), b) + + a = S("y") + assert_equal(S("z"), a.succ!) + assert_equal(S("z"), a) + + a = S("zz") + assert_equal(S("aaa"), a.succ!) + assert_equal(S("aaa"), a) + + a = S("123") + assert_equal(S("124"), a.succ!) + assert_equal(S("124"), a) + + a = S("999") + assert_equal(S("1000"), a.succ!) + assert_equal(S("1000"), a) + + a = S("1999zzz") + assert_equal(S("2000aaa"), a.succ!) + assert_equal(S("2000aaa"), a) + + a = S("ZZZZ999") + assert_equal(S("AAAAA000"), a.succ!) + assert_equal(S("AAAAA000"), a) + + a = S("**") + assert_equal(S("*+"), a.succ!) + assert_equal(S("*+"), a) + + a = S("No.9") + assert_equal(S("No.10"), a.succ!) + assert_equal(S("No.10"), a) + + assert_equal("aaaaaaaaaaaa", "zzzzzzzzzzz".succ!) + assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", "zzzzzzzzzzzzzzzzzzzzzzz".succ!) + end + + def test_sum + n = S("\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001") + assert_equal(15, n.sum) + n += S("\001") + assert_equal(16, n.sum(17)) + n[0] = 2.chr + assert_not_equal(15, n.sum) + assert_equal(17, n.sum(0)) + assert_equal(17, n.sum(-1)) + end + + def check_sum(str, bits=16) + sum = 0 + str.each_byte {|c| sum += c} + sum = sum & ((1 << bits) - 1) if bits != 0 + assert_equal(sum, str.sum(bits)) + end + + def test_sum_2 + assert_equal(0, "".sum) + assert_equal(294, "abc".sum) + check_sum("abc") + check_sum("\x80") + -3.upto(70) {|bits| + check_sum("xyz", bits) + } + end + + def test_sum_long + s8421505 = "\xff" * 8421505 + assert_equal(127, s8421505.sum(31)) + assert_equal(2147483775, s8421505.sum(0)) + s16843010 = ("\xff" * 16843010) + assert_equal(254, s16843010.sum(32)) + assert_equal(4294967550, s16843010.sum(0)) + end + + def test_swapcase + assert_equal(S("hi&LOW"), S("HI&low").swapcase) + end + + def test_swapcase! + a = S("hi&LOW") + b = a.dup + assert_equal(S("HI&low"), a.swapcase!) + assert_equal(S("HI&low"), a) + assert_equal(S("hi&LOW"), b) + + a = S("$^#^%$#!!") + assert_nil(a.swapcase!) + assert_equal(S("$^#^%$#!!"), a) + end + + def test_to_f + assert_equal(344.3, S("344.3").to_f) + assert_equal(5.9742e24, S("5.9742e24").to_f) + assert_equal(98.6, S("98.6 degrees").to_f) + assert_equal(0.0, S("degrees 100.0").to_f) + assert_equal([ 0.0].pack('G'), [S(" 0.0").to_f].pack('G')) + assert_equal([-0.0].pack('G'), [S("-0.0").to_f].pack('G')) + end + + 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) } + 2.upto(36) {|radix| + assert_equal(radix, "10".to_i(radix)) + assert_equal(radix**2, "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)) + + 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} + end + + def test_to_s + a = S("me") + assert_equal("me", a.to_s) + assert_equal(a.__id__, a.to_s.__id__) if @cls == String + end + + def test_to_str + a = S("me") + assert_equal("me", a.to_s) + assert_equal(a.__id__, a.to_s.__id__) if @cls == String + + o = Object.new + def o.to_str + "at" + end + assert_equal("meat", a.concat(o)) + + o = Object.new + def o.to_str + foo_bar() + end + assert_match(/foo_bar/, assert_raise(NoMethodError) {a.concat(o)}.message) + end + + def test_tr + assert_equal(S("hippo"), S("hello").tr(S("el"), S("ip"))) + 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) + 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?) + + bug6156 = '[ruby-core:43335]' + str, range, star = %w[b a-z *].map{|s|s.encode("utf-16le")} + assert_equal(star, str.tr(range, star), bug6156) + end + + def test_tr! + a = S("hello") + b = a.dup + assert_equal(S("hippo"), a.tr!(S("el"), S("ip"))) + assert_equal(S("hippo"), a) + assert_equal(S("hello"),b) + + a = S("hello") + assert_equal(S("*e**o"), a.tr!(S("^aeiou"), S("*"))) + assert_equal(S("*e**o"), a) + + a = S("IBM") + assert_equal(S("HAL"), a.tr!(S("B-Z"), S("A-Z"))) + assert_equal(S("HAL"), a) + + a = S("ibm") + assert_nil(a.tr!(S("B-Z"), S("A-Z"))) + assert_equal(S("ibm"), a) + + a = "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 + + 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?) + end + + def test_tr_s! + a = S("hello") + b = a.dup + assert_equal(S("hypo"), a.tr_s!(S("el"), S("yp"))) + assert_equal(S("hypo"), a) + assert_equal(S("hello"), b) + + a = S("hello") + assert_equal(S("h*o"), a.tr_s!(S("el"), S("*"))) + assert_equal(S("h*o"), a) + end + + def test_unpack + a = [S("cat"), S("wom"), S("x"), S("yy")] + assert_equal(a, S("catwomx yy ").unpack(S("A3A3A3A3"))) + + assert_equal([S("cat")], S("cat \000\000").unpack(S("A*"))) + assert_equal([S("cwx"), S("wx"), S("x"), S("yy")], + S("cwx yy ").unpack(S("A3@1A3@2A3A3"))) + assert_equal([S("cat"), S("wom"), S("x\000\000"), S("yy\000")], + S("catwomx\000\000yy\000").unpack(S("a3a3a3a3"))) + assert_equal([S("cat \000\000")], S("cat \000\000").unpack(S("a*"))) + assert_equal([S("ca")], S("catdog").unpack(S("a2"))) + + assert_equal([S("cat\000\000")], + S("cat\000\000\000\000\000dog").unpack(S("a5"))) + + assert_equal([S("01100001")], S("\x61").unpack(S("B8"))) + assert_equal([S("01100001")], S("\x61").unpack(S("B*"))) + assert_equal([S("0110000100110111")], S("\x61\x37").unpack(S("B16"))) + assert_equal([S("01100001"), S("00110111")], S("\x61\x37").unpack(S("B8B8"))) + assert_equal([S("0110")], S("\x60").unpack(S("B4"))) + + assert_equal([S("01")], S("\x40").unpack(S("B2"))) + + assert_equal([S("01100001")], S("\x86").unpack(S("b8"))) + assert_equal([S("01100001")], S("\x86").unpack(S("b*"))) + + assert_equal([S("0110000100110111")], S("\x86\xec").unpack(S("b16"))) + assert_equal([S("01100001"), S("00110111")], S("\x86\xec").unpack(S("b8b8"))) + + assert_equal([S("0110")], S("\x06").unpack(S("b4"))) + assert_equal([S("01")], S("\x02").unpack(S("b2"))) + + assert_equal([ 65, 66, 67 ], S("ABC").unpack(S("C3"))) + assert_equal([ 255, 66, 67 ], S("\377BC").unpack("C*")) + assert_equal([ 65, 66, 67 ], S("ABC").unpack("c3")) + assert_equal([ -1, 66, 67 ], S("\377BC").unpack("c*")) + + + assert_equal([S("4142"), S("0a"), S("1")], S("AB\n\x10").unpack(S("H4H2H1"))) + assert_equal([S("1424"), S("a0"), S("2")], S("AB\n\x02").unpack(S("h4h2h1"))) + + assert_equal([S("abc\002defcat\001"), S(""), S("")], + S("abc=02def=\ncat=\n=01=\n").unpack(S("M9M3M4"))) + + assert_equal([S("hello\n")], S("aGVsbG8K\n").unpack(S("m"))) + + assert_equal([S("hello\nhello\n")], S(",:&5L;&\\*:&5L;&\\*\n").unpack(S("u"))) + + assert_equal([0xa9, 0x42, 0x2260], S("\xc2\xa9B\xe2\x89\xa0").unpack(S("U*"))) + +=begin + skipping "Not tested: + D,d & double-precision float, native format\\ + E & double-precision float, little-endian byte order\\ + e & single-precision float, little-endian byte order\\ + F,f & single-precision float, native format\\ + G & double-precision float, network (big-endian) byte order\\ + g & single-precision float, network (big-endian) byte order\\ + I & unsigned integer\\ + i & integer\\ + L & unsigned long\\ + l & long\\ + + m & string encoded in base64 (uuencoded)\\ + N & long, network (big-endian) byte order\\ + n & short, network (big-endian) byte-order\\ + P & pointer to a structure (fixed-length string)\\ + p & pointer to a null-terminated string\\ + S & unsigned short\\ + s & short\\ + V & long, little-endian byte order\\ + v & short, little-endian byte order\\ + X & back up a byte\\ + x & null byte\\ + Z & ASCII string (null padded, count is width)\\ +" +=end + end + + def test_upcase + assert_equal(S("HELLO"), S("hello").upcase) + assert_equal(S("HELLO"), S("hello").upcase) + assert_equal(S("HELLO"), S("HELLO").upcase) + assert_equal(S("ABC HELLO 123"), S("abc HELLO 123").upcase) + end + + def test_upcase! + a = S("hello") + b = a.dup + assert_equal(S("HELLO"), a.upcase!) + assert_equal(S("HELLO"), a) + assert_equal(S("hello"), b) + + a = S("HELLO") + assert_nil(a.upcase!) + assert_equal(S("HELLO"), a) + end + + def test_upto + a = S("aa") + start = S("aa") + count = 0 + assert_equal(S("aa"), a.upto(S("zz")) {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(676, count) + end + + def test_upto_numeric + a = S("00") + start = S("00") + count = 0 + assert_equal(S("00"), a.upto(S("23")) {|s| + assert_equal(start, s, "[ruby-dev:39361]") + assert_equal(Encoding::US_ASCII, s.encoding) + start.succ! + count += 1 + }) + assert_equal(24, count, "[ruby-dev:39361]") + end + + def test_upto_nonalnum + first = S("\u3041") + last = S("\u3093") + count = 0 + assert_equal(first, first.upto(last) {|s| + count += 1 + s.replace(last) + }) + assert_equal(83, count, "[ruby-dev:39626]") + end + + def test_mod_check + assert_raise(RuntimeError) { + s = "" + s.sub!(/\A/) { s.replace "z" * 2000; "zzz" } + } + end + + def test_frozen_check + assert_raise(RuntimeError) { + s = "" + s.sub!(/\A/) { s.freeze; "zzz" } + } + end + + class S2 < String + end + def test_str_new4 + s = (0..54).to_a.join # length = 100 + s2 = S2.new(s[10,90]) + s3 = s2[10,80] + assert_equal((10..54).to_a.to_a.join, s2) + assert_equal((15..54).to_a.to_a.join, s3) + end + + def test_rb_str_new4 + s = "a" * 100 + s2 = s[10,90] + assert_equal("a" * 90, s2) + s3 = s2[10,80] + assert_equal("a" * 80, s3) + end + + class StringLike + def initialize(str) + @str = str + end + + def to_str + @str + end + end + + def test_rb_str_to_str + assert_equal("ab", "a" + StringLike.new("b")) + end + + def test_rb_str_shared_replace + s = "a" * 100 + s.succ! + assert_equal("a" * 99 + "b", s) + s = "" + s.succ! + assert_equal("", s) + end + + def test_times + assert_raise(ArgumentError) { "a" * (-1) } + end + + def test_splice! + l = S("1234\n234\n34\n4\n") + assert_equal(S("1234\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]") + assert_equal(S("234\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]") + assert_equal(S("34\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]") + assert_equal(S("4\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]") + assert_nil(l.slice!(/\A.*\n/), "[ruby-dev:31665]") + end + + def test_times2 + s1 = '' + 100.times {|n| + s2 = "a" * n + assert_equal(s1, s2) + s1 << 'a' + } + + assert_raise(ArgumentError) { "foo" * (-1) } + end + + def test_respond_to + o = Object.new + 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) + end + + def test_match_method + assert_equal("bar", "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")) + x = nil + "foo".match(o, "bar", "baz") {|y| x = y } + assert_equal("foobarbaz", x) + + assert_raise(ArgumentError) { "foo".match } + end + + def test_clear + s = "foo" * 100 + s.clear + assert_equal("", s) + end + + def test_to_s_2 + c = Class.new(String) + s = c.new + s.replace("foo") + assert_equal("foo", s.to_s) + assert_instance_of(String, s.to_s) + end + + def test_inspect_nul + bug8290 = '[ruby-core:54458]' + s = "\0" + "12" + assert_equal '"\u000012"', s.inspect, bug8290 + 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) } + def (hyphen = Object.new).to_str; "-"; end + assert_equal(%w(foo - bar), "foo-bar".partition(hyphen), '[ruby-core:23540]') + + bug6206 = '[ruby-dev:45441]' + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + s = S("a:".force_encoding(enc)) + assert_equal([enc]*3, s.partition("|").map(&:encoding), bug6206) + end + + assert_equal(["\u30E6\u30FC\u30B6", "@", "\u30C9\u30E1.\u30A4\u30F3"], + "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".partition(/[@.]/)) + 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) } + def (hyphen = Object.new).to_str; "-"; end + assert_equal(%w(foo - bar), "foo-bar".rpartition(hyphen), '[ruby-core:23540]') + + bug6206 = '[ruby-dev:45441]' + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + s = S("a:".force_encoding(enc)) + assert_equal([enc]*3, s.rpartition("|").map(&:encoding), bug6206) + end + + bug8138 = '[ruby-dev:47183]' + assert_equal(["\u30E6\u30FC\u30B6@\u30C9\u30E1", ".", "\u30A4\u30F3"], + "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".rpartition(/[@.]/), bug8138) + end + + def test_setter + assert_raise(TypeError) { $/ = 1 } + name = "\u{5206 884c}" + assert_separately([], <<-"end;") # do + alias $#{name} $/ + assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 } + end; + end + + def test_to_id + c = Class.new + c.class_eval do + def initialize + @foo = :foo + end + end + + assert_raise(TypeError) do + c.class_eval { attr 1 } + end + + o = Object.new + def o.to_str; :foo; end + assert_raise(TypeError) do + c.class_eval { attr 1 } + end + + class << o;remove_method :to_str;end + def o.to_str; "foo"; end + assert_nothing_raised do + c.class_eval { attr o } + end + assert_equal(:foo, c.new.foo) + end + + def test_gsub_enumerator + assert_normal_exit %q{"abc".gsub(/./).next}, "[ruby-dev:34828]" + end + + def test_clear_nonasciicompat + assert_equal("", "\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")) + end + + def test_substr_negative_begin + assert_equal("\u3042", ("\u3042" * 100)[-1]) + end + +=begin + def test_compare_different_encoding_string + s1 = "\xff".force_encoding("UTF-8") + s2 = "\xff".force_encoding("ISO-2022-JP") + assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort) + end +=end + + def test_casecmp + assert_equal(1, "\u3042B".casecmp("\u3042a")) + end + + def test_upcase2 + assert_equal("\u3042AB", "\u3042aB".upcase) + end + + def test_downcase2 + assert_equal("\u3042ab", "\u3042aB".downcase) + end + + def test_rstrip + assert_equal("\u3042", "\u3042 ".rstrip) + assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip } + end + +=begin + def test_symbol_table_overflow + assert_in_out_err([], <<-INPUT, [], /symbol table overflow \(symbol [a-z]{8}\) \(RuntimeError\)/) + ("aaaaaaaa".."zzzzzzzz").each {|s| s.to_sym } + INPUT + end +=end + + def test_shared_force_encoding + s = "\u{3066}\u{3059}\u{3068}".gsub(//, '') + h = {} + h[s] = nil + k = h.keys[0] + assert_equal(s, k, '[ruby-dev:39068]') + assert_equal(Encoding::UTF_8, k.encoding, '[ruby-dev:39068]') + s.dup.force_encoding(Encoding::ASCII_8BIT).gsub(//, '') + k = h.keys[0] + assert_equal(s, k, '[ruby-dev:39068]') + assert_equal(Encoding::UTF_8, k.encoding, '[ruby-dev:39068]') + end + + def test_ascii_incomat_inspect + bug4081 = '[ruby-core:33283]' + [Encoding::UTF_16LE, Encoding::UTF_16BE, + Encoding::UTF_32LE, Encoding::UTF_32BE].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) + end + begin + verbose, $VERBOSE = $VERBOSE, nil + ext = Encoding.default_external + Encoding.default_external = "us-ascii" + $VERBOSE = verbose + i = "abc\"\\".force_encoding("utf-8").inspect + ensure + $VERBOSE = nil + Encoding.default_external = ext + $VERBOSE = verbose + end + assert_equal('"abc\\"\\\\"', i, bug4081) + end + + def test_dummy_inspect + assert_equal('"\e\x24\x42\x22\x4C\x22\x68\e\x28\x42"', + "\u{ffe2}\u{2235}".encode("cp50220").inspect) + end + + def test_prepend + assert_equal(S("hello world!"), "world!".prepend("hello ")) + + foo = Object.new + def foo.to_str + "b" + end + assert_equal(S("ba"), "a".prepend(foo)) + + a = S("world") + b = S("hello ") + a.prepend(b) + assert_equal(S("hello world"), a) + assert_equal(S("hello "), b) + end + + def u(str) + str.force_encoding(Encoding::UTF_8) + 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)) + + bug7954 = '[ruby-dev:47108]' + assert_equal(false, "\u3042".byteslice(0, 2).valid_encoding?, bug7954) + assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954) + end + + def test_unknown_string_option + str = nil + assert_nothing_raised(SyntaxError) do + eval(%{ + str = begin"hello"end + }) + end + assert_equal "hello", str + end + + def test_eq_tilde_can_be_overridden + assert_separately([], <<-RUBY) + class String + undef =~ + def =~(str) + "foo" + end + end + + assert_equal("foo", "" =~ //) + RUBY + end + + class Bug9581 < String + def =~ re; :foo end + end + + def test_regexp_match_subclass + s = Bug9581.new("abc") + r = /abc/ + assert_equal(:foo, s =~ r) + assert_equal(:foo, s.send(:=~, r)) + assert_equal(:foo, s.send(:=~, /abc/)) + assert_equal(:foo, s =~ /abc/, "should not use optimized instruction") + end + + 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 + a << "a" * 0x1_0000 + rescue NoMemoryError + end + end; + end if [0].pack("l!").bytesize < [nil].pack("p").bytesize + # enable only when string size range is smaller than memory space +end + +class TestString2 < TestString + def initialize(*args) + super + @cls = S2 + end +end diff --git a/jni/ruby/test/ruby/test_stringchar.rb b/jni/ruby/test/ruby/test_stringchar.rb new file mode 100644 index 0000000..7f7342c --- /dev/null +++ b/jni/ruby/test/ruby/test_stringchar.rb @@ -0,0 +1,181 @@ +require 'test/unit' + +class TestStringchar < Test::Unit::TestCase + def test_string + assert_equal("abcd", "abcd") + assert_match(/abcd/, "abcd") + assert_operator("abcd", :===, "abcd") + # compile time string concatenation + assert_equal("abcd", "ab" "cd") + assert_equal("22aacd44", "#{22}aa" "cd#{44}") + assert_equal("22aacd445566", "#{22}aa" "cd#{44}" "55" "#{66}") + assert_operator("abc", :!~, /^$/) + assert_operator("abc\n", :!~, /^$/) + assert_operator("abc", :!~, /^d*$/) + assert_equal(3, ("abc" =~ /d*$/)) + assert("" =~ /^$/) + assert("\n" =~ /^$/) + assert("a\n\n" =~ /^$/) + assert("abcabc" =~ /.*a/); assert_equal("abca", $&) + assert("abcabc" =~ /.*c/); assert_equal("abcabc", $&) + assert("abcabc" =~ /.*?a/); assert_equal("a", $&) + assert("abcabc" =~ /.*?c/); assert_equal("abc", $&) + assert(/(.|\n)*?\n(b|\n)/ =~ "a\nb\n\n"); assert_equal("a\nb", $&) + + assert(/^(ab+)+b/ =~ "ababb"); assert_equal("ababb", $&) + assert(/^(?:ab+)+b/ =~ "ababb"); assert_equal("ababb", $&) + assert(/^(ab+)+/ =~ "ababb"); assert_equal("ababb", $&) + assert(/^(?:ab+)+/ =~ "ababb"); assert_equal("ababb", $&) + + assert(/(\s+\d+){2}/ =~ " 1 2"); assert_equal(" 1 2", $&) + assert(/(?:\s+\d+){2}/ =~ " 1 2"); assert_equal(" 1 2", $&) + + x = <<END; +ABCD +ABCD +END + x.gsub!(/((.|\n)*?)B((.|\n)*?)D/m ,'\1\3') + assert_equal("AC\nAC\n", x) + + assert_match(/foo(?=(bar)|(baz))/, "foobar") + assert_match(/foo(?=(bar)|(baz))/, "foobaz") + + $foo = "abc" + assert_equal("abc = abc", "#$foo = abc") + assert_equal("abc = abc", "#{$foo} = abc") + + foo = "abc" + assert_equal("abc = abc", "#{foo} = abc") + + assert_equal('-----', '-' * 5) + assert_equal('-', '-' * 1) + assert_equal('', '-' * 0) + + foo = '-' + assert_equal('-----', foo * 5) + assert_equal('-', foo * 1) + assert_equal('', foo * 0) + + x = "a.gif" + assert_equal("gif", x.sub(/.*\.([^\.]+)$/, '\1')) + assert_equal("b.gif", x.sub(/.*\.([^\.]+)$/, 'b.\1')) + assert_equal("", x.sub(/.*\.([^\.]+)$/, '\2')) + assert_equal("ab", x.sub(/.*\.([^\.]+)$/, 'a\2b')) + assert_equal("<a.gif>", x.sub(/.*\.([^\.]+)$/, '<\&>')) + end + + def test_char + # character constants(assumes ASCII) + assert_equal(?a, "a"[0]) + assert_equal(?a, ?a) + assert_equal("\1", ?\C-a) + assert_equal("\341", ?\M-a) + assert_equal("\201", ?\M-\C-a) + assert_equal(?A, "a".upcase![0]) + assert_equal(?a, "A".downcase![0]) + assert_equal("ABC", "abc".tr!("a-z", "A-Z")) + assert_equal("ABC", "aabbcccc".tr_s!("a-z", "A-Z")) + assert_equal("abc", "abcc".squeeze!("a-z")) + assert_equal("ad", "abcd".delete!("bc")) + + x = "abcdef" + y = [ ?a, ?b, ?c, ?d, ?e, ?f ] + bad = false + x.each_byte {|i| + if i.chr != y.shift + bad = true + break + end + } + assert(!bad) + + s = "a string" + s[0..s.size]="another string" + assert_equal("another string", s) + + s = <<EOS +#{ +[1,2,3].join(",") +} +EOS + assert_equal("1,2,3\n", s) + assert_equal(926381, "Just".to_i(36)) + assert_equal(-23200231779, "-another".to_i(36)) + assert_equal("ruby", 1299022.to_s(36)) + assert_equal("-hacker", -1045307475.to_s(36)) + assert_equal(265419172580680477752431643787347, "Just_another_Ruby_hacker".to_i(36)) + assert_equal("-justanotherrubyhacker", -265419172580680477752431643787347.to_s(36)) + + a = [] + (0..255).each {|n| + ch = [n].pack("C") + a.push ch if /a#{Regexp.quote ch}b/x =~ "ab" + } + assert_equal(0, a.size) + end + + def test_bang + s = "aBc" + s.upcase + assert_equal("aBc", s) + s.upcase! + assert_equal("ABC", s) + + s = "aBc" + s.downcase + assert_equal("aBc", s) + s.downcase! + assert_equal("abc", s) + + s = "aBc" + s.swapcase + assert_equal("aBc", s) + s.swapcase! + assert_equal("AbC", s) + + s = "aBc" + s.capitalize + assert_equal("aBc", s) + s.capitalize! + assert_equal("Abc", s) + + s = "aBc" + s.tr("a-z", "A-Z") + assert_equal("aBc", s) + s.tr!("a-z", "A-Z") + assert_equal("ABC", s) + + s = "aaBBcc" + s.tr_s("a-z", "A-Z") + assert_equal("aaBBcc", s) + s.tr_s!("a-z", "A-Z") + assert_equal("ABBC", s) + + s = "aaBBcc" + s.squeeze("a-z") + assert_equal("aaBBcc", s) + s.squeeze!("a-z") + assert_equal("aBBc", s) + + s = "aaBBcc" + s.delete("a-z") + assert_equal("aaBBcc", s) + s.delete!("a-z") + assert_equal("BB", s) + end + + def test_dump + bug3996 = '[ruby-core:32935]' + Encoding.list.find_all {|enc| enc.ascii_compatible?}.each do |enc| + (0..256).map do |c| + begin + s = c.chr(enc) + rescue RangeError, ArgumentError + break + else + assert_not_match(/\0/, s.dump, bug3996) + end + end + end + end +end diff --git a/jni/ruby/test/ruby/test_struct.rb b/jni/ruby/test/ruby/test_struct.rb new file mode 100644 index 0000000..df859f7 --- /dev/null +++ b/jni/ruby/test/ruby/test_struct.rb @@ -0,0 +1,374 @@ +# -*- coding: us-ascii -*- +require 'test/unit' +require 'timeout' + +module TestStruct + def test_struct + struct_test = @Struct.new("Test", :foo, :bar) + assert_equal(@Struct::Test, struct_test) + + test = struct_test.new(1, 2) + assert_equal(1, test.foo) + assert_equal(2, test.bar) + assert_equal(1, test[0]) + assert_equal(2, test[1]) + + a, b = test.to_a + assert_equal(1, a) + assert_equal(2, b) + + test[0] = 22 + assert_equal(22, test.foo) + + test.bar = 47 + assert_equal(47, test.bar) + end + + # [ruby-dev:26247] more than 10 struct members causes segmentation fault + def test_morethan10members + list = %w( a b c d e f g h i j k l m n o p ) + until list.empty? + c = @Struct.new(* list.map {|ch| ch.intern }).new + list.each do |ch| + c.__send__(ch) + end + list.pop + end + end + + def test_small_structs + names = [:a, :b, :c, :d] + 1.upto(4) {|n| + fields = names[0, n] + klass = @Struct.new(*fields) + o = klass.new(*(0...n).to_a) + fields.each_with_index {|name, i| + assert_equal(i, o[name]) + } + o = klass.new(*(0...n).to_a.reverse) + fields.each_with_index {|name, i| + assert_equal(n-i-1, o[name]) + } + } + end + + def test_inherit + klass = @Struct.new(:a) + klass2 = Class.new(klass) + o = klass2.new(1) + assert_equal(1, o.a) + end + + def test_members + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal([:a], klass.members) + assert_equal([:a], o.members) + end + + def test_ref + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal(1, o[:a]) + assert_raise(NameError) { o[:b] } + end + + def test_set + klass = @Struct.new(:a) + o = klass.new(1) + o[:a] = 2 + assert_equal(2, o[:a]) + assert_raise(NameError) { o[:b] = 3 } + end + + def test_struct_new + assert_raise(NameError) { @Struct.new("foo") } + assert_nothing_raised { @Struct.new("Foo") } + @Struct.instance_eval { remove_const(:Foo) } + assert_nothing_raised { @Struct.new(:a) { } } + assert_raise(RuntimeError) { @Struct.new(:a) { raise } } + + assert_equal([:utime, :stime, :cutime, :cstime], Process.times.members) + end + + def test_initialize + klass = @Struct.new(:a) + assert_raise(ArgumentError) { klass.new(1, 2) } + end + + def test_each + klass = @Struct.new(:a, :b) + o = klass.new(1, 2) + assert_equal([1, 2], o.each.to_a) + end + + def test_each_pair + klass = @Struct.new(:a, :b) + o = klass.new(1, 2) + assert_equal([[:a, 1], [:b, 2]], o.each_pair.to_a) + bug7382 = '[ruby-dev:46533]' + a = [] + o.each_pair {|x| a << x} + assert_equal([[:a, 1], [:b, 2]], a, bug7382) + end + + def test_inspect + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal("#<struct a=1>", o.inspect) + o.a = o + assert_match(/^#<struct a=#<struct #<.*?>:...>>$/, o.inspect) + + @Struct.new("Foo", :a) + o = @Struct::Foo.new(1) + assert_equal("#<struct #@Struct::Foo a=1>", o.inspect) + @Struct.instance_eval { remove_const(:Foo) } + + klass = @Struct.new(:a, :b) + o = klass.new(1, 2) + assert_equal("#<struct a=1, b=2>", o.inspect) + + klass = @Struct.new(:@a) + o = klass.new(1) + assert_equal(1, o.__send__(:@a)) + assert_equal("#<struct :@a=1>", o.inspect) + o.__send__(:"@a=", 2) + assert_equal(2, o.__send__(:@a)) + assert_equal("#<struct :@a=2>", o.inspect) + o.__send__("@a=", 3) + assert_equal(3, o.__send__(:@a)) + assert_equal("#<struct :@a=3>", o.inspect) + + methods = klass.instance_methods(false) + assert_equal([:@a, :"@a="].inspect, methods.inspect, '[Bug #8756]') + assert_include(methods, :@a) + assert_include(methods, :"@a=") + end + + def test_init_copy + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal(o, o.dup) + end + + def test_aref + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal(1, o[0]) + assert_raise(IndexError) { o[-2] } + assert_raise(IndexError) { o[1] } + assert_raise_with_message(NameError, /foo/) {o["foo"]} + assert_raise_with_message(NameError, /foo/) {o[:foo]} + end + + def test_aset + klass = @Struct.new(:a) + o = klass.new(1) + o[0] = 2 + assert_equal(2, o[:a]) + assert_raise(IndexError) { o[-2] = 3 } + assert_raise(IndexError) { o[1] = 3 } + assert_raise_with_message(NameError, /foo/) {o["foo"] = 3} + assert_raise_with_message(NameError, /foo/) {o[:foo] = 3} + end + + def test_values_at + klass = @Struct.new(:a, :b, :c, :d, :e, :f) + o = klass.new(1, 2, 3, 4, 5, 6) + assert_equal([2, 4, 6], o.values_at(1, 3, 5)) + assert_equal([2, 3, 4, 3, 4, 5], o.values_at(1..3, 2...5)) + end + + def test_select + klass = @Struct.new(:a, :b, :c, :d, :e, :f) + o = klass.new(1, 2, 3, 4, 5, 6) + assert_equal([1, 3, 5], o.select {|v| v % 2 != 0 }) + assert_raise(ArgumentError) { o.select(1) } + end + + def test_big_struct + klass1 = @Struct.new(*('a'..'z').map(&:to_sym)) + o = klass1.new + assert_nil o.z + assert_equal(:foo, o.z = :foo) + assert_equal(:foo, o.z) + assert_equal(:foo, o[25]) + end + + def test_overridden_aset + bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by []= method' + + struct = Class.new(Struct.new(*(:a..:z), :result)) do + def []=(*args) + raise args.inspect + end + end + + obj = struct.new + assert_nothing_raised(RuntimeError, bug10601) do + obj.result = 42 + end + assert_equal(42, obj.result, bug10601) + end + + def test_overridden_aref + bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by [] method' + + struct = Class.new(Struct.new(*(:a..:z), :result)) do + def [](*args) + raise args.inspect + end + end + + obj = struct.new + obj.result = 42 + result = assert_nothing_raised(RuntimeError, bug10601) do + break obj.result + end + assert_equal(42, result, bug10601) + end + + def test_equal + klass1 = @Struct.new(:a) + klass2 = @Struct.new(:a, :b) + o1 = klass1.new(1) + o2 = klass1.new(1) + o3 = klass2.new(1) + assert_equal(o1, o2) + assert_not_equal(o1, o3) + end + + def test_hash + klass = @Struct.new(:a) + o = klass.new(1) + assert_kind_of(Fixnum, o.hash) + end + + def test_eql + klass1 = @Struct.new(:a) + klass2 = @Struct.new(:a, :b) + o1 = klass1.new(1) + o2 = klass1.new(1) + o3 = klass2.new(1) + assert_operator(o1, :eql?, o2) + assert_not_operator(o1, :eql?, o3) + end + + def test_size + klass = @Struct.new(:a) + o = klass.new(1) + assert_equal(1, o.size) + end + + def test_error + assert_raise(TypeError){ + @Struct.new(0) + } + end + + def test_redefinition_warning + @Struct.new("RedefinitionWarning") + e = EnvUtil.verbose_warning do + @Struct.new("RedefinitionWarning") + end + assert_match(/redefining constant #@Struct::RedefinitionWarning/, e) + end + + def test_nonascii + struct_test = @Struct.new("R\u{e9}sum\u{e9}", :"r\u{e9}sum\u{e9}") + assert_equal(@Struct.const_get("R\u{e9}sum\u{e9}"), struct_test, '[ruby-core:24849]') + a = struct_test.new(42) + assert_equal("#<struct #@Struct::R\u{e9}sum\u{e9} r\u{e9}sum\u{e9}=42>", a.inspect, '[ruby-core:24849]') + e = EnvUtil.verbose_warning do + @Struct.new("R\u{e9}sum\u{e9}", :"r\u{e9}sum\u{e9}") + end + assert_nothing_raised(Encoding::CompatibilityError) do + assert_match(/redefining constant #@Struct::R\u{e9}sum\u{e9}/, e) + end + end + + def test_junk + struct_test = @Struct.new("Foo", "a\000") + o = struct_test.new(1) + assert_equal(1, o.send("a\000")) + @Struct.instance_eval { remove_const(:Foo) } + end + + def test_comparison_when_recursive + klass1 = @Struct.new(:a, :b, :c) + + x = klass1.new(1, 2, nil); x.c = x + y = klass1.new(1, 2, nil); y.c = y + Timeout.timeout(1) { + assert_equal x, y + assert_operator x, :eql?, y + } + + z = klass1.new(:something, :other, nil); z.c = z + Timeout.timeout(1) { + assert_not_equal x, z + assert_not_operator x, :eql?, z + } + + x.c = y; y.c = x + Timeout.timeout(1) { + assert_equal x, y + assert_operator x, :eql?, y + } + + x.c = z; z.c = x + Timeout.timeout(1) { + assert_not_equal x, z + assert_not_operator x, :eql?, z + } + end + + def test_to_h + klass = @Struct.new(:a, :b, :c, :d, :e, :f) + o = klass.new(1, 2, 3, 4, 5, 6) + assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h) + end + + def test_question_mark_in_member + klass = @Struct.new(:a, :b?) + x = Object.new + o = klass.new("test", x) + assert_same(x, o.b?) + o.send("b?=", 42) + assert_equal(42, o.b?) + end + + def test_bang_mark_in_member + klass = @Struct.new(:a, :b!) + x = Object.new + o = klass.new("test", x) + assert_same(x, o.b!) + o.send("b!=", 42) + assert_equal(42, o.b!) + end + + def test_setter_method_returns_value + klass = @Struct.new(:a) + x = klass.new + assert_equal "[Bug #9353]", x.send(:a=, "[Bug #9353]") + end + + class TopStruct < Test::Unit::TestCase + include TestStruct + + def initialize(*) + super + @Struct = Struct + end + end + + class SubStruct < Test::Unit::TestCase + include TestStruct + SubStruct = Class.new(Struct) + + def initialize(*) + super + @Struct = SubStruct + end + end +end diff --git a/jni/ruby/test/ruby/test_super.rb b/jni/ruby/test/ruby/test_super.rb new file mode 100644 index 0000000..7d4048b --- /dev/null +++ b/jni/ruby/test/ruby/test_super.rb @@ -0,0 +1,528 @@ +require 'test/unit' + +class TestSuper < Test::Unit::TestCase + class Base + def single(a) a end + def double(a, b) [a,b] end + def array(*a) a end + def optional(a = 0) a end + def keyword(**a) a end + end + class Single1 < Base + def single(*) super end + end + class Single2 < Base + def single(a,*) super end + end + class Double1 < Base + def double(*) super end + end + class Double2 < Base + def double(a,*) super end + end + class Double3 < Base + def double(a,b,*) super end + end + class Array1 < Base + def array(*) super end + end + class Array2 < Base + def array(a,*) super end + end + class Array3 < Base + def array(a,b,*) super end + end + class Array4 < Base + def array(a,b,c,*) super end + end + class Optional1 < Base + def optional(a = 1) super end + end + class Optional2 < Base + def optional(a, b = 1) super end + end + class Optional3 < Base + def single(a = 1) super end + end + class Optional4 < Base + def array(a = 1, *) super end + end + class Optional5 < Base + def array(a = 1, b = 2, *) super end + end + class Keyword1 < Base + def keyword(foo: "keyword1") super end + end + class Keyword2 < Base + def keyword(foo: "keyword2") + foo = "changed1" + x = super + foo = "changed2" + y = super + [x, y] + end + end + + def test_single1 + assert_equal(1, Single1.new.single(1)) + end + def test_single2 + assert_equal(1, Single2.new.single(1)) + end + def test_double1 + assert_equal([1, 2], Double1.new.double(1, 2)) + end + def test_double2 + assert_equal([1, 2], Double2.new.double(1, 2)) + end + def test_double3 + assert_equal([1, 2], Double3.new.double(1, 2)) + end + def test_array1 + assert_equal([], Array1.new.array()) + assert_equal([1], Array1.new.array(1)) + end + def test_array2 + assert_equal([1], Array2.new.array(1)) + assert_equal([1,2], Array2.new.array(1, 2)) + end + def test_array3 + assert_equal([1,2], Array3.new.array(1, 2)) + assert_equal([1,2,3], Array3.new.array(1, 2, 3)) + end + def test_array4 + assert_equal([1,2,3], Array4.new.array(1, 2, 3)) + assert_equal([1,2,3,4], Array4.new.array(1, 2, 3, 4)) + end + def test_optional1 + assert_equal(9, Optional1.new.optional(9)) + assert_equal(1, Optional1.new.optional) + end + def test_optional2 + assert_raise(ArgumentError) do + # call Base#optional with 2 arguments; the 2nd arg is supplied + assert_equal(9, Optional2.new.optional(9)) + end + assert_raise(ArgumentError) do + # call Base#optional with 2 arguments + assert_equal(9, Optional2.new.optional(9, 2)) + end + end + def test_optional3 + assert_equal(9, Optional3.new.single(9)) + # call Base#single with 1 argument; the arg is supplied + assert_equal(1, Optional3.new.single) + end + def test_optional4 + assert_equal([1], Optional4.new.array) + assert_equal([9], Optional4.new.array(9)) + assert_equal([9, 8], Optional4.new.array(9, 8)) + end + def test_optional5 + assert_equal([1, 2], Optional5.new.array) + assert_equal([9, 2], Optional5.new.array(9)) + assert_equal([9, 8], Optional5.new.array(9, 8)) + assert_equal([9, 8, 7], Optional5.new.array(9, 8, 7)) + end + def test_keyword1 + assert_equal({foo: "keyword1"}, Keyword1.new.keyword) + bug8008 = '[ruby-core:53114] [Bug #8008]' + assert_equal({foo: bug8008}, Keyword1.new.keyword(foo: bug8008)) + end + def test_keyword2 + assert_equal([{foo: "changed1"}, {foo: "changed2"}], Keyword2.new.keyword) + end + + class A + def tt(aa) + "A#tt" + end + + def uu(a) + class << self + define_method(:tt) do |sym| + super(sym) + end + end + end + end + + def test_define_method + a = A.new + a.uu(12) + assert_equal("A#tt", a.tt(12), "[ruby-core:3856]") + assert_raise_with_message(RuntimeError, /implicit argument passing of super from method defined by define_method/, "[ruby-core:24244]") { + lambda { + Class.new { + define_method(:a) {super} + }.new.a + }.call + } + end + + class SubSeq + def initialize + @first=11 + @first or fail + end + + def subseq + @first or fail + end + end + + class Indexed + def subseq + SubSeq.new + end + end + + Overlaid = proc do + class << self + def subseq + super.instance_eval(& Overlaid) + end + end + end + + def test_overlaid + assert_nothing_raised('[ruby-dev:40959]') do + overlaid = proc do |obj| + def obj.reverse + super + end + end + overlaid.call(str = "123") + overlaid.call([1,2,3]) + str.reverse + end + + assert_nothing_raised('[ruby-core:27230]') do + mid=Indexed.new + mid.instance_eval(&Overlaid) + mid.subseq + mid.subseq + end + end + + module DoubleInclude + class Base + def foo + [:Base] + end + end + + module Override + def foo + super << :Override + end + end + + class A < Base + end + + class B < A + end + + B.send(:include, Override) + A.send(:include, Override) + end + + # [Bug #3351] + def test_double_include + assert_equal([:Base, :Override], DoubleInclude::B.new.foo) + # should be changed as follows? + # assert_equal([:Base, :Override, :Override], DoubleInclude::B.new.foo) + end + + module DoubleInclude2 + class Base + def foo + [:Base] + end + end + + module Override + def foo + super << :Override + end + end + + class A < Base + def foo + super << :A + end + end + + class B < A + def foo + super << :B + end + end + + B.send(:include, Override) + A.send(:include, Override) + end + + def test_double_include2 + assert_equal([:Base, :Override, :A, :Override, :B], + DoubleInclude2::B.new.foo) + end + + def test_super_in_instance_eval + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + def foo + x = Object.new + x.instance_eval do + super() + end + end + } + obj = sub_class.new + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do + obj.foo + end + end + + def test_super_in_instance_eval_with_define_method + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + define_method(:foo) do + x = Object.new + x.instance_eval do + super() + end + end + } + obj = sub_class.new + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do + obj.foo + end + end + + def test_super_in_orphan_block + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + def foo + lambda { super() } + end + } + obj = sub_class.new + assert_equal([:super, obj], obj.foo.call) + end + + def test_super_in_orphan_block_with_instance_eval + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + def foo + x = Object.new + x.instance_eval do + lambda { super() } + end + end + } + obj = sub_class.new + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do + obj.foo.call + end + end + + def test_yielding_super + a = Class.new { def yielder; yield; end } + x = Class.new { define_singleton_method(:hello) { 'hi' } } + y = Class.new(x) { + define_singleton_method(:hello) { + m = a.new + m.yielder { super() } + } + } + assert_equal 'hi', y.hello + end + + def test_super_in_thread + hoge = Class.new { + def bar; 'hoge'; end + } + foo = Class.new(hoge) { + def bar; Thread.new { super }.join.value; end + } + + assert_equal 'hoge', foo.new.bar + end + + def assert_super_in_block(type) + bug7064 = '[ruby-core:47680]' + assert_normal_exit "#{type} {super}", bug7064 + end + + def test_super_in_at_exit + assert_super_in_block("at_exit") + end + def test_super_in_END + assert_super_in_block("END") + end + + def test_super_in_BEGIN + assert_super_in_block("BEGIN") + end + + class X + def foo(*args) + args + end + end + + class Y < X + define_method(:foo) do |*args| + super(*args) + end + end + + def test_super_splat + # [ruby-list:49575] + y = Y.new + assert_equal([1, 2], y.foo(1, 2)) + assert_equal([1, false], y.foo(1, false)) + assert_equal([1, 2, 3, 4, 5], y.foo(1, 2, 3, 4, 5)) + assert_equal([false, true], y.foo(false, true)) + assert_equal([false, false], y.foo(false, false)) + assert_equal([1, 2, 3, false, 5], y.foo(1, 2, 3, false, 5)) + end + + def test_missing_super_in_method_module + bug9315 = '[ruby-core:59358] [Bug #9315]' + a = Module.new do + def foo + super + end + end + b = Class.new do + include a + end + assert_raise(NoMethodError, bug9315) do + b.new.method(:foo).call + end + end + + def test_module_super_in_method_module + bug9315 = '[ruby-core:59589] [Bug #9315]' + a = Module.new do + def foo + super + end + end + c = Class.new do + def foo + :ok + end + end + o = c.new.extend(a) + assert_nothing_raised(NoMethodError, bug9315) do + assert_equal(:ok, o.method(:foo).call, bug9315) + end + end + + def test_missing_super_in_module_unbound_method + bug9377 = '[ruby-core:59619] [Bug #9377]' + + a = Module.new do + def foo; super end + end + + m = a.instance_method(:foo).bind(Object.new) + assert_raise(NoMethodError, bug9377) do + m.call + end + end + + def test_super_in_module_unbound_method + bug9721 = '[ruby-core:61936] [Bug #9721]' + + a = Module.new do + def foo(result) + result << "A" + end + end + + b = Module.new do + def foo(result) + result << "B" + super + end + end + + um = b.instance_method(:foo) + + m = um.bind(Object.new.extend(a)) + result = [] + assert_nothing_raised(NoMethodError, bug9721) do + m.call(result) + end + assert_equal(%w[B A], result, bug9721) + + bug9740 = '[ruby-core:62017] [Bug #9740]' + + b.module_eval do + define_method(:foo) do |result| + um.bind(self).call(result) + end + end + + result.clear + o = Object.new.extend(a).extend(b) + assert_nothing_raised(NoMethodError, SystemStackError, bug9740) do + o.foo(result) + end + assert_equal(%w[B A], result, bug9721) + end + + def test_from_eval + bug10263 = '[ruby-core:65122] [Bug #10263a]' + a = Class.new do + def foo + "A" + end + end + b = Class.new(a) do + def foo + binding.eval("super") + end + end + assert_equal("A", b.new.foo, bug10263) + end + + def test_super_with_block + a = Class.new do + def foo + yield + end + end + + b = Class.new(a) do + def foo + super{ + "b" + } + end + end + + assert_equal "b", b.new.foo{"c"} + end +end diff --git a/jni/ruby/test/ruby/test_symbol.rb b/jni/ruby/test/ruby/test_symbol.rb new file mode 100644 index 0000000..ee29cd5 --- /dev/null +++ b/jni/ruby/test/ruby/test_symbol.rb @@ -0,0 +1,289 @@ +require 'test/unit' + +class TestSymbol < Test::Unit::TestCase + # [ruby-core:3573] + + def assert_eval_inspected(sym, valid = true) + n = sym.inspect + if valid + bug5136 = '[ruby-dev:44314]' + assert_not_match(/\A:"/, n, bug5136) + end + assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(n))} + end + + def test_inspect_invalid + # 2) Symbol#inspect sometimes returns invalid symbol representations: + assert_eval_inspected(:"!") + assert_eval_inspected(:"=", false) + assert_eval_inspected(:"0", false) + assert_eval_inspected(:"$1") + assert_eval_inspected(:"@1", false) + assert_eval_inspected(:"@@1", false) + assert_eval_inspected(:"@", false) + assert_eval_inspected(:"@@", false) + end + + def assert_inspect_evaled(n) + assert_nothing_raised(SyntaxError) {assert_equal(n, eval(n).inspect)} + end + + def test_inspect_suboptimal + # 3) Symbol#inspect sometimes returns suboptimal symbol representations: + assert_inspect_evaled(':foo') + assert_inspect_evaled(':foo!') + assert_inspect_evaled(':bar?') + assert_inspect_evaled(":<<") + assert_inspect_evaled(':>>') + assert_inspect_evaled(':<=') + assert_inspect_evaled(':>=') + assert_inspect_evaled(':=~') + assert_inspect_evaled(':==') + assert_inspect_evaled(':===') + assert_raise(SyntaxError) {eval ':='} + assert_inspect_evaled(':*') + assert_inspect_evaled(':**') + assert_raise(SyntaxError) {eval ':***'} + assert_inspect_evaled(':+') + assert_inspect_evaled(':-') + assert_inspect_evaled(':+@') + assert_inspect_evaled(':-@') + assert_inspect_evaled(':|') + assert_inspect_evaled(':^') + assert_inspect_evaled(':&') + assert_inspect_evaled(':/') + assert_inspect_evaled(':%') + assert_inspect_evaled(':~') + assert_inspect_evaled(':`') + assert_inspect_evaled(':[]') + assert_inspect_evaled(':[]=') + assert_raise(SyntaxError) {eval ':||'} + assert_raise(SyntaxError) {eval ':&&'} + assert_raise(SyntaxError) {eval ':['} + end + + def test_inspect_dollar + # 4) :$- always treats next character literally: + assert_raise(SyntaxError) {eval ':$-'} + assert_raise(SyntaxError) {eval ":$-\n"} + assert_raise(SyntaxError) {eval ":$- "} + assert_raise(SyntaxError) {eval ":$-#"} + assert_raise(SyntaxError) {eval ':$-('} + end + + def test_inspect_number + # 5) Inconsistency between :$0 and :$1? The first one is valid, but the + # latter isn't. + assert_inspect_evaled(':$0') + assert_inspect_evaled(':$1') + end + + def test_inspect + valid = %W{$a @a @@a < << <= <=> > >> >= =~ == === * ** + +@ - -@ + | ^ & / % ~ \` [] []= ! != !~ a a? a! a= A A? A! A=} + valid.each do |sym| + assert_equal(':' + sym, sym.intern.inspect) + end + + invalid = %w{$a? $a! $a= @a? @a! @a= @@a? @@a! @@a= =} + invalid.each do |sym| + assert_equal(':"' + sym + '"', sym.intern.inspect) + end + end + + def test_to_proc + assert_equal %w(1 2 3), (1..3).map(&:to_s) + [ + [], + [1], + [1, 2], + [1, [2, 3]], + ].each do |ary| + ary_id = ary.object_id + assert_equal ary_id, :object_id.to_proc.call(ary) + ary_ids = ary.collect{|x| x.object_id } + assert_equal ary_ids, ary.collect(&:object_id) + end + end + + def test_call + o = Object.new + def o.foo(x, y); x + y; end + + assert_equal(3, :foo.to_proc.call(o, 1, 2)) + assert_raise(ArgumentError) { :foo.to_proc.call } + end + + def m_block_given? + block_given? + end + + def m2_block_given?(m = nil) + if m + [block_given?, m.call(self)] + else + block_given? + end + end + + def test_block_given_to_proc + bug8531 = '[Bug #8531]' + m = :m_block_given?.to_proc + assert(!m.call(self), "#{bug8531} without block") + assert(m.call(self) {}, "#{bug8531} with block") + assert(!m.call(self), "#{bug8531} without block second") + end + + def test_block_persist_between_calls + bug8531 = '[Bug #8531]' + m2 = :m2_block_given?.to_proc + assert_equal([true, false], m2.call(self, m2) {}, "#{bug8531} nested with block") + assert_equal([false, false], m2.call(self, m2), "#{bug8531} nested without block") + end + + def test_succ + assert_equal(:fop, :foo.succ) + end + + def test_cmp + assert_equal(0, :FoO <=> :FoO) + assert_equal(-1, :FoO <=> :fOO) + assert_equal(1, :fOO <=> :FoO) + assert_nil(:foo <=> "foo") + end + + def test_casecmp + assert_equal(0, :FoO.casecmp(:fOO)) + assert_equal(1, :FoO.casecmp(:BaR)) + assert_equal(-1, :baR.casecmp(:FoO)) + assert_nil(:foo.casecmp("foo")) + end + + def test_length + assert_equal(3, :FoO.length) + assert_equal(3, :FoO.size) + end + + def test_empty + assert_equal(false, :FoO.empty?) + assert_equal(true, :"".empty?) + end + + def test_case + assert_equal(:FOO, :FoO.upcase) + assert_equal(:foo, :FoO.downcase) + assert_equal(:Foo, :foo.capitalize) + assert_equal(:fOo, :FoO.swapcase) + end + + def test_symbol_poped + assert_nothing_raised { eval('a = 1; :"#{ a }"; 1') } + end + + def test_ascii_incomat_inspect + [Encoding::UTF_16LE, Encoding::UTF_16BE, + Encoding::UTF_32LE, Encoding::UTF_32BE].each do |e| + assert_equal(':"abc"', "abc".encode(e).to_sym.inspect) + assert_equal(':"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).to_sym.inspect) + end + end + + def test_symbol_encoding + assert_equal(Encoding::US_ASCII, "$-A".force_encoding("iso-8859-15").intern.encoding) + assert_equal(Encoding::US_ASCII, "foobar~!".force_encoding("iso-8859-15").intern.encoding) + assert_equal(Encoding::UTF_8, "\u{2192}".intern.encoding) + assert_raise(EncodingError) {"\xb0a".force_encoding("utf-8").intern} + end + + def test_singleton_method + assert_raise(TypeError) { a = :foo; def a.foo; end } + end + + SymbolsForEval = [ + :foo, + "dynsym_#{Random.rand(10000)}_#{Time.now}".to_sym + ] + + def test_instance_eval + bug11086 = '[ruby-core:68961] [Bug #11086]' + SymbolsForEval.each do |sym| + assert_nothing_raised(TypeError, sym, bug11086) { + sym.instance_eval {} + } + assert_raise(TypeError, sym, bug11086) { + sym.instance_eval {def foo; end} + } + end + end + + def test_instance_exec + bug11086 = '[ruby-core:68961] [Bug #11086]' + SymbolsForEval.each do |sym| + assert_nothing_raised(TypeError, sym, bug11086) { + sym.instance_exec {} + } + assert_raise(TypeError, sym, bug11086) { + sym.instance_exec {def foo; end} + } + end + end + + def test_frozen_symbol + assert_equal(true, :foo.frozen?) + assert_equal(true, :each.frozen?) + assert_equal(true, :+.frozen?) + assert_equal(true, "foo#{Time.now.to_i}".to_sym.frozen?) + assert_equal(true, :foo.to_sym.frozen?) + end + + def test_symbol_gc_1 + assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;".".intern]', + '', + child_env: '--disable-gems') + assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;:"."]', + '', + child_env: '--disable-gems') + assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;%i"."]', + '', + child_env: '--disable-gems') + assert_normal_exit('tap{".".intern};GC.start(immediate_sweep:false);' + + 'eval %[syms=Symbol.all_symbols;GC.start;syms.each(&:to_sym)]', + '', + child_env: '--disable-gems') + end + + def test_dynamic_attrset_id + bug10259 = '[ruby-dev:48559] [Bug #10259]' + class << (obj = Object.new) + attr_writer :unagi + end + assert_nothing_raised(NoMethodError, bug10259) {obj.send("unagi=".intern, 1)} + end + + def test_symbol_fstr_leak + bug10686 = '[ruby-core:67268] [Bug #10686]' + x = 0 + assert_no_memory_leak([], '', <<-"end;", bug10686, limit: 1.65) + 200_000.times { |i| i.to_s.to_sym } + end; + end + + def test_hash_redefinition + assert_separately([], <<-'end;') + bug11035 = '[ruby-core:68767] [Bug #11035]' + class Symbol + def hash + raise + end + end + + h = {} + assert_nothing_raised(RuntimeError, bug11035) { + h[:foo] = 1 + } + assert_nothing_raised(RuntimeError, bug11035) { + h['bar'.to_sym] = 2 + } + end; + end +end diff --git a/jni/ruby/test/ruby/test_syntax.rb b/jni/ruby/test/ruby/test_syntax.rb new file mode 100644 index 0000000..8df641d --- /dev/null +++ b/jni/ruby/test/ruby/test_syntax.rb @@ -0,0 +1,622 @@ +require 'test/unit' + +class TestSyntax < Test::Unit::TestCase + def assert_syntax_files(test) + srcdir = File.expand_path("../../..", __FILE__) + srcdir = File.join(srcdir, test) + assert_separately(%W[--disable-gem - #{srcdir}], + __FILE__, __LINE__, <<-'eom', timeout: Float::INFINITY) + dir = ARGV.shift + for script in Dir["#{dir}/**/*.rb"].sort + assert_valid_syntax(IO::read(script), script) + end + eom + end + + def test_syntax_lib; assert_syntax_files("lib"); end + def test_syntax_sample; assert_syntax_files("sample"); end + def test_syntax_ext; assert_syntax_files("ext"); end + def test_syntax_test; assert_syntax_files("test"); end + + def test_defined_empty_argument + bug8220 = '[ruby-core:53999] [Bug #8220]' + assert_ruby_status(%w[--disable-gem], 'puts defined? ()', bug8220) + end + + def test_must_ascii_compatible + require 'tempfile' + f = Tempfile.new("must_ac_") + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + make_tmpsrc(f, "# -*- coding: #{enc.name} -*-") + assert_nothing_raised(ArgumentError, enc.name) {load(f.path)} + end + Encoding.list.each do |enc| + next if enc.ascii_compatible? + make_tmpsrc(f, "# -*- coding: #{enc.name} -*-") + assert_raise(ArgumentError, enc.name) {load(f.path)} + end + ensure + f.close! if f + end + + def test_script_lines + require 'tempfile' + f = Tempfile.new("bug4361_") + bug4361 = '[ruby-dev:43168]' + with_script_lines do |debug_lines| + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + make_tmpsrc(f, "# -*- coding: #{enc.name} -*-\n#----------------") + load(f.path) + assert_equal([f.path], debug_lines.keys) + assert_equal([enc, enc], debug_lines[f.path].map(&:encoding), bug4361) + end + end + ensure + f.close! if f + end + + def test_newline_in_block_parameters + bug = '[ruby-dev:45292]' + ["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params| + params = ["|", *params, "|"].join("\n") + assert_valid_syntax("1.times{#{params}}", __FILE__, "#{bug} #{params.inspect}") + end + end + + tap do |_, + bug6115 = '[ruby-dev:45308]', + blockcall = '["elem"].each_with_object [] do end', + methods = [['map', 'no'], ['inject([])', 'with']], + blocks = [['do end', 'do'], ['{}', 'brace']], + *| + [%w'. dot', %w':: colon'].product(methods, blocks) do |(c, n1), (m, n2), (b, n3)| + m = m.tr_s('()', ' ').strip if n2 == 'do' + name = "test_#{n3}_block_after_blockcall_#{n1}_#{n2}_arg" + code = "#{blockcall}#{c}#{m} #{b}" + define_method(name) {assert_valid_syntax(code, bug6115)} + end + end + + def test_do_block_in_cmdarg + bug9726 = '[ruby-core:61950] [Bug #9726]' + assert_valid_syntax("tap (proc do end)", __FILE__, bug9726) + end + + def test_keyword_rest + bug5989 = '[ruby-core:42455]' + assert_valid_syntax("def kwrest_test(**a) a; end", __FILE__, bug5989) + assert_valid_syntax("def kwrest_test2(**a, &b) end", __FILE__, bug5989) + o = Object.new + def o.kw(**a) a end + assert_equal({}, o.kw, bug5989) + assert_equal({foo: 1}, o.kw(foo: 1), bug5989) + assert_equal({foo: 1, bar: 2}, o.kw(foo: 1, bar: 2), bug5989) + EnvUtil.under_gc_stress do + eval("def o.m(k: 0) k end") + end + assert_equal(42, o.m(k: 42), '[ruby-core:45744]') + bug7922 = '[ruby-core:52744] [Bug #7922]' + def o.bug7922(**) end + assert_nothing_raised(ArgumentError, bug7922) {o.bug7922(foo: 42)} + end + + def test_keyword_splat + assert_valid_syntax("foo(**h)", __FILE__) + o = Object.new + def o.kw(k1: 1, k2: 2) [k1, k2] end + h = {k1: 11, k2: 12} + assert_equal([11, 12], o.kw(**h)) + assert_equal([11, 12], o.kw(k2: 22, **h)) + assert_equal([11, 22], o.kw(**h, **{k2: 22})) + assert_equal([11, 12], o.kw(**{k2: 22}, **h)) + + bug10315 = '[ruby-core:65368] [Bug #10315]' + assert_equal([23, 2], o.kw(**{k1: 22}, **{k1: 23}), bug10315) + + h = {k3: 31} + assert_raise(ArgumentError) {o.kw(**h)} + h = {"k1"=>11, k2: 12} + assert_raise(TypeError) {o.kw(**h)} + + bug10315 = '[ruby-core:65625] [Bug #10315]' + a = [] + def a.add(x) push(x); x; end + def a.f(k:) k; end + a.clear + r = nil + assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), k: a.add(2))")} + assert_equal(2, r) + assert_equal([1, 2], a, bug10315) + a.clear + r = nil + assert_warn(/duplicated/) {r = eval("a.f({k: a.add(1), k: a.add(2)})")} + assert_equal(2, r) + assert_equal([1, 2], a, bug10315) + end + + def test_keyword_empty_splat + assert_separately([], <<-'end;') + bug10719 = '[ruby-core:67446] [Bug #10719]' + assert_valid_syntax("foo(a: 1, **{})", bug10719) + end; + end + + def test_keyword_self_reference + bug9593 = '[ruby-core:61299] [Bug #9593]' + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var: defined?(var)) var end") + end + assert_equal(42, o.foo(var: 42)) + assert_equal("local-variable", o.foo, bug9593) + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var: var) var end") + end + assert_nil(o.foo, bug9593) + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var: bar(var)) var end") + end + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var: bar {var}) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("def foo(var: bar {|var| var}) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("def foo(var: def bar(var) var; end) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("proc {|var: 1| var}") + end + end + + def test_optional_self_reference + bug9593 = '[ruby-core:61299] [Bug #9593]' + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = defined?(var)) var end") + end + assert_equal(42, o.foo(42)) + assert_equal("local-variable", o.foo, bug9593) + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = var) var end") + end + assert_nil(o.foo, bug9593) + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = bar(var)) var end") + end + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = bar {var}) var end") + end + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = (def bar;end; var)) var end") + end + + o = Object.new + assert_warn(/circular argument reference - var/) do + o.instance_eval("def foo(var = (def self.bar;end; var)) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("def foo(var = bar {|var| var}) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("def foo(var = def bar(var) var; end) var end") + end + + o = Object.new + assert_warn("") do + o.instance_eval("proc {|var = 1| var}") + end + end + + def test_warn_grouped_expression + bug5214 = '[ruby-core:39050]' + assert_warning("", bug5214) do + assert_valid_syntax("foo \\\n(\n true)", "test", verbose: true) + end + end + + def test_warn_unreachable + assert_warning("test:3: warning: statement not reached\n") do + code = "loop do\n" "break\n" "foo\n" "end" + assert_valid_syntax(code, "test", verbose: true) + end + end + + def test_warn_balanced + warning = <<WARN +test:1: warning: `%s' after local variable or literal is interpreted as binary operator +test:1: warning: even though it seems like %s +WARN + [ + [:**, "argument prefix"], + [:*, "argument prefix"], + [:<<, "here document"], + [:&, "argument prefix"], + [:+, "unary operator"], + [:-, "unary operator"], + [:/, "regexp literal"], + [:%, "string literal"], + ].each do |op, syn| + assert_warning(warning % [op, syn]) do + assert_valid_syntax("puts 1 #{op}0", "test", verbose: true) + end + end + end + + def test_cmd_symbol_after_keyword + bug6347 = '[ruby-dev:45563]' + assert_not_label(:foo, 'if true then not_label:foo end', bug6347) + assert_not_label(:foo, 'if false; else not_label:foo end', bug6347) + assert_not_label(:foo, 'begin not_label:foo end', bug6347) + assert_not_label(:foo, 'begin ensure not_label:foo end', bug6347) + end + + def test_cmd_symbol_in_string + bug6347 = '[ruby-dev:45563]' + assert_not_label(:foo, '"#{not_label:foo}"', bug6347) + end + + def test_cmd_symbol_singleton_class + bug6347 = '[ruby-dev:45563]' + @not_label = self + assert_not_label(:foo, 'class << not_label:foo; end', bug6347) + end + + def test_cmd_symbol_superclass + bug6347 = '[ruby-dev:45563]' + @not_label = Object + assert_not_label(:foo, 'class Foo < not_label:foo; end', bug6347) + end + + def test_duplicated_arg + assert_syntax_error("def foo(a, a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_, _) end } + end + + def test_duplicated_rest + assert_syntax_error("def foo(a, *a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_, *_) end } + end + + def test_duplicated_opt + assert_syntax_error("def foo(a, a=1) end", /duplicated argument name/) + assert_nothing_raised { def foo(_, _=1) end } + end + + def test_duplicated_opt_rest + assert_syntax_error("def foo(a=1, *a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_=1, *_) end } + end + + def test_duplicated_rest_opt + assert_syntax_error("def foo(*a, a=1) end", /duplicated argument name/) + end + + def test_duplicated_rest_post + assert_syntax_error("def foo(*a, a) end", /duplicated argument name/) + end + + def test_duplicated_opt_post + assert_syntax_error("def foo(a=1, a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_=1, _) end } + end + + def test_duplicated_kw + assert_syntax_error("def foo(a, a: 1) end", /duplicated argument name/) + assert_nothing_raised { def foo(_, _: 1) end } + end + + def test_duplicated_rest_kw + assert_syntax_error("def foo(*a, a: 1) end", /duplicated argument name/) + assert_nothing_raised {def foo(*_, _: 1) end} + end + + def test_duplicated_opt_kw + assert_syntax_error("def foo(a=1, a: 1) end", /duplicated argument name/) + assert_nothing_raised { def foo(_=1, _: 1) end } + end + + def test_duplicated_kw_kwrest + assert_syntax_error("def foo(a: 1, **a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_: 1, **_) end } + end + + def test_duplicated_rest_kwrest + assert_syntax_error("def foo(*a, **a) end", /duplicated argument name/) + assert_nothing_raised { def foo(*_, **_) end } + end + + def test_duplicated_opt_kwrest + assert_syntax_error("def foo(a=1, **a) end", /duplicated argument name/) + assert_nothing_raised { def foo(_=1, **_) end } + end + + def test_duplicated_when + w = 'warning: duplicated when clause is ignored' + assert_warning(/3: #{w}.+4: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){ + eval %q{ + case 1 + when 1, 1 + when 1, 1 + when 1, 1 + end + } + } + assert_warning(/#{w}/){#/3: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){ + a = 1 + eval %q{ + case 1 + when 1, 1 + when 1, a + when 1, 1 + end + } + } + end + + def test_invalid_next + assert_syntax_error("def m; next; end", /Invalid next/) + end + + def test_lambda_with_space + feature6390 = '[ruby-dev:45605]' + assert_valid_syntax("-> (x, y) {}", __FILE__, feature6390) + end + + def test_do_block_in_cmdarg_begin + bug6419 = '[ruby-dev:45631]' + assert_valid_syntax("p begin 1.times do 1 end end", __FILE__, bug6419) + end + + def test_do_block_in_call_args + bug9308 = '[ruby-core:59342] [Bug #9308]' + assert_valid_syntax("bar def foo; self.each do end end", bug9308) + end + + def test_do_block_in_lambda + bug11107 = '[ruby-core:69017] [Bug #11107]' + assert_valid_syntax('p ->() do a() do end end', bug11107) + end + + def test_do_block_after_lambda + bug11380 = '[ruby-core:70067] [Bug #11380]' + assert_valid_syntax('p -> { :hello }, a: 1 do end', bug11380) + end + + def test_reserved_method_no_args + bug6403 = '[ruby-dev:45626]' + assert_valid_syntax("def self; :foo; end", __FILE__, bug6403) + end + + def test_unassignable + gvar = global_variables + %w[self nil true false __FILE__ __LINE__ __ENCODING__].each do |kwd| + assert_raise(SyntaxError) {eval("#{kwd} = nil")} + assert_equal(gvar, global_variables) + end + end + + Bug7559 = '[ruby-dev:46737]' + + def test_lineno_command_call_quote + expected = __LINE__ + 1 + actual = caller_lineno "a +b +c +d +e" + assert_equal(expected, actual, "#{Bug7559}: ") + end + + def test_lineno_after_heredoc + bug7559 = '[ruby-dev:46737]' + expected, _, actual = __LINE__, <<eom, __LINE__ + a + b + c + d +eom + assert_equal(expected, actual, bug7559) + end + + def test_lineno_operation_brace_block + expected = __LINE__ + 1 + actual = caller_lineno\ + {} + assert_equal(expected, actual) + end + + def assert_constant_reassignment_nested(preset, op, expected, err = [], bug = '[Bug #5449]') + [ + ["p ", ""], # no-pop + ["", "p Foo::Bar"], # pop + ].each do |p1, p2| + src = <<-EOM.gsub(/^\s*\n/, '') + class Foo + #{"Bar = " + preset if preset} + end + #{p1}Foo::Bar #{op}= 42 + #{p2} + EOM + msg = "\# #{bug}\n#{src}" + assert_valid_syntax(src, caller_locations(1, 1)[0].path, msg) + assert_in_out_err([], src, expected, err, msg) + end + end + + def test_constant_reassignment_nested + already = /already initialized constant Foo::Bar/ + uninitialized = /uninitialized constant Foo::Bar/ + assert_constant_reassignment_nested(nil, "||", %w[42]) + assert_constant_reassignment_nested("false", "||", %w[42], already) + assert_constant_reassignment_nested("true", "||", %w[true]) + assert_constant_reassignment_nested(nil, "&&", [], uninitialized) + assert_constant_reassignment_nested("false", "&&", %w[false]) + assert_constant_reassignment_nested("true", "&&", %w[42], already) + assert_constant_reassignment_nested(nil, "+", [], uninitialized) + assert_constant_reassignment_nested("false", "+", [], /undefined method/) + assert_constant_reassignment_nested("11", "+", %w[53], already) + end + + def assert_constant_reassignment_toplevel(preset, op, expected, err = [], bug = '[Bug #5449]') + [ + ["p ", ""], # no-pop + ["", "p ::Bar"], # pop + ].each do |p1, p2| + src = <<-EOM.gsub(/^\s*\n/, '') + #{"Bar = " + preset if preset} + class Foo + #{p1}::Bar #{op}= 42 + #{p2} + end + EOM + msg = "\# #{bug}\n#{src}" + assert_valid_syntax(src, caller_locations(1, 1)[0].path, msg) + assert_in_out_err([], src, expected, err, msg) + end + end + + def test_constant_reassignment_toplevel + already = /already initialized constant Bar/ + uninitialized = /uninitialized constant Bar/ + assert_constant_reassignment_toplevel(nil, "||", %w[42]) + assert_constant_reassignment_toplevel("false", "||", %w[42], already) + assert_constant_reassignment_toplevel("true", "||", %w[true]) + assert_constant_reassignment_toplevel(nil, "&&", [], uninitialized) + assert_constant_reassignment_toplevel("false", "&&", %w[false]) + assert_constant_reassignment_toplevel("true", "&&", %w[42], already) + assert_constant_reassignment_toplevel(nil, "+", [], uninitialized) + assert_constant_reassignment_toplevel("false", "+", [], /undefined method/) + assert_constant_reassignment_toplevel("11", "+", %w[53], already) + end + + def test_integer_suffix + ["1if true", "begin 1end"].each do |src| + assert_valid_syntax(src) + assert_equal(1, eval(src), src) + end + end + + def test_value_of_def + assert_separately [], <<-EOS + assert_equal(:foo, (def foo; end)) + assert_equal(:foo, (def (Object.new).foo; end)) + EOS + end + + def test_heredoc_cr + assert_syntax_error("puts <<""EOS\n""ng\n""EOS\r""NO\n", /can't find string "EOS" anywhere before EOF/) + end + + def test__END___cr + assert_syntax_error("__END__\r<<<<<\n", /unexpected <</) + end + + def test_warning_for_cr + feature8699 = '[ruby-core:56240] [Feature #8699]' + assert_warning(/encountered \\r/, feature8699) do + eval("\r""__id__\r") + end + end + + def test_unexpected_fraction + msg = /unexpected fraction/ + assert_syntax_error("0x0.0", msg) + assert_syntax_error("0b0.0", msg) + assert_syntax_error("0d0.0", msg) + assert_syntax_error("0o0.0", msg) + assert_syntax_error("0.0.0", msg) + end + + def test_error_message_encoding + bug10114 = '[ruby-core:64228] [Bug #10114]' + code = "# -*- coding: utf-8 -*-\n" "def n \"\u{2208}\"; end" + assert_syntax_error(code, /def n "\u{2208}"; end/, bug10114) + end + + def test_bad_kwarg + bug10545 = '[ruby-dev:48742] [Bug #10545]' + src = 'def foo(A: a) end' + assert_syntax_error(src, /formal argument/, bug10545) + end + + def test_null_range_cmdarg + bug10957 = '[ruby-core:68477] [Bug #10957]' + assert_ruby_status(['-c', '-e', 'p ()..0'], "", bug10957) + assert_ruby_status(['-c', '-e', 'p ()...0'], "", bug10957) + assert_syntax_error('0..%w.', /unterminated string/, bug10957) + assert_syntax_error('0...%w.', /unterminated string/, bug10957) + end + + def test_too_big_nth_ref + bug11192 = '[ruby-core:69393] [Bug #11192]' + assert_warn(/too big/, bug11192) do + eval('$99999999999999999') + end + end + + private + + def not_label(x) @result = x; @not_label ||= nil end + def assert_not_label(expected, src, message = nil) + @result = nil + assert_nothing_raised(SyntaxError, message) {eval(src)} + assert_equal(expected, @result, message) + end + + def make_tmpsrc(f, src) + f.open + f.truncate(0) + f.puts(src) + f.close + end + + def with_script_lines + script_lines = nil + debug_lines = {} + Object.class_eval do + if defined?(SCRIPT_LINES__) + script_lines = SCRIPT_LINES__ + remove_const :SCRIPT_LINES__ + end + const_set(:SCRIPT_LINES__, debug_lines) + end + yield debug_lines + ensure + Object.class_eval do + remove_const :SCRIPT_LINES__ + const_set(:SCRIPT_LINES__, script_lines) if script_lines + end + end + + def caller_lineno(*) + caller_locations(1, 1)[0].lineno + end +end diff --git a/jni/ruby/test/ruby/test_system.rb b/jni/ruby/test/ruby/test_system.rb new file mode 100644 index 0000000..b328cbc --- /dev/null +++ b/jni/ruby/test/ruby/test_system.rb @@ -0,0 +1,162 @@ +require 'test/unit' +require 'tmpdir' + +class TestSystem < Test::Unit::TestCase + def test_system + ruby = EnvUtil.rubybin + assert_equal("foobar\n", `echo foobar`) + assert_equal('foobar', `#{ruby} -e 'print "foobar"'`) + + Dir.mktmpdir("ruby_script_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}" + + tmp = open(tmpfilename, "w") + tmp.print "print $zzz\n"; + tmp.close + + assert_equal('true', `#{ruby} -s #{tmpfilename} -zzz`) + assert_equal('555', `#{ruby} -s #{tmpfilename} -zzz=555`) + + tmp = open(tmpfilename, "w") + tmp.print "#! /usr/local/bin/ruby -s\n"; + tmp.print "print $zzz\n"; + tmp.close + + assert_equal('678', `#{ruby} #{tmpfilename} -zzz=678`) + + tmp = open(tmpfilename, "w") + tmp.print "this is a leading junk\n"; + tmp.print "#! /usr/local/bin/ruby -s\n"; + tmp.print "print $zzz if defined? $zzz\n"; + tmp.print "__END__\n"; + tmp.print "this is a trailing junk\n"; + tmp.close + + assert_equal('', `#{ruby} -x #{tmpfilename}`) + assert_equal('555', `#{ruby} -x #{tmpfilename} -zzz=555`) + + tmp = open(tmpfilename, "w") + tmp.print "#! /non/exist\\interpreter?/./to|be:ignored\n"; + tmp.print "this is a leading junk\n"; + tmp.print "#! /usr/local/bin/ruby -s\n"; + tmp.print "print $zzz if defined? $zzz\n"; + tmp.print "__END__\n"; + tmp.print "this is a trailing junk\n"; + tmp.close + + assert_equal('', `#{ruby} #{tmpfilename}`) + assert_equal('555', `#{ruby} #{tmpfilename} -zzz=555`) + + tmp = open(tmpfilename, "w") + for i in 1..5 + tmp.print i, "\n" + end + tmp.close + + `#{ruby} -i.bak -pe '$_.sub!(/^[0-9]+$/){$&.to_i * 5}' #{tmpfilename}` + tmp = open(tmpfilename, "r") + while tmp.gets + assert_equal(0, $_.to_i % 5) + end + tmp.close + + File.unlink tmpfilename or `/bin/rm -f "#{tmpfilename}"` + File.unlink "#{tmpfilename}.bak" or `/bin/rm -f "#{tmpfilename}.bak"` + + if /mswin|mingw/ =~ RUBY_PLATFORM + testname = '[ruby-dev:38588]' + batch = "batch_tmp.#{$$}" + tmpfilename = "#{tmpdir}/#{batch}.bat" + open(tmpfilename, "wb") {|f| f.print "\r\n"} + assert(system(tmpfilename), testname) + assert(system("#{tmpdir}/#{batch}"), testname) + assert(system(tmpfilename, "1"), testname) + assert(system("#{tmpdir}/#{batch}", "1"), testname) + begin + path = ENV["PATH"] + ENV["PATH"] = "#{tmpdir.tr(File::SEPARATOR, File::ALT_SEPARATOR)}#{File::PATH_SEPARATOR + path if path}" + assert(system("#{batch}.bat"), testname) + assert(system(batch), testname) + assert(system("#{batch}.bat", "1"), testname) + assert(system(batch, "1"), testname) + ensure + ENV["PATH"] = path + end + File.unlink tmpfilename + + testname = '[ruby-core:44505]' + assert_match(/Windows/, `ver`, testname) + assert_equal 0, $?.to_i, testname + end + } + end + + def test_system_at + if /mswin|mingw/ =~ RUBY_PLATFORM + bug4393 = '[ruby-core:35218]' + + # @ + builtin command + assert_equal("foo\n", `@echo foo`, bug4393); + assert_equal("foo\n", `@@echo foo`, bug4393); + assert_equal("@@foo\n", `@@echo @@foo`, bug4393); + + # @ + non builtin command + Dir.mktmpdir("ruby_script_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}" + + tmp = open(tmpfilename, "w") + tmp.print "foo\nbar\nbaz\n@foo"; + tmp.close + + assert_match(/\Abar\nbaz\n?\z/, `@@findstr "ba" #{tmpfilename.gsub("/", "\\")}`, bug4393); + } + end + end + + def test_system_redirect_win + if /mswin|mingw/ !~ RUBY_PLATFORM + return + end + + Dir.mktmpdir("ruby_script_tmp") do |tmpdir| + cmd = nil + message = proc do + [ + '[ruby-talk:258939]', + "out.txt:", + *File.readlines("out.txt").map{|s|" "+s.inspect}, + "err.txt:", + *File.readlines("err.txt").map{|s|" "+s.inspect}, + "system(#{cmd.inspect})" + ].join("\n") + end + class << message + alias to_s call + end + Dir.chdir(tmpdir) do + open("input.txt", "w") {|f| f.puts "BFI3CHL671"} + cmd = "%WINDIR%/system32/find.exe \"BFI3CHL671\" input.txt > out.txt 2>err.txt" + assert_equal(true, system(cmd), message) + cmd = "\"%WINDIR%/system32/find.exe\" \"BFI3CHL671\" input.txt > out.txt 2>err.txt" + assert_equal(true, system(cmd), message) + cmd = "\"%WINDIR%/system32/find.exe BFI3CHL671\" input.txt > out.txt 2>err.txt" + assert_equal(false, system(cmd), message) + end + end + end + + def test_empty_evstr + assert_equal("", eval('"#{}"', nil, __FILE__, __LINE__), "[ruby-dev:25113]") + end + + def test_fallback_to_sh + Dir.mktmpdir("ruby_script_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}" + open(tmpfilename, "w") {|f| + f.puts ": ;" + f.chmod(0755) + } + assert_equal(true, system(tmpfilename), '[ruby-core:32745]') + } + end if File.executable?("/bin/sh") +end diff --git a/jni/ruby/test/ruby/test_thread.rb b/jni/ruby/test/ruby/test_thread.rb new file mode 100644 index 0000000..87d5f0f --- /dev/null +++ b/jni/ruby/test/ruby/test_thread.rb @@ -0,0 +1,1036 @@ +# -*- coding: us-ascii -*- +require 'test/unit' +require 'thread' + +class TestThread < Test::Unit::TestCase + class Thread < ::Thread + Threads = [] + def self.new(*) + th = super + Threads << th + th + end + end + + def setup + Thread::Threads.clear + end + + def teardown + Thread::Threads.each do |t| + t.kill if t.alive? + begin + t.join + rescue Exception + end + end + end + + def test_inspect + th = Module.new {break module_eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")}.start{} + assert_match(/::C\u{30b9 30ec 30c3 30c9}:/, th.inspect) + ensure + th.join + end + + def test_main_thread_variable_in_enumerator + assert_equal Thread.main, Thread.current + + Thread.current.thread_variable_set :foo, "bar" + + thread, value = Fiber.new { + Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)] + }.resume + + assert_equal Thread.current, thread + assert_equal Thread.current.thread_variable_get(:foo), value + end + + def test_thread_variable_in_enumerator + Thread.new { + Thread.current.thread_variable_set :foo, "bar" + + thread, value = Fiber.new { + Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)] + }.resume + + assert_equal Thread.current, thread + assert_equal Thread.current.thread_variable_get(:foo), value + }.join + end + + def test_thread_variables + assert_equal [], Thread.new { Thread.current.thread_variables }.join.value + + t = Thread.new { + Thread.current.thread_variable_set(:foo, "bar") + Thread.current.thread_variables + } + assert_equal [:foo], t.join.value + end + + def test_thread_variable? + Thread.new { assert_not_send([Thread.current, :thread_variable?, "foo"]) }.value + t = Thread.new { + Thread.current.thread_variable_set("foo", "bar") + }.join + + assert_send([t, :thread_variable?, "foo"]) + assert_send([t, :thread_variable?, :foo]) + assert_not_send([t, :thread_variable?, :bar]) + end + + def test_thread_variable_strings_and_symbols_are_the_same_key + t = Thread.new {}.join + t.thread_variable_set("foo", "bar") + assert_equal "bar", t.thread_variable_get(:foo) + end + + def test_thread_variable_frozen + t = Thread.new { }.join + t.freeze + assert_raise(RuntimeError) do + t.thread_variable_set(:foo, "bar") + end + end + + def test_mutex_synchronize + m = Mutex.new + r = 0 + max = 10 + (1..max).map{ + Thread.new{ + i=0 + while i<max*max + i+=1 + m.synchronize{ + r += 1 + } + end + } + }.each{|e| + e.join + } + assert_equal(max * max * max, r) + end + + def test_mutex_synchronize_yields_no_block_params + bug8097 = '[ruby-core:53424] [Bug #8097]' + assert_empty(Mutex.new.synchronize {|*params| break params}, bug8097) + end + + def test_local_barrier + dir = File.dirname(__FILE__) + lbtest = File.join(dir, "lbtest.rb") + $:.unshift File.join(File.dirname(dir), 'ruby') + $:.shift + 3.times { + `#{EnvUtil.rubybin} #{lbtest}` + assert_not_predicate($?, :coredump?, '[ruby-dev:30653]') + } + end + + def test_priority + c1 = c2 = 0 + run = true + t1 = Thread.new { c1 += 1 while run } + t1.priority = 3 + t2 = Thread.new { c2 += 1 while run } + t2.priority = -3 + assert_equal(3, t1.priority) + assert_equal(-3, t2.priority) + sleep 0.5 + 5.times do + assert_not_predicate(t1, :stop?) + assert_not_predicate(t2, :stop?) + break if c1 > c2 + sleep 0.1 + end + run = false + t1.kill + t2.kill + assert_operator(c1, :>, c2, "[ruby-dev:33124]") # not guaranteed + end + + def test_new + assert_raise(ThreadError) do + Thread.new + end + + t1 = Thread.new { sleep } + assert_raise(ThreadError) do + t1.instance_eval { initialize { } } + end + + t2 = Thread.new(&method(:sleep).to_proc) + assert_raise(ThreadError) do + t2.instance_eval { initialize { } } + end + + ensure + t1.kill if t1 + t2.kill if t2 + end + + def test_join + t = Thread.new { sleep } + assert_nil(t.join(0.05)) + + ensure + t.kill if t + end + + def test_join2 + ok = false + t1 = Thread.new { ok = true; sleep } + Thread.pass until ok + Thread.pass until t1.stop? + t2 = Thread.new do + Thread.pass while ok + t1.join(0.01) + end + t3 = Thread.new do + ok = false + t1.join + end + assert_nil(t2.value) + t1.wakeup + assert_equal(t1, t3.value) + + ensure + t1.kill if t1 + t2.kill if t2 + t3.kill if t3 + end + + def test_kill_main_thread + assert_in_out_err([], <<-INPUT, %w(1), []) + p 1 + Thread.kill Thread.current + p 2 + INPUT + end + + def test_kill_wrong_argument + bug4367 = '[ruby-core:35086]' + assert_raise(TypeError, bug4367) { + Thread.kill(nil) + } + o = Object.new + assert_raise(TypeError, bug4367) { + Thread.kill(o) + } + end + + def test_kill_thread_subclass + c = Class.new(Thread) + t = c.new { sleep 10 } + assert_nothing_raised { Thread.kill(t) } + assert_equal(nil, t.value) + end + + def test_exit + s = 0 + Thread.new do + s += 1 + Thread.exit + s += 2 + end.join + assert_equal(1, s) + end + + def test_wakeup + s = 0 + t = Thread.new do + s += 1 + Thread.stop + s += 1 + end + Thread.pass until t.stop? + assert_equal(1, s) + t.wakeup + Thread.pass while t.alive? + assert_equal(2, s) + assert_raise(ThreadError) { t.wakeup } + + ensure + t.kill if t + end + + def test_stop + assert_in_out_err([], <<-INPUT, %w(2), []) + begin + Thread.stop + p 1 + rescue ThreadError + p 2 + end + INPUT + end + + def test_list + assert_in_out_err([], <<-INPUT) do |r, e| + t1 = Thread.new { sleep } + Thread.pass + t2 = Thread.new { loop { Thread.pass } } + Thread.new { }.join + p [Thread.current, t1, t2].map{|t| t.object_id }.sort + p Thread.list.map{|t| t.object_id }.sort + INPUT + assert_equal(r.first, r.last) + assert_equal([], e) + end + end + + def test_main + assert_in_out_err([], <<-INPUT, %w(true false), []) + p Thread.main == Thread.current + Thread.new { p Thread.main == Thread.current }.join + INPUT + end + + def test_abort_on_exception + assert_in_out_err([], <<-INPUT, %w(false 1), []) + p Thread.abort_on_exception + begin + t = Thread.new { raise } + Thread.pass until t.stop? + p 1 + rescue + p 2 + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(true 2), []) + Thread.abort_on_exception = true + p Thread.abort_on_exception + begin + Thread.new { raise } + sleep 0.5 + p 1 + rescue + p 2 + end + INPUT + + assert_in_out_err(%w(--disable-gems -d), <<-INPUT, %w(false 2), %r".+") + p Thread.abort_on_exception + begin + t = Thread.new { raise } + Thread.pass until t.stop? + p 1 + rescue + p 2 + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(false true 2), []) + p Thread.abort_on_exception + begin + ok = false + t = Thread.new { Thread.pass until ok; raise } + t.abort_on_exception = true + p t.abort_on_exception + ok = 1 + sleep 1 + p 1 + rescue + p 2 + end + INPUT + end + + def test_status_and_stop_p + a = ::Thread.new { raise("die now") } + b = Thread.new { Thread.stop } + c = Thread.new { Thread.exit } + e = Thread.current + Thread.pass while a.alive? or !b.stop? or c.alive? + + assert_equal(nil, a.status) + assert_predicate(a, :stop?) + + assert_equal("sleep", b.status) + assert_predicate(b, :stop?) + + assert_equal(false, c.status) + assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect) + assert_predicate(c, :stop?) + + es1 = e.status + es2 = e.stop? + assert_equal(["run", false], [es1, es2]) + + ensure + a.kill if a + b.kill if b + c.kill if c + end + + def test_switch_while_busy_loop + bug1402 = "[ruby-dev:38319] [Bug #1402]" + flag = true + th = Thread.current + waiter = Thread.start { + sleep 0.1 + flag = false + sleep 1 + th.raise(bug1402) + } + assert_nothing_raised(RuntimeError, bug1402) do + nil while flag + end + assert(!flag, bug1402) + ensure + waiter.kill.join + end + + def test_safe_level + ok = false + t = Thread.new do + EnvUtil.suppress_warning do + $SAFE = 3 + end + ok = true + sleep + end + Thread.pass until ok + assert_equal(0, Thread.current.safe_level) + assert_equal(3, t.safe_level) + + ensure + t.kill if t + end + + def test_thread_local + t = Thread.new { sleep } + + assert_equal(false, t.key?(:foo)) + + t["foo"] = "foo" + t["bar"] = "bar" + t["baz"] = "baz" + + assert_equal(true, t.key?(:foo)) + assert_equal(true, t.key?("foo")) + assert_equal(false, t.key?(:qux)) + assert_equal(false, t.key?("qux")) + + assert_equal([:foo, :bar, :baz], t.keys) + + ensure + t.kill if t + end + + def test_thread_local_security + assert_raise(RuntimeError) do + Thread.new do + Thread.current[:foo] = :bar + Thread.current.freeze + Thread.current[:foo] = :baz + end.join + end + end + + def test_thread_local_dynamic_symbol + bug10667 = '[ruby-core:67185] [Bug #10667]' + t = Thread.new {}.join + key_str = "foo#{rand}" + key_sym = key_str.to_sym + t.thread_variable_set(key_str, "bar") + assert_equal("bar", t.thread_variable_get(key_str), "#{bug10667}: string key") + assert_equal("bar", t.thread_variable_get(key_sym), "#{bug10667}: symbol key") + end + + def test_select_wait + assert_nil(IO.select(nil, nil, nil, 0.001)) + t = Thread.new do + IO.select(nil, nil, nil, nil) + end + Thread.pass until t.stop? + assert_predicate(t, :alive?) + t.kill + end + + def test_mutex_deadlock + m = Mutex.new + m.synchronize do + assert_raise(ThreadError) do + m.synchronize do + assert(false) + end + end + end + end + + def test_mutex_interrupt + m = Mutex.new + m.lock + t = Thread.new do + m.lock + :foo + end + Thread.pass until t.stop? + t.kill + assert_nil(t.value) + end + + def test_mutex_illegal_unlock + m = Mutex.new + m.lock + assert_raise(ThreadError) do + Thread.new do + m.unlock + end.join + end + end + + def test_mutex_fifo_like_lock + m1 = Mutex.new + m2 = Mutex.new + m1.lock + m2.lock + m1.unlock + m2.unlock + assert_equal(false, m1.locked?) + assert_equal(false, m2.locked?) + + m3 = Mutex.new + m1.lock + m2.lock + m3.lock + m1.unlock + m2.unlock + m3.unlock + assert_equal(false, m1.locked?) + assert_equal(false, m2.locked?) + assert_equal(false, m3.locked?) + end + + def test_mutex_trylock + m = Mutex.new + assert_equal(true, m.try_lock) + assert_equal(false, m.try_lock, '[ruby-core:20943]') + + Thread.new{ + assert_equal(false, m.try_lock) + }.join + + m.unlock + end + + def test_recursive_outer + arr = [] + obj = Struct.new(:foo, :visited).new(arr, false) + arr << obj + def obj.hash + self[:visited] = true + super + raise "recursive_outer should short circuit intermediate calls" + end + assert_nothing_raised {arr.hash} + assert(obj[:visited], "obj.hash was not called") + end + + def test_thread_instance_variable + bug4389 = '[ruby-core:35192]' + assert_in_out_err([], <<-INPUT, %w(), [], bug4389) + class << Thread.current + @data = :data + end + INPUT + end + + def test_no_valid_cfp + skip 'with win32ole, cannot run this testcase because win32ole redefines Thread#intialize' if defined?(WIN32OLE) + bug5083 = '[ruby-dev:44208]' + assert_equal([], Thread.new(&Module.method(:nesting)).value, bug5083) + assert_instance_of(Thread, Thread.new(:to_s, &Class.new.method(:undef_method)).join, bug5083) + end + + def make_handle_interrupt_test_thread1 flag + r = [] + ready_p = false + done = false + th = Thread.new{ + begin + Thread.handle_interrupt(RuntimeError => flag){ + begin + ready_p = true + sleep 0.01 until done + rescue + r << :c1 + end + } + rescue + r << :c2 + end + } + Thread.pass until ready_p + th.raise + begin + done = true + th.join + rescue + r << :c3 + end + r + end + + def test_handle_interrupt + [[:never, :c2], + [:immediate, :c1], + [:on_blocking, :c1]].each{|(flag, c)| + assert_equal([flag, c], [flag] + make_handle_interrupt_test_thread1(flag)) + } + # TODO: complex cases are needed. + end + + def test_handle_interrupt_invalid_argument + assert_raise(ArgumentError) { + Thread.handle_interrupt(RuntimeError => :immediate) # no block + } + assert_raise(ArgumentError) { + Thread.handle_interrupt(RuntimeError => :xyzzy) {} + } + assert_raise(TypeError) { + Thread.handle_interrupt([]) {} # array + } + end + + def for_test_handle_interrupt_with_return + Thread.handle_interrupt(Object => :never){ + Thread.current.raise RuntimeError.new("have to be rescured") + return + } + rescue + end + + def test_handle_interrupt_with_return + assert_nothing_raised do + for_test_handle_interrupt_with_return + _dummy_for_check_ints=nil + end + end + + def test_handle_interrupt_with_break + assert_nothing_raised do + begin + Thread.handle_interrupt(Object => :never){ + Thread.current.raise RuntimeError.new("have to be rescured") + break + } + rescue + end + _dummy_for_check_ints=nil + end + end + + def test_handle_interrupt_blocking + r=:ng + e=Class.new(Exception) + th_s = Thread.current + begin + th = Thread.start{ + Thread.handle_interrupt(Object => :on_blocking){ + begin + Thread.current.raise RuntimeError + r=:ok + sleep + ensure + th_s.raise e + end + } + } + sleep 1 + r=:ng + th.raise RuntimeError + th.join + rescue e + end + assert_equal(:ok,r) + end + + def test_handle_interrupt_and_io + assert_in_out_err([], <<-INPUT, %w(ok), []) + th_waiting = true + + t = Thread.new { + Thread.handle_interrupt(RuntimeError => :on_blocking) { + nil while th_waiting + # async interrupt should be raised _before_ writing puts arguments + puts "ng" + } + } + + Thread.pass while t.stop? + t.raise RuntimeError + th_waiting = false + t.join rescue nil + puts "ok" + INPUT + end + + def test_handle_interrupt_and_p + assert_in_out_err([], <<-INPUT, %w(:ok :ok), []) + th_waiting = false + + t = Thread.new { + Thread.handle_interrupt(RuntimeError => :on_blocking) { + th_waiting = true + nil while th_waiting + # p shouldn't provide interruptible point + p :ok + p :ok + } + } + + Thread.pass until th_waiting + t.raise RuntimeError + th_waiting = false + t.join rescue nil + INPUT + end + + def test_handle_interrupted? + q = Queue.new + Thread.handle_interrupt(RuntimeError => :never){ + done = false + th = Thread.new{ + q.push :e + begin + begin + Thread.pass until done + rescue => e + q.push :ng1 + end + begin + Thread.handle_interrupt(Object => :immediate){} if Thread.pending_interrupt? + rescue RuntimeError => e + q.push :ok + end + rescue => e + q.push :ng2 + ensure + q.push :ng3 + end + } + q.pop + th.raise + done = true + th.join + assert_equal(:ok, q.pop) + } + end + + def test_thread_timer_and_ensure + assert_normal_exit(<<_eom, 'r36492', timeout: 3) + flag = false + t = Thread.new do + begin + sleep + ensure + 1 until flag + end + end + + Thread.pass until t.status == "sleep" + + t.kill + t.alive? == true + flag = true + t.join +_eom + end + + def test_uninitialized + c = Class.new(Thread) + c.class_eval { def initialize; end } + assert_raise(ThreadError) { c.new.start } + end + + def test_backtrace + Thread.new{ + assert_equal(Array, Thread.main.backtrace.class) + }.join + + t = Thread.new{} + t.join + assert_equal(nil, t.backtrace) + end + + def test_thread_timer_and_interrupt + bug5757 = '[ruby-dev:44985]' + t0 = Time.now.to_f + pid = nil + cmd = 'Signal.trap(:INT, "DEFAULT"); r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read' + opt = {} + opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM + s, _err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, opt) do |in_p, out_p, err_p, cpid| + out_p.gets + pid = cpid + Process.kill(:SIGINT, pid) + Process.wait(pid) + [$?, err_p.read] + end + t1 = Time.now.to_f + assert_equal(pid, s.pid, bug5757) + assert_equal([false, true, false, Signal.list["INT"]], + [s.exited?, s.signaled?, s.stopped?, s.termsig], + "[s.exited?, s.signaled?, s.stopped?, s.termsig]") + assert_in_delta(t1 - t0, 1, 1, bug5757) + end + + def test_thread_join_in_trap + assert_separately [], <<-'EOS' + Signal.trap(:INT, "DEFAULT") + t0 = Thread.current + assert_nothing_raised{ + t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$)} + + Signal.trap :INT do + t.join + end + + t.join + } + EOS + end + + def test_thread_value_in_trap + assert_separately [], <<-'EOS' + Signal.trap(:INT, "DEFAULT") + t0 = Thread.current + t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$); :normal_end} + + Signal.trap :INT do + t.value + end + assert_equal(:normal_end, t.value) + EOS + end + + def test_thread_join_current + assert_raise(ThreadError) do + Thread.current.join + end + end + + def test_thread_join_main_thread + assert_raise(ThreadError) do + Thread.new(Thread.current) {|t| + t.join + }.join + end + end + + def test_main_thread_status_at_exit + assert_in_out_err([], <<-'INPUT', ["false false aborting"], []) +require 'thread' +q = Queue.new +Thread.new(Thread.current) {|mth| + begin + q.push nil + mth.run + Thread.pass until mth.stop? + p :mth_stopped # don't run if killed by rb_thread_terminate_all + ensure + puts "#{mth.alive?} #{mth.status} #{Thread.current.status}" + end +} +q.pop + INPUT + end + + def test_thread_status_in_trap + # when running trap handler, Thread#status must show "run" + # Even though interrupted from sleeping function + assert_in_out_err([], <<-INPUT, %w(sleep run), []) + Signal.trap(:INT) { + puts Thread.current.status + exit + } + t = Thread.current + + Thread.new(Thread.current) {|mth| + Thread.pass until t.stop? + puts mth.status + Process.kill(:INT, $$) + } + sleep 0.1 + INPUT + end + + # Bug #7450 + def test_thread_status_raise_after_kill + ary = [] + + t = Thread.new { + begin + ary << Thread.current.status + sleep #1 + ensure + begin + ary << Thread.current.status + sleep #2 + ensure + ary << Thread.current.status + end + end + } + + begin + Thread.pass until ary.size >= 1 + Thread.pass until t.stop? + t.kill # wake up sleep #1 + Thread.pass until ary.size >= 2 + Thread.pass until t.stop? + t.raise "wakeup" # wake up sleep #2 + Thread.pass while t.alive? + assert_equal(ary, ["run", "aborting", "aborting"]) + ensure + t.join rescue nil + end + end + + def test_mutex_owned + mutex = Mutex.new + + assert_equal(mutex.owned?, false) + mutex.synchronize { + # Now, I have the mutex + assert_equal(mutex.owned?, true) + } + assert_equal(mutex.owned?, false) + end + + def test_mutex_owned2 + begin + mutex = Mutex.new + th = Thread.new { + # lock forever + mutex.lock + sleep + } + + Thread.pass until th.status == "sleep" + # acquired another thread. + assert_equal(mutex.locked?, true) + assert_equal(mutex.owned?, false) + ensure + th.kill if th + end + end + + def test_mutex_unlock_on_trap + assert_in_out_err([], <<-INPUT, %w(locked unlocked false), []) + m = Mutex.new + + trapped = false + Signal.trap("INT") { |signo| + m.unlock + trapped = true + puts "unlocked" + } + + m.lock + puts "locked" + Process.kill("INT", $$) + Thread.pass until trapped + puts m.locked? + INPUT + end + + def invoke_rec script, vm_stack_size, machine_stack_size, use_length = true + env = {} + env['RUBY_THREAD_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size + env['RUBY_THREAD_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size + out, = EnvUtil.invoke_ruby([env, '-e', script], '', true, true) + use_length ? out.length : out + end + + def test_stack_size + h_default = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', nil, nil, false)) + h_0 = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 0, 0, false)) + h_large = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 1024 * 1024 * 10, 1024 * 1024 * 10, false)) + + assert_operator(h_default[:thread_vm_stack_size], :>, h_0[:thread_vm_stack_size], + "0 thread_vm_stack_size") + assert_operator(h_default[:thread_vm_stack_size], :<, h_large[:thread_vm_stack_size], + "large thread_vm_stack_size") + assert_operator(h_default[:thread_machine_stack_size], :>=, h_0[:thread_machine_stack_size], + "0 thread_machine_stack_size") + assert_operator(h_default[:thread_machine_stack_size], :<=, h_large[:thread_machine_stack_size], + "large thread_machine_stack_size") + end + + def test_vm_machine_stack_size + script = 'def rec; print "."; STDOUT.flush; rec; end; rec' + size_default = invoke_rec script, nil, nil + assert_operator(size_default, :>, 0, "default size") + size_0 = invoke_rec script, 0, nil + assert_operator(size_default, :>, size_0, "0 size") + size_large = invoke_rec script, 1024 * 1024 * 10, nil + assert_operator(size_default, :<, size_large, "large size") + end + + def test_machine_stack_size + # check machine stack size + # Note that machine stack size may not change size (depend on OSs) + script = 'def rec; print "."; STDOUT.flush; 1.times{1.times{1.times{rec}}}; end; Thread.new{rec}.join' + vm_stack_size = 1024 * 1024 + size_default = invoke_rec script, vm_stack_size, nil + size_0 = invoke_rec script, vm_stack_size, 0 + assert_operator(size_default, :>=, size_0, "0 size") + size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10 + assert_operator(size_default, :<=, size_large, "large size") + end unless /mswin|mingw/ =~ RUBY_PLATFORM + + def test_blocking_mutex_unlocked_on_fork + bug8433 = '[ruby-core:55102] [Bug #8433]' + + mutex = Mutex.new + flag = false + mutex.lock + + th = Thread.new do + mutex.synchronize do + flag = true + sleep + end + end + + Thread.pass until th.stop? + mutex.unlock + + pid = Process.fork do + exit(mutex.locked?) + end + + th.kill + + pid, status = Process.waitpid2(pid) + assert_equal(false, status.success?, bug8433) + end if Process.respond_to?(:fork) + + def test_fork_in_thread + bug9751 = '[ruby-core:62070] [Bug #9751]' + f = nil + th = Thread.start do + unless f = IO.popen("-") + STDERR.reopen(STDOUT) + exit + end + Process.wait2(f.pid) + end + unless th.join(3) + Process.kill(:QUIT, f.pid) + Process.kill(:KILL, f.pid) unless th.join(1) + end + _, status = th.value + output = f.read + f.close + assert_not_predicate(status, :signaled?, FailDesc[status, bug9751, output]) + assert_predicate(status, :success?, bug9751) + end if Process.respond_to?(:fork) +end diff --git a/jni/ruby/test/ruby/test_threadgroup.rb b/jni/ruby/test/ruby/test_threadgroup.rb new file mode 100644 index 0000000..e158f5a --- /dev/null +++ b/jni/ruby/test/ruby/test_threadgroup.rb @@ -0,0 +1,57 @@ +require 'test/unit' +require 'thread' + +class TestThreadGroup < Test::Unit::TestCase + def test_thread_init + thgrp = ThreadGroup.new + th = Thread.new{ + thgrp.add(Thread.current) + Thread.new{sleep 1} + }.value + assert_equal(thgrp, th.group) + ensure + th.join + end + + def test_frozen_thgroup + thgrp = ThreadGroup.new + + t = Thread.new{1} + Thread.new{ + thgrp.add(Thread.current) + thgrp.freeze + assert_raise(ThreadError) do + Thread.new{1}.join + end + assert_raise(ThreadError) do + thgrp.add(t) + end + assert_raise(ThreadError) do + ThreadGroup.new.add Thread.current + end + }.join + t.join + end + + def test_enclosed_thgroup + thgrp = ThreadGroup.new + assert_equal(false, thgrp.enclosed?) + + t = Thread.new{1} + Thread.new{ + thgrp.add(Thread.current) + thgrp.enclose + assert_equal(true, thgrp.enclosed?) + assert_nothing_raised do + Thread.new{1}.join + end + assert_raise(ThreadError) do + thgrp.add t + end + assert_raise(ThreadError) do + ThreadGroup.new.add Thread.current + end + }.join + t.join + end +end diff --git a/jni/ruby/test/ruby/test_time.rb b/jni/ruby/test/ruby/test_time.rb new file mode 100644 index 0000000..f4fb5bf --- /dev/null +++ b/jni/ruby/test/ruby/test_time.rb @@ -0,0 +1,1049 @@ +require 'test/unit' +require 'delegate' +require 'timeout' +require 'delegate' + +class TestTime < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + end + + def in_timezone(zone) + orig_zone = ENV['TZ'] + + ENV['TZ'] = zone + yield + ensure + ENV['TZ'] = orig_zone + end + + def no_leap_seconds? + # 1972-06-30T23:59:60Z is the first leap second. + Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59) == 1 + end + + def get_t2000 + if no_leap_seconds? + # Sat Jan 01 00:00:00 UTC 2000 + Time.at(946684800).gmtime + else + Time.utc(2000, 1, 1) + end + end + + def test_new + assert_equal(Time.utc(2000,2,10), Time.new(2000,2,10, 11,0,0, 3600*11)) + assert_equal(Time.utc(2000,2,10), Time.new(2000,2,9, 13,0,0, -3600*11)) + assert_equal(Time.utc(2000,2,10), Time.new(2000,2,10, 11,0,0, "+11:00")) + assert_equal(Rational(1,2), Time.new(2000,2,10, 11,0,5.5, "+11:00").subsec) + bug4090 = '[ruby-dev:42631]' + tm = [2001,2,28,23,59,30] + t = Time.new(*tm, "-12:00") + assert_equal([2001,2,28,23,59,30,-43200], [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.gmt_offset], bug4090) + assert_raise(ArgumentError) { Time.new(2000,1,1, 0,0,0, "+01:60") } + end + + def test_time_add() + assert_equal(Time.utc(2000, 3, 21, 3, 30) + 3 * 3600, + Time.utc(2000, 3, 21, 6, 30)) + assert_equal(Time.utc(2000, 3, 21, 3, 30) + (-3 * 3600), + Time.utc(2000, 3, 21, 0, 30)) + assert_equal(0, (Time.at(1.1) + 0.9).usec) + + assert_predicate((Time.utc(2000, 4, 1) + 24), :utc?) + assert_not_predicate((Time.local(2000, 4, 1) + 24), :utc?) + + t = Time.new(2000, 4, 1, 0, 0, 0, "+01:00") + 24 + assert_not_predicate(t, :utc?) + assert_equal(3600, t.utc_offset) + t = Time.new(2000, 4, 1, 0, 0, 0, "+02:00") + 24 + assert_not_predicate(t, :utc?) + assert_equal(7200, t.utc_offset) + end + + def test_time_subt() + assert_equal(Time.utc(2000, 3, 21, 3, 30) - 3 * 3600, + Time.utc(2000, 3, 21, 0, 30)) + assert_equal(Time.utc(2000, 3, 21, 3, 30) - (-3 * 3600), + Time.utc(2000, 3, 21, 6, 30)) + assert_equal(900000, (Time.at(1.1) - 0.2).usec) + end + + def test_time_time() + assert_equal(Time.utc(2000, 3, 21, 3, 30) \ + -Time.utc(2000, 3, 21, 0, 30), 3*3600) + assert_equal(Time.utc(2000, 3, 21, 0, 30) \ + -Time.utc(2000, 3, 21, 3, 30), -3*3600) + end + + def negative_time_t? + begin + Time.at(-1) + true + rescue ArgumentError + false + end + end + + def test_timegm + if negative_time_t? + assert_equal(-0x80000000, Time.utc(1901, 12, 13, 20, 45, 52).tv_sec) + assert_equal(-2, Time.utc(1969, 12, 31, 23, 59, 58).tv_sec) + assert_equal(-1, Time.utc(1969, 12, 31, 23, 59, 59).tv_sec) + end + + assert_equal(0, Time.utc(1970, 1, 1, 0, 0, 0).tv_sec) # the Epoch + assert_equal(1, Time.utc(1970, 1, 1, 0, 0, 1).tv_sec) + assert_equal(31535999, Time.utc(1970, 12, 31, 23, 59, 59).tv_sec) + assert_equal(31536000, Time.utc(1971, 1, 1, 0, 0, 0).tv_sec) + assert_equal(78796799, Time.utc(1972, 6, 30, 23, 59, 59).tv_sec) + + if no_leap_seconds? + assert_equal(78796800, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec) + assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec) + assert_equal(946684800, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec) + assert_equal(0x7fffffff, Time.utc(2038, 1, 19, 3, 14, 7).tv_sec) + assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec) + else + assert_equal(2, Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59)) + assert_equal(78796800, Time.utc(1972, 6, 30, 23, 59, 60).tv_sec) + assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec) + assert_equal(78796802, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec) + assert_equal(946684822, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec) + end + end + + def test_strtime + t = nil + assert_nothing_raised { t = Time.utc("2000", "1", "2" , "3", "4", "5") } + assert_equal(Time.utc(2000,1,2,3,4,5), t) + end + + def test_huge_difference + if negative_time_t? + assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) - 0xffffffff, "[ruby-dev:22619]") + assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) + (-0xffffffff)) + assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) + 0xffffffff, "[ruby-dev:22619]") + assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) - (-0xffffffff)) + end + end + + def test_big_minus + begin + bigtime0 = Time.at(2**60) + bigtime1 = Time.at(2**60+1) + rescue RangeError + return + end + assert_equal(1.0, bigtime1 - bigtime0) + end + + def test_at + assert_equal(100000, Time.at("0.1".to_r).usec) + assert_equal(10000, Time.at("0.01".to_r).usec) + assert_equal(1000, Time.at("0.001".to_r).usec) + assert_equal(100, Time.at("0.0001".to_r).usec) + assert_equal(10, Time.at("0.00001".to_r).usec) + assert_equal(1, Time.at("0.000001".to_r).usec) + assert_equal(100000000, Time.at("0.1".to_r).nsec) + assert_equal(10000000, Time.at("0.01".to_r).nsec) + assert_equal(1000000, Time.at("0.001".to_r).nsec) + assert_equal(100000, Time.at("0.0001".to_r).nsec) + assert_equal(10000, Time.at("0.00001".to_r).nsec) + assert_equal(1000, Time.at("0.000001".to_r).nsec) + assert_equal(100, Time.at("0.0000001".to_r).nsec) + assert_equal(10, Time.at("0.00000001".to_r).nsec) + assert_equal(1, Time.at("0.000000001".to_r).nsec) + assert_equal(100000, Time.at(0.1).usec) + assert_equal(10000, Time.at(0.01).usec) + assert_equal(1000, Time.at(0.001).usec) + assert_equal(100, Time.at(0.0001).usec) + assert_equal(10, Time.at(0.00001).usec) + assert_equal(3, Time.at(0.000003).usec) + assert_equal(100000000, Time.at(0.1).nsec) + assert_equal(10000000, Time.at(0.01).nsec) + assert_equal(1000000, Time.at(0.001).nsec) + assert_equal(100000, Time.at(0.0001).nsec) + assert_equal(10000, Time.at(0.00001).nsec) + assert_equal(3000, Time.at(0.000003).nsec) + assert_equal(200, Time.at(0.0000002r).nsec) + assert_equal(199, Time.at(0.0000002).nsec) + assert_equal(10, Time.at(0.00000001).nsec) + assert_equal(1, Time.at(0.000000001).nsec) + + assert_equal(0, Time.at(1e-10).nsec) + assert_equal(0, Time.at(4e-10).nsec) + assert_equal(0, Time.at(6e-10).nsec) + assert_equal(1, Time.at(14e-10).nsec) + assert_equal(1, Time.at(16e-10).nsec) + if negative_time_t? + assert_equal(999999999, Time.at(-1e-10).nsec) + assert_equal(999999999, Time.at(-4e-10).nsec) + assert_equal(999999999, Time.at(-6e-10).nsec) + assert_equal(999999998, Time.at(-14e-10).nsec) + assert_equal(999999998, Time.at(-16e-10).nsec) + end + + t = Time.at(-4611686019).utc + assert_equal(1823, t.year) + + t = Time.at(4611686018, 999999).utc + assert_equal(2116, t.year) + assert_equal("0.999999".to_r, t.subsec) + + t = Time.at(2**40 + "1/3".to_r, 9999999999999).utc + assert_equal(36812, t.year) + + t = Time.at(-0x3fff_ffff_ffff_ffff) + assert_equal(-146138510344, t.year) + t = Time.at(-0x4000_0000_0000_0000) + assert_equal(-146138510344, t.year) + t = Time.at(-0x4000_0000_0000_0001) + assert_equal(-146138510344, t.year) + t = Time.at(-0x5000_0000_0000_0001) + assert_equal(-182673138422, t.year) + t = Time.at(-0x6000_0000_0000_0000) + assert_equal(-219207766501, t.year) + + t = Time.at(0).utc + assert_equal([1970,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-86400).utc + assert_equal([1969,12,31, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-86400 * (400 * 365 + 97)).utc + assert_equal([1970-400,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-86400 * (400 * 365 + 97)*1000).utc + assert_equal([1970-400*1000,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-86400 * (400 * 365 + 97)*2421).utc + assert_equal([1970-400*2421,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-86400 * (400 * 365 + 97)*1000000).utc + assert_equal([1970-400*1000000,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + + t = Time.at(-30613683110400).utc + assert_equal([-968139,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + t = Time.at(-30613683110401).utc + assert_equal([-968140,12,31, 23,59,59], [t.year, t.mon, t.day, t.hour, t.min, t.sec]) + end + + def test_at2 + assert_equal(100, Time.at(0, 0.1).nsec) + assert_equal(10, Time.at(0, 0.01).nsec) + assert_equal(1, Time.at(0, 0.001).nsec) + end + + def test_at_rational + assert_equal(1, Time.at(Rational(1,1) / 1000000000).nsec) + assert_equal(1, Time.at(1167609600 + Rational(1,1) / 1000000000).nsec) + end + + def test_utc_subsecond + assert_equal(500000, Time.utc(2007,1,1,0,0,1.5).usec) + assert_equal(100000, Time.utc(2007,1,1,0,0,Rational(11,10)).usec) + end + + def test_eq_nsec + assert_equal(Time.at(0, 0.123), Time.at(0, 0.123)) + assert_not_equal(Time.at(0, 0.123), Time.at(0, 0.124)) + end + + def assert_marshal_roundtrip(t) + iv_names = t.instance_variables + iv_vals1 = iv_names.map {|n| t.instance_variable_get n } + m = Marshal.dump(t) + t2 = Marshal.load(m) + iv_vals2 = iv_names.map {|n| t2.instance_variable_get n } + assert_equal(t, t2) + assert_equal(iv_vals1, iv_vals2) + t2 + end + + def test_marshal_nsec + assert_marshal_roundtrip(Time.at(0, 0.123)) + assert_marshal_roundtrip(Time.at(0, 0.120)) + end + + def test_marshal_nsec_191 + # generated by ruby 1.9.1p376 + m = "\x04\bIu:\tTime\r \x80\x11\x80@\xE2\x01\x00\x06:\rsubmicro\"\ax\x90" + t = Marshal.load(m) + assert_equal(Time.at(Rational(123456789, 1000000000)), t, "[ruby-dev:40133]") + end + + def test_marshal_rational + assert_marshal_roundtrip(Time.at(0, Rational(1,3))) + assert_not_match(/Rational/, Marshal.dump(Time.at(0, Rational(1,3)))) + end + + def test_marshal_ivar + t = Time.at(123456789, 987654.321) + t.instance_eval { @var = 135 } + assert_marshal_roundtrip(t) + assert_marshal_roundtrip(Marshal.load(Marshal.dump(t))) + end + + def test_marshal_timezone + bug = '[ruby-dev:40063]' + + t1 = Time.gm(2000) + m = Marshal.dump(t1.getlocal("-02:00")) + t2 = Marshal.load(m) + assert_equal(t1, t2) + assert_equal(-7200, t2.utc_offset, bug) + m = Marshal.dump(t1.getlocal("+08:15")) + t2 = Marshal.load(m) + assert_equal(t1, t2) + assert_equal(29700, t2.utc_offset, bug) + end + + def test_marshal_zone + t = Time.utc(2013, 2, 24) + assert_equal('UTC', t.zone) + assert_equal('UTC', Marshal.load(Marshal.dump(t)).zone) + + in_timezone('JST-9') do + t = Time.local(2013, 2, 24) + assert_equal('JST', Time.local(2013, 2, 24).zone) + assert_equal('JST', Marshal.load(Marshal.dump(t)).zone) + end + end + + def test_marshal_zone_gc + assert_separately(%w(--disable-gems), <<-'end;', timeout: 30) + ENV["TZ"] = "JST-9" + s = Marshal.dump(Time.now) + t = Marshal.load(s) + n = 0 + done = 100000 + while t.zone.dup == "JST" && n < done + n += 1 + end + assert_equal done, n, "Bug #9652" + assert_equal "JST", t.zone, "Bug #9652" + end; + end + + def test_marshal_to_s + t1 = Time.new(2011,11,8, 0,42,25, 9*3600) + t2 = Time.at(Marshal.load(Marshal.dump(t1))) + assert_equal("2011-11-08 00:42:25 +0900", t2.to_s, + "[ruby-dev:44827] [Bug #5586]") + end + + Bug8795 = '[ruby-core:56648] [Bug #8795]' + + def test_marshal_broken_offset + data = "\x04\bIu:\tTime\r\xEFF\x1C\x80\x00\x00\x00\x00\x06:\voffset" + t1 = t2 = nil + in_timezone('UTC') do + assert_nothing_raised(TypeError, ArgumentError, Bug8795) do + t1 = Marshal.load(data + "T") + t2 = Marshal.load(data + "\"\x0ebadoffset") + end + assert_equal(0, t1.utc_offset) + assert_equal(0, t2.utc_offset) + end + end + + def test_marshal_broken_zone + data = "\x04\bIu:\tTime\r\xEFF\x1C\x80\x00\x00\x00\x00\x06:\tzone" + t1 = t2 = nil + in_timezone('UTC') do + assert_nothing_raised(TypeError, ArgumentError, Bug8795) do + t1 = Marshal.load(data + "T") + t2 = Marshal.load(data + "\"\b\0\0\0") + end + assert_equal('UTC', t1.zone) + assert_equal('UTC', t2.zone) + end + end + + def test_at3 + t2000 = get_t2000 + assert_equal(t2000, Time.at(t2000)) +# assert_raise(RangeError) do +# Time.at(2**31-1, 1_000_000) +# Time.at(2**63-1, 1_000_000) +# end +# assert_raise(RangeError) do +# Time.at(-2**31, -1_000_000) +# Time.at(-2**63, -1_000_000) +# end + end + + def test_utc_or_local + t2000 = get_t2000 + assert_equal(t2000, Time.gm(2000)) + assert_equal(t2000, Time.gm(0, 0, 0, 1, 1, 2000, :foo, :bar, false, :baz)) + assert_equal(t2000, Time.gm(2000, "jan")) + assert_equal(t2000, Time.gm(2000, "1")) + assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, 0, 0)) + assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, 0, "0")) + assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, "0", :foo, :foo)) + assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -1, :foo, :foo) } + assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -1.0, :foo, :foo) } + assert_raise(RangeError) do + Time.gm(2000, 1, 1, 0, 0, 10_000_000_000_000_000_001.0, :foo, :foo) + end + assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -(2**31), :foo, :foo) } + o = Object.new + def o.to_int; 0; end + def o.to_r; nil; end + assert_raise(TypeError) { Time.gm(2000, 1, 1, 0, 0, o, :foo, :foo) } + def o.to_r; ""; end + assert_raise(TypeError) { Time.gm(2000, 1, 1, 0, 0, o, :foo, :foo) } + def o.to_r; Rational(11); end + assert_equal(11, Time.gm(2000, 1, 1, 0, 0, o).sec) + o = Object.new + def o.to_int; 10; end + assert_equal(10, Time.gm(2000, 1, 1, 0, 0, o).sec) + assert_raise(ArgumentError) { Time.gm(2000, 13) } + + t = Time.local(2000) + assert_equal(t.gmt_offset, t2000 - t) + + assert_equal(-4427700000, Time.utc(-4427700000,12,1).year) + assert_equal(-2**30+10, Time.utc(-2**30+10,1,1).year) + end + + def test_time_interval + m = Mutex.new.lock + assert_nothing_raised { + Timeout.timeout(10) { + m.sleep(0) + } + } + assert_raise(ArgumentError) { m.sleep(-1) } + end + + def test_to_f + t2000 = Time.at(946684800).gmtime + assert_equal(946684800.0, t2000.to_f) + end + + def test_to_f_accuracy + # https://bugs.ruby-lang.org/issues/10135#note-1 + f = 1381089302.195 + assert_equal(f, Time.at(f).to_f, "[ruby-core:64373] [Bug #10135] note-1") + end + + def test_cmp + t2000 = get_t2000 + assert_equal(-1, t2000 <=> Time.gm(2001)) + assert_equal(1, t2000 <=> Time.gm(1999)) + assert_nil(t2000 <=> 0) + end + + def test_eql + t2000 = get_t2000 + assert_operator(t2000, :eql?, t2000) + assert_not_operator(t2000, :eql?, Time.gm(2001)) + end + + def test_utc_p + assert_predicate(Time.gm(2000), :gmt?) + assert_not_predicate(Time.local(2000), :gmt?) + assert_not_predicate(Time.at(0), :gmt?) + end + + def test_hash + t2000 = get_t2000 + assert_kind_of(Integer, t2000.hash) + end + + def test_reinitialize + bug8099 = '[ruby-core:53436] [Bug #8099]' + t2000 = get_t2000 + assert_raise(TypeError, bug8099) { + t2000.send(:initialize, 2013, 03, 14) + } + assert_equal(get_t2000, t2000, bug8099) + end + + def test_init_copy + t2000 = get_t2000 + assert_equal(t2000, t2000.dup) + assert_raise(TypeError) do + t2000.instance_eval { initialize_copy(nil) } + end + end + + def test_localtime_gmtime + assert_nothing_raised do + t = Time.gm(2000) + assert_predicate(t, :gmt?) + t.localtime + assert_not_predicate(t, :gmt?) + t.localtime + assert_not_predicate(t, :gmt?) + t.gmtime + assert_predicate(t, :gmt?) + t.gmtime + assert_predicate(t, :gmt?) + end + + t1 = Time.gm(2000) + t2 = t1.getlocal + assert_equal(t1, t2) + t3 = t1.getlocal("-02:00") + assert_equal(t1, t3) + assert_equal(-7200, t3.utc_offset) + assert_equal([1999, 12, 31, 22, 0, 0], [t3.year, t3.mon, t3.mday, t3.hour, t3.min, t3.sec]) + t1.localtime + assert_equal(t1, t2) + assert_equal(t1.gmt?, t2.gmt?) + assert_equal(t1, t3) + + t1 = Time.local(2000) + t2 = t1.getgm + assert_equal(t1, t2) + t3 = t1.getlocal("-02:00") + assert_equal(t1, t3) + assert_equal(-7200, t3.utc_offset) + t1.gmtime + assert_equal(t1, t2) + assert_equal(t1.gmt?, t2.gmt?) + assert_equal(t1, t3) + end + + def test_asctime + t2000 = get_t2000 + assert_equal("Sat Jan 1 00:00:00 2000", t2000.asctime) + assert_equal(Encoding::US_ASCII, t2000.asctime.encoding) + assert_kind_of(String, Time.at(0).asctime) + end + + def test_to_s + t2000 = get_t2000 + assert_equal("2000-01-01 00:00:00 UTC", t2000.to_s) + assert_equal(Encoding::US_ASCII, t2000.to_s.encoding) + assert_kind_of(String, Time.at(946684800).getlocal.to_s) + assert_equal(Time.at(946684800).getlocal.to_s, Time.at(946684800).to_s) + end + + def assert_zone_encoding(time) + zone = time.zone + assert_predicate(zone, :valid_encoding?) + if zone.ascii_only? + assert_equal(Encoding::US_ASCII, zone.encoding) + else + enc = Encoding.default_internal || Encoding.find('locale') + assert_equal(enc, zone.encoding) + end + end + + def test_zone + assert_zone_encoding Time.now + end + + def test_plus_minus_succ + t2000 = get_t2000 + # assert_raise(RangeError) { t2000 + 10000000000 } + # assert_raise(RangeError) t2000 - 3094168449 } + # assert_raise(RangeError) { t2000 + 1200798848 } + assert_raise(TypeError) { t2000 + Time.now } + assert_equal(t2000 + 1, t2000.succ) + end + + def test_plus_type + t0 = Time.utc(2000,1,1) + n0 = t0.to_i + n1 = n0+1 + t1 = Time.at(n1) + assert_equal(t1, t0 + 1) + assert_equal(t1, t0 + 1.0) + assert_equal(t1, t0 + Rational(1,1)) + assert_equal(t1, t0 + SimpleDelegator.new(1)) + assert_equal(t1, t0 + SimpleDelegator.new(1.0)) + assert_equal(t1, t0 + SimpleDelegator.new(Rational(1,1))) + assert_raise(TypeError) { t0 + nil } + assert_raise(TypeError) { t0 + "1" } + assert_raise(TypeError) { t0 + SimpleDelegator.new("1") } + assert_equal(0.5, (t0 + 1.5).subsec) + assert_equal(Rational(1,3), (t0 + Rational(4,3)).subsec) + assert_equal(0.5, (t0 + SimpleDelegator.new(1.5)).subsec) + assert_equal(Rational(1,3), (t0 + SimpleDelegator.new(Rational(4,3))).subsec) + end + + def test_minus + t = Time.at(-4611686018).utc - 100 + assert_equal(1823, t.year) + end + + def test_readers + t2000 = get_t2000 + assert_equal(0, t2000.sec) + assert_equal(0, t2000.min) + assert_equal(0, t2000.hour) + assert_equal(1, t2000.mday) + assert_equal(1, t2000.mon) + assert_equal(2000, t2000.year) + assert_equal(6, t2000.wday) + assert_equal(1, t2000.yday) + assert_equal(false, t2000.isdst) + assert_equal("UTC", t2000.zone) + assert_zone_encoding(t2000) + assert_equal(0, t2000.gmt_offset) + assert_not_predicate(t2000, :sunday?) + assert_not_predicate(t2000, :monday?) + assert_not_predicate(t2000, :tuesday?) + assert_not_predicate(t2000, :wednesday?) + assert_not_predicate(t2000, :thursday?) + assert_not_predicate(t2000, :friday?) + assert_predicate(t2000, :saturday?) + assert_equal([0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], t2000.to_a) + + t = Time.at(946684800).getlocal + assert_equal(t.sec, Time.at(946684800).sec) + assert_equal(t.min, Time.at(946684800).min) + assert_equal(t.hour, Time.at(946684800).hour) + assert_equal(t.mday, Time.at(946684800).mday) + assert_equal(t.mon, Time.at(946684800).mon) + assert_equal(t.year, Time.at(946684800).year) + assert_equal(t.wday, Time.at(946684800).wday) + assert_equal(t.yday, Time.at(946684800).yday) + assert_equal(t.isdst, Time.at(946684800).isdst) + assert_equal(t.zone, Time.at(946684800).zone) + assert_zone_encoding(Time.at(946684800)) + assert_equal(t.gmt_offset, Time.at(946684800).gmt_offset) + assert_equal(t.sunday?, Time.at(946684800).sunday?) + assert_equal(t.monday?, Time.at(946684800).monday?) + assert_equal(t.tuesday?, Time.at(946684800).tuesday?) + assert_equal(t.wednesday?, Time.at(946684800).wednesday?) + assert_equal(t.thursday?, Time.at(946684800).thursday?) + assert_equal(t.friday?, Time.at(946684800).friday?) + assert_equal(t.saturday?, Time.at(946684800).saturday?) + assert_equal(t.to_a, Time.at(946684800).to_a) + end + + def test_strftime + t2000 = get_t2000 + t = Time.at(946684800).getlocal + assert_equal("Sat", t2000.strftime("%a")) + assert_equal("Saturday", t2000.strftime("%A")) + assert_equal("Jan", t2000.strftime("%b")) + assert_equal("January", t2000.strftime("%B")) + assert_kind_of(String, t2000.strftime("%c")) + assert_equal("01", t2000.strftime("%d")) + assert_equal("00", t2000.strftime("%H")) + assert_equal("12", t2000.strftime("%I")) + assert_equal("001", t2000.strftime("%j")) + assert_equal("01", t2000.strftime("%m")) + assert_equal("00", t2000.strftime("%M")) + assert_equal("AM", t2000.strftime("%p")) + assert_equal("00", t2000.strftime("%S")) + assert_equal("00", t2000.strftime("%U")) + assert_equal("00", t2000.strftime("%W")) + assert_equal("6", t2000.strftime("%w")) + assert_equal("01/01/00", t2000.strftime("%x")) + assert_equal("00:00:00", t2000.strftime("%X")) + assert_equal("00", t2000.strftime("%y")) + assert_equal("2000", t2000.strftime("%Y")) + assert_equal("UTC", t2000.strftime("%Z")) + assert_equal("%", t2000.strftime("%%")) + assert_equal("0", t2000.strftime("%-S")) + + assert_equal("", t2000.strftime("")) + assert_equal("foo\0bar\x0000\x0000\x0000", t2000.strftime("foo\0bar\0%H\0%M\0%S")) + assert_equal("foo" * 1000, t2000.strftime("foo" * 1000)) + + t = Time.mktime(2000, 1, 1) + assert_equal("Sat", t.strftime("%a")) + end + + def test_strftime_subsec + t = Time.at(946684800, 123456.789) + assert_equal("123", t.strftime("%3N")) + assert_equal("123456", t.strftime("%6N")) + assert_equal("123456789", t.strftime("%9N")) + assert_equal("1234567890", t.strftime("%10N")) + assert_equal("123456789", t.strftime("%0N")) + end + + def test_strftime_sec + t = get_t2000.getlocal + assert_equal("000", t.strftime("%3S")) + end + + def test_strftime_seconds_from_epoch + t = Time.at(946684800, 123456.789) + assert_equal("946684800", t.strftime("%s")) + assert_equal("946684800", t.utc.strftime("%s")) + end + + def test_strftime_zone + t = Time.mktime(2001, 10, 1) + assert_equal("2001-10-01", t.strftime("%F")) + assert_equal(Encoding::UTF_8, t.strftime("\u3042%Z").encoding) + assert_equal(true, t.strftime("\u3042%Z").valid_encoding?) + end + + def test_strftime_flags + t = Time.mktime(2001, 10, 1, 2, 0, 0) + assert_equal("01", t.strftime("%d")) + assert_equal("01", t.strftime("%0d")) + assert_equal(" 1", t.strftime("%_d")) + assert_equal(" 1", t.strftime("%e")) + assert_equal("01", t.strftime("%0e")) + assert_equal(" 1", t.strftime("%_e")) + assert_equal("AM", t.strftime("%p")) + assert_equal("am", t.strftime("%#p")) + assert_equal("am", t.strftime("%P")) + assert_equal("AM", t.strftime("%#P")) + assert_equal("02", t.strftime("%H")) + assert_equal("02", t.strftime("%0H")) + assert_equal(" 2", t.strftime("%_H")) + assert_equal("02", t.strftime("%I")) + assert_equal("02", t.strftime("%0I")) + assert_equal(" 2", t.strftime("%_I")) + assert_equal(" 2", t.strftime("%k")) + assert_equal("02", t.strftime("%0k")) + assert_equal(" 2", t.strftime("%_k")) + assert_equal(" 2", t.strftime("%l")) + assert_equal("02", t.strftime("%0l")) + assert_equal(" 2", t.strftime("%_l")) + t = Time.mktime(2001, 10, 1, 14, 0, 0) + assert_equal("PM", t.strftime("%p")) + assert_equal("pm", t.strftime("%#p")) + assert_equal("pm", t.strftime("%P")) + assert_equal("PM", t.strftime("%#P")) + assert_equal("14", t.strftime("%H")) + assert_equal("14", t.strftime("%0H")) + assert_equal("14", t.strftime("%_H")) + assert_equal("02", t.strftime("%I")) + assert_equal("02", t.strftime("%0I")) + assert_equal(" 2", t.strftime("%_I")) + assert_equal("14", t.strftime("%k")) + assert_equal("14", t.strftime("%0k")) + assert_equal("14", t.strftime("%_k")) + assert_equal(" 2", t.strftime("%l")) + assert_equal("02", t.strftime("%0l")) + assert_equal(" 2", t.strftime("%_l")) + end + + def test_strftime_invalid_flags + t = Time.mktime(2001, 10, 1, 2, 0, 0) + assert_equal("%4^p", t.strftime("%4^p"), 'prec after flag') + end + + def test_strftime_year + t = Time.utc(1,1,4) + assert_equal("0001", t.strftime("%Y")) + assert_equal("0001", t.strftime("%G")) + + t = Time.utc(0,1,4) + assert_equal("0000", t.strftime("%Y")) + assert_equal("0000", t.strftime("%G")) + + t = Time.utc(-1,1,4) + assert_equal("-0001", t.strftime("%Y")) + assert_equal("-0001", t.strftime("%G")) + end + + def test_strftime_weeknum + # [ruby-dev:37155] + t = Time.mktime(1970, 1, 18) + assert_equal("0", t.strftime("%w")) + assert_equal("7", t.strftime("%u")) + end + + def test_strftime_ctrlchar + # [ruby-dev:37160] + t2000 = get_t2000 + assert_equal("\t", t2000.strftime("%t")) + assert_equal("\t", t2000.strftime("%0t")) + assert_equal("\t", t2000.strftime("%1t")) + assert_equal(" \t", t2000.strftime("%3t")) + assert_equal("00\t", t2000.strftime("%03t")) + assert_equal("\n", t2000.strftime("%n")) + assert_equal("\n", t2000.strftime("%0n")) + assert_equal("\n", t2000.strftime("%1n")) + assert_equal(" \n", t2000.strftime("%3n")) + assert_equal("00\n", t2000.strftime("%03n")) + end + + def test_strftime_weekflags + # [ruby-dev:37162] + t2000 = get_t2000 + assert_equal("SAT", t2000.strftime("%#a")) + assert_equal("SATURDAY", t2000.strftime("%#A")) + assert_equal("JAN", t2000.strftime("%#b")) + assert_equal("JANUARY", t2000.strftime("%#B")) + assert_equal("JAN", t2000.strftime("%#h")) + assert_equal("FRIDAY", Time.local(2008,1,4).strftime("%#A")) + end + + def test_strftime_rational + t = Time.utc(2000,3,14, 6,53,"58.979323846".to_r) # Pi Day + assert_equal("03/14/2000 6:53:58.97932384600000000000000000000", + t.strftime("%m/%d/%Y %l:%M:%S.%29N")) + assert_equal("03/14/2000 6:53:58.9793238460", + t.strftime("%m/%d/%Y %l:%M:%S.%10N")) + assert_equal("03/14/2000 6:53:58.979323846", + t.strftime("%m/%d/%Y %l:%M:%S.%9N")) + assert_equal("03/14/2000 6:53:58.97932384", + t.strftime("%m/%d/%Y %l:%M:%S.%8N")) + + t = Time.utc(1592,3,14, 6,53,"58.97932384626433832795028841971".to_r) # Pi Day + assert_equal("03/14/1592 6:53:58.97932384626433832795028841971", + t.strftime("%m/%d/%Y %l:%M:%S.%29N")) + assert_equal("03/14/1592 6:53:58.9793238462", + t.strftime("%m/%d/%Y %l:%M:%S.%10N")) + assert_equal("03/14/1592 6:53:58.979323846", + t.strftime("%m/%d/%Y %l:%M:%S.%9N")) + assert_equal("03/14/1592 6:53:58.97932384", + t.strftime("%m/%d/%Y %l:%M:%S.%8N")) + end + + def test_strftime_far_future + # [ruby-core:33985] + assert_equal("3000000000", Time.at(3000000000).strftime('%s')) + end + + def test_strftime_too_wide + bug4457 = '[ruby-dev:43285]' + assert_raise(Errno::ERANGE, bug4457) {Time.now.strftime('%8192z')} + end + + def test_strfimte_zoneoffset + t2000 = get_t2000 + t = t2000.getlocal("+09:00:00") + assert_equal("+0900", t.strftime("%z")) + assert_equal("+09:00", t.strftime("%:z")) + assert_equal("+09:00:00", t.strftime("%::z")) + assert_equal("+09", t.strftime("%:::z")) + + t = t2000.getlocal("+09:00:01") + assert_equal("+0900", t.strftime("%z")) + assert_equal("+09:00", t.strftime("%:z")) + assert_equal("+09:00:01", t.strftime("%::z")) + assert_equal("+09:00:01", t.strftime("%:::z")) + end + + def test_strftime_padding + bug4458 = '[ruby-dev:43287]' + t2000 = get_t2000 + t = t2000.getlocal("+09:00") + assert_equal("+0900", t.strftime("%z")) + assert_equal("+09:00", t.strftime("%:z")) + assert_equal(" +900", t.strftime("%_10z"), bug4458) + assert_equal("+000000900", t.strftime("%10z"), bug4458) + assert_equal(" +9:00", t.strftime("%_10:z"), bug4458) + assert_equal("+000009:00", t.strftime("%10:z"), bug4458) + assert_equal(" +9:00:00", t.strftime("%_10::z"), bug4458) + assert_equal("+009:00:00", t.strftime("%10::z"), bug4458) + assert_equal("+000000009", t.strftime("%10:::z")) + t = t2000.getlocal("-05:00") + assert_equal("-0500", t.strftime("%z")) + assert_equal("-05:00", t.strftime("%:z")) + assert_equal(" -500", t.strftime("%_10z"), bug4458) + assert_equal("-000000500", t.strftime("%10z"), bug4458) + assert_equal(" -5:00", t.strftime("%_10:z"), bug4458) + assert_equal("-000005:00", t.strftime("%10:z"), bug4458) + assert_equal(" -5:00:00", t.strftime("%_10::z"), bug4458) + assert_equal("-005:00:00", t.strftime("%10::z"), bug4458) + assert_equal("-000000005", t.strftime("%10:::z")) + + bug6323 = '[ruby-core:44447]' + t = t2000.getlocal("+00:36") + assert_equal(" +036", t.strftime("%_10z"), bug6323) + assert_equal("+000000036", t.strftime("%10z"), bug6323) + assert_equal(" +0:36", t.strftime("%_10:z"), bug6323) + assert_equal("+000000:36", t.strftime("%10:z"), bug6323) + assert_equal(" +0:36:00", t.strftime("%_10::z"), bug6323) + assert_equal("+000:36:00", t.strftime("%10::z"), bug6323) + assert_equal("+000000:36", t.strftime("%10:::z")) + t = t2000.getlocal("-00:55") + assert_equal(" -055", t.strftime("%_10z"), bug6323) + assert_equal("-000000055", t.strftime("%10z"), bug6323) + assert_equal(" -0:55", t.strftime("%_10:z"), bug6323) + assert_equal("-000000:55", t.strftime("%10:z"), bug6323) + assert_equal(" -0:55:00", t.strftime("%_10::z"), bug6323) + assert_equal("-000:55:00", t.strftime("%10::z"), bug6323) + assert_equal("-000000:55", t.strftime("%10:::z")) + end + + def test_strftime_invalid_modifier + t2000 = get_t2000 + t = t2000.getlocal("+09:00") + assert_equal("%:y", t.strftime("%:y"), 'invalid conversion after : modifier') + assert_equal("%:0z", t.strftime("%:0z"), 'flag after : modifier') + assert_equal("%:10z", t.strftime("%:10z"), 'prec after : modifier') + assert_equal("%Ob", t.strftime("%Ob"), 'invalid conversion after locale modifier') + assert_equal("%Eb", t.strftime("%Eb"), 'invalid conversion after locale modifier') + assert_equal("%O0y", t.strftime("%O0y"), 'flag after locale modifier') + assert_equal("%E0y", t.strftime("%E0y"), 'flag after locale modifier') + assert_equal("%O10y", t.strftime("%O10y"), 'prec after locale modifier') + assert_equal("%E10y", t.strftime("%E10y"), 'prec after locale modifier') + end + + def test_delegate + d1 = SimpleDelegator.new(t1 = Time.utc(2000)) + d2 = SimpleDelegator.new(t2 = Time.utc(2001)) + assert_equal(-1, t1 <=> t2) + assert_equal(1, t2 <=> t1) + assert_equal(-1, d1 <=> d2) + assert_equal(1, d2 <=> d1) + end + + def test_to_r + assert_kind_of(Rational, Time.new(2000,1,1,0,0,Rational(4,3)).to_r) + assert_kind_of(Rational, Time.utc(1970).to_r) + end + + def test_round + t = Time.utc(1999,12,31, 23,59,59) + t2 = (t+0.4).round + assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + t2 = (t+0.49).round + assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + t2 = (t+0.5).round + assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + t2 = (t+1.4).round + assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + t2 = (t+1.49).round + assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + t2 = (t+1.5).round + assert_equal([1,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a) + assert_equal(0, t2.subsec) + + t2 = (t+0.123456789).round(4) + assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a) + assert_equal(Rational(1235,10000), t2.subsec) + + off = 0.0 + 100.times {|i| + t2 = (t+off).round(1) + assert_equal(Rational(i % 10, 10), t2.subsec) + off += 0.1 + } + end + + def test_getlocal_dont_share_eigenclass + bug5012 = "[ruby-dev:44071]" + + t0 = Time.now + class << t0; end + t1 = t0.getlocal + + def t0.m + 0 + end + + assert_raise(NoMethodError, bug5012) { t1.m } + end + + def test_sec_str + bug6193 = '[ruby-core:43569]' + t = nil + assert_nothing_raised(bug6193) {t = Time.new(2012, 1, 2, 3, 4, "5")} + assert_equal(Time.new(2012, 1, 2, 3, 4, 5), t, bug6193) + end + + def test_past + [ + [-(1 << 100), 1, 1, 0, 0, 0], + [-4000, 1, 1, 0, 0, 0], + [-3000, 1, 1, 0, 0, 0], + ].each {|year, mon, day, hour, min, sec| + t = Time.utc(year, mon, day, hour, min, sec) + assert_equal(year, t.year) + assert_equal(mon, t.mon) + assert_equal(day, t.day) + assert_equal(hour, t.hour) + assert_equal(min, t.min) + assert_equal(sec, t.sec) + } + end + + def test_1901 + assert_equal(-0x80000001, Time.utc(1901, 12, 13, 20, 45, 51).tv_sec) + [ + [1901, 12, 13, 20, 45, 50], + [1901, 12, 13, 20, 45, 51], + [1901, 12, 13, 20, 45, 52], # -0x80000000 + [1901, 12, 13, 20, 45, 53], + ].each {|year, mon, day, hour, min, sec| + t = Time.utc(year, mon, day, hour, min, sec) + assert_equal(year, t.year) + assert_equal(mon, t.mon) + assert_equal(day, t.day) + assert_equal(hour, t.hour) + assert_equal(min, t.min) + assert_equal(sec, t.sec) + } + end + + def test_1970 + assert_equal(0, Time.utc(1970, 1, 1, 0, 0, 0).tv_sec) + [ + [1969, 12, 31, 23, 59, 59], + [1970, 1, 1, 0, 0, 0], + [1970, 1, 1, 0, 0, 1], + ].each {|year, mon, day, hour, min, sec| + t = Time.utc(year, mon, day, hour, min, sec) + assert_equal(year, t.year) + assert_equal(mon, t.mon) + assert_equal(day, t.day) + assert_equal(hour, t.hour) + assert_equal(min, t.min) + assert_equal(sec, t.sec) + } + end + + def test_2038 + if no_leap_seconds? + assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec) + end + [ + [2038, 1, 19, 3, 14, 7], + [2038, 1, 19, 3, 14, 8], + [2038, 1, 19, 3, 14, 9], + [2039, 1, 1, 0, 0, 0], + ].each {|year, mon, day, hour, min, sec| + t = Time.utc(year, mon, day, hour, min, sec) + assert_equal(year, t.year) + assert_equal(mon, t.mon) + assert_equal(day, t.day) + assert_equal(hour, t.hour) + assert_equal(min, t.min) + assert_equal(sec, t.sec) + } + end + + def test_future + [ + [3000, 1, 1, 0, 0, 0], + [4000, 1, 1, 0, 0, 0], + [1 << 100, 1, 1, 0, 0, 0], + ].each {|year, mon, day, hour, min, sec| + t = Time.utc(year, mon, day, hour, min, sec) + assert_equal(year, t.year) + assert_equal(mon, t.mon) + assert_equal(day, t.day) + assert_equal(hour, t.hour) + assert_equal(min, t.min) + assert_equal(sec, t.sec) + } + end + + def test_getlocal_nil + now = Time.now + now2 = nil + now3 = nil + assert_nothing_raised { + now2 = now.getlocal + now3 = now.getlocal(nil) + } + assert_equal now2, now3 + assert_equal now2.zone, now3.zone + end +end diff --git a/jni/ruby/test/ruby/test_time_tz.rb b/jni/ruby/test/ruby/test_time_tz.rb new file mode 100644 index 0000000..fb1ab9b --- /dev/null +++ b/jni/ruby/test/ruby/test_time_tz.rb @@ -0,0 +1,415 @@ +require 'test/unit' + +class TestTimeTZ < Test::Unit::TestCase + has_right_tz = true + has_lisbon_tz = true + force_tz_test = ENV["RUBY_FORCE_TIME_TZ_TEST"] == "yes" + case RUBY_PLATFORM + when /linux/ + force_tz_test = true + when /darwin|freebsd/ + has_lisbon_tz = false + force_tz_test = true + end + + if force_tz_test + module Util + def with_tz(tz) + old = ENV["TZ"] + begin + ENV["TZ"] = tz + yield + ensure + ENV["TZ"] = old + end + end + end + else + module Util + def with_tz(tz) + if ENV["TZ"] == tz + yield + end + end + end + end + + module Util + def have_tz_offset?(tz) + with_tz(tz) {!Time.now.utc_offset.zero?} + end + + def format_gmtoff(gmtoff, colon=false) + if gmtoff < 0 + expected = "-" + gmtoff = -gmtoff + else + expected = "+" + end + gmtoff /= 60 + expected << "%02d" % [gmtoff / 60] + expected << ":" if colon + expected << "%02d" % [gmtoff % 60] + expected + end + + def format_gmtoff2(gmtoff) + if gmtoff < 0 + expected = "-" + gmtoff = -gmtoff + else + expected = "+" + end + expected << "%02d:%02d:%02d" % [gmtoff / 3600, gmtoff % 3600 / 60, gmtoff % 60] + expected + end + + def group_by(e, &block) + if e.respond_to? :group_by + e.group_by(&block) + else + h = {} + e.each {|o| + (h[yield(o)] ||= []) << o + } + h + end + end + + end + + include Util + extend Util + + has_right_tz &&= have_tz_offset?("right/America/Los_Angeles") + has_lisbon_tz &&= have_tz_offset?("Europe/Lisbon") + + def time_to_s(t) + t.to_s + end + + + def assert_time_constructor(tz, expected, method, args, message=nil) + m = message ? "#{message}\n" : "" + m << "TZ=#{tz} Time.#{method}(#{args.map {|arg| arg.inspect }.join(', ')})" + real = time_to_s(Time.send(method, *args)) + assert_equal(expected, real, m) + end + + def test_america_los_angeles + with_tz(tz="America/Los_Angeles") { + assert_time_constructor(tz, "2007-03-11 03:00:00 -0700", :local, [2007,3,11,2,0,0]) + assert_time_constructor(tz, "2007-03-11 03:59:59 -0700", :local, [2007,3,11,2,59,59]) + assert_equal("PST", Time.new(0x1_0000_0000_0000_0000, 1).zone) + assert_equal("PDT", Time.new(0x1_0000_0000_0000_0000, 8).zone) + assert_equal(false, Time.new(0x1_0000_0000_0000_0000, 1).isdst) + assert_equal(true, Time.new(0x1_0000_0000_0000_0000, 8).isdst) + } + end + + def test_america_managua + with_tz(tz="America/Managua") { + assert_time_constructor(tz, "1993-01-01 01:00:00 -0500", :local, [1993,1,1,0,0,0]) + assert_time_constructor(tz, "1993-01-01 01:59:59 -0500", :local, [1993,1,1,0,59,59]) + } + end + + def test_asia_singapore + with_tz(tz="Asia/Singapore") { + assert_time_constructor(tz, "1981-12-31 23:59:59 +0730", :local, [1981,12,31,23,59,59]) + assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,0,0]) + assert_time_constructor(tz, "1982-01-01 00:59:59 +0800", :local, [1982,1,1,0,29,59]) + assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,30,0]) + } + end + + def test_asia_tokyo + with_tz(tz="Asia/Tokyo") { + assert_time_constructor(tz, "1951-05-06 03:00:00 +1000", :local, [1951,5,6,2,0,0]) + assert_time_constructor(tz, "1951-05-06 03:59:59 +1000", :local, [1951,5,6,2,59,59]) + assert_time_constructor(tz, "2010-06-10 06:13:28 +0900", :local, [2010,6,10,6,13,28]) + } + end + + def test_canada_newfoundland + with_tz(tz="America/St_Johns") { + assert_time_constructor(tz, "2007-11-03 23:00:59 -0230", :new, [2007,11,3,23,0,59,:dst]) + assert_time_constructor(tz, "2007-11-03 23:01:00 -0230", :new, [2007,11,3,23,1,0,:dst]) + assert_time_constructor(tz, "2007-11-03 23:59:59 -0230", :new, [2007,11,3,23,59,59,:dst]) + assert_time_constructor(tz, "2007-11-04 00:00:00 -0230", :new, [2007,11,4,0,0,0,:dst]) + assert_time_constructor(tz, "2007-11-04 00:00:59 -0230", :new, [2007,11,4,0,0,59,:dst]) + assert_time_constructor(tz, "2007-11-03 23:01:00 -0330", :new, [2007,11,3,23,1,0,:std]) + assert_time_constructor(tz, "2007-11-03 23:59:59 -0330", :new, [2007,11,3,23,59,59,:std]) + assert_time_constructor(tz, "2007-11-04 00:00:59 -0330", :new, [2007,11,4,0,0,59,:std]) + assert_time_constructor(tz, "2007-11-04 00:01:00 -0330", :new, [2007,11,4,0,1,0,:std]) + } + end + + def test_europe_brussels + with_tz(tz="Europe/Brussels") { + assert_time_constructor(tz, "1916-04-30 23:59:59 +0100", :local, [1916,4,30,23,59,59]) + assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1], "[ruby-core:30672]") + assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,0,59,59]) + assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1,1,0,0]) + assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,1,59,59]) + } + end + + def test_europe_berlin + with_tz(tz="Europe/Berlin") { + assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [2011,10,30,2,0,0], "[ruby-core:67345] [Bug #10698]") + assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [0,0,2,30,10,2011,nil,nil,false,nil]) + assert_time_constructor(tz, "2011-10-30 02:00:00 +0200", :local, [0,0,2,30,10,2011,nil,nil,true,nil]) + } + end + + def test_europe_lisbon + with_tz("Europe/Lisbon") { + assert_equal("LMT", Time.new(-0x1_0000_0000_0000_0000).zone) + } + end if has_lisbon_tz + + def test_europe_moscow + with_tz(tz="Europe/Moscow") { + assert_time_constructor(tz, "1992-03-29 00:00:00 +0400", :local, [1992,3,28,23,0,0]) + assert_time_constructor(tz, "1992-03-29 00:59:59 +0400", :local, [1992,3,28,23,59,59]) + } + end + + def test_pacific_kiritimati + with_tz(tz="Pacific/Kiritimati") { + assert_time_constructor(tz, "1994-12-31 23:59:59 -1000", :local, [1994,12,31,23,59,59]) + assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,1,0,0,0]) + assert_time_constructor(tz, "1995-01-02 23:59:59 +1400", :local, [1995,1,1,23,59,59]) + assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,2,0,0,0]) + } + end + + def test_right_utc + with_tz(tz="right/UTC") { + assert_time_constructor(tz, "2008-12-31 23:59:59 UTC", :utc, [2008,12,31,23,59,59]) + assert_time_constructor(tz, "2008-12-31 23:59:60 UTC", :utc, [2008,12,31,23,59,60]) + assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,24,0,0]) + assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2009,1,1,0,0,0]) + } + end if has_right_tz + + def test_right_america_los_angeles + with_tz(tz="right/America/Los_Angeles") { + assert_time_constructor(tz, "2008-12-31 15:59:59 -0800", :local, [2008,12,31,15,59,59]) + assert_time_constructor(tz, "2008-12-31 15:59:60 -0800", :local, [2008,12,31,15,59,60]) + assert_time_constructor(tz, "2008-12-31 16:00:00 -0800", :local, [2008,12,31,16,0,0]) + } + end if has_right_tz + + MON2NUM = { + "Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, + "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12 + } + + @testnum = 0 + def self.gen_test_name(hint) + @testnum += 1 + s = "test_gen_#{@testnum}" + s.sub(/gen_/) { "gen" + "_#{hint}_".gsub(/[^0-9A-Za-z]+/, '_') } + end + + def self.parse_zdump_line(line) + return nil if /\A\#/ =~ line || /\A\s*\z/ =~ line + if /\A(\S+)\s+ + \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+UTC? + \s+=\s+ + \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+\S+ + \s+isdst=\d+\s+gmtoff=(-?\d+)\n + \z/x !~ line + raise "unexpected zdump line: #{line.inspect}" + end + tz, u_mon, u_day, u_hour, u_min, u_sec, u_year, + l_mon, l_day, l_hour, l_min, l_sec, l_year, gmtoff = $~.captures + u_year = u_year.to_i + u_mon = MON2NUM[u_mon] + u_day = u_day.to_i + u_hour = u_hour.to_i + u_min = u_min.to_i + u_sec = u_sec.to_i + l_year = l_year.to_i + l_mon = MON2NUM[l_mon] + l_day = l_day.to_i + l_hour = l_hour.to_i + l_min = l_min.to_i + l_sec = l_sec.to_i + gmtoff = gmtoff.to_i + [tz, + [u_year, u_mon, u_day, u_hour, u_min, u_sec], + [l_year, l_mon, l_day, l_hour, l_min, l_sec], + gmtoff] + end + + def self.gen_zdump_test(data) + sample = [] + data.each_line {|line| + s = parse_zdump_line(line) + sample << s if s + } + sample.each {|tz, u, l, gmtoff| + expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u + expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)]) + mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})" + mesg = "#{mesg_utc}.localtime" + define_method(gen_test_name(tz)) { + with_tz(tz) { + t = nil + assert_nothing_raised(mesg) { t = Time.utc(*u) } + assert_equal(expected_utc, time_to_s(t), mesg_utc) + assert_nothing_raised(mesg) { t.localtime } + assert_equal(expected, time_to_s(t), mesg) + assert_equal(gmtoff, t.gmtoff) + assert_equal(format_gmtoff(gmtoff), t.strftime("%z")) + assert_equal(format_gmtoff(gmtoff, true), t.strftime("%:z")) + assert_equal(format_gmtoff2(gmtoff), t.strftime("%::z")) + assert_equal(Encoding::US_ASCII, t.zone.encoding) + } + } + } + + group_by(sample) {|tz, _, _, _| tz }.each {|tz, a| + a.each_with_index {|(_, _, l, gmtoff), i| + expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)]) + monotonic_to_past = i == 0 || (a[i-1][2] <=> l) < 0 + monotonic_to_future = i == a.length-1 || (l <=> a[i+1][2]) < 0 + if monotonic_to_past && monotonic_to_future + define_method(gen_test_name(tz)) { + with_tz(tz) { + assert_time_constructor(tz, expected, :local, l) + assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil]) + assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil]) + assert_time_constructor(tz, expected, :new, l) + assert_time_constructor(tz, expected, :new, l+[:std]) + assert_time_constructor(tz, expected, :new, l+[:dst]) + } + } + elsif monotonic_to_past && !monotonic_to_future + define_method(gen_test_name(tz)) { + with_tz(tz) { + assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil]) + assert_time_constructor(tz, expected, :new, l+[:dst]) + } + } + elsif !monotonic_to_past && monotonic_to_future + define_method(gen_test_name(tz)) { + with_tz(tz) { + assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil]) + assert_time_constructor(tz, expected, :new, l+[:std]) + } + } + else + define_method(gen_test_name(tz)) { + flunk("time in reverse order: TZ=#{tz} #{expected}") + } + end + } + } + end + + gen_zdump_test <<'End' +America/Lima Sun Apr 1 03:59:59 1990 UTC = Sat Mar 31 23:59:59 1990 PEST isdst=1 gmtoff=-14400 +America/Lima Sun Apr 1 04:00:00 1990 UTC = Sat Mar 31 23:00:00 1990 PET isdst=0 gmtoff=-18000 +America/Lima Sat Jan 1 04:59:59 1994 UTC = Fri Dec 31 23:59:59 1993 PET isdst=0 gmtoff=-18000 +America/Lima Sat Jan 1 05:00:00 1994 UTC = Sat Jan 1 01:00:00 1994 PEST isdst=1 gmtoff=-14400 +America/Lima Fri Apr 1 03:59:59 1994 UTC = Thu Mar 31 23:59:59 1994 PEST isdst=1 gmtoff=-14400 +America/Lima Fri Apr 1 04:00:00 1994 UTC = Thu Mar 31 23:00:00 1994 PET isdst=0 gmtoff=-18000 +America/Los_Angeles Sun Apr 2 09:59:59 2006 UTC = Sun Apr 2 01:59:59 2006 PST isdst=0 gmtoff=-28800 +America/Los_Angeles Sun Apr 2 10:00:00 2006 UTC = Sun Apr 2 03:00:00 2006 PDT isdst=1 gmtoff=-25200 +America/Los_Angeles Sun Oct 29 08:59:59 2006 UTC = Sun Oct 29 01:59:59 2006 PDT isdst=1 gmtoff=-25200 +America/Los_Angeles Sun Oct 29 09:00:00 2006 UTC = Sun Oct 29 01:00:00 2006 PST isdst=0 gmtoff=-28800 +America/Los_Angeles Sun Mar 11 09:59:59 2007 UTC = Sun Mar 11 01:59:59 2007 PST isdst=0 gmtoff=-28800 +America/Los_Angeles Sun Mar 11 10:00:00 2007 UTC = Sun Mar 11 03:00:00 2007 PDT isdst=1 gmtoff=-25200 +America/Los_Angeles Sun Nov 4 08:59:59 2007 UTC = Sun Nov 4 01:59:59 2007 PDT isdst=1 gmtoff=-25200 +America/Los_Angeles Sun Nov 4 09:00:00 2007 UTC = Sun Nov 4 01:00:00 2007 PST isdst=0 gmtoff=-28800 +America/Managua Thu Sep 24 04:59:59 1992 UTC = Wed Sep 23 23:59:59 1992 EST isdst=0 gmtoff=-18000 +America/Managua Thu Sep 24 05:00:00 1992 UTC = Wed Sep 23 23:00:00 1992 CST isdst=0 gmtoff=-21600 +America/Managua Fri Jan 1 05:59:59 1993 UTC = Thu Dec 31 23:59:59 1992 CST isdst=0 gmtoff=-21600 +America/Managua Fri Jan 1 06:00:00 1993 UTC = Fri Jan 1 01:00:00 1993 EST isdst=0 gmtoff=-18000 +America/Managua Wed Jan 1 04:59:59 1997 UTC = Tue Dec 31 23:59:59 1996 EST isdst=0 gmtoff=-18000 +America/Managua Wed Jan 1 05:00:00 1997 UTC = Tue Dec 31 23:00:00 1996 CST isdst=0 gmtoff=-21600 +Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0 gmtoff=27000 +Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0 gmtoff=27000 +Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0 gmtoff=28800 +Asia/Tokyo Sat May 5 16:59:59 1951 UTC = Sun May 6 01:59:59 1951 JST isdst=0 gmtoff=32400 +Asia/Tokyo Sat May 5 17:00:00 1951 UTC = Sun May 6 03:00:00 1951 JDT isdst=1 gmtoff=36000 +Asia/Tokyo Fri Sep 7 15:59:59 1951 UTC = Sat Sep 8 01:59:59 1951 JDT isdst=1 gmtoff=36000 +Asia/Tokyo Fri Sep 7 16:00:00 1951 UTC = Sat Sep 8 01:00:00 1951 JST isdst=0 gmtoff=32400 +America/St_Johns Sun Mar 11 03:30:59 2007 UTC = Sun Mar 11 00:00:59 2007 NST isdst=0 gmtoff=-12600 +America/St_Johns Sun Mar 11 03:31:00 2007 UTC = Sun Mar 11 01:01:00 2007 NDT isdst=1 gmtoff=-9000 +America/St_Johns Sun Nov 4 02:30:59 2007 UTC = Sun Nov 4 00:00:59 2007 NDT isdst=1 gmtoff=-9000 +America/St_Johns Sun Nov 4 02:31:00 2007 UTC = Sat Nov 3 23:01:00 2007 NST isdst=0 gmtoff=-12600 +Europe/Brussels Sun Apr 30 22:59:59 1916 UTC = Sun Apr 30 23:59:59 1916 CET isdst=0 gmtoff=3600 +Europe/Brussels Sun Apr 30 23:00:00 1916 UTC = Mon May 1 01:00:00 1916 CEST isdst=1 gmtoff=7200 +Europe/Brussels Sat Sep 30 22:59:59 1916 UTC = Sun Oct 1 00:59:59 1916 CEST isdst=1 gmtoff=7200 +Europe/Brussels Sat Sep 30 23:00:00 1916 UTC = Sun Oct 1 00:00:00 1916 CET isdst=0 gmtoff=3600 +Europe/London Sun Mar 16 01:59:59 1947 UTC = Sun Mar 16 01:59:59 1947 GMT isdst=0 gmtoff=0 +Europe/London Sun Mar 16 02:00:00 1947 UTC = Sun Mar 16 03:00:00 1947 BST isdst=1 gmtoff=3600 +Europe/London Sun Apr 13 00:59:59 1947 UTC = Sun Apr 13 01:59:59 1947 BST isdst=1 gmtoff=3600 +Europe/London Sun Apr 13 01:00:00 1947 UTC = Sun Apr 13 03:00:00 1947 BDST isdst=1 gmtoff=7200 +Europe/London Sun Aug 10 00:59:59 1947 UTC = Sun Aug 10 02:59:59 1947 BDST isdst=1 gmtoff=7200 +Europe/London Sun Aug 10 01:00:00 1947 UTC = Sun Aug 10 02:00:00 1947 BST isdst=1 gmtoff=3600 +Europe/London Sun Nov 2 01:59:59 1947 UTC = Sun Nov 2 02:59:59 1947 BST isdst=1 gmtoff=3600 +Europe/London Sun Nov 2 02:00:00 1947 UTC = Sun Nov 2 02:00:00 1947 GMT isdst=0 gmtoff=0 +Europe/Moscow Sat Jan 18 23:59:59 1992 UTC = Sun Jan 19 01:59:59 1992 MSK isdst=0 gmtoff=7200 +Europe/Moscow Sun Jan 19 00:00:00 1992 UTC = Sun Jan 19 03:00:00 1992 MSK isdst=0 gmtoff=10800 +Europe/Moscow Sat Mar 28 19:59:59 1992 UTC = Sat Mar 28 22:59:59 1992 MSK isdst=0 gmtoff=10800 +Europe/Moscow Sat Mar 28 20:00:00 1992 UTC = Sun Mar 29 00:00:00 1992 MSD isdst=1 gmtoff=14400 +Europe/Moscow Sat Sep 26 18:59:59 1992 UTC = Sat Sep 26 22:59:59 1992 MSD isdst=1 gmtoff=14400 +Europe/Moscow Sat Sep 26 19:00:00 1992 UTC = Sat Sep 26 22:00:00 1992 MSK isdst=0 gmtoff=10800 +Pacific/Kiritimati Sun Jan 1 09:59:59 1995 UTC = Sat Dec 31 23:59:59 1994 LINT isdst=0 gmtoff=-36000 +Pacific/Kiritimati Sun Jan 1 10:00:00 1995 UTC = Mon Jan 2 00:00:00 1995 LINT isdst=0 gmtoff=50400 +End + gen_zdump_test <<'End' if has_right_tz +right/America/Los_Angeles Fri Jun 30 23:59:60 1972 UTC = Fri Jun 30 16:59:60 1972 PDT isdst=1 gmtoff=-25200 +right/America/Los_Angeles Wed Dec 31 23:59:60 2008 UTC = Wed Dec 31 15:59:60 2008 PST isdst=0 gmtoff=-28800 +#right/Asia/Tokyo Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 08:59:60 1972 JST isdst=0 gmtoff=32400 +#right/Asia/Tokyo Sat Dec 31 23:59:60 2005 UTC = Sun Jan 1 08:59:60 2006 JST isdst=0 gmtoff=32400 +right/Europe/Paris Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 00:59:60 1972 CET isdst=0 gmtoff=3600 +right/Europe/Paris Wed Dec 31 23:59:60 2008 UTC = Thu Jan 1 00:59:60 2009 CET isdst=0 gmtoff=3600 +End + + def self.gen_variational_zdump_test(hint, data) + sample = [] + data.each_line {|line| + s = parse_zdump_line(line) + sample << s if s + } + + define_method(gen_test_name(hint)) { + results = [] + sample.each {|tz, u, l, gmtoff| + expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u + expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)]) + mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})" + mesg = "#{mesg_utc}.localtime" + with_tz(tz) { + t = nil + assert_nothing_raised(mesg) { t = Time.utc(*u) } + assert_equal(expected_utc, time_to_s(t), mesg_utc) + assert_nothing_raised(mesg) { t.localtime } + + results << [ + expected == time_to_s(t), + gmtoff == t.gmtoff, + format_gmtoff(gmtoff) == t.strftime("%z"), + format_gmtoff(gmtoff, true) == t.strftime("%:z"), + format_gmtoff2(gmtoff) == t.strftime("%::z") + ] + } + } + assert_includes(results, [true, true, true, true, true]) + } + end + + # tzdata-2014g fixed the offset for lisbon from -0:36:32 to -0:36:45. + # [ruby-core:65058] [Bug #10245] + gen_variational_zdump_test "lisbon", <<'End' if has_lisbon_tz +Europe/Lisbon Mon Jan 1 00:36:31 1912 UTC = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2192 +Europe/Lisbon Mon Jan 1 00:36:44 1912 UT = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2205 +End +end diff --git a/jni/ruby/test/ruby/test_trace.rb b/jni/ruby/test/ruby/test_trace.rb new file mode 100644 index 0000000..775c458 --- /dev/null +++ b/jni/ruby/test/ruby/test_trace.rb @@ -0,0 +1,61 @@ +require 'test/unit' + +class TestTrace < Test::Unit::TestCase + def test_trace + $x = 1234 + $y = 0 + trace_var :$x, proc{$y = $x} + $x = 40414 + assert_equal($x, $y) + + untrace_var :$x + $x = 19660208 + assert_not_equal($x, $y) + + trace_var :$x, proc{$x *= 2} + $x = 5 + assert_equal(10, $x) + + untrace_var :$x + end + + def test_trace_tainted_proc + $x = 1234 + s = proc { $y = :foo } + trace_var :$x, s + s.taint + $x = 42 + assert_equal(:foo, $y) + ensure + untrace_var :$x + end + + def test_trace_proc_that_raises_exception + $x = 1234 + trace_var :$x, proc { raise } + assert_raise(RuntimeError) { $x = 42 } + ensure + untrace_var :$x + end + + def test_trace_string + $x = 1234 + trace_var :$x, "$y = :bar" + $x = 42 + assert_equal(:bar, $y) + ensure + untrace_var :$x + end + + def test_trace_break + bug2722 = '[ruby-core:31783]' + a = Object.new.extend(Enumerable) + def a.each + yield + end + assert(Thread.start { + Thread.current.add_trace_func(proc{}) + a.any? {true} + }.value, bug2722) + end +end diff --git a/jni/ruby/test/ruby/test_transcode.rb b/jni/ruby/test/ruby/test_transcode.rb new file mode 100644 index 0000000..4bade11 --- /dev/null +++ b/jni/ruby/test/ruby/test_transcode.rb @@ -0,0 +1,2121 @@ +# encoding: ASCII-8BIT # make sure this runs in binary mode +# some of the comments are in UTF-8 + +require 'test/unit' + +class TestTranscode < Test::Unit::TestCase + def test_errors + assert_raise(Encoding::ConverterNotFoundError) { 'abc'.encode('foo', 'bar') } + assert_raise(Encoding::ConverterNotFoundError) { 'abc'.encode!('foo', 'bar') } + assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode('foo') } + assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode!('foo') } + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode('utf-8','ASCII-8BIT') } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode('utf-8','US-ASCII') } + assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode('utf-8','iso-8859-3') } + assert_raise(RuntimeError) { 'hello'.freeze.encode!('iso-8859-1') } + assert_raise(RuntimeError) { '\u3053\u3093\u306b\u3061\u306f'.freeze.encode!('iso-8859-1') } # こんにちは + end + + def test_arguments + assert_equal('abc', 'abc'.force_encoding('utf-8').encode('iso-8859-1')) + # check that encoding is kept when no conversion is done + assert_equal('abc'.force_encoding('Shift_JIS'), 'abc'.force_encoding('Shift_JIS').encode('Shift_JIS')) + assert_equal('abc'.force_encoding('Shift_JIS'), 'abc'.force_encoding('Shift_JIS').encode!('Shift_JIS')) + # assert that encoding is correctly set + assert_equal("D\u00FCrst".encoding, "D\xFCrst".force_encoding('iso-8859-1').encode('utf-8').encoding) + # check that Encoding can be used as parameter + assert_equal("D\u00FCrst", "D\xFCrst".encode('utf-8', Encoding.find('ISO-8859-1'))) + assert_equal("D\u00FCrst", "D\xFCrst".encode(Encoding.find('utf-8'), 'ISO-8859-1')) + assert_equal("D\u00FCrst", "D\xFCrst".encode(Encoding.find('utf-8'), Encoding.find('ISO-8859-1'))) + end + + def test_noargument + EnvUtil.with_default_internal(nil) do + assert_equal("\u3042".encode, "\u3042") + assert_equal("\xE3\x81\x82\x81".force_encoding("utf-8").encode, + "\xE3\x81\x82\x81".force_encoding("utf-8")) + end + EnvUtil.with_default_internal('EUC-JP') do + assert_equal("\u3042".encode, "\xA4\xA2".force_encoding('EUC-JP')) + assert_equal("\xE3\x81\x82\x81".force_encoding("utf-8").encode, + "\xA4\xA2?".force_encoding('EUC-JP')) + end + end + + def test_length + assert_equal("\u20AC"*20, ("\xA4"*20).encode('utf-8', 'iso-8859-15')) + assert_equal("\u20AC"*20, ("\xA4"*20).encode!('utf-8', 'iso-8859-15')) + assert_equal("\u20AC"*2000, ("\xA4"*2000).encode('utf-8', 'iso-8859-15')) + assert_equal("\u20AC"*2000, ("\xA4"*2000).encode!('utf-8', 'iso-8859-15')) + assert_equal("\u20AC"*200000, ("\xA4"*200000).encode('utf-8', 'iso-8859-15')) + assert_equal("\u20AC"*200000, ("\xA4"*200000).encode!('utf-8', 'iso-8859-15')) + end + + def check_both_ways(utf8, raw, encoding) + assert_equal(utf8.force_encoding('utf-8'), raw.encode('utf-8', encoding),utf8.dump+raw.dump) + assert_equal(raw.force_encoding(encoding), utf8.encode(encoding, 'utf-8')) + end + + def check_both_ways2(str1, enc1, str2, enc2) + assert_equal(str1.force_encoding(enc1), str2.encode(enc1, enc2)) + assert_equal(str2.force_encoding(enc2), str1.encode(enc2, enc1)) + end + + def test_encoding_of_ascii_originating_from_binary + binary_string = [0x82, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6c, 0x6f, + 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67] + class << binary_string + # create a copy on write substring that contains + # just the ascii characters (i.e. this is...), in JRuby + # the underlying string have the same buffer backing + # it up, but the offset of the string will be 1 instead + # of 0. + def make_cow_substring + pack('C27').slice(1, 26) + end + end + + ascii_string = binary_string.make_cow_substring + assert_equal("this is a very long string", ascii_string) + assert_equal(Encoding::ASCII_8BIT, ascii_string.encoding) + utf8_string = nil + assert_nothing_raised("JRUBY-6764") do + utf8_string = ascii_string.encode(Encoding::UTF_8) + end + assert_equal("this is a very long string", utf8_string) + assert_equal(Encoding::UTF_8, utf8_string.encoding) + end + + def test_encodings + check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D", + "\x82\xdc\x82\xc2\x82\xe0\x82\xc6 \x82\xe4\x82\xab\x82\xd0\x82\xeb", 'shift_jis') # まつもと ゆきひろ + check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D", + "\xa4\xde\xa4\xc4\xa4\xe2\xa4\xc8 \xa4\xe6\xa4\xad\xa4\xd2\xa4\xed", 'euc-jp') + check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D", + "\xa4\xde\xa4\xc4\xa4\xe2\xa4\xc8 \xa4\xe6\xa4\xad\xa4\xd2\xa4\xed", 'euc-jis-2004') + check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘 + check_both_ways("\u677E\u672C\u884C\u5F18", "\xbe\xbe\xcb\xdc\xb9\xd4\xb9\xb0", 'euc-jp') + check_both_ways("\u677E\u672C\u884C\u5F18", "\xbe\xbe\xcb\xdc\xb9\xd4\xb9\xb0", 'euc-jis-2004') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-1') # Dürst + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-2') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-3') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-4') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-9') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-10') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-13') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-14') + check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-15') + check_both_ways("r\u00E9sum\u00E9", "r\xE9sum\xE9", 'iso-8859-1') # résumé + check_both_ways("\u0065\u006C\u0151\u00ED\u0072\u00E1\u0073", "el\xF5\xEDr\xE1s", 'iso-8859-2') # előírás + check_both_ways("\u043F\u0435\u0440\u0435\u0432\u043E\u0434", + "\xDF\xD5\xE0\xD5\xD2\xDE\xD4", 'iso-8859-5') # перевод + check_both_ways("\u0643\u062A\u0628", "\xE3\xCA\xC8", 'iso-8859-6') # كتب + check_both_ways("\u65E5\u8A18", "\x93\xFA\x8BL", 'shift_jis') # 日記 + check_both_ways("\u65E5\u8A18", "\xC6\xFC\xB5\xAD", 'euc-jp') + check_both_ways("\u65E5\u8A18", "\xC6\xFC\xB5\xAD", 'euc-jis-2004') + check_both_ways("\uC560\uC778\uAD6C\uD568\u0020\u6734\uC9C0\uC778", + "\xBE\xD6\xC0\xCE\xB1\xB8\xC7\xD4\x20\xDA\xD3\xC1\xF6\xC0\xCE", 'euc-kr') # 애인구함 朴지인 + check_both_ways("\uC544\uD58F\uD58F\u0020\uB620\uBC29\uD6BD\uB2D8\u0020\uC0AC\uB791\uD716", + "\xBE\xC6\xC1\x64\xC1\x64\x20\x8C\x63\xB9\xE6\xC4\x4F\xB4\xD4\x20\xBB\xE7\xB6\xFB\xC5\x42", 'cp949') # 아햏햏 똠방횽님 사랑휖 + assert_equal(Encoding::ISO_8859_1, "D\xFCrst".force_encoding('iso-8859-2').encode('iso-8859-1', 'iso-8859-1').encoding) + end + + def test_twostep + assert_equal("D\xFCrst".force_encoding('iso-8859-2'), "D\xFCrst".encode('iso-8859-2', 'iso-8859-1')) + end + + def test_ascii_range + encodings = [ + 'US-ASCII', 'ASCII-8BIT', + 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', + 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', + 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', + 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-13', + 'ISO-8859-14', 'ISO-8859-15', + 'EUC-JP', 'SHIFT_JIS', 'EUC-KR' + ] + all_ascii = (0..127).to_a.pack 'C*' + encodings.each do |enc| + test_start = all_ascii + assert_equal(test_start, test_start.encode('UTF-8',enc).encode(enc).force_encoding('ASCII-8BIT')) + end + end + + def test_all_bytes + encodings_8859 = [ + 'ISO-8859-1', 'ISO-8859-2', + #'ISO-8859-3', # not all bytes used + 'ISO-8859-4', 'ISO-8859-5', + #'ISO-8859-6', # not all bytes used + #'ISO-8859-7', # not all bytes used + #'ISO-8859-8', # not all bytes used + 'ISO-8859-9', 'ISO-8859-10', + #'ISO-8859-11', # not all bytes used + #'ISO-8859-12', # not available + 'ISO-8859-13','ISO-8859-14','ISO-8859-15', + #'ISO-8859-16', # not available + ] + all_bytes = (0..255).to_a.pack 'C*' + encodings_8859.each do |enc| + test_start = all_bytes + assert_equal(test_start, test_start.encode('UTF-8',enc).encode(enc).force_encoding('ASCII-8BIT')) + end + end + + def test_windows_874 + check_both_ways("\u20AC", "\x80", 'windows-874') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x84".encode("utf-8", 'windows-874') } + check_both_ways("\u2026", "\x85", 'windows-874') # … + assert_raise(Encoding::UndefinedConversionError) { "\x86".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-874') } + check_both_ways("\u2018", "\x91", 'windows-874') # ‘ + check_both_ways("\u2014", "\x97", 'windows-874') # — + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-874') } + check_both_ways("\u00A0", "\xA0", 'windows-874') # non-breaking space + check_both_ways("\u0E0F", "\xAF", 'windows-874') # ฏ + check_both_ways("\u0E10", "\xB0", 'windows-874') # ฐ + check_both_ways("\u0E1F", "\xBF", 'windows-874') # ฟ + check_both_ways("\u0E20", "\xC0", 'windows-874') # ภ + check_both_ways("\u0E2F", "\xCF", 'windows-874') # ฯ + check_both_ways("\u0E30", "\xD0", 'windows-874') # ะ + check_both_ways("\u0E3A", "\xDA", 'windows-874') # ฺ + assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'windows-874') } + check_both_ways("\u0E3F", "\xDF", 'windows-874') # ฿ + check_both_ways("\u0E40", "\xE0", 'windows-874') # เ + check_both_ways("\u0E4F", "\xEF", 'windows-874') # ๏ + check_both_ways("\u0E50", "\xF0", 'windows-874') # ๐ + check_both_ways("\u0E5B", "\xFB", 'windows-874') # ๛ + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-874') } + end + + def test_windows_1250 + check_both_ways("\u20AC", "\x80", 'windows-1250') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1250') } + check_both_ways("\u201A", "\x82", 'windows-1250') # ‚ + assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1250') } + check_both_ways("\u201E", "\x84", 'windows-1250') # „ + check_both_ways("\u2021", "\x87", 'windows-1250') # ‡ + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1250') } + check_both_ways("\u2030", "\x89", 'windows-1250') # ‰ + check_both_ways("\u0179", "\x8F", 'windows-1250') # Ź + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1250') } + check_both_ways("\u2018", "\x91", 'windows-1250') # ‘ + check_both_ways("\u2014", "\x97", 'windows-1250') # — + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1250') } + check_both_ways("\u2122", "\x99", 'windows-1250') # ™ + check_both_ways("\u00A0", "\xA0", 'windows-1250') # non-breaking space + check_both_ways("\u017B", "\xAF", 'windows-1250') # Ż + check_both_ways("\u00B0", "\xB0", 'windows-1250') # ° + check_both_ways("\u017C", "\xBF", 'windows-1250') # ż + check_both_ways("\u0154", "\xC0", 'windows-1250') # Ŕ + check_both_ways("\u010E", "\xCF", 'windows-1250') # Ď + check_both_ways("\u0110", "\xD0", 'windows-1250') # Đ + check_both_ways("\u00DF", "\xDF", 'windows-1250') # ß + check_both_ways("\u0155", "\xE0", 'windows-1250') # ŕ + check_both_ways("\u010F", "\xEF", 'windows-1250') # ď + check_both_ways("\u0111", "\xF0", 'windows-1250') # đ + check_both_ways("\u02D9", "\xFF", 'windows-1250') # ˙ + end + + def test_windows_1251 + check_both_ways("\u0402", "\x80", 'windows-1251') # Ђ + check_both_ways("\u20AC", "\x88", 'windows-1251') # € + check_both_ways("\u040F", "\x8F", 'windows-1251') # Џ + check_both_ways("\u0452", "\x90", 'windows-1251') # ђ + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1251') } + check_both_ways("\u045F", "\x9F", 'windows-1251') # џ + check_both_ways("\u00A0", "\xA0", 'windows-1251') # non-breaking space + check_both_ways("\u0407", "\xAF", 'windows-1251') # Ї + check_both_ways("\u00B0", "\xB0", 'windows-1251') # ° + check_both_ways("\u0457", "\xBF", 'windows-1251') # ї + check_both_ways("\u0410", "\xC0", 'windows-1251') # А + check_both_ways("\u041F", "\xCF", 'windows-1251') # П + check_both_ways("\u0420", "\xD0", 'windows-1251') # Р + check_both_ways("\u042F", "\xDF", 'windows-1251') # Я + check_both_ways("\u0430", "\xE0", 'windows-1251') # а + check_both_ways("\u043F", "\xEF", 'windows-1251') # п + check_both_ways("\u0440", "\xF0", 'windows-1251') # р + check_both_ways("\u044F", "\xFF", 'windows-1251') # я + end + + def test_windows_1252 + check_both_ways("\u20AC", "\x80", 'windows-1252') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1252') } + check_both_ways("\u201A", "\x82", 'windows-1252') # ‚ + check_both_ways("\u0152", "\x8C", 'windows-1252') # >Œ + assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1252') } + check_both_ways("\u017D", "\x8E", 'windows-1252') # Ž + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1252') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1252') } + check_both_ways("\u2018", "\x91", 'windows-1252') #‘ + check_both_ways("\u0153", "\x9C", 'windows-1252') # œ + assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1252') } + check_both_ways("\u017E", "\x9E", 'windows-1252') # ž + check_both_ways("\u00A0", "\xA0", 'windows-1252') # non-breaking space + check_both_ways("\u00AF", "\xAF", 'windows-1252') # ¯ + check_both_ways("\u00B0", "\xB0", 'windows-1252') # ° + check_both_ways("\u00BF", "\xBF", 'windows-1252') # ¿ + check_both_ways("\u00C0", "\xC0", 'windows-1252') # À + check_both_ways("\u00CF", "\xCF", 'windows-1252') # Ï + check_both_ways("\u00D0", "\xD0", 'windows-1252') # Ð + check_both_ways("\u00DF", "\xDF", 'windows-1252') # ß + check_both_ways("\u00E0", "\xE0", 'windows-1252') # à + check_both_ways("\u00EF", "\xEF", 'windows-1252') # ï + check_both_ways("\u00F0", "\xF0", 'windows-1252') # ð + check_both_ways("\u00FF", "\xFF", 'windows-1252') # ÿ + end + + def test_windows_1253 + check_both_ways("\u20AC", "\x80", 'windows-1253') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1253') } + check_both_ways("\u201A", "\x82", 'windows-1253') # ‚ + check_both_ways("\u2021", "\x87", 'windows-1253') # ‡ + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1253') } + check_both_ways("\u2030", "\x89", 'windows-1253') # ‰ + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1253') } + check_both_ways("\u2039", "\x8B", 'windows-1253') # ‹ + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1253') } + check_both_ways("\u2018", "\x91", 'windows-1253') # ‘ + check_both_ways("\u2014", "\x97", 'windows-1253') # — + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1253') } + check_both_ways("\u2122", "\x99", 'windows-1253') # ™ + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1253') } + check_both_ways("\u203A", "\x9B", 'windows-1253') # › + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1253') } + check_both_ways("\u00A0", "\xA0", 'windows-1253') # non-breaking space + check_both_ways("\u2015", "\xAF", 'windows-1253') # ― + check_both_ways("\u00B0", "\xB0", 'windows-1253') # ° + check_both_ways("\u038F", "\xBF", 'windows-1253') # Ώ + check_both_ways("\u0390", "\xC0", 'windows-1253') # ΐ + check_both_ways("\u039F", "\xCF", 'windows-1253') # Ο + check_both_ways("\u03A0", "\xD0", 'windows-1253') # Π + check_both_ways("\u03A1", "\xD1", 'windows-1253') # Ρ + assert_raise(Encoding::UndefinedConversionError) { "\xD2".encode("utf-8", 'windows-1253') } + check_both_ways("\u03A3", "\xD3", 'windows-1253') # Σ + check_both_ways("\u03AF", "\xDF", 'windows-1253') # ί + check_both_ways("\u03B0", "\xE0", 'windows-1253') # ΰ + check_both_ways("\u03BF", "\xEF", 'windows-1253') # ο + check_both_ways("\u03C0", "\xF0", 'windows-1253') # π + check_both_ways("\u03CE", "\xFE", 'windows-1253') # ώ + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1253') } + end + + def test_windows_1254 + check_both_ways("\u20AC", "\x80", 'windows-1254') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1254') } + check_both_ways("\u201A", "\x82", 'windows-1254') # ‚ + check_both_ways("\u0152", "\x8C", 'windows-1254') # Œ + assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1254') } + check_both_ways("\u2018", "\x91", 'windows-1254') # ‘ + check_both_ways("\u0153", "\x9C", 'windows-1254') # œ + assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x9E".encode("utf-8", 'windows-1254') } + check_both_ways("\u0178", "\x9F", 'windows-1254') # Ÿ + check_both_ways("\u00A0", "\xA0", 'windows-1254') # non-breaking space + check_both_ways("\u00AF", "\xAF", 'windows-1254') # ¯ + check_both_ways("\u00B0", "\xB0", 'windows-1254') # ° + check_both_ways("\u00BF", "\xBF", 'windows-1254') # ¿ + check_both_ways("\u00C0", "\xC0", 'windows-1254') # À + check_both_ways("\u00CF", "\xCF", 'windows-1254') # Ï + check_both_ways("\u011E", "\xD0", 'windows-1254') # Ğ + check_both_ways("\u00DF", "\xDF", 'windows-1254') # ß + check_both_ways("\u00E0", "\xE0", 'windows-1254') # à + check_both_ways("\u00EF", "\xEF", 'windows-1254') # ï + check_both_ways("\u011F", "\xF0", 'windows-1254') # ğ + check_both_ways("\u00FF", "\xFF", 'windows-1254') # ÿ + end + + def test_windows_1255 + check_both_ways("\u20AC", "\x80", 'windows-1255') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1255') } + check_both_ways("\u201A", "\x82", 'windows-1255') # ‚ + check_both_ways("\u2030", "\x89", 'windows-1255') # ‰ + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1255') } + check_both_ways("\u2039", "\x8B", 'windows-1255') # ‹ + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1255') } + check_both_ways("\u2018", "\x91", 'windows-1255') # ‘ + check_both_ways("\u2122", "\x99", 'windows-1255') # ™ + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1255') } + check_both_ways("\u203A", "\x9B", 'windows-1255') # › + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1255') } + check_both_ways("\u00A0", "\xA0", 'windows-1255') # non-breaking space + check_both_ways("\u00A1", "\xA1", 'windows-1255') # ¡ + check_both_ways("\u00D7", "\xAA", 'windows-1255') # × + check_both_ways("\u00AF", "\xAF", 'windows-1255') # ¯ + check_both_ways("\u00B0", "\xB0", 'windows-1255') # ° + check_both_ways("\u00B8", "\xB8", 'windows-1255') # ¸ + check_both_ways("\u00F7", "\xBA", 'windows-1255') # ÷ + check_both_ways("\u00BF", "\xBF", 'windows-1255') # ¿ + check_both_ways("\u05B0", "\xC0", 'windows-1255') # ְ + check_both_ways("\u05B9", "\xC9", 'windows-1255') # ֹ + assert_raise(Encoding::UndefinedConversionError) { "\xCA".encode("utf-8", 'windows-1255') } + check_both_ways("\u05BB", "\xCB", 'windows-1255') # ֻ + check_both_ways("\u05BF", "\xCF", 'windows-1255') # ֿ + check_both_ways("\u05C0", "\xD0", 'windows-1255') # ׀ + check_both_ways("\u05F3", "\xD7", 'windows-1255') # ׳ + check_both_ways("\u05F4", "\xD8", 'windows-1255') # ״ + assert_raise(Encoding::UndefinedConversionError) { "\xD9".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\xDF".encode("utf-8", 'windows-1255') } + check_both_ways("\u05D0", "\xE0", 'windows-1255') # א + check_both_ways("\u05DF", "\xEF", 'windows-1255') # ן + check_both_ways("\u05E0", "\xF0", 'windows-1255') # נ + check_both_ways("\u05EA", "\xFA", 'windows-1255') # ת + assert_raise(Encoding::UndefinedConversionError) { "\xFB".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-1255') } + check_both_ways("\u200E", "\xFD", 'windows-1255') # left-to-right mark + check_both_ways("\u200F", "\xFE", 'windows-1255') # right-to-left mark + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1255') } + end + + def test_windows_1256 + check_both_ways("\u20AC", "\x80", 'windows-1256') # € + check_both_ways("\u0679", "\x8A", 'windows-1256') # ٹ + check_both_ways("\u0688", "\x8F", 'windows-1256') # ڈ + check_both_ways("\u06AF", "\x90", 'windows-1256') # گ + check_both_ways("\u06A9", "\x98", 'windows-1256') # ک + check_both_ways("\u0691", "\x9A", 'windows-1256') # ڑ + check_both_ways("\u06BA", "\x9F", 'windows-1256') # ں + check_both_ways("\u00A0", "\xA0", 'windows-1256') # non-breaking space + check_both_ways("\u06BE", "\xAA", 'windows-1256') # ھ + check_both_ways("\u00AF", "\xAF", 'windows-1256') # ¯ + check_both_ways("\u00B0", "\xB0", 'windows-1256') # ° + check_both_ways("\u061F", "\xBF", 'windows-1256') # ؟ + check_both_ways("\u06C1", "\xC0", 'windows-1256') # ہ + check_both_ways("\u062F", "\xCF", 'windows-1256') # د + check_both_ways("\u0630", "\xD0", 'windows-1256') # ذ + check_both_ways("\u0643", "\xDF", 'windows-1256') # ك + check_both_ways("\u00E0", "\xE0", 'windows-1256') # à + check_both_ways("\u00EF", "\xEF", 'windows-1256') # ï + check_both_ways("\u064B", "\xF0", 'windows-1256') # ًً + check_both_ways("\u06D2", "\xFF", 'windows-1256') # ے + end + + def test_windows_1257 + check_both_ways("\u20AC", "\x80", 'windows-1257') # € + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1257') } + check_both_ways("\u201A", "\x82", 'windows-1257') # ‚ + assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1257') } + check_both_ways("\u201E", "\x84", 'windows-1257') # „ + check_both_ways("\u2021", "\x87", 'windows-1257') # ‡ + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1257') } + check_both_ways("\u2030", "\x89", 'windows-1257') # ‰ + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1257') } + check_both_ways("\u2039", "\x8B", 'windows-1257') # ‹ + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1257') } + check_both_ways("\u00A8", "\x8D", 'windows-1257') # ¨ + check_both_ways("\u02C7", "\x8E", 'windows-1257') # ˇ + check_both_ways("\u00B8", "\x8F", 'windows-1257') # ¸ + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1257') } + check_both_ways("\u2018", "\x91", 'windows-1257') # ‘ + check_both_ways("\u2014", "\x97", 'windows-1257') # — + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1257') } + check_both_ways("\u2122", "\x99", 'windows-1257') # ™ + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1257') } + check_both_ways("\u203A", "\x9B", 'windows-1257') # › + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1257') } + check_both_ways("\u00AF", "\x9D", 'windows-1257') # ¯ + check_both_ways("\u02DB", "\x9E", 'windows-1257') # ˛ + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1257') } + check_both_ways("\u00A0", "\xA0", 'windows-1257') # non-breaking space + assert_raise(Encoding::UndefinedConversionError) { "\xA1".encode("utf-8", 'windows-1257') } + check_both_ways("\u00A2", "\xA2", 'windows-1257') # ¢ + check_both_ways("\u00A4", "\xA4", 'windows-1257') # ¤ + assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode("utf-8", 'windows-1257') } + check_both_ways("\u00A6", "\xA6", 'windows-1257') # ¦ + check_both_ways("\u00C6", "\xAF", 'windows-1257') # Æ + check_both_ways("\u00B0", "\xB0", 'windows-1257') # ° + check_both_ways("\u00E6", "\xBF", 'windows-1257') # æ + check_both_ways("\u0104", "\xC0", 'windows-1257') # Ą + check_both_ways("\u013B", "\xCF", 'windows-1257') # Ļ + check_both_ways("\u0160", "\xD0", 'windows-1257') # Š + check_both_ways("\u00DF", "\xDF", 'windows-1257') # ß + check_both_ways("\u0105", "\xE0", 'windows-1257') # ą + check_both_ways("\u013C", "\xEF", 'windows-1257') # ļ + check_both_ways("\u0161", "\xF0", 'windows-1257') # š + check_both_ways("\u02D9", "\xFF", 'windows-1257') # ˙ + end + + def test_IBM437 + check_both_ways("\u00C7", "\x80", 'IBM437') # Ç + check_both_ways("\u00C5", "\x8F", 'IBM437') # Å + check_both_ways("\u00C9", "\x90", 'IBM437') # É + check_both_ways("\u0192", "\x9F", 'IBM437') # ƒ + check_both_ways("\u00E1", "\xA0", 'IBM437') # á + check_both_ways("\u00BB", "\xAF", 'IBM437') # » + check_both_ways("\u2591", "\xB0", 'IBM437') # ░ + check_both_ways("\u2510", "\xBF", 'IBM437') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM437') # └ + check_both_ways("\u2567", "\xCF", 'IBM437') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM437') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM437') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM437') # α + check_both_ways("\u2229", "\xEF", 'IBM437') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM437') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM437') # non-breaking space + end + + def test_IBM775 + check_both_ways("\u0106", "\x80", 'IBM775') # Ć + check_both_ways("\u00C5", "\x8F", 'IBM775') # Å + check_both_ways("\u00C9", "\x90", 'IBM775') # É + check_both_ways("\u00A4", "\x9F", 'IBM775') # ¤ + check_both_ways("\u0100", "\xA0", 'IBM775') # Ā + check_both_ways("\u00BB", "\xAF", 'IBM775') # » + check_both_ways("\u2591", "\xB0", 'IBM775') # ░ + check_both_ways("\u2510", "\xBF", 'IBM775') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM775') # └ + check_both_ways("\u017D", "\xCF", 'IBM775') # Ž + check_both_ways("\u0105", "\xD0", 'IBM775') # ą + check_both_ways("\u2580", "\xDF", 'IBM775') # ▀ + check_both_ways("\u00D3", "\xE0", 'IBM775') # Ó + check_both_ways("\u2019", "\xEF", 'IBM775') # ’ + check_both_ways("\u00AD", "\xF0", 'IBM775') # osft hyphen + check_both_ways("\u00A0", "\xFF", 'IBM775') # non-breaking space + end + + def test_IBM852 + check_both_ways("\u00C7", "\x80", 'IBM852') # Ç + check_both_ways("\u0106", "\x8F", 'IBM852') # Ć + check_both_ways("\u00C9", "\x90", 'IBM852') # É + check_both_ways("\u010D", "\x9F", 'IBM852') # č + check_both_ways("\u00E1", "\xA0", 'IBM852') # á + check_both_ways("\u00BB", "\xAF", 'IBM852') # » + check_both_ways("\u2591", "\xB0", 'IBM852') # ░ + check_both_ways("\u2510", "\xBF", 'IBM852') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM852') # └ + check_both_ways("\u00A4", "\xCF", 'IBM852') # ¤ + check_both_ways("\u0111", "\xD0", 'IBM852') # đ + check_both_ways("\u2580", "\xDF", 'IBM852') # ▀ + check_both_ways("\u00D3", "\xE0", 'IBM852') # Ó + check_both_ways("\u00B4", "\xEF", 'IBM852') # ´ + check_both_ways("\u00AD", "\xF0", 'IBM852') # osft hyphen + check_both_ways("\u00A0", "\xFF", 'IBM852') # non-breaking space + end + + def test_IBM855 + check_both_ways("\u0452", "\x80", 'IBM855') # ђ + check_both_ways("\u0408", "\x8F", 'IBM855') # Ј + check_both_ways("\u0459", "\x90", 'IBM855') # љ + check_both_ways("\u042A", "\x9F", 'IBM855') # Ъ + check_both_ways("\u0430", "\xA0", 'IBM855') # а + check_both_ways("\u00BB", "\xAF", 'IBM855') # » + check_both_ways("\u2591", "\xB0", 'IBM855') # ░ + check_both_ways("\u2510", "\xBF", 'IBM855') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM855') # └ + check_both_ways("\u00A4", "\xCF", 'IBM855') # ¤ + check_both_ways("\u043B", "\xD0", 'IBM855') # л + check_both_ways("\u2580", "\xDF", 'IBM855') # ▀ + check_both_ways("\u042F", "\xE0", 'IBM855') # Я + check_both_ways("\u2116", "\xEF", 'IBM855') # № + check_both_ways("\u00AD", "\xF0", 'IBM855') # osft hyphen + check_both_ways("\u00A0", "\xFF", 'IBM855') # non-breaking space + end + + def test_IBM857 + check_both_ways("\u00C7", "\x80", 'IBM857') # Ç + check_both_ways("\u00C5", "\x8F", 'IBM857') # Å + check_both_ways("\u00C9", "\x90", 'IBM857') # É + check_both_ways("\u015F", "\x9F", 'IBM857') # ş + check_both_ways("\u00E1", "\xA0", 'IBM857') # á + check_both_ways("\u00BB", "\xAF", 'IBM857') # » + check_both_ways("\u2591", "\xB0", 'IBM857') # ░ + check_both_ways("\u2510", "\xBF", 'IBM857') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM857') # └ + check_both_ways("\u00A4", "\xCF", 'IBM857') # ¤ + check_both_ways("\u00BA", "\xD0", 'IBM857') # º + check_both_ways("\u00C8", "\xD4", 'IBM857') # È + assert_raise(Encoding::UndefinedConversionError) { "\xD5".encode("utf-8", 'IBM857') } + check_both_ways("\u00CD", "\xD6", 'IBM857') # Í + check_both_ways("\u2580", "\xDF", 'IBM857') # ▀ + check_both_ways("\u00D3", "\xE0", 'IBM857') # Ó + check_both_ways("\u00B5", "\xE6", 'IBM857') # µ + assert_raise(Encoding::UndefinedConversionError) { "\xE7".encode("utf-8", 'IBM857') } + check_both_ways("\u00D7", "\xE8", 'IBM857') # × + check_both_ways("\u00B4", "\xEF", 'IBM857') # ´ + check_both_ways("\u00AD", "\xF0", 'IBM857') # soft hyphen + check_both_ways("\u00B1", "\xF1", 'IBM857') # ± + assert_raise(Encoding::UndefinedConversionError) { "\xF2".encode("utf-8", 'IBM857') } + check_both_ways("\u00BE", "\xF3", 'IBM857') # ¾ + check_both_ways("\u00A0", "\xFF", 'IBM857') # non-breaking space + end + + def test_IBM860 + check_both_ways("\u00C7", "\x80", 'IBM860') # Ç + check_both_ways("\u00C2", "\x8F", 'IBM860') #  + check_both_ways("\u00C9", "\x90", 'IBM860') # É + check_both_ways("\u00D3", "\x9F", 'IBM860') # Ó + check_both_ways("\u00E1", "\xA0", 'IBM860') # á + check_both_ways("\u00BB", "\xAF", 'IBM860') # » + check_both_ways("\u2591", "\xB0", 'IBM860') # ░ + check_both_ways("\u2510", "\xBF", 'IBM860') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM860') # └ + check_both_ways("\u2567", "\xCF", 'IBM860') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM860') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM860') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM860') # α + check_both_ways("\u2229", "\xEF", 'IBM860') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM860') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM860') # non-breaking space + end + + def test_IBM861 + check_both_ways("\u00C7", "\x80", 'IBM861') # Ç + check_both_ways("\u00C5", "\x8F", 'IBM861') # Å + check_both_ways("\u00C9", "\x90", 'IBM861') # É + check_both_ways("\u0192", "\x9F", 'IBM861') # ƒ + check_both_ways("\u00E1", "\xA0", 'IBM861') # á + check_both_ways("\u00BB", "\xAF", 'IBM861') # » + check_both_ways("\u2591", "\xB0", 'IBM861') # ░ + check_both_ways("\u2510", "\xBF", 'IBM861') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM861') # └ + check_both_ways("\u2567", "\xCF", 'IBM861') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM861') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM861') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM861') # α + check_both_ways("\u2229", "\xEF", 'IBM861') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM861') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM861') # non-breaking space + end + + def test_IBM862 + check_both_ways("\u05D0", "\x80", 'IBM862') # א + check_both_ways("\u05DF", "\x8F", 'IBM862') # ן + check_both_ways("\u05E0", "\x90", 'IBM862') # נ + check_both_ways("\u0192", "\x9F", 'IBM862') # ƒ + check_both_ways("\u00E1", "\xA0", 'IBM862') # á + check_both_ways("\u00BB", "\xAF", 'IBM862') # » + check_both_ways("\u2591", "\xB0", 'IBM862') # ░ + check_both_ways("\u2510", "\xBF", 'IBM862') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM862') # └ + check_both_ways("\u2567", "\xCF", 'IBM862') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM862') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM862') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM862') # α + check_both_ways("\u2229", "\xEF", 'IBM862') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM862') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM862') # non-breaking space + end + + def test_IBM863 + check_both_ways("\u00C7", "\x80", 'IBM863') # Ç + check_both_ways("\u00A7", "\x8F", 'IBM863') # § + check_both_ways("\u00C9", "\x90", 'IBM863') # É + check_both_ways("\u0192", "\x9F", 'IBM863') # ƒ + check_both_ways("\u00A6", "\xA0", 'IBM863') # ¦ + check_both_ways("\u00BB", "\xAF", 'IBM863') # » + check_both_ways("\u2591", "\xB0", 'IBM863') # ░ + check_both_ways("\u2510", "\xBF", 'IBM863') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM863') # └ + check_both_ways("\u2567", "\xCF", 'IBM863') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM863') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM863') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM863') # α + check_both_ways("\u2229", "\xEF", 'IBM863') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM863') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM863') # non-breaking space + end + + def test_IBM865 + check_both_ways("\u00C7", "\x80", 'IBM865') # Ç + check_both_ways("\u00C5", "\x8F", 'IBM865') # Å + check_both_ways("\u00C9", "\x90", 'IBM865') # É + check_both_ways("\u0192", "\x9F", 'IBM865') # ƒ + check_both_ways("\u00E1", "\xA0", 'IBM865') # á + check_both_ways("\u00A4", "\xAF", 'IBM865') # ¤ + check_both_ways("\u2591", "\xB0", 'IBM865') # ░ + check_both_ways("\u2510", "\xBF", 'IBM865') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM865') # └ + check_both_ways("\u2567", "\xCF", 'IBM865') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM865') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM865') # ▀ + check_both_ways("\u03B1", "\xE0", 'IBM865') # α + check_both_ways("\u2229", "\xEF", 'IBM865') # ∩ + check_both_ways("\u2261", "\xF0", 'IBM865') # ≡ + check_both_ways("\u00A0", "\xFF", 'IBM865') # non-breaking space + end + + def test_IBM866 + check_both_ways("\u0410", "\x80", 'IBM866') # А + check_both_ways("\u041F", "\x8F", 'IBM866') # П + check_both_ways("\u0420", "\x90", 'IBM866') # Р + check_both_ways("\u042F", "\x9F", 'IBM866') # Я + check_both_ways("\u0430", "\xA0", 'IBM866') # а + check_both_ways("\u043F", "\xAF", 'IBM866') # п + check_both_ways("\u2591", "\xB0", 'IBM866') # ░ + check_both_ways("\u2510", "\xBF", 'IBM866') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM866') # └ + check_both_ways("\u2567", "\xCF", 'IBM866') # ╧ + check_both_ways("\u2568", "\xD0", 'IBM866') # ╨ + check_both_ways("\u2580", "\xDF", 'IBM866') # ▀ + check_both_ways("\u0440", "\xE0", 'IBM866') # р + check_both_ways("\u044F", "\xEF", 'IBM866') # я + check_both_ways("\u0401", "\xF0", 'IBM866') # Ё + check_both_ways("\u00A0", "\xFF", 'IBM866') # non-breaking space + end + + def test_IBM869 + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'IBM869') } + assert_raise(Encoding::UndefinedConversionError) { "\x85".encode("utf-8", 'IBM869') } + check_both_ways("\u0386", "\x86", 'IBM869') # Ά + assert_raise(Encoding::UndefinedConversionError) { "\x87".encode("utf-8", 'IBM869') } + check_both_ways("\u00B7", "\x88", 'IBM869') # · + check_both_ways("\u0389", "\x8F", 'IBM869') # Ή + check_both_ways("\u038A", "\x90", 'IBM869') # Ί + check_both_ways("\u038C", "\x92", 'IBM869') # Ό + assert_raise(Encoding::UndefinedConversionError) { "\x93".encode("utf-8", 'IBM869') } + assert_raise(Encoding::UndefinedConversionError) { "\x94".encode("utf-8", 'IBM869') } + check_both_ways("\u038E", "\x95", 'IBM869') # Ύ + check_both_ways("\u03AF", "\x9F", 'IBM869') # ί + check_both_ways("\u03CA", "\xA0", 'IBM869') # ϊ + check_both_ways("\u00BB", "\xAF", 'IBM869') # » + check_both_ways("\u2591", "\xB0", 'IBM869') # ░ + check_both_ways("\u2510", "\xBF", 'IBM869') # ┐ + check_both_ways("\u2514", "\xC0", 'IBM869') # └ + check_both_ways("\u03A3", "\xCF", 'IBM869') # Σ + check_both_ways("\u03A4", "\xD0", 'IBM869') # Τ + check_both_ways("\u2580", "\xDF", 'IBM869') # ▀ + check_both_ways("\u03B6", "\xE0", 'IBM869') # ζ + check_both_ways("\u0384", "\xEF", 'IBM869') # ΄ + check_both_ways("\u00AD", "\xF0", 'IBM869') # soft hyphen + check_both_ways("\u00A0", "\xFF", 'IBM869') # non-breaking space + end + + def test_macCroatian + check_both_ways("\u00C4", "\x80", 'macCroatian') # Ä + check_both_ways("\u00E8", "\x8F", 'macCroatian') # è + check_both_ways("\u00EA", "\x90", 'macCroatian') # ê + check_both_ways("\u00FC", "\x9F", 'macCroatian') # ü + check_both_ways("\u2020", "\xA0", 'macCroatian') # † + check_both_ways("\u00D8", "\xAF", 'macCroatian') # Ø + check_both_ways("\u221E", "\xB0", 'macCroatian') # ∞ + check_both_ways("\u00F8", "\xBF", 'macCroatian') # ø + check_both_ways("\u00BF", "\xC0", 'macCroatian') # ¿ + check_both_ways("\u0153", "\xCF", 'macCroatian') # œ + check_both_ways("\u0110", "\xD0", 'macCroatian') # Đ + check_both_ways("\u00A9", "\xD9", 'macCroatian') # © + check_both_ways("\u2044", "\xDA", 'macCroatian') # ⁄ + check_both_ways("\u203A", "\xDD", 'macCroatian') # › + check_both_ways("\u00C6", "\xDE", 'macCroatian') # Æ + check_both_ways("\u00BB", "\xDF", 'macCroatian') # » + check_both_ways("\u2013", "\xE0", 'macCroatian') # – + check_both_ways("\u00B7", "\xE1", 'macCroatian') # · + check_both_ways("\u00C2", "\xE5", 'macCroatian') #  + check_both_ways("\u0107", "\xE6", 'macCroatian') # ć + check_both_ways("\u00C1", "\xE7", 'macCroatian') # Á + check_both_ways("\u010D", "\xE8", 'macCroatian') # č + check_both_ways("\u00C8", "\xE9", 'macCroatian') # È + check_both_ways("\u00D4", "\xEF", 'macCroatian') # Ô + check_both_ways("\u0111", "\xF0", 'macCroatian') # đ + check_both_ways("\u00D2", "\xF1", 'macCroatian') # Ò + check_both_ways("\u00AF", "\xF8", 'macCroatian') # ¯ + check_both_ways("\u03C0", "\xF9", 'macCroatian') # π + check_both_ways("\u00CB", "\xFA", 'macCroatian') # Ë + check_both_ways("\u00CA", "\xFD", 'macCroatian') # Ê + check_both_ways("\u00E6", "\xFE", 'macCroatian') # æ + check_both_ways("\u02C7", "\xFF", 'macCroatian') # ˇ + end + + def test_macCyrillic + check_both_ways("\u0410", "\x80", 'macCyrillic') # А + check_both_ways("\u041F", "\x8F", 'macCyrillic') # П + check_both_ways("\u0420", "\x90", 'macCyrillic') # Р + check_both_ways("\u042F", "\x9F", 'macCyrillic') # Я + check_both_ways("\u2020", "\xA0", 'macCyrillic') # † + check_both_ways("\u0453", "\xAF", 'macCyrillic') # ѓ + check_both_ways("\u221E", "\xB0", 'macCyrillic') # ∞ + check_both_ways("\u045A", "\xBF", 'macCyrillic') # њ + check_both_ways("\u0458", "\xC0", 'macCyrillic') # ј + check_both_ways("\u0455", "\xCF", 'macCyrillic') # ѕ + check_both_ways("\u2013", "\xD0", 'macCyrillic') # – + check_both_ways("\u044F", "\xDF", 'macCyrillic') # я + check_both_ways("\u0430", "\xE0", 'macCyrillic') # а + check_both_ways("\u043F", "\xEF", 'macCyrillic') # п + check_both_ways("\u0440", "\xF0", 'macCyrillic') # р + check_both_ways("\u00A4", "\xFF", 'macCyrillic') # ¤ + end + + def test_macGreek + check_both_ways("\u00C4", "\x80", 'macGreek') # Ä + check_both_ways("\u00E8", "\x8F", 'macGreek') # è + check_both_ways("\u00EA", "\x90", 'macGreek') # ê + check_both_ways("\u00FC", "\x9F", 'macGreek') # ü + check_both_ways("\u2020", "\xA0", 'macGreek') # † + check_both_ways("\u0393", "\xA1", 'macGreek') # Γ + check_both_ways("\u0387", "\xAF", 'macGreek') # · + check_both_ways("\u0391", "\xB0", 'macGreek') # Α + check_both_ways("\u03A9", "\xBF", 'macGreek') # Ω + check_both_ways("\u03AC", "\xC0", 'macGreek') # ά + check_both_ways("\u0153", "\xCF", 'macGreek') # œ + check_both_ways("\u2013", "\xD0", 'macGreek') # – + check_both_ways("\u038F", "\xDF", 'macGreek') # Ώ + check_both_ways("\u03CD", "\xE0", 'macGreek') # ύ + check_both_ways("\u03BF", "\xEF", 'macGreek') # ο + check_both_ways("\u03C0", "\xF0", 'macGreek') # π + check_both_ways("\u03B0", "\xFE", 'macGreek') # ΰ + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'macGreek') } + end + + def test_macIceland + check_both_ways("\u00C4", "\x80", 'macIceland') # Ä + check_both_ways("\u00E8", "\x8F", 'macIceland') # è + check_both_ways("\u00EA", "\x90", 'macIceland') # ê + check_both_ways("\u00FC", "\x9F", 'macIceland') # ü + check_both_ways("\u00DD", "\xA0", 'macIceland') # Ý + check_both_ways("\u00D8", "\xAF", 'macIceland') # Ø + check_both_ways("\u221E", "\xB0", 'macIceland') # ∞ + check_both_ways("\u00F8", "\xBF", 'macIceland') # ø + check_both_ways("\u00BF", "\xC0", 'macIceland') # ¿ + check_both_ways("\u0153", "\xCF", 'macIceland') # œ + check_both_ways("\u2013", "\xD0", 'macIceland') # – + check_both_ways("\u00FE", "\xDF", 'macIceland') # þ + check_both_ways("\u00FD", "\xE0", 'macIceland') # ý + check_both_ways("\u00D4", "\xEF", 'macIceland') # Ô + #check_both_ways("\uF8FF", "\xF0", 'macIceland') # Apple logo + check_both_ways("\u02C7", "\xFF", 'macIceland') # ˇ + end + + def test_macRoman + check_both_ways("\u00C4", "\x80", 'macRoman') # Ä + check_both_ways("\u00E8", "\x8F", 'macRoman') # è + check_both_ways("\u00EA", "\x90", 'macRoman') # ê + check_both_ways("\u00FC", "\x9F", 'macRoman') # ü + check_both_ways("\u2020", "\xA0", 'macRoman') # † + #check_both_ways("\u00DB", "\xAF", 'macRoman') # Ø + check_both_ways("\u221E", "\xB0", 'macRoman') # ∞ + check_both_ways("\u00F8", "\xBF", 'macRoman') # ø + check_both_ways("\u00BF", "\xC0", 'macRoman') # ¿ + check_both_ways("\u0153", "\xCF", 'macRoman') # œ + check_both_ways("\u2013", "\xD0", 'macRoman') # – + check_both_ways("\u00A4", "\xDB", 'macRoman') # ¤ + check_both_ways("\uFB02", "\xDF", 'macRoman') # fl + check_both_ways("\u2021", "\xE0", 'macRoman') # ‡ + check_both_ways("\u00D4", "\xEF", 'macRoman') # Ô + #check_both_ways("\uF8FF", "\xF0", 'macRoman') # Apple logo + check_both_ways("\u02C7", "\xFF", 'macRoman') # ˇ + end + + def test_macRomania + check_both_ways("\u00C4", "\x80", 'macRomania') # Ä + check_both_ways("\u00E8", "\x8F", 'macRomania') # è + check_both_ways("\u00EA", "\x90", 'macRomania') # ê + check_both_ways("\u00FC", "\x9F", 'macRomania') # ü + check_both_ways("\u2020", "\xA0", 'macRomania') # † + check_both_ways("\u015E", "\xAF", 'macRomania') # Ş + check_both_ways("\u221E", "\xB0", 'macRomania') # ∞ + check_both_ways("\u015F", "\xBF", 'macRomania') # ş + check_both_ways("\u00BF", "\xC0", 'macRomania') # ¿ + check_both_ways("\u0153", "\xCF", 'macRomania') # œ + check_both_ways("\u2013", "\xD0", 'macRomania') # – + check_both_ways("\u00A4", "\xDB", 'macRomania') # € + check_both_ways("\u0163", "\xDF", 'macRomania') # ţ + check_both_ways("\u2021", "\xE0", 'macRomania') # ‡ + check_both_ways("\u00D4", "\xEF", 'macRomania') # Ô + #check_both_ways("\uF8FF", "\xF0", 'macRomania') # Apple logo + check_both_ways("\u02C7", "\xFF", 'macRomania') # ˇ + end + + def test_macTurkish + check_both_ways("\u00C4", "\x80", 'macTurkish') # Ä + check_both_ways("\u00E8", "\x8F", 'macTurkish') # è + check_both_ways("\u00EA", "\x90", 'macTurkish') # ê + check_both_ways("\u00FC", "\x9F", 'macTurkish') # ü + check_both_ways("\u2020", "\xA0", 'macTurkish') # † + check_both_ways("\u00D8", "\xAF", 'macTurkish') # Ø + check_both_ways("\u221E", "\xB0", 'macTurkish') # ∞ + check_both_ways("\u00F8", "\xBF", 'macTurkish') # ø + check_both_ways("\u00BF", "\xC0", 'macTurkish') # ¿ + check_both_ways("\u0153", "\xCF", 'macTurkish') # œ + check_both_ways("\u2013", "\xD0", 'macTurkish') # – + check_both_ways("\u015F", "\xDF", 'macTurkish') # ş + check_both_ways("\u2021", "\xE0", 'macTurkish') # ‡ + check_both_ways("\u00D4", "\xEF", 'macTurkish') # Ô + #check_both_ways("\uF8FF", "\xF0", 'macTurkish') # Apple logo + check_both_ways("\u00D9", "\xF4", 'macTurkish') # Ù + assert_raise(Encoding::UndefinedConversionError) { "\xF5".encode("utf-8", 'macTurkish') } + check_both_ways("\u02C6", "\xF6", 'macTurkish') # ˆ + check_both_ways("\u02C7", "\xFF", 'macTurkish') # ˇ + end + + def test_macUkraine + check_both_ways("\u0410", "\x80", 'macUkraine') # А + check_both_ways("\u041F", "\x8F", 'macUkraine') # П + check_both_ways("\u0420", "\x90", 'macUkraine') # Р + check_both_ways("\u042F", "\x9F", 'macUkraine') # Я + check_both_ways("\u2020", "\xA0", 'macUkraine') # † + check_both_ways("\u0453", "\xAF", 'macUkraine') # ѓ + check_both_ways("\u221E", "\xB0", 'macUkraine') # ∞ + check_both_ways("\u045A", "\xBF", 'macUkraine') # њ + check_both_ways("\u0458", "\xC0", 'macUkraine') # ј + check_both_ways("\u0455", "\xCF", 'macUkraine') # ѕ + check_both_ways("\u2013", "\xD0", 'macUkraine') # – + check_both_ways("\u044F", "\xDF", 'macUkraine') # я + check_both_ways("\u0430", "\xE0", 'macUkraine') # а + check_both_ways("\u043F", "\xEF", 'macUkraine') # п + check_both_ways("\u0440", "\xF0", 'macUkraine') # р + check_both_ways("\u00A4", "\xFF", 'macUkraine') # ¤ + end + + def test_koi8_u + check_both_ways("\u2500", "\x80", 'KOI8-U') # ─ + check_both_ways("\u2590", "\x8F", 'KOI8-U') # ▐ + check_both_ways("\u2591", "\x90", 'KOI8-U') # ░ + check_both_ways("\u00F7", "\x9F", 'KOI8-U') # ÷ + check_both_ways("\u2550", "\xA0", 'KOI8-U') # ═ + check_both_ways("\u0454", "\xA4", 'KOI8-U') # є + check_both_ways("\u0456", "\xA6", 'KOI8-U') # і + check_both_ways("\u0457", "\xA7", 'KOI8-U') # ї + check_both_ways("\u0491", "\xAD", 'KOI8-U') # ґ + check_both_ways("\u255E", "\xAF", 'KOI8-U') # ╞ + check_both_ways("\u255F", "\xB0", 'KOI8-U') # ╟ + check_both_ways("\u0404", "\xB4", 'KOI8-U') # Є + check_both_ways("\u0406", "\xB6", 'KOI8-U') # І + check_both_ways("\u0407", "\xB7", 'KOI8-U') # Ї + check_both_ways("\u0490", "\xBD", 'KOI8-U') # Ґ + check_both_ways("\u00A9", "\xBF", 'KOI8-U') # © + check_both_ways("\u044E", "\xC0", 'KOI8-U') # ю + check_both_ways("\u043E", "\xCF", 'KOI8-U') # о + check_both_ways("\u043F", "\xD0", 'KOI8-U') # п + check_both_ways("\u044A", "\xDF", 'KOI8-U') # ъ + check_both_ways("\u042E", "\xE0", 'KOI8-U') # Ю + check_both_ways("\u041E", "\xEF", 'KOI8-U') # О + check_both_ways("\u041F", "\xF0", 'KOI8-U') # П + check_both_ways("\u042A", "\xFF", 'KOI8-U') # Ъ + end + + def test_koi8_r + check_both_ways("\u2500", "\x80", 'KOI8-R') # ─ + check_both_ways("\u2590", "\x8F", 'KOI8-R') # ▐ + check_both_ways("\u2591", "\x90", 'KOI8-R') # ░ + check_both_ways("\u00F7", "\x9F", 'KOI8-R') # ÷ + check_both_ways("\u2550", "\xA0", 'KOI8-R') # ═ + check_both_ways("\u255E", "\xAF", 'KOI8-R') # ╞ + check_both_ways("\u255F", "\xB0", 'KOI8-R') # ╟ + check_both_ways("\u00A9", "\xBF", 'KOI8-R') # © + check_both_ways("\u044E", "\xC0", 'KOI8-R') # ю + check_both_ways("\u043E", "\xCF", 'KOI8-R') # о + check_both_ways("\u043F", "\xD0", 'KOI8-R') # п + check_both_ways("\u044A", "\xDF", 'KOI8-R') # ъ + check_both_ways("\u042E", "\xE0", 'KOI8-R') # Ю + check_both_ways("\u041E", "\xEF", 'KOI8-R') # О + check_both_ways("\u041F", "\xF0", 'KOI8-R') # П + check_both_ways("\u042A", "\xFF", 'KOI8-R') # Ъ + end + + def test_TIS_620 + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xA0".encode("utf-8", 'TIS-620') } + check_both_ways("\u0E01", "\xA1", 'TIS-620') # ก + check_both_ways("\u0E0F", "\xAF", 'TIS-620') # ฏ + check_both_ways("\u0E10", "\xB0", 'TIS-620') # ฐ + check_both_ways("\u0E1F", "\xBF", 'TIS-620') # ฟ + check_both_ways("\u0E20", "\xC0", 'TIS-620') # ภ + check_both_ways("\u0E2F", "\xCF", 'TIS-620') # ฯ + check_both_ways("\u0E30", "\xD0", 'TIS-620') # ะ + check_both_ways("\u0E3A", "\xDA", 'TIS-620') # ฺ + assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'TIS-620') } + check_both_ways("\u0E3F", "\xDF", 'TIS-620') # ฿ + check_both_ways("\u0E40", "\xE0", 'TIS-620') # เ + check_both_ways("\u0E4F", "\xEF", 'TIS-620') # ๏ + check_both_ways("\u0E50", "\xF0", 'TIS-620') # ๐ + check_both_ways("\u0E5B", "\xFB", 'TIS-620') # ๛ + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'TIS-620') } + end + + def test_CP850 + check_both_ways("\u00C7", "\x80", 'CP850') # Ç + check_both_ways("\u00C5", "\x8F", 'CP850') # Å + check_both_ways("\u00C9", "\x90", 'CP850') # É + check_both_ways("\u0192", "\x9F", 'CP850') # ƒ + check_both_ways("\u00E1", "\xA0", 'CP850') # á + check_both_ways("\u00BB", "\xAF", 'CP850') # » + check_both_ways("\u2591", "\xB0", 'CP850') # ░ + check_both_ways("\u2510", "\xBF", 'CP850') # ┐ + check_both_ways("\u2514", "\xC0", 'CP850') # └ + check_both_ways("\u00A4", "\xCF", 'CP850') # ¤ + check_both_ways("\u00F0", "\xD0", 'CP850') # ð + check_both_ways("\u2580", "\xDF", 'CP850') # ▀ + check_both_ways("\u00D3", "\xE0", 'CP850') # Ó + check_both_ways("\u00B4", "\xEF", 'CP850') # ´ + check_both_ways("\u00AD", "\xF0", 'CP850') # soft hyphen + check_both_ways("\u00A0", "\xFF", 'CP850') # non-breaking space + end + + def test_CP852 + check_both_ways("\u00C7", "\x80", 'CP852') # Ç + check_both_ways("\u0106", "\x8F", 'CP852') # Ć + check_both_ways("\u00C9", "\x90", 'CP852') # É + check_both_ways("\u010D", "\x9F", 'CP852') # č + check_both_ways("\u00E1", "\xA0", 'CP852') # á + check_both_ways("\u00BB", "\xAF", 'CP852') # » + check_both_ways("\u2591", "\xB0", 'CP852') # ░ + check_both_ways("\u2510", "\xBF", 'CP852') # ┐ + check_both_ways("\u2514", "\xC0", 'CP852') # └ + check_both_ways("\u00A4", "\xCF", 'CP852') # ¤ + check_both_ways("\u0111", "\xD0", 'CP852') # đ + check_both_ways("\u2580", "\xDF", 'CP852') # ▀ + check_both_ways("\u00D3", "\xE0", 'CP852') # Ó + check_both_ways("\u00B4", "\xEF", 'CP852') # ´ + check_both_ways("\u00AD", "\xF0", 'CP852') # soft hyphen + check_both_ways("\u00A0", "\xFF", 'CP852') # non-breaking space + end + + def test_CP855 + check_both_ways("\u0452", "\x80", 'CP855') # ђ + check_both_ways("\u0408", "\x8F", 'CP855') # Ј + check_both_ways("\u0459", "\x90", 'CP855') # љ + check_both_ways("\u042A", "\x9F", 'CP855') # Ъ + check_both_ways("\u0430", "\xA0", 'CP855') # а + check_both_ways("\u00BB", "\xAF", 'CP855') # » + check_both_ways("\u2591", "\xB0", 'CP855') # ░ + check_both_ways("\u2510", "\xBF", 'CP855') # ┐ + check_both_ways("\u2514", "\xC0", 'CP855') # └ + check_both_ways("\u00A4", "\xCF", 'CP855') # ¤ + check_both_ways("\u043B", "\xD0", 'CP855') # л + check_both_ways("\u2580", "\xDF", 'CP855') # ▀ + check_both_ways("\u042F", "\xE0", 'CP855') # Я + check_both_ways("\u2116", "\xEF", 'CP855') # № + check_both_ways("\u00AD", "\xF0", 'CP855') # soft hyphen + check_both_ways("\u00A0", "\xFF", 'CP855') # non-breaking space + end + + def check_utf_16_both_ways(utf8, raw) + copy = raw.dup + 0.step(copy.length-1, 2) { |i| copy[i+1], copy[i] = copy[i], copy[i+1] } + check_both_ways(utf8, raw, 'utf-16be') + check_both_ways(utf8, copy, 'utf-16le') + end + + def test_utf_16 + check_utf_16_both_ways("abc", "\x00a\x00b\x00c") + check_utf_16_both_ways("\u00E9", "\x00\xE9"); + check_utf_16_both_ways("\u00E9\u0070\u00E9\u0065", "\x00\xE9\x00\x70\x00\xE9\x00\x65") # épée + check_utf_16_both_ways("\u677E\u672C\u884C\u5F18", "\x67\x7E\x67\x2C\x88\x4C\x5F\x18") # 松本行弘 + check_utf_16_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x97\x52\x5C\x71\x5B\x66\x96\x62\x59\x27\x5B\x66") # 青山学院大学 + check_utf_16_both_ways("Martin D\u00FCrst", "\x00M\x00a\x00r\x00t\x00i\x00n\x00 \x00D\x00\xFC\x00r\x00s\x00t") # Martin Dürst + # BMP + check_utf_16_both_ways("\u0000", "\x00\x00") + check_utf_16_both_ways("\u007F", "\x00\x7F") + check_utf_16_both_ways("\u0080", "\x00\x80") + check_utf_16_both_ways("\u0555", "\x05\x55") + check_utf_16_both_ways("\u04AA", "\x04\xAA") + check_utf_16_both_ways("\u0333", "\x03\x33") + check_utf_16_both_ways("\u04CC", "\x04\xCC") + check_utf_16_both_ways("\u00F0", "\x00\xF0") + check_utf_16_both_ways("\u070F", "\x07\x0F") + check_utf_16_both_ways("\u07FF", "\x07\xFF") + check_utf_16_both_ways("\u0800", "\x08\x00") + check_utf_16_both_ways("\uD7FF", "\xD7\xFF") + check_utf_16_both_ways("\uE000", "\xE0\x00") + check_utf_16_both_ways("\uFFFF", "\xFF\xFF") + check_utf_16_both_ways("\u5555", "\x55\x55") + check_utf_16_both_ways("\uAAAA", "\xAA\xAA") + check_utf_16_both_ways("\u3333", "\x33\x33") + check_utf_16_both_ways("\uCCCC", "\xCC\xCC") + check_utf_16_both_ways("\uF0F0", "\xF0\xF0") + check_utf_16_both_ways("\u0F0F", "\x0F\x0F") + check_utf_16_both_ways("\uFF00", "\xFF\x00") + check_utf_16_both_ways("\u00FF", "\x00\xFF") + # outer planes + check_utf_16_both_ways("\u{10000}", "\xD8\x00\xDC\x00") + check_utf_16_both_ways("\u{FFFFF}", "\xDB\xBF\xDF\xFF") + check_utf_16_both_ways("\u{100000}", "\xDB\xC0\xDC\x00") + check_utf_16_both_ways("\u{10FFFF}", "\xDB\xFF\xDF\xFF") + check_utf_16_both_ways("\u{105555}", "\xDB\xD5\xDD\x55") + check_utf_16_both_ways("\u{55555}", "\xD9\x15\xDD\x55") + check_utf_16_both_ways("\u{AAAAA}", "\xDA\x6A\xDE\xAA") + check_utf_16_both_ways("\u{33333}", "\xD8\x8C\xDF\x33") + check_utf_16_both_ways("\u{CCCCC}", "\xDA\xF3\xDC\xCC") + check_utf_16_both_ways("\u{8F0F0}", "\xD9\xFC\xDC\xF0") + check_utf_16_both_ways("\u{F0F0F}", "\xDB\x83\xDF\x0F") + check_utf_16_both_ways("\u{8FF00}", "\xD9\xFF\xDF\x00") + check_utf_16_both_ways("\u{F00FF}", "\xDB\x80\xDC\xFF") + end + + def test_utf_16_bom + expected = "\u{3042}\u{3044}\u{20bb7}" + assert_equal(expected, %w/fffe4230443042d8b7df/.pack("H*").encode("UTF-8","UTF-16")) + check_both_ways(expected, %w/feff30423044d842dfb7/.pack("H*"), "UTF-16") + assert_raise(Encoding::InvalidByteSequenceError){%w/feffdfb7/.pack("H*").encode("UTF-8","UTF-16")} + assert_raise(Encoding::InvalidByteSequenceError){%w/fffeb7df/.pack("H*").encode("UTF-8","UTF-16")} + end + + def test_utf_32_bom + expected = "\u{3042}\u{3044}\u{20bb7}" + assert_equal(expected, %w/fffe00004230000044300000b70b0200/.pack("H*").encode("UTF-8","UTF-32")) + check_both_ways(expected, %w/0000feff000030420000304400020bb7/.pack("H*"), "UTF-32") + assert_raise(Encoding::InvalidByteSequenceError){%w/0000feff00110000/.pack("H*").encode("UTF-8","UTF-32")} + end + + def check_utf_32_both_ways(utf8, raw) + copy = raw.dup + 0.step(copy.length-1, 4) do |i| + copy[i+3], copy[i+2], copy[i+1], copy[i] = copy[i], copy[i+1], copy[i+2], copy[i+3] + end + check_both_ways(utf8, raw, 'utf-32be') + #check_both_ways(utf8, copy, 'utf-32le') + end + + def test_utf_32 + check_utf_32_both_ways("abc", "\x00\x00\x00a\x00\x00\x00b\x00\x00\x00c") + check_utf_32_both_ways("\u00E9", "\x00\x00\x00\xE9"); + check_utf_32_both_ways("\u00E9\u0070\u00E9\u0065", + "\x00\x00\x00\xE9\x00\x00\x00\x70\x00\x00\x00\xE9\x00\x00\x00\x65") # épée + check_utf_32_both_ways("\u677E\u672C\u884C\u5F18", + "\x00\x00\x67\x7E\x00\x00\x67\x2C\x00\x00\x88\x4C\x00\x00\x5F\x18") # 松本行弘 + check_utf_32_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", + "\x00\x00\x97\x52\x00\x00\x5C\x71\x00\x00\x5B\x66\x00\x00\x96\x62\x00\x00\x59\x27\x00\x00\x5B\x66") # 青山学院大学 + check_utf_32_both_ways("Martin D\u00FCrst", + "\x00\x00\x00M\x00\x00\x00a\x00\x00\x00r\x00\x00\x00t\x00\x00\x00i\x00\x00\x00n\x00\x00\x00 \x00\x00\x00D\x00\x00\x00\xFC\x00\x00\x00r\x00\x00\x00s\x00\x00\x00t") # Martin Dürst + # BMP + check_utf_32_both_ways("\u0000", "\x00\x00\x00\x00") + check_utf_32_both_ways("\u007F", "\x00\x00\x00\x7F") + check_utf_32_both_ways("\u0080", "\x00\x00\x00\x80") + check_utf_32_both_ways("\u0555", "\x00\x00\x05\x55") + check_utf_32_both_ways("\u04AA", "\x00\x00\x04\xAA") + check_utf_32_both_ways("\u0333", "\x00\x00\x03\x33") + check_utf_32_both_ways("\u04CC", "\x00\x00\x04\xCC") + check_utf_32_both_ways("\u00F0", "\x00\x00\x00\xF0") + check_utf_32_both_ways("\u070F", "\x00\x00\x07\x0F") + check_utf_32_both_ways("\u07FF", "\x00\x00\x07\xFF") + check_utf_32_both_ways("\u0800", "\x00\x00\x08\x00") + check_utf_32_both_ways("\uD7FF", "\x00\x00\xD7\xFF") + check_utf_32_both_ways("\uE000", "\x00\x00\xE0\x00") + check_utf_32_both_ways("\uFFFF", "\x00\x00\xFF\xFF") + check_utf_32_both_ways("\u5555", "\x00\x00\x55\x55") + check_utf_32_both_ways("\uAAAA", "\x00\x00\xAA\xAA") + check_utf_32_both_ways("\u3333", "\x00\x00\x33\x33") + check_utf_32_both_ways("\uCCCC", "\x00\x00\xCC\xCC") + check_utf_32_both_ways("\uF0F0", "\x00\x00\xF0\xF0") + check_utf_32_both_ways("\u0F0F", "\x00\x00\x0F\x0F") + check_utf_32_both_ways("\uFF00", "\x00\x00\xFF\x00") + check_utf_32_both_ways("\u00FF", "\x00\x00\x00\xFF") + # outer planes + check_utf_32_both_ways("\u{10000}", "\x00\x01\x00\x00") + check_utf_32_both_ways("\u{FFFFF}", "\x00\x0F\xFF\xFF") + check_utf_32_both_ways("\u{100000}","\x00\x10\x00\x00") + check_utf_32_both_ways("\u{10FFFF}","\x00\x10\xFF\xFF") + check_utf_32_both_ways("\u{105555}","\x00\x10\x55\x55") + check_utf_32_both_ways("\u{55555}", "\x00\x05\x55\x55") + check_utf_32_both_ways("\u{AAAAA}", "\x00\x0A\xAA\xAA") + check_utf_32_both_ways("\u{33333}", "\x00\x03\x33\x33") + check_utf_32_both_ways("\u{CCCCC}", "\x00\x0C\xCC\xCC") + check_utf_32_both_ways("\u{8F0F0}", "\x00\x08\xF0\xF0") + check_utf_32_both_ways("\u{F0F0F}", "\x00\x0F\x0F\x0F") + check_utf_32_both_ways("\u{8FF00}", "\x00\x08\xFF\x00") + check_utf_32_both_ways("\u{F00FF}", "\x00\x0F\x00\xFF") + end + + def test_invalid_ignore + # arguments only + assert_nothing_raised { 'abc'.encode('utf-8', invalid: :replace, replace: "") } + # check handling of UTF-8 ill-formed subsequences + assert_equal("\x00\x41\x00\x3E\x00\x42".force_encoding('UTF-16BE'), + "\x41\xC2\x3E\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: "")) + assert_equal("\x00\x41\x00\xF1\x00\x42".force_encoding('UTF-16BE'), + "\x41\xC2\xC3\xB1\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: "")) + assert_equal("\x00\x42".force_encoding('UTF-16BE'), + "\xF0\x80\x80\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: "")) + assert_equal(''.force_encoding('UTF-16BE'), + "\x82\xAB".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: "")) + + assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"), + "\xA1\xA1\xFF".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: "")) + assert_equal("\e$B\x24\x22\x24\x24\e(B".force_encoding("ISO-2022-JP"), + "\xA4\xA2\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: "")) + assert_equal("\e$B\x24\x22\x24\x24\e(B".force_encoding("ISO-2022-JP"), + "\xA4\xA2\xFF\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: "")) + end + + def test_invalid_replace + # arguments only + assert_nothing_raised { 'abc'.encode('UTF-8', invalid: :replace) } + assert_equal("\xEF\xBF\xBD".force_encoding("UTF-8"), + "\x80".encode("UTF-8", "UTF-16BE", invalid: :replace)) + assert_equal("\xFF\xFD".force_encoding("UTF-16BE"), + "\x80".encode("UTF-16BE", "UTF-8", invalid: :replace)) + assert_equal("\xFD\xFF".force_encoding("UTF-16LE"), + "\x80".encode("UTF-16LE", "UTF-8", invalid: :replace)) + assert_equal("\x00\x00\xFF\xFD".force_encoding("UTF-32BE"), + "\x80".encode("UTF-32BE", "UTF-8", invalid: :replace)) + assert_equal("\xFD\xFF\x00\x00".force_encoding("UTF-32LE"), + "\x80".encode("UTF-32LE", "UTF-8", invalid: :replace)) + + assert_equal("\uFFFD!", + "\xdc\x00\x00!".encode("utf-8", "utf-16be", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\xd8\x00\x00!".encode("utf-8", "utf-16be", :invalid=>:replace)) + + assert_equal("\uFFFD!", + "\x00\xdc!\x00".encode("utf-8", "utf-16le", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x00\xd8!\x00".encode("utf-8", "utf-16le", :invalid=>:replace)) + + assert_equal("\uFFFD!", + "\x01\x00\x00\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace), "[ruby-dev:35726]") + assert_equal("\uFFFD!", + "\x00\xff\x00\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x00\x00\xd8\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace)) + + assert_equal("\uFFFD!", + "\x00\x00\x00\xff!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x00\x00\xff\x00!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x00\xd8\x00\x00!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace)) + + assert_equal("\uFFFD!", + "\xff!".encode("utf-8", "euc-jp", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\xff!".encode("utf-8", "euc-jis-2004", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\xa1!".encode("utf-8", "euc-jp", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\xa1!".encode("utf-8", "euc-jis-2004", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x8f\xa1!".encode("utf-8", "euc-jp", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x8f\xa1!".encode("utf-8", "euc-jis-2004", :invalid=>:replace)) + + assert_equal("?", + "\xdc\x00".encode("EUC-JP", "UTF-16BE", :invalid=>:replace), "[ruby-dev:35776]") + assert_equal("ab?cd?ef", + "\0a\0b\xdc\x00\0c\0d\xdf\x00\0e\0f".encode("EUC-JP", "UTF-16BE", :invalid=>:replace)) + + assert_equal("\e$B!!\e(B?".force_encoding("ISO-2022-JP"), + "\xA1\xA1\xFF".encode("ISO-2022-JP", "EUC-JP", invalid: :replace)) + assert_equal("\e$B\x24\x22\e(B?\e$B\x24\x24\e(B".force_encoding("ISO-2022-JP"), + "\xA4\xA2\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace)) + assert_equal("\e$B\x24\x22\e(B??\e$B\x24\x24\e(B".force_encoding("ISO-2022-JP"), + "\xA4\xA2\xFF\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace)) + end + + def test_invalid_replace_string + assert_equal("a<x>A", "a\x80A".encode("us-ascii", "euc-jp", :invalid=>:replace, :replace=>"<x>")) + assert_equal("a<x>A", "a\x80A".encode("us-ascii", "euc-jis-2004", :invalid=>:replace, :replace=>"<x>")) + end + + def test_undef_replace + assert_equal("?", "\u20AC".encode("EUC-JP", :undef=>:replace), "[ruby-dev:35709]") + end + + def test_undef_replace_string + assert_equal("a<x>A", "a\u3042A".encode("us-ascii", :undef=>:replace, :replace=>"<x>")) + end + + def test_shift_jis + check_both_ways("\u3000", "\x81\x40", 'shift_jis') # full-width space + check_both_ways("\u00D7", "\x81\x7E", 'shift_jis') # × + check_both_ways("\u00F7", "\x81\x80", 'shift_jis') # ÷ + check_both_ways("\u25C7", "\x81\x9E", 'shift_jis') # ◇ + check_both_ways("\u25C6", "\x81\x9F", 'shift_jis') # ◆ + check_both_ways("\u25EF", "\x81\xFC", 'shift_jis') # ◯ + check_both_ways("\u6A97", "\x9F\x40", 'shift_jis') # 檗 + check_both_ways("\u6BEF", "\x9F\x7E", 'shift_jis') # 毯 + check_both_ways("\u9EBE", "\x9F\x80", 'shift_jis') # 麾 + check_both_ways("\u6CBE", "\x9F\x9E", 'shift_jis') # 沾 + check_both_ways("\u6CBA", "\x9F\x9F", 'shift_jis') # 沺 + check_both_ways("\u6ECC", "\x9F\xFC", 'shift_jis') # 滌 + check_both_ways("\u6F3E", "\xE0\x40", 'shift_jis') # 漾 + check_both_ways("\u70DD", "\xE0\x7E", 'shift_jis') # 烝 + check_both_ways("\u70D9", "\xE0\x80", 'shift_jis') # 烙 + check_both_ways("\u71FC", "\xE0\x9E", 'shift_jis') # 燼 + check_both_ways("\u71F9", "\xE0\x9F", 'shift_jis') # 燹 + check_both_ways("\u73F1", "\xE0\xFC", 'shift_jis') # 珱 + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\xFC".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\xFC".encode("utf-8", 'shift_jis') } + #check_both_ways("\u9ADC", "\xFC\x40", 'shift_jis') # 髜 (IBM extended) + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\xFC".encode("utf-8", 'shift_jis') } + check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘 + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x90\xC2\x8E\x52\x8A\x77\x89\x40\x91\xE5\x8A\x77", 'shift_jis') # 青山学院大学 + check_both_ways("\u795E\u6797\u7FA9\u535A", "\x90\x5F\x97\xD1\x8B\x60\x94\x8E", 'shift_jis') # 神林義博 + end + + def test_windows_31j + check_both_ways("\u222A", "\x81\xBE", 'Windows-31J') # Union + check_both_ways("\uFFE2", "\x81\xCA", 'Windows-31J') # Fullwidth Not Sign + check_both_ways("\u2235", "\x81\xE6", 'Windows-31J') # Because + check_both_ways("\u2160", "\x87\x54", 'Windows-31J') # Roman Numeral One + check_both_ways("\u2170", "\xFA\x40", 'Windows-31J') # Small Roman Numeral One + end + + def test_euc_jp + check_both_ways("\u3000", "\xA1\xA1", 'euc-jp') # full-width space + check_both_ways("\u00D7", "\xA1\xDF", 'euc-jp') # × + check_both_ways("\u00F7", "\xA1\xE0", 'euc-jp') # ÷ + check_both_ways("\u25C7", "\xA1\xFE", 'euc-jp') # ◇ + check_both_ways("\u25C6", "\xA2\xA1", 'euc-jp') # ◆ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xD1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xEB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFD".encode("utf-8", 'euc-jp') } + check_both_ways("\u25EF", "\xA2\xFE", 'euc-jp') # ◯ + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xBA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xE0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xFB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA4\xF4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xD9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xD0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xF2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xCF\xD4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xCF\xFE".encode("utf-8", 'euc-jp') } + check_both_ways("\u6A97", "\xDD\xA1", 'euc-jp') # 檗 + check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jp') # 毯 + check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jp') # 麾 + check_both_ways("\u6CBE", "\xDD\xFE", 'euc-jp') # 沾 + check_both_ways("\u6CBA", "\xDE\xA1", 'euc-jp') # 沺 + check_both_ways("\u6ECC", "\xDE\xFE", 'euc-jp') # 滌 + check_both_ways("\u6F3E", "\xDF\xA1", 'euc-jp') # 漾 + check_both_ways("\u70DD", "\xDF\xDF", 'euc-jp') # 烝 + check_both_ways("\u70D9", "\xDF\xE0", 'euc-jp') # 烙 + check_both_ways("\u71FC", "\xDF\xFE", 'euc-jp') # 燼 + check_both_ways("\u71F9", "\xE0\xA1", 'euc-jp') # 燹 + check_both_ways("\u73F1", "\xE0\xFE", 'euc-jp') # 珱 + assert_raise(Encoding::UndefinedConversionError) { "\xF4\xA7".encode("utf-8", 'euc-jp') } + #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended) + + check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jp') # 松本行弘 + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC0\xC4\xBB\xB3\xB3\xD8\xB1\xA1\xC2\xE7\xB3\xD8", 'euc-jp') # 青山学院大学 + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xBF\xC0\xCE\xD3\xB5\xC1\xC7\xEE", 'euc-jp') # 神林義博 + end + + def test_euc_jis_2004 + check_both_ways("\u3000", "\xA1\xA1", 'euc-jis-2004') # full-width space + check_both_ways("\u00D7", "\xA1\xDF", 'euc-jis-2004') # × + check_both_ways("\u00F7", "\xA1\xE0", 'euc-jis-2004') # ÷ + check_both_ways("\u25C7", "\xA1\xFE", 'euc-jis-2004') # ◇ + check_both_ways("\u25C6", "\xA2\xA1", 'euc-jis-2004') # ◆ + check_both_ways("\uFF07", "\xA2\xAF", 'euc-jis-2004') # ' + check_both_ways("\u309F", "\xA2\xB9", 'euc-jis-2004') # ゟ + check_both_ways("\u2284", "\xA2\xC2", 'euc-jis-2004') # ⊄ + check_both_ways("\u2306", "\xA2\xC9", 'euc-jis-2004') # ⌆ + check_both_ways("\u2295", "\xA2\xD1", 'euc-jis-2004') # ⊕ + check_both_ways("\u3017", "\xA2\xDB", 'euc-jis-2004') # 〗 + check_both_ways("\u2262", "\xA2\xEB", 'euc-jis-2004') # ≢ + check_both_ways("\u2194", "\xA2\xF1", 'euc-jis-2004') # ↔ + check_both_ways("\u266E", "\xA2\xFA", 'euc-jis-2004') # ♮ + check_both_ways("\u2669", "\xA2\xFD", 'euc-jis-2004') # ♩ + check_both_ways("\u25EF", "\xA2\xFE", 'euc-jis-2004') # ◯ + check_both_ways("\u2935", "\xA3\xAF", 'euc-jis-2004') # ⤵ + check_both_ways("\u29BF", "\xA3\xBA", 'euc-jis-2004') # ⦿ + check_both_ways("\u2022", "\xA3\xC0", 'euc-jis-2004') # • + check_both_ways("\u2213", "\xA3\xDB", 'euc-jis-2004') # ∓ + check_both_ways("\u2127", "\xA3\xE0", 'euc-jis-2004') # ℧ + check_both_ways("\u30A0", "\xA3\xFB", 'euc-jis-2004') # ゠ + check_both_ways("\uFF54", "\xA3\xF4", 'euc-jis-2004') # t + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jis-2004') } + check_both_ways("\u2664", "\xA6\xB9", 'euc-jis-2004') # ♤ + check_both_ways("\u2663", "\xA6\xC0", 'euc-jis-2004') # ♣ + check_both_ways("\u03C2", "\xA6\xD9", 'euc-jis-2004') # ς + check_both_ways("\u23BE", "\xA7\xC2", 'euc-jis-2004') # ⎾ + check_both_ways("\u23CC", "\xA7\xD0", 'euc-jis-2004') # ⏌ + check_both_ways("\u30F7", "\xA7\xF2", 'euc-jis-2004') # ヷ + check_both_ways("\u3251", "\xA8\xC1", 'euc-jis-2004') # ㉑ + check_both_ways("\u{20B9F}", "\xCF\xD4", 'euc-jis-2004') # 𠮑 + check_both_ways("\u541E", "\xCF\xFE", 'euc-jis-2004') # 吞 + check_both_ways("\u6A97", "\xDD\xA1", 'euc-jis-2004') # 檗 + check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jis-2004') # 毯 + check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jis-2004') # 麾 + check_both_ways("\u6CBE", "\xDD\xFE", 'euc-jis-2004') # 沾 + check_both_ways("\u6CBA", "\xDE\xA1", 'euc-jis-2004') # 沺 + check_both_ways("\u6ECC", "\xDE\xFE", 'euc-jis-2004') # 滌 + check_both_ways("\u6F3E", "\xDF\xA1", 'euc-jis-2004') # 漾 + check_both_ways("\u70DD", "\xDF\xDF", 'euc-jis-2004') # 烝 + check_both_ways("\u70D9", "\xDF\xE0", 'euc-jis-2004') # 烙 + check_both_ways("\u71FC", "\xDF\xFE", 'euc-jis-2004') # 燼 + check_both_ways("\u71F9", "\xE0\xA1", 'euc-jis-2004') # 燹 + check_both_ways("\u73F1", "\xE0\xFE", 'euc-jis-2004') # 珱 + check_both_ways("\u5653", "\xF4\xA7", 'euc-jis-2004') # 噓 + #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended) + + check_both_ways("\u9DD7", "\xFE\xE5", 'euc-jis-2004') # 鷗 + check_both_ways("\u{2000B}", "\xAE\xA2", 'euc-jis-2004') # 𠀋 + check_both_ways("\u{2A6B2}", "\x8F\xFE\xF6", 'euc-jis-2004') # 𪚲 + + check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jis-2004') # 松本行弘 + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC0\xC4\xBB\xB3\xB3\xD8\xB1\xA1\xC2\xE7\xB3\xD8", 'euc-jis-2004') # 青山学院大学 + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xBF\xC0\xCE\xD3\xB5\xC1\xC7\xEE", 'euc-jis-2004') # 神林義博 + end + + def test_eucjp_ms + check_both_ways("\u2116", "\xAD\xE2", 'eucJP-ms') # NUMERO SIGN + check_both_ways("\u221A", "\xA2\xE5", 'eucJP-ms') # SQUARE ROOT + check_both_ways("\u3231", "\xAD\xEA", 'eucJP-ms') # PARENTHESIZED IDEOGRAPH STOCK + check_both_ways("\uFF5E", "\xA1\xC1", 'eucJP-ms') # WAVE DASH + end + + def test_eucjp_sjis + check_both_ways2("\xa1\xa1", "EUC-JP", "\x81\x40", "Shift_JIS") + check_both_ways2("\xa1\xdf", "EUC-JP", "\x81\x7e", "Shift_JIS") + check_both_ways2("\xa1\xe0", "EUC-JP", "\x81\x80", "Shift_JIS") + check_both_ways2("\xa1\xfe", "EUC-JP", "\x81\x9e", "Shift_JIS") + check_both_ways2("\xa2\xa1", "EUC-JP", "\x81\x9f", "Shift_JIS") + check_both_ways2("\xa2\xfe", "EUC-JP", "\x81\xfc", "Shift_JIS") + + check_both_ways2("\xdd\xa1", "EUC-JP", "\x9f\x40", "Shift_JIS") + check_both_ways2("\xdd\xdf", "EUC-JP", "\x9f\x7e", "Shift_JIS") + check_both_ways2("\xdd\xe0", "EUC-JP", "\x9f\x80", "Shift_JIS") + check_both_ways2("\xdd\xfe", "EUC-JP", "\x9f\x9e", "Shift_JIS") + check_both_ways2("\xde\xa1", "EUC-JP", "\x9f\x9f", "Shift_JIS") + check_both_ways2("\xde\xfe", "EUC-JP", "\x9f\xfc", "Shift_JIS") + + check_both_ways2("\xdf\xa1", "EUC-JP", "\xe0\x40", "Shift_JIS") + check_both_ways2("\xdf\xdf", "EUC-JP", "\xe0\x7e", "Shift_JIS") + check_both_ways2("\xdf\xe0", "EUC-JP", "\xe0\x80", "Shift_JIS") + check_both_ways2("\xdf\xfe", "EUC-JP", "\xe0\x9e", "Shift_JIS") + check_both_ways2("\xe0\xa1", "EUC-JP", "\xe0\x9f", "Shift_JIS") + check_both_ways2("\xe0\xfe", "EUC-JP", "\xe0\xfc", "Shift_JIS") + + check_both_ways2("\xf4\xa1", "EUC-JP", "\xea\x9f", "Shift_JIS") + check_both_ways2("\xf4\xa2", "EUC-JP", "\xea\xa0", "Shift_JIS") + check_both_ways2("\xf4\xa3", "EUC-JP", "\xea\xa1", "Shift_JIS") + check_both_ways2("\xf4\xa4", "EUC-JP", "\xea\xa2", "Shift_JIS") # end of JIS X 0208 1983 + check_both_ways2("\xf4\xa5", "EUC-JP", "\xea\xa3", "Shift_JIS") + check_both_ways2("\xf4\xa6", "EUC-JP", "\xea\xa4", "Shift_JIS") # end of JIS X 0208 1990 + + check_both_ways2("\x8e\xa1", "EUC-JP", "\xa1", "Shift_JIS") + check_both_ways2("\x8e\xdf", "EUC-JP", "\xdf", "Shift_JIS") + end + + def test_eucjp_sjis_unassigned + check_both_ways2("\xfd\xa1", "EUC-JP", "\xef\x40", "Shift_JIS") + check_both_ways2("\xfd\xa1", "EUC-JP", "\xef\x40", "Shift_JIS") + check_both_ways2("\xfd\xdf", "EUC-JP", "\xef\x7e", "Shift_JIS") + check_both_ways2("\xfd\xe0", "EUC-JP", "\xef\x80", "Shift_JIS") + check_both_ways2("\xfd\xfe", "EUC-JP", "\xef\x9e", "Shift_JIS") + check_both_ways2("\xfe\xa1", "EUC-JP", "\xef\x9f", "Shift_JIS") + check_both_ways2("\xfe\xfe", "EUC-JP", "\xef\xfc", "Shift_JIS") + end + + def test_eucjp_sjis_undef + assert_raise(Encoding::UndefinedConversionError) { "\x8e\xe0".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8e\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xfe".encode("Shift_JIS", "EUC-JP") } + + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\xfc".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\xfc".encode("EUC-JP", "Shift_JIS") } + end + + def test_iso_2022_jp + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$C".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x0e".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(Dd!\x1b(B".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::UndefinedConversionError) { "\u9299".encode("iso-2022-jp") } + assert_raise(Encoding::UndefinedConversionError) { "\uff71\uff72\uff73\uff74\uff75".encode("iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(I12345\x1b(B".encode("utf-8", "iso-2022-jp") } + assert_equal("\xA1\xA1".force_encoding("euc-jp"), + "\e$B!!\e(B".encode("EUC-JP", "ISO-2022-JP")) + assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"), + "\xA1\xA1".encode("ISO-2022-JP", "EUC-JP")) + end + + def test_from_cp50221 + assert_equal("!", "\e(B\x21".encode("utf-8", "cp50221")) + assert_equal("!", "\e(J\x21".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\xB1".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\e(B\xB1".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\e(J\xB1".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\e(I\xB1".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\e(I\x31".encode("utf-8", "cp50221")) + assert_equal("\uFF71", "\x0E\xB1".encode("utf-8", "cp50221")) + assert_equal("\u3000", "\e$@\x21\x21".encode("utf-8", "cp50221")) + assert_equal("\u3000", "\e$B\x21\x21".encode("utf-8", "cp50221")) + assert_equal("\u2460", "\e$B\x2D\x21".encode("utf-8", "cp50221")) + assert_equal("\u7e8a", "\e$B\x79\x21".encode("utf-8", "cp50221")) + assert_equal("\u5fde", "\e$B\x7A\x21".encode("utf-8", "cp50221")) + assert_equal("\u72be", "\e$B\x7B\x21".encode("utf-8", "cp50221")) + assert_equal("\u91d7", "\e$B\x7C\x21".encode("utf-8", "cp50221")) + assert_equal("\xA1\xDF".force_encoding("sjis"), + "\e(I!_\e(B".encode("sjis","cp50220")) + end + + def test_to_cp50221 + assert_equal("\e$B!#!,\e(B".force_encoding("cp50220"), + "\xA1\xDF".encode("cp50220","sjis")) + assert_equal("\e$B%*!+%,%I%J!+%N!+%P%\\%^!+%Q%]%\"\e(B".force_encoding("cp50220"), + "\xB5\xDE\xB6\xDE\xC4\xDE\xC5\xDE\xC9\xDE\xCA\xDE\xCE\xDE\xCF\xDE\xCA\xDF\xCE\xDF\xB1". + encode("cp50220", "sjis")) + end + + def test_iso_2022_jp_1 + # check_both_ways("\u9299", "\x1b$(Dd!\x1b(B", "iso-2022-jp-1") # JIS X 0212 区68 点01 銙 + end + + def test_unicode_public_review_issue_121 # see http://www.unicode.org/review/pr-121.html + assert_equal("\x00\x61\xFF\xFD\xFF\xFD\xFF\xFD\x00\x62".force_encoding('UTF-16BE'), + "\x61\xF1\x80\x80\xE1\x80\xC2\x62".encode('UTF-16BE', 'UTF-8', invalid: :replace)) # option 2 + assert_equal("\x61\x00\xFD\xFF\xFD\xFF\xFD\xFF\x62\x00".force_encoding('UTF-16LE'), + "\x61\xF1\x80\x80\xE1\x80\xC2\x62".encode('UTF-16LE', 'UTF-8', invalid: :replace)) # option 2 + + # additional clarification + assert_equal("\xFF\xFD\xFF\xFD\xFF\xFD\xFF\xFD".force_encoding('UTF-16BE'), + "\xF0\x80\x80\x80".encode('UTF-16BE', 'UTF-8', invalid: :replace)) + assert_equal("\xFD\xFF\xFD\xFF\xFD\xFF\xFD\xFF".force_encoding('UTF-16LE'), + "\xF0\x80\x80\x80".encode('UTF-16LE', 'UTF-8', invalid: :replace)) + end + + def test_yen_sign + check_both_ways("\u005C", "\x5C", "Shift_JIS") + check_both_ways("\u005C", "\x5C", "Windows-31J") + check_both_ways("\u005C", "\x5C", "EUC-JP") + check_both_ways("\u005C", "\x5C", "eucJP-ms") + check_both_ways("\u005C", "\x5C", "CP51932") + check_both_ways("\u005C", "\x5C", "ISO-2022-JP") + assert_equal("\u005C", "\e(B\x5C\e(B".encode("UTF-8", "ISO-2022-JP")) + assert_equal("\u005C", "\e(J\x5C\e(B".encode("UTF-8", "ISO-2022-JP")) + assert_equal("\u005C", "\x5C".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) + assert_equal("\u005C", "\e(J\x5C\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Windows-31J") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("eucJP-ms") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("CP51932") } + + # FULLWIDTH REVERSE SOLIDUS + check_both_ways("\uFF3C", "\x81\x5F", "Shift_JIS") + check_both_ways("\uFF3C", "\x81\x5F", "Windows-31J") + check_both_ways("\uFF3C", "\xA1\xC0", "EUC-JP") + check_both_ways("\uFF3C", "\xA1\xC0", "eucJP-ms") + check_both_ways("\uFF3C", "\xA1\xC0", "CP51932") + end + + def test_tilde_overline + check_both_ways("\u007E", "\x7E", "Shift_JIS") + check_both_ways("\u007E", "\x7E", "Windows-31J") + check_both_ways("\u007E", "\x7E", "EUC-JP") + check_both_ways("\u007E", "\x7E", "eucJP-ms") + check_both_ways("\u007E", "\x7E", "CP51932") + check_both_ways("\u007E", "\x7E", "ISO-2022-JP") + assert_equal("\u007E", "\e(B\x7E\e(B".encode("UTF-8", "ISO-2022-JP")) + assert_equal("\u007E", "\e(J\x7E\e(B".encode("UTF-8", "ISO-2022-JP")) + assert_equal("\u007E", "\x7E".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) + assert_equal("\u007E", "\e(J\x7E\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Windows-31J") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("eucJP-ms") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("CP51932") } + end + + def test_gb2312 + check_both_ways("\u3000", "\xA1\xA1", 'GB2312') # full-width space + check_both_ways("\u3013", "\xA1\xFE", 'GB2312') # 〓 + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB2312') } + check_both_ways("\u2488", "\xA2\xB1", 'GB2312') # ⒈ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB2312') } + check_both_ways("\u3220", "\xA2\xE5", 'GB2312') # ㈠ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB2312') } + check_both_ways("\u2160", "\xA2\xF1", 'GB2312') # Ⅰ + check_both_ways("\uFF01", "\xA3\xA1", 'GB2312') # ! + check_both_ways("\uFFE3", "\xA3\xFE", 'GB2312') #  ̄ + check_both_ways("\u3041", "\xA4\xA1", 'GB2312') # ぁ + check_both_ways("\u30A1", "\xA5\xA1", 'GB2312') # ァ + check_both_ways("\u0391", "\xA6\xA1", 'GB2312') # Α + check_both_ways("\u03B1", "\xA6\xC1", 'GB2312') # α + check_both_ways("\u0410", "\xA7\xA1", 'GB2312') # А + check_both_ways("\u0430", "\xA7\xD1", 'GB2312') # а + check_both_ways("\u0101", "\xA8\xA1", 'GB2312') # ā + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB2312') } + check_both_ways("\u3105", "\xA8\xC5", 'GB2312') # ㄅ + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB2312') } + check_both_ways("\u2500", "\xA9\xA4", 'GB2312') # ─ + check_both_ways("\u554A", "\xB0\xA1", 'GB2312') # 啊 + check_both_ways("\u5265", "\xB0\xFE", 'GB2312') # 剥 + check_both_ways("\u4FCA", "\xBF\xA1", 'GB2312') # 俊 + check_both_ways("\u5080", "\xBF\xFE", 'GB2312') # 傀 + check_both_ways("\u9988", "\xC0\xA1", 'GB2312') # 馈 + check_both_ways("\u4FD0", "\xC0\xFE", 'GB2312') # 俐 + check_both_ways("\u7A00", "\xCF\xA1", 'GB2312') # 稀 + check_both_ways("\u6653", "\xCF\xFE", 'GB2312') # 晓 + check_both_ways("\u5C0F", "\xD0\xA1", 'GB2312') # 小 + check_both_ways("\u7384", "\xD0\xFE", 'GB2312') # 玄 + check_both_ways("\u4F4F", "\xD7\xA1", 'GB2312') # 住 + check_both_ways("\u5EA7", "\xD7\xF9", 'GB2312') # 座 + assert_raise(Encoding::UndefinedConversionError) { "\xD7\xFA".encode("utf-8", 'GB2312') } + check_both_ways("\u647A", "\xDF\xA1", 'GB2312') # 摺 + check_both_ways("\u553C", "\xDF\xFE", 'GB2312') # 唼 + check_both_ways("\u5537", "\xE0\xA1", 'GB2312') # 唷 + check_both_ways("\u5E3C", "\xE0\xFE", 'GB2312') # 帼 + check_both_ways("\u94E9", "\xEF\xA1", 'GB2312') # 铩 + check_both_ways("\u7A14", "\xEF\xFE", 'GB2312') # 稔 + check_both_ways("\u7A39", "\xF0\xA1", 'GB2312') # 稹 + check_both_ways("\u7619", "\xF0\xFE", 'GB2312') # 瘙 + check_both_ways("\u9CCC", "\xF7\xA1", 'GB2312') # 鳌 + check_both_ways("\u9F44", "\xF7\xFE", 'GB2312') # 齄 + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GB2312') # 青山学院大学 + end + + def test_gbk + check_both_ways("\u4E02", "\x81\x40", 'GBK') # 丂 + check_both_ways("\u4E8A", "\x81\x7E", 'GBK') # 亊 + check_both_ways("\u4E90", "\x81\x80", 'GBK') # 亐 + check_both_ways("\u4FA2", "\x81\xFE", 'GBK') # 侢 + check_both_ways("\u5EC6", "\x8F\x40", 'GBK') # 廆 + check_both_ways("\u5F24", "\x8F\x7E", 'GBK') # 弤 + check_both_ways("\u5F28", "\x8F\x80", 'GBK') # 弨 + check_both_ways("\u6007", "\x8F\xFE", 'GBK') # 怇 + check_both_ways("\u6008", "\x90\x40", 'GBK') # 怈 + check_both_ways("\u6080", "\x90\x7E", 'GBK') # 悀 + check_both_ways("\u6081", "\x90\x80", 'GBK') # 悁 + check_both_ways("\u6146", "\x90\xFE", 'GBK') # 慆 + check_both_ways("\u70DC", "\x9F\x40", 'GBK') # 烜 + check_both_ways("\u7134", "\x9F\x7E", 'GBK') # 焴 + check_both_ways("\u7135", "\x9F\x80", 'GBK') # 焵 + check_both_ways("\u71D3", "\x9F\xFE", 'GBK') # 燓 + check_both_ways("\u71D6", "\xA0\x40", 'GBK') # 燖 + check_both_ways("\u721A", "\xA0\x7E", 'GBK') # 爚 + check_both_ways("\u721B", "\xA0\x80", 'GBK') # 爛 + check_both_ways("\u72DB", "\xA0\xFE", 'GBK') # 狛 + check_both_ways("\u3000", "\xA1\xA1", 'GBK') # full-width space + check_both_ways("\u3001", "\xA1\xA2", 'GBK') # 、 + check_both_ways("\u3013", "\xA1\xFE", 'GBK') # 〓 + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GBK') } + check_both_ways("\u2170", "\xA2\xA1", 'GBK') # ⅰ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GBK') } + check_both_ways("\u2488", "\xA2\xB1", 'GBK') # ⒈ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GBK') } + check_both_ways("\u3220", "\xA2\xE5", 'GBK') # ㈠ + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GBK') } + check_both_ways("\u2160", "\xA2\xF1", 'GBK') # Ⅰ + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GBK') } + check_both_ways("\uFF01", "\xA3\xA1", 'GBK') # ! + check_both_ways("\uFFE3", "\xA3\xFE", 'GBK') #  ̄ + assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GBK') } + check_both_ways("\u3041", "\xA4\xA1", 'GBK') # ぁ + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GBK') } + check_both_ways("\u30A1", "\xA5\xA1", 'GBK') # ァ + check_both_ways("\u0391", "\xA6\xA1", 'GBK') # Α + check_both_ways("\u03B1", "\xA6\xC1", 'GBK') # α + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GBK') } + check_both_ways("\uFE3B", "\xA6\xEE", 'GBK') # ︻ + check_both_ways("\u0410", "\xA7\xA1", 'GBK') # А + check_both_ways("\u0430", "\xA7\xD1", 'GBK') # а + check_both_ways("\u02CA", "\xA8\x40", 'GBK') # ˊ + check_both_ways("\u2587", "\xA8\x7E", 'GBK') # ▇ + assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GBK') } + check_both_ways("\u0101", "\xA8\xA1", 'GBK') # ā + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GBK') } + check_both_ways("\u3105", "\xA8\xC5", 'GBK') # ㄅ + check_both_ways("\u3021", "\xA9\x40", 'GBK') # 〡 + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GBK') } + check_both_ways("\u3007", "\xA9\x96", 'GBK') # 〇 + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GBK') } + check_both_ways("\u2500", "\xA9\xA4", 'GBK') # ─ + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GBK') } + check_both_ways("\u7588", "\xAF\x40", 'GBK') # 疈 + check_both_ways("\u7607", "\xAF\x7E", 'GBK') # 瘇 + check_both_ways("\u7608", "\xAF\x80", 'GBK') # 瘈 + check_both_ways("\u7644", "\xAF\xA0", 'GBK') # 癄 + assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GBK') } + check_both_ways("\u7645", "\xB0\x40", 'GBK') # 癅 + check_both_ways("\u769B", "\xB0\x7E", 'GBK') # 皛 + check_both_ways("\u769C", "\xB0\x80", 'GBK') # 皜 + check_both_ways("\u5265", "\xB0\xFE", 'GBK') # 剥 + check_both_ways("\u7DFB", "\xBF\x40", 'GBK') # 緻 + check_both_ways("\u7E39", "\xBF\x7E", 'GBK') # 縹 + check_both_ways("\u7E3A", "\xBF\x80", 'GBK') # 縺 + check_both_ways("\u5080", "\xBF\xFE", 'GBK') # 傀 + check_both_ways("\u7E5E", "\xC0\x40", 'GBK') # 繞 + check_both_ways("\u7E9E", "\xC0\x7E", 'GBK') # 纞 + check_both_ways("\u7EAE", "\xC0\x80", 'GBK') # 纮 + check_both_ways("\u4FD0", "\xC0\xFE", 'GBK') # 俐 + check_both_ways("\u87A5", "\xCF\x40", 'GBK') # 螥 + check_both_ways("\u87F8", "\xCF\x7E", 'GBK') # 蟸 + check_both_ways("\u87FA", "\xCF\x80", 'GBK') # 蟺 + check_both_ways("\u6653", "\xCF\xFE", 'GBK') # 晓 + check_both_ways("\u8824", "\xD0\x40", 'GBK') # 蠤 + check_both_ways("\u887A", "\xD0\x7E", 'GBK') # 衺 + check_both_ways("\u887B", "\xD0\x80", 'GBK') # 衻 + check_both_ways("\u7384", "\xD0\xFE", 'GBK') # 玄 + check_both_ways("\u9019", "\xDF\x40", 'GBK') # 這 + check_both_ways("\u9081", "\xDF\x7E", 'GBK') # 邁 + check_both_ways("\u9084", "\xDF\x80", 'GBK') # 還 + check_both_ways("\u553C", "\xDF\xFE", 'GBK') # 唼 + check_both_ways("\u90C2", "\xE0\x40", 'GBK') # 郂 + check_both_ways("\u911C", "\xE0\x7E", 'GBK') # 鄜 + check_both_ways("\u911D", "\xE0\x80", 'GBK') # 鄝 + check_both_ways("\u5E3C", "\xE0\xFE", 'GBK') # 帼 + check_both_ways("\u986F", "\xEF\x40", 'GBK') # 顯 + check_both_ways("\u98E4", "\xEF\x7E", 'GBK') # 飤 + check_both_ways("\u98E5", "\xEF\x80", 'GBK') # 飥 + check_both_ways("\u7A14", "\xEF\xFE", 'GBK') # 稔 + check_both_ways("\u9908", "\xF0\x40", 'GBK') # 餈 + check_both_ways("\u9949", "\xF0\x7E", 'GBK') # 饉 + check_both_ways("\u994A", "\xF0\x80", 'GBK') # 饊 + check_both_ways("\u7619", "\xF0\xFE", 'GBK') # 瘙 + check_both_ways("\u9F32", "\xFD\x40", 'GBK') # 鼲 + check_both_ways("\u9F78", "\xFD\x7E", 'GBK') # 齸 + check_both_ways("\u9F79", "\xFD\x80", 'GBK') # 齹 + check_both_ways("\uF9F1", "\xFD\xA0", 'GBK') # 隣 + assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GBK') } + check_both_ways("\uFA0C", "\xFE\x40", 'GBK') # 兀 + check_both_ways("\uFA29", "\xFE\x4F", 'GBK') # 﨩 + assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GBK') } + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GBK') # 青山学院大学 + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GBK') # 神林義博 + end + + def test_gb18030 + # overall roundtrip test + all_unicode = (0x0..0xD7FF).to_a.pack 'U*' #追加 + all_unicode << (0xE000..0xFFFF).to_a.pack("U*") #追加 + + assert_equal(all_unicode, all_unicode.encode("gb18030").encode("UTF-8")) #追加 + + # tests from GBK + check_both_ways("\u4E02", "\x81\x40", 'GB18030') # + check_both_ways("\u4E8A", "\x81\x7E", 'GB18030') # + check_both_ways("\u4E90", "\x81\x80", 'GB18030') # + check_both_ways("\u4FA2", "\x81\xFE", 'GB18030') # 侢 + check_both_ways("\u5EC6", "\x8F\x40", 'GB18030') # + check_both_ways("\u5F24", "\x8F\x7E", 'GB18030') # 弤 + check_both_ways("\u5F28", "\x8F\x80", 'GB18030') # 弨 + check_both_ways("\u6007", "\x8F\xFE", 'GB18030') # + check_both_ways("\u6008", "\x90\x40", 'GB18030') # + check_both_ways("\u6080", "\x90\x7E", 'GB18030') # 悀 + check_both_ways("\u6081", "\x90\x80", 'GB18030') # + check_both_ways("\u6146", "\x90\xFE", 'GB18030') # + check_both_ways("\u70DC", "\x9F\x40", 'GB18030') # + check_both_ways("\u7134", "\x9F\x7E", 'GB18030') # 焴 + check_both_ways("\u7135", "\x9F\x80", 'GB18030') # 焵 + check_both_ways("\u71D3", "\x9F\xFE", 'GB18030') # + check_both_ways("\u71D6", "\xA0\x40", 'GB18030') # + check_both_ways("\u721A", "\xA0\x7E", 'GB18030') # + check_both_ways("\u721B", "\xA0\x80", 'GB18030') # + check_both_ways("\u72DB", "\xA0\xFE", 'GB18030') # + check_both_ways("\u3000", "\xA1\xA1", 'GB18030') # full-width space + check_both_ways("\u3001", "\xA1\xA2", 'GB18030') # + check_both_ways("\u3013", "\xA1\xFE", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GB18030') } + check_both_ways("\u2170", "\xA2\xA1", 'GB18030') # ⅰ + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB18030') } + check_both_ways("\u2488", "\xA2\xB1", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB18030') } + check_both_ways("\u3220", "\xA2\xE5", 'GB18030') # ㈠ + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB18030') } + check_both_ways("\u2160", "\xA2\xF1", 'GB18030') # Ⅰ + #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GB18030') } + check_both_ways("\uFF01", "\xA3\xA1", 'GB18030') # E + check_both_ways("\uFFE3", "\xA3\xFE", 'GB18030') # E + #assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GB18030') } + check_both_ways("\u3041", "\xA4\xA1", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GB18030') } + check_both_ways("\u30A1", "\xA5\xA1", 'GB18030') # ァ + check_both_ways("\u0391", "\xA6\xA1", 'GB18030') # + check_both_ways("\u03B1", "\xA6\xC1", 'GB18030') # α + #assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GB18030') } + check_both_ways("\uFE3B", "\xA6\xEE", 'GB18030') # E + check_both_ways("\u0410", "\xA7\xA1", 'GB18030') # + check_both_ways("\u0430", "\xA7\xD1", 'GB18030') # а + check_both_ways("\u02CA", "\xA8\x40", 'GB18030') # + check_both_ways("\u2587", "\xA8\x7E", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GB18030') } + check_both_ways("\u0101", "\xA8\xA1", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB18030') } + check_both_ways("\u3105", "\xA8\xC5", 'GB18030') # + check_both_ways("\u3021", "\xA9\x40", 'GB18030') # 〡 + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GB18030') } + check_both_ways("\u3007", "\xA9\x96", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB18030') } + check_both_ways("\u2500", "\xA9\xA4", 'GB18030') # ─ + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GB18030') } + check_both_ways("\u7588", "\xAF\x40", 'GB18030') # + check_both_ways("\u7607", "\xAF\x7E", 'GB18030') # + check_both_ways("\u7608", "\xAF\x80", 'GB18030') # + check_both_ways("\u7644", "\xAF\xA0", 'GB18030') # + #assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GB18030') } + check_both_ways("\u7645", "\xB0\x40", 'GB18030') # + check_both_ways("\u769B", "\xB0\x7E", 'GB18030') # + check_both_ways("\u769C", "\xB0\x80", 'GB18030') # + check_both_ways("\u5265", "\xB0\xFE", 'GB18030') # 剥 + check_both_ways("\u7DFB", "\xBF\x40", 'GB18030') # 緻 + check_both_ways("\u7E39", "\xBF\x7E", 'GB18030') # 縹 + check_both_ways("\u7E3A", "\xBF\x80", 'GB18030') # 縺 + check_both_ways("\u5080", "\xBF\xFE", 'GB18030') # 傀 + check_both_ways("\u7E5E", "\xC0\x40", 'GB18030') # + check_both_ways("\u7E9E", "\xC0\x7E", 'GB18030') # + check_both_ways("\u7EAE", "\xC0\x80", 'GB18030') # 纮 + check_both_ways("\u4FD0", "\xC0\xFE", 'GB18030') # + check_both_ways("\u87A5", "\xCF\x40", 'GB18030') # 螥 + check_both_ways("\u87F8", "\xCF\x7E", 'GB18030') # 蟸 + check_both_ways("\u87FA", "\xCF\x80", 'GB18030') # 蟺 + check_both_ways("\u6653", "\xCF\xFE", 'GB18030') # + check_both_ways("\u8824", "\xD0\x40", 'GB18030') # 蠤 + check_both_ways("\u887A", "\xD0\x7E", 'GB18030') # 衺 + check_both_ways("\u887B", "\xD0\x80", 'GB18030') # 衻 + check_both_ways("\u7384", "\xD0\xFE", 'GB18030') # + check_both_ways("\u9019", "\xDF\x40", 'GB18030') # + check_both_ways("\u9081", "\xDF\x7E", 'GB18030') # + check_both_ways("\u9084", "\xDF\x80", 'GB18030') # + check_both_ways("\u553C", "\xDF\xFE", 'GB18030') # 唼 + check_both_ways("\u90C2", "\xE0\x40", 'GB18030') # + check_both_ways("\u911C", "\xE0\x7E", 'GB18030') # + check_both_ways("\u911D", "\xE0\x80", 'GB18030') # + check_both_ways("\u5E3C", "\xE0\xFE", 'GB18030') # 帼 + check_both_ways("\u986F", "\xEF\x40", 'GB18030') # 顯 + check_both_ways("\u98E4", "\xEF\x7E", 'GB18030') # 飤 + check_both_ways("\u98E5", "\xEF\x80", 'GB18030') # 飥 + check_both_ways("\u7A14", "\xEF\xFE", 'GB18030') # + check_both_ways("\u9908", "\xF0\x40", 'GB18030') # + check_both_ways("\u9949", "\xF0\x7E", 'GB18030') # + check_both_ways("\u994A", "\xF0\x80", 'GB18030') # + check_both_ways("\u7619", "\xF0\xFE", 'GB18030') # + check_both_ways("\u9F32", "\xFD\x40", 'GB18030') # 鼲 + check_both_ways("\u9F78", "\xFD\x7E", 'GB18030') # 齸 + check_both_ways("\u9F79", "\xFD\x80", 'GB18030') # 齹 + check_both_ways("\uF9F1", "\xFD\xA0", 'GB18030') # E + #assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GB18030') } + check_both_ways("\uFA0C", "\xFE\x40", 'GB18030') # E + check_both_ways("\uFA29", "\xFE\x4F", 'GB18030') # E + #assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GB18030') } + check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GB18030') # 青山学院大学 + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GB18030') # 神林義 + + # new tests for GB18030 + check_both_ways("\u9FA6", "\x82\x35\x8F\x33", 'GB18030') # 龦 + check_both_ways("\uD7FF", "\x83\x36\xC7\x38", 'GB18030') # No name () + + check_both_ways("\u0452", "\x81\x30\xD3\x30", 'GB18030') # + check_both_ways("\u200F", "\x81\x36\xA5\x31", 'GB18030') # RIGHT-TO-LEFT MARK + + check_both_ways("\uE865", "\x83\x36\xD0\x30", 'GB18030') # No name (Private Use Area) + check_both_ways("\uF92B", "\x84\x30\x85\x34", 'GB18030') # E + + check_both_ways("\u2643", "\x81\x37\xA8\x39", 'GB18030') # + check_both_ways("\u2E80", "\x81\x38\xFD\x38", 'GB18030') # ⺀ + + check_both_ways("\uFA2A", "\x84\x30\x9C\x38", 'GB18030') # E + check_both_ways("\uFE2F", "\x84\x31\x85\x37", 'GB18030') # No name (Combining Half Marks) + + check_both_ways("\u3CE1", "\x82\x31\xD4\x38", 'GB18030') # 㳡 + check_both_ways("\u4055", "\x82\x32\xAF\x32", 'GB18030') # + + check_both_ways("\u361B", "\x82\x30\xA6\x33", 'GB18030') # + check_both_ways("\u3917", "\x82\x30\xF2\x37", 'GB18030') # + + check_both_ways("\u49B8", "\x82\x34\xA1\x31", 'GB18030') # 䦸 + check_both_ways("\u4C76", "\x82\x34\xE7\x33", 'GB18030') # 䱶 + + check_both_ways("\u4160", "\x82\x32\xC9\x37", 'GB18030') # 䅠 + check_both_ways("\u4336", "\x82\x32\xF8\x37", 'GB18030') # 䌶 + + check_both_ways("\u478E", "\x82\x33\xE8\x38", 'GB18030') # + check_both_ways("\u4946", "\x82\x34\x96\x38", 'GB18030') # + + check_both_ways("\u44D7", "\x82\x33\xA3\x39", 'GB18030') # + check_both_ways("\u464B", "\x82\x33\xC9\x31", 'GB18030') # + + check_both_ways("\uFFE6", "\x84\x31\xA2\x34", 'GB18030') # E + check_both_ways("\uFFFF", "\x84\x31\xA4\x39", 'GB18030') # not a character + + check_both_ways("\u{10000}", "\x90\x30\x81\x30", 'GB18030') # 𐀀 + check_both_ways("\u{10FFFE}", "\xE3\x32\x9A\x34", 'GB18030') # No name (Not a character) + check_both_ways("\u{10FFFF}", "\xE3\x32\x9A\x35", 'GB18030') # No name (Not a character) + end + + def test_Big5 + check_both_ways("\u3000", "\xA1\x40", 'Big5') # full-width space + check_both_ways("\uFE5A", "\xA1\x7E", 'Big5') # ﹚ + check_both_ways("\uFE5B", "\xA1\xA1", 'Big5') # ﹛ + #check_both_ways("\uFF0F", "\xA1\xFE", 'Big5') # / + check_both_ways("\uFF57", "\xA3\x40", 'Big5') # w + check_both_ways("\u310F", "\xA3\x7E", 'Big5') # ㄏ + check_both_ways("\u3110", "\xA3\xA1", 'Big5') # ㄐ + check_both_ways("\u02CB", "\xA3\xBF", 'Big5') # ˋ + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5') } + check_both_ways("\u6D6C", "\xAF\x40", 'Big5') # 浬 + check_both_ways("\u7837", "\xAF\x7E", 'Big5') # 砷 + check_both_ways("\u7825", "\xAF\xA1", 'Big5') # 砥 + check_both_ways("\u8343", "\xAF\xFE", 'Big5') # 荃 + check_both_ways("\u8654", "\xB0\x40", 'Big5') # 虔 + check_both_ways("\u9661", "\xB0\x7E", 'Big5') # 陡 + check_both_ways("\u965B", "\xB0\xA1", 'Big5') # 陛 + check_both_ways("\u5A40", "\xB0\xFE", 'Big5') # 婀 + check_both_ways("\u6FC3", "\xBF\x40", 'Big5') # 濃 + check_both_ways("\u7E0A", "\xBF\x7E", 'Big5') # 縊 + check_both_ways("\u7E11", "\xBF\xA1", 'Big5') # 縑 + check_both_ways("\u931A", "\xBF\xFE", 'Big5') # 錚 + check_both_ways("\u9310", "\xC0\x40", 'Big5') # 錐 + check_both_ways("\u5687", "\xC0\x7E", 'Big5') # 嚇 + check_both_ways("\u568F", "\xC0\xA1", 'Big5') # 嚏 + check_both_ways("\u77AC", "\xC0\xFE", 'Big5') # 瞬 + check_both_ways("\u8B96", "\xC6\x40", 'Big5') # 讖 + check_both_ways("\u7C72", "\xC6\x7E", 'Big5') # 籲 + #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5') } + check_both_ways("\u4E42", "\xC9\x40", 'Big5') # 乂 + check_both_ways("\u6C15", "\xC9\x7E", 'Big5') # 氕 + check_both_ways("\u6C36", "\xC9\xA1", 'Big5') # 氶 + check_both_ways("\u6C4B", "\xC9\xFE", 'Big5') # 汋 + check_both_ways("\u67DC", "\xCF\x40", 'Big5') # 柜 + check_both_ways("\u6D42", "\xCF\x7E", 'Big5') # 浂 + check_both_ways("\u6D01", "\xCF\xA1", 'Big5') # 洁 + check_both_ways("\u7A80", "\xCF\xFE", 'Big5') # 窀 + check_both_ways("\u7A7E", "\xD0\x40", 'Big5') # 穾 + check_both_ways("\u82EA", "\xD0\x7E", 'Big5') # 苪 + check_both_ways("\u82E4", "\xD0\xA1", 'Big5') # 苤 + check_both_ways("\u54F1", "\xD0\xFE", 'Big5') # 哱 + check_both_ways("\u7A1B", "\xDF\x40", 'Big5') # 稛 + check_both_ways("\u816F", "\xDF\x7E", 'Big5') # 腯 + check_both_ways("\u8144", "\xDF\xA1", 'Big5') # 腄 + check_both_ways("\u89E4", "\xDF\xFE", 'Big5') # 觤 + check_both_ways("\u89E1", "\xE0\x40", 'Big5') # 觡 + check_both_ways("\u903F", "\xE0\x7E", 'Big5') # 逿 + check_both_ways("\u9044", "\xE0\xA1", 'Big5') # 遄 + check_both_ways("\u50E0", "\xE0\xFE", 'Big5') # 僠 + check_both_ways("\u979E", "\xEF\x40", 'Big5') # 鞞 + check_both_ways("\u9D30", "\xEF\x7E", 'Big5') # 鴰 + check_both_ways("\u9D45", "\xEF\xA1", 'Big5') # 鵅 + check_both_ways("\u7376", "\xEF\xFE", 'Big5') # 獶 + check_both_ways("\u74B8", "\xF0\x40", 'Big5') # 璸 + check_both_ways("\u81D2", "\xF0\x7E", 'Big5') # 臒 + check_both_ways("\u81D0", "\xF0\xA1", 'Big5') # 臐 + check_both_ways("\u8E67", "\xF0\xFE", 'Big5') # 蹧 + check_both_ways("\u7E98", "\xF9\x40", 'Big5') # 纘 + check_both_ways("\u9F0A", "\xF9\x7E", 'Big5') # 鼊 + check_both_ways("\u9FA4", "\xF9\xA1", 'Big5') # 龤 + check_both_ways("\u9F98", "\xF9\xD5", 'Big5') # 龘 + #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5') } + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5') # 神林義博 + end + + def test_Big5_Hkscs + check_both_ways("\u3000", "\xA1\x40", 'Big5-HKSCS') # full-width space + check_both_ways("\uFE5A", "\xA1\x7E", 'Big5-HKSCS') # ﹚ + check_both_ways("\uFE5B", "\xA1\xA1", 'Big5-HKSCS') # ﹛ + #check_both_ways("\uFF0F", "\xA1\xFE", 'Big5-HKSCS') # / + check_both_ways("\uFF57", "\xA3\x40", 'Big5-HKSCS') # w + check_both_ways("\u310F", "\xA3\x7E", 'Big5-HKSCS') # ㄏ + check_both_ways("\u3110", "\xA3\xA1", 'Big5-HKSCS') # ㄐ + check_both_ways("\u02CB", "\xA3\xBF", 'Big5-HKSCS') # ˋ + #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5-HKSCS') } + check_both_ways("\u6D6C", "\xAF\x40", 'Big5-HKSCS') # 浬 + check_both_ways("\u7837", "\xAF\x7E", 'Big5-HKSCS') # 砷 + check_both_ways("\u7825", "\xAF\xA1", 'Big5-HKSCS') # 砥 + check_both_ways("\u8343", "\xAF\xFE", 'Big5-HKSCS') # 荃 + check_both_ways("\u8654", "\xB0\x40", 'Big5-HKSCS') # 虔 + check_both_ways("\u9661", "\xB0\x7E", 'Big5-HKSCS') # 陡 + check_both_ways("\u965B", "\xB0\xA1", 'Big5-HKSCS') # 陛 + check_both_ways("\u5A40", "\xB0\xFE", 'Big5-HKSCS') # 婀 + check_both_ways("\u6FC3", "\xBF\x40", 'Big5-HKSCS') # 濃 + check_both_ways("\u7E0A", "\xBF\x7E", 'Big5-HKSCS') # 縊 + check_both_ways("\u7E11", "\xBF\xA1", 'Big5-HKSCS') # 縑 + check_both_ways("\u931A", "\xBF\xFE", 'Big5-HKSCS') # 錚 + check_both_ways("\u9310", "\xC0\x40", 'Big5-HKSCS') # 錐 + check_both_ways("\u5687", "\xC0\x7E", 'Big5-HKSCS') # 嚇 + check_both_ways("\u568F", "\xC0\xA1", 'Big5-HKSCS') # 嚏 + check_both_ways("\u77AC", "\xC0\xFE", 'Big5-HKSCS') # 瞬 + check_both_ways("\u8B96", "\xC6\x40", 'Big5-HKSCS') # 讖 + check_both_ways("\u7C72", "\xC6\x7E", 'Big5-HKSCS') # 籲 + #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5-HKSCS') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5-HKSCS') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5-HKSCS') } + check_both_ways("\u4E42", "\xC9\x40", 'Big5-HKSCS') # 乂 + check_both_ways("\u6C15", "\xC9\x7E", 'Big5-HKSCS') # 氕 + check_both_ways("\u6C36", "\xC9\xA1", 'Big5-HKSCS') # 氶 + check_both_ways("\u6C4B", "\xC9\xFE", 'Big5-HKSCS') # 汋 + check_both_ways("\u67DC", "\xCF\x40", 'Big5-HKSCS') # 柜 + check_both_ways("\u6D42", "\xCF\x7E", 'Big5-HKSCS') # 浂 + check_both_ways("\u6D01", "\xCF\xA1", 'Big5-HKSCS') # 洁 + check_both_ways("\u7A80", "\xCF\xFE", 'Big5-HKSCS') # 窀 + check_both_ways("\u7A7E", "\xD0\x40", 'Big5-HKSCS') # 穾 + check_both_ways("\u82EA", "\xD0\x7E", 'Big5-HKSCS') # 苪 + check_both_ways("\u82E4", "\xD0\xA1", 'Big5-HKSCS') # 苤 + check_both_ways("\u54F1", "\xD0\xFE", 'Big5-HKSCS') # 哱 + check_both_ways("\u7A1B", "\xDF\x40", 'Big5-HKSCS') # 稛 + check_both_ways("\u816F", "\xDF\x7E", 'Big5-HKSCS') # 腯 + check_both_ways("\u8144", "\xDF\xA1", 'Big5-HKSCS') # 腄 + check_both_ways("\u89E4", "\xDF\xFE", 'Big5-HKSCS') # 觤 + check_both_ways("\u89E1", "\xE0\x40", 'Big5-HKSCS') # 觡 + check_both_ways("\u903F", "\xE0\x7E", 'Big5-HKSCS') # 逿 + check_both_ways("\u9044", "\xE0\xA1", 'Big5-HKSCS') # 遄 + check_both_ways("\u50E0", "\xE0\xFE", 'Big5-HKSCS') # 僠 + check_both_ways("\u979E", "\xEF\x40", 'Big5-HKSCS') # 鞞 + check_both_ways("\u9D30", "\xEF\x7E", 'Big5-HKSCS') # 鴰 + check_both_ways("\u9D45", "\xEF\xA1", 'Big5-HKSCS') # 鵅 + check_both_ways("\u7376", "\xEF\xFE", 'Big5-HKSCS') # 獶 + check_both_ways("\u74B8", "\xF0\x40", 'Big5-HKSCS') # 璸 + check_both_ways("\u81D2", "\xF0\x7E", 'Big5-HKSCS') # 臒 + check_both_ways("\u81D0", "\xF0\xA1", 'Big5-HKSCS') # 臐 + check_both_ways("\u8E67", "\xF0\xFE", 'Big5-HKSCS') # 蹧 + check_both_ways("\u7E98", "\xF9\x40", 'Big5-HKSCS') # 纘 + check_both_ways("\u9F0A", "\xF9\x7E", 'Big5-HKSCS') # 鼊 + check_both_ways("\u9FA4", "\xF9\xA1", 'Big5-HKSCS') # 龤 + check_both_ways("\u9F98", "\xF9\xD5", 'Big5-HKSCS') # 龘 + #check_both_ways("\u{23ED7}", "\x8E\x40", 'Big5-HKSCS') # 𣻗 + #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5-HKSCS') } + check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5-HKSCS') # 神林義博 + end + + def test_Big5_UAO + check_both_ways("\u4e17", "\x81\x40", 'Big5-UAO') # 丗 + end + + def test_nothing_changed + a = "James".force_encoding("US-ASCII") + b = a.encode("Shift_JIS") + assert_equal(Encoding::US_ASCII, a.encoding) + assert_equal(Encoding::Shift_JIS, b.encoding) + end + + def test_utf8_mac + # composition exclusion + assert_equal("\u05DB\u05BF", "\u05DB\u05BF".encode("UTF-8", "UTF8-MAC")) #"\u{fb4d}" + + assert_equal("\u{1ff7}", "\u03C9\u0342\u0345".encode("UTF-8", "UTF8-MAC")) + + assert_equal("\u05DB\u05BF", "\u{fb4d}".encode("UTF8-MAC").force_encoding("UTF-8")) + assert_equal("\u03C9\u0342\u0345", "\u{1ff7}".encode("UTF8-MAC").force_encoding("UTF-8")) + + check_both_ways("\u{e9 74 e8}", "e\u0301te\u0300", 'UTF8-MAC') + end + + def test_fallback + assert_equal("\u3042".encode("EUC-JP"), "\u{20000}".encode("EUC-JP", + fallback: {"\u{20000}" => "\u3042".encode("EUC-JP")})) + assert_equal("\u3042".encode("EUC-JP"), "\u{20000}".encode("EUC-JP", + fallback: {"\u{20000}" => "\u3042"})) + assert_equal("[ISU]", "\u{1F4BA}".encode("SJIS-KDDI", + fallback: {"\u{1F4BA}" => "[ISU]"})) + end + + def test_fallback_hash_default + fallback = Hash.new {|h, x| "U+%.4X" % x.unpack("U")} + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback)) + end + + def test_fallback_proc + fallback = proc {|x| "U+%.4X" % x.unpack("U")} + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback)) + end + + def test_fallback_method + def (fallback = "U+%.4X").escape(x) + self % x.unpack("U") + end + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback.method(:escape))) + end + + bug8940 = '[ruby-core:57318] [Bug #8940]' + %w[UTF-32 UTF-16].each do |enc| + define_method("test_pseudo_encoding_inspect(#{enc})") do + assert_normal_exit("'aaa'.encode('#{enc}').inspect", bug8940) + assert_equal(4, 'aaa'.encode(enc).length, "should count in #{enc} with BOM") + end + end + + def test_encode_with_invalid_chars + bug8995 = '[ruby-dev:47747]' + EnvUtil.with_default_internal(Encoding::UTF_8) do + str = "\xff".force_encoding('utf-8') + assert_equal str, str.encode, bug8995 + assert_equal "\ufffd", str.encode(invalid: :replace), bug8995 + end + end + + def test_valid_dummy_encoding + bug9314 = '[ruby-core:59354] [Bug #9314]' + assert_separately(%W[- -- #{bug9314}], <<-'end;') + bug = ARGV.shift + result = assert_nothing_raised(TypeError, bug) {break "test".encode(Encoding::UTF_16)} + assert_equal("\xFE\xFF\x00t\x00e\x00s\x00t", result.b, bug) + result = assert_nothing_raised(TypeError, bug) {break "test".encode(Encoding::UTF_32)} + assert_equal("\x00\x00\xFE\xFF\x00\x00\x00t\x00\x00\x00e\x00\x00\x00s\x00\x00\x00t", result.b, bug) + end; + end + + def test_loading_race + assert_separately([], <<-'end;') #do + bug11277 = '[ruby-dev:49106] [Bug #11277]' + num = 2 + th = (0...num).map do |i| + Thread.new {"\u3042".encode("EUC-JP")} + end + result = nil + assert_warning("", bug11277) do + assert_nothing_raised(Encoding::ConverterNotFoundError, bug11277) do + result = th.map(&:value) + end + end + expected = "\xa4\xa2".force_encoding(Encoding::EUC_JP) + assert_equal([expected]*num, result, bug11277) + end; + end + + def test_universal_newline + bug11324 = '[ruby-core:69841] [Bug #11324]' + usascii = Encoding::US_ASCII + s = "A\nB\r\nC".force_encoding(usascii) + assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true), bug11324) + assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true, undef: :replace), bug11324) + assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true, undef: :replace, replace: ''), bug11324) + end +end diff --git a/jni/ruby/test/ruby/test_undef.rb b/jni/ruby/test/ruby/test_undef.rb new file mode 100644 index 0000000..e1c9807 --- /dev/null +++ b/jni/ruby/test/ruby/test_undef.rb @@ -0,0 +1,37 @@ +require 'test/unit' + +class TestUndef < Test::Unit::TestCase + class Undef0 + def foo + "foo" + end + undef foo + end + + class Undef1 + def bar + "bar" + end + end + + class Undef2 < Undef1 + undef bar + end + + def test_undef + x = Undef0.new + assert_raise(NoMethodError) { x.foo } + y = Undef1.new + assert_equal "bar", y.bar + z = Undef2.new + assert_raise(NoMethodError) { z.foo } + end + + def test_special_const_undef + assert_raise(TypeError) do + 1.instance_eval do + undef to_s + end + end + end +end diff --git a/jni/ruby/test/ruby/test_unicode_escape.rb b/jni/ruby/test/ruby/test_unicode_escape.rb new file mode 100644 index 0000000..9d0d787 --- /dev/null +++ b/jni/ruby/test/ruby/test_unicode_escape.rb @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- + +require 'test/unit' + +class TestUnicodeEscape < Test::Unit::TestCase + def test_basic + assert_equal('Matz - 松本行弘', + "Matz - \u677E\u672C\u884C\u5F18") + assert_equal('Matz - まつもと ゆきひろ', + "Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D") + assert_equal('Matz - まつもと ゆきひろ', + "Matz - \u{307E}\u{3064}\u{3082}\u{3068} \u{3086}\u{304D}\u{3072}\u{308D}") + assert_equal('Matz - まつもと ゆきひろ', + "Matz - \u{307E 3064 3082 3068 20 3086 304D 3072 308D}") + assert_equal("Aoyama Gakuin University - \xE9\x9D\x92\xE5\xB1\xB1\xE5\xAD\xA6\xE9\x99\xA2\xE5\xA4\xA7\xE5\xAD\xA6", + "Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66") + assert_equal('Aoyama Gakuin University - 青山学院大学', + "Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66") + assert_equal('青山学院大学', "\u9752\u5C71\u5B66\u9662\u5927\u5B66") + assert_equal("Martin D\xC3\xBCrst", "Martin D\u00FCrst") + assert_equal('Martin Dürst', "Martin D\u00FCrst") + assert_equal('ü', "\u00FC") + assert_equal("Martin D\xC3\xBCrst", "Martin D\u{FC}rst") + assert_equal('Martin Dürst', "Martin D\u{FC}rst") + assert_equal('ü', "\u{FC}") + assert_equal('ü', %Q|\u{FC}|) + assert_equal('ü', %W{\u{FC}}[0]) + + # \u escapes in here documents + assert_equal('Matz - まつもと ゆきひろ', <<EOS.chop) +Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D +EOS + + assert_equal('Matz - まつもと ゆきひろ', <<"EOS".chop) +Matz - \u{307E 3064 3082 3068} \u{3086 304D 3072 308D} +EOS + assert_not_equal('Matz - まつもと ゆきひろ', <<'EOS'.chop) +Matz - \u{307E 3064 3082 3068} \u{3086 304D 3072 308D} +EOS + + # single-quoted things don't expand \u + assert_not_equal('ü', '\u{FC}') + assert_not_equal('ü', %q|\u{FC}|) + assert_not_equal('ü', %w{\u{FC}}[0]) + assert_equal('\u00fc', "\\" + "u00fc") + + # \u in %x strings + assert_match(/^("?)A\1$/, `echo "\u0041"`) #" + assert_match(/^("?)A\1$/, %x{echo "\u0041"}) #" + assert_match(/^("?)ü\1$/, + `#{EnvUtil.rubybin} -e "#coding:utf-8\nputs \\"\\u{FC}\\""`.force_encoding("utf-8")) #" + + # \u in quoted symbols + assert_equal(:A, :"\u0041") + assert_equal(:a, :"\u0061") + assert_equal(:ま, :ま) + assert_equal(:ü, :ü) + assert_equal(:"\u{41}", :"\u0041") + assert_equal(:ü, :"\u{fc}") + + # the NUL character is allowed in symbols + bug = '[ruby-dev:41447]' + sym = "\0".to_sym + assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\u{0}")))} + assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\u0000")))} + assert_nothing_raised(SyntaxError, bug) {assert_equal("\u{fc}\0A".to_sym, eval(%q(:"\u{fc 0 0041}")))} + assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\x00")))} + assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\0")))} + end + + def test_regexp + + # Compare regexps to regexps + assert_not_equal(/Yukihiro Matsumoto - 松本行弘/, + /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/) + assert_not_equal(/Yukihiro Matsumoto - 松本行弘/, + /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/) + assert_not_equal(/Matz - まつもと ゆきひろ/, + /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/) + assert_not_equal(/Aoyama Gakuin University - 青山学院大学/, + /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/) + assert_not_equal(/青山学院大学/, /\u9752\u5C71\u5B66\u9662\u5927\u5B66/) + assert_not_equal(/Martin Dürst/, /Martin D\u00FCrst/) + assert_not_equal(/ü/, /\u00FC/) + assert_not_equal(/Martin Dürst/, /Martin D\u{FC}rst/) + assert_not_equal(/ü/, /\u{FC}/) + assert_not_equal(/ü/, %r{\u{FC}}) + assert_not_equal(/ü/i, %r{\u00FC}i) + + assert_equal('Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18', + /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/.source) + assert_equal('Yukihiro Matsumoto - \u{677E 672C 884C 5F18}', + /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/.source) + assert_equal('Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D', + /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/.source) + assert_equal('Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66', + /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/.source) + assert_equal('\u9752\u5C71\u5B66\u9662\u5927\u5B66', + /\u9752\u5C71\u5B66\u9662\u5927\u5B66/.source) + assert_equal('Martin D\u00FCrst', /Martin D\u00FCrst/.source) + assert_equal('\u00FC', /\u00FC/.source) + assert_equal('Martin D\u{FC}rst', /Martin D\u{FC}rst/.source) + assert_equal('\u{FC}', /\u{FC}/.source) + assert_equal('\u{FC}', %r{\u{FC}}.source) + assert_equal('\u00FC', %r{\u00FC}i.source) + + # match strings to regexps + assert_equal(0, "Yukihiro Matsumoto - 松本行弘" =~ /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/) + assert_equal(0, "Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18" =~ /Yukihiro Matsumoto - \u677E\u672C\u884C/) + assert_equal(0, "Yukihiro Matsumoto - 松本行弘" =~ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/) + assert_equal(0, %Q{Yukihiro Matsumoto - \u{677E 672C 884C 5F18}} =~ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/) + assert_equal(0, "Matz - まつもと ゆきひろ" =~ /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/) + assert_equal(0, "Aoyama Gakuin University - 青山学院大学" =~ /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/) + assert_equal(0, "青山学院大学" =~ /\u9752\u5C71\u5B66\u9662\u5927\u5B66/) + assert_equal(0, "Martin Dürst" =~ /Martin D\u00FCrst/) + assert_equal(0, "ü" =~ /\u00FC/) + assert_equal(0, "Martin Dürst" =~ /Martin D\u{FC}rst/) + assert_equal(0, "ü" =~ %r{\u{FC}}) + assert_equal(0, "ü" =~ %r{\u00FC}i) + + # Flip order of the two operands + assert_equal(0, /Martin D\u00FCrst/ =~ "Martin Dürst") + assert_equal(4, /\u00FC/ =~ "testü") + assert_equal(3, /Martin D\u{FC}rst/ =~ "fooMartin Dürstbar") + assert_equal(3, %r{\u{FC}} =~ "fooübar") + + # Put \u in strings, literal character in regexp + assert_equal(0, "Martin D\u00FCrst" =~ /Martin Dürst/) + assert_equal(4, "test\u00FC" =~ /ü/) + assert_equal(3, "fooMartin D\u{FC}rstbar" =~ /Martin Dürst/) + assert_equal(3, %Q{foo\u{FC}bar} =~ %r<ü>) + + assert_match(eval('/\u{2a}/'), "*") + assert_raise(SyntaxError) { eval('/\u{6666}/n') } + assert_raise(SyntaxError) { eval('/\u{6666}/e') } + assert_raise(SyntaxError) { eval('/\u{6666}/s') } + assert_nothing_raised { eval('/\u{6666}/u') } + end + + def test_dynamic_regexp + assert_match(Regexp.new("Martin D\\u{FC}rst"), "Martin Dürst") + end + + def test_syntax_variants + # all hex digits + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89AB\uCDEF") + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89AB\uCDEF") + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89ab\ucdef") + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89ab\ucdef") + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89aB\uCdEf") + assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89aB\ucDEF") + end + + def test_fulton + # examples from Hal Fulton's book (second edition), chapter 4 + # precomposed e'pe'e + assert_equal('épée', "\u00E9\u0070\u00E9\u0065") + assert_equal('épée', "\u00E9p\u00E9e") + assert_equal("\xC3\xA9\x70\xC3\xA9\x65", "\u00E9\u0070\u00E9\u0065") + assert_equal("\xC3\xA9\x70\xC3\xA9\x65", "\u00E9p\u00E9e") + # decomposed e'pe'e + assert_equal('épée', "\u0065\u0301\u0070\u0065\u0301\u0065") + assert_equal('épée', "e\u0301pe\u0301e") + assert_equal("\x65\xCC\x81\x70\x65\xCC\x81\x65", "\u0065\u0301\u0070\u0065\u0301\u0065") + assert_equal("\x65\xCC\x81\x70\x65\xCC\x81\x65", "e\u0301pe\u0301e") + # combinations of NFC/D, NFKC/D + assert_equal('öffnen', "\u00F6\u0066\u0066\u006E\u0065\u006E") + assert_equal("\xC3\xB6ffnen", "\u00F6\u0066\u0066\u006E\u0065\u006E") + assert_equal('öffnen', "\u00F6ffnen") + assert_equal("\xC3\xB6ffnen", "\u00F6ffnen") + assert_equal('öffnen', "\u006F\u0308\u0066\u0066\u006E\u0065\u006E") + assert_equal("\x6F\xCC\x88ffnen", "\u006F\u0308\u0066\u0066\u006E\u0065\u006E") + assert_equal('öffnen', "o\u0308ffnen") + assert_equal("\x6F\xCC\x88ffnen", "o\u0308ffnen") + assert_equal('öffnen', "\u00F6\uFB00\u006E\u0065\u006E") + assert_equal("\xC3\xB6\xEF\xAC\x80nen", "\u00F6\uFB00\u006E\u0065\u006E") + assert_equal('öffnen', "\u00F6\uFB00nen") + assert_equal("\xC3\xB6\xEF\xAC\x80nen", "\u00F6\uFB00nen") + assert_equal('öffnen', "\u006F\u0308\uFB00\u006E\u0065\u006E") + assert_equal("\x6F\xCC\x88\xEF\xAC\x80nen", "\u006F\u0308\uFB00\u006E\u0065\u006E") + assert_equal('öffnen', "o\u0308\uFB00nen") + assert_equal("\x6F\xCC\x88\xEF\xAC\x80nen", "o\u0308\uFB00nen") + # German sharp s (sz) + assert_equal('Straße', "\u0053\u0074\u0072\u0061\u00DF\u0065") + assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u0053\u0074\u0072\u0061\u00DF\u0065") + assert_equal('Straße', "Stra\u00DFe") + assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "Stra\u00DFe") + assert_equal('Straße', "\u{53}\u{74}\u{72}\u{61}\u{DF}\u{65}") + assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u{53}\u{74}\u{72}\u{61}\u{DF}\u{65}") + assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u{53 74 72 61 DF 65}") + assert_equal('Straße', "Stra\u{DF}e") + assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "Stra\u{DF}e") + end + + def test_edge_cases + # start and end of each outer plane + assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}") + assert_equal("\xF4\x80\x80\x80", "\u{100000}") + assert_equal("\xF3\xBF\xBF\xBF", "\u{FFFFF}") + assert_equal("\xF3\xB0\x80\x80", "\u{F0000}") + assert_equal("\xF3\xAF\xBF\xBF", "\u{EFFFF}") + assert_equal("\xF3\xA0\x80\x80", "\u{E0000}") + assert_equal("\xF3\x9F\xBF\xBF", "\u{DFFFF}") + assert_equal("\xF3\x90\x80\x80", "\u{D0000}") + assert_equal("\xF3\x8F\xBF\xBF", "\u{CFFFF}") + assert_equal("\xF3\x80\x80\x80", "\u{C0000}") + assert_equal("\xF2\xBF\xBF\xBF", "\u{BFFFF}") + assert_equal("\xF2\xB0\x80\x80", "\u{B0000}") + assert_equal("\xF2\xAF\xBF\xBF", "\u{AFFFF}") + assert_equal("\xF2\xA0\x80\x80", "\u{A0000}") + assert_equal("\xF2\x9F\xBF\xBF", "\u{9FFFF}") + assert_equal("\xF2\x90\x80\x80", "\u{90000}") + assert_equal("\xF2\x8F\xBF\xBF", "\u{8FFFF}") + assert_equal("\xF2\x80\x80\x80", "\u{80000}") + assert_equal("\xF1\xBF\xBF\xBF", "\u{7FFFF}") + assert_equal("\xF1\xB0\x80\x80", "\u{70000}") + assert_equal("\xF1\xAF\xBF\xBF", "\u{6FFFF}") + assert_equal("\xF1\xA0\x80\x80", "\u{60000}") + assert_equal("\xF1\x9F\xBF\xBF", "\u{5FFFF}") + assert_equal("\xF1\x90\x80\x80", "\u{50000}") + assert_equal("\xF1\x8F\xBF\xBF", "\u{4FFFF}") + assert_equal("\xF1\x80\x80\x80", "\u{40000}") + assert_equal("\xF0\xBF\xBF\xBF", "\u{3FFFF}") + assert_equal("\xF0\xB0\x80\x80", "\u{30000}") + assert_equal("\xF0\xAF\xBF\xBF", "\u{2FFFF}") + assert_equal("\xF0\xA0\x80\x80", "\u{20000}") + assert_equal("\xF0\x9F\xBF\xBF", "\u{1FFFF}") + assert_equal("\xF0\x90\x80\x80", "\u{10000}") + # BMP + assert_equal("\xEF\xBF\xBF", "\uFFFF") + assert_equal("\xEE\x80\x80", "\uE000") + assert_equal("\xED\x9F\xBF", "\uD7FF") + assert_equal("\xE0\xA0\x80", "\u0800") + assert_equal("\xDF\xBF", "\u07FF") + assert_equal("\xC2\x80", "\u0080") + assert_equal("\x7F", "\u007F") + assert_equal("\x00", "\u0000") + end + + def test_chars + assert_equal(?\u0041, ?A) + assert_equal(?\u{79}, ?\x79) + assert_equal(?\u{0}, ?\000) + assert_equal(?\u0000, ?\000) + end + + # Tests to make sure that disallowed cases fail + def test_fail + assert_raise(SyntaxError) { eval %q("\uabc") } # too short + assert_raise(SyntaxError) { eval %q("\uab") } # too short + assert_raise(SyntaxError) { eval %q("\ua") } # too short + assert_raise(SyntaxError) { eval %q("\u") } # too short + assert_raise(SyntaxError) { eval %q("\u{110000}") } # too high + assert_raise(SyntaxError) { eval %q("\u{abcdeff}") } # too long + assert_raise(SyntaxError) { eval %q("\ughij") } # bad hex digits + assert_raise(SyntaxError) { eval %q("\u{ghij}") } # bad hex digits + + assert_raise(SyntaxError) { eval %q("\u{123 456 }")} # extra space + assert_raise(SyntaxError) { eval %q("\u{ 123 456}")} # extra space + assert_raise(SyntaxError) { eval %q("\u{123 456}")} # extra space + +# The utf-8 encoding object currently does not object to codepoints +# in the surrogate blocks, so these do not raise an error. +# assert_raise(SyntaxError) { "\uD800" } # surrogate block +# assert_raise(SyntaxError) { "\uDCBA" } # surrogate block +# assert_raise(SyntaxError) { "\uDFFF" } # surrogate block +# assert_raise(SyntaxError) { "\uD847\uDD9A" } # surrogate pair + + end +end diff --git a/jni/ruby/test/ruby/test_variable.rb b/jni/ruby/test/ruby/test_variable.rb new file mode 100644 index 0000000..8f5329b --- /dev/null +++ b/jni/ruby/test/ruby/test_variable.rb @@ -0,0 +1,121 @@ +require 'test/unit' + +class TestVariable < Test::Unit::TestCase + class Gods + @@rule = "Uranus" + def ruler0 + @@rule + end + + def self.ruler1 # <= per method definition style + @@rule + end + class << self # <= multiple method definition style + def ruler2 + @@rule + end + end + end + + module Olympians + @@rule ="Zeus" + def ruler3 + @@rule + end + end + + class Titans < Gods + @@rule = "Cronus" # modifies @@rule in Gods + include Olympians + def ruler4 + EnvUtil.suppress_warning { + @@rule + } + end + end + + def test_variable + assert_instance_of(Fixnum, $$) + + # read-only variable + assert_raise(NameError) do + $$ = 5 + end + assert_normal_exit("$*=0; $*", "[ruby-dev:36698]") + + foobar = "foobar" + $_ = foobar + assert_equal(foobar, $_) + + assert_equal("Cronus", Gods.new.ruler0) + assert_equal("Cronus", Gods.ruler1) + assert_equal("Cronus", Gods.ruler2) + assert_equal("Cronus", Titans.ruler1) + assert_equal("Cronus", Titans.ruler2) + atlas = Titans.new + assert_equal("Cronus", atlas.ruler0) + assert_equal("Zeus", atlas.ruler3) + assert_equal("Cronus", atlas.ruler4) + assert_nothing_raised do + class << Gods + defined?(@@rule) && @@rule + end + end + end + + def test_local_variables + lvar = 1 + assert_instance_of(Symbol, local_variables[0], "[ruby-dev:34008]") + lvar + end + + def test_local_variables2 + x = 1 + proc do |y| + assert_equal([:x, :y], local_variables.sort) + end.call + x + end + + def test_local_variables3 + x = 1 + proc do |y| + 1.times do |z| + assert_equal([:x, :y, :z], local_variables.sort) + end + end.call + x + end + + def test_shadowing_local_variables + bug9486 = '[ruby-core:60501] [Bug #9486]' + x = tap {|x| break local_variables} + assert_equal([:x, :bug9486], x) + end + + def test_shadowing_block_local_variables + bug9486 = '[ruby-core:60501] [Bug #9486]' + x = tap {|;x| break local_variables} + assert_equal([:x, :bug9486], x) + end + + def test_global_variable_0 + assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, []) + end + + def test_global_variable_poped + assert_nothing_raised { + EnvUtil.suppress_warning { + eval("$foo; 1") + } + } + end + + def test_constant_poped + assert_nothing_raised { + EnvUtil.suppress_warning { + eval("TestVariable::Gods; 1") + } + } + end +end diff --git a/jni/ruby/test/ruby/test_weakmap.rb b/jni/ruby/test/ruby/test_weakmap.rb new file mode 100644 index 0000000..1279944 --- /dev/null +++ b/jni/ruby/test/ruby/test_weakmap.rb @@ -0,0 +1,133 @@ +require 'test/unit' + +class TestWeakMap < Test::Unit::TestCase + def setup + @wm = ObjectSpace::WeakMap.new + end + + def test_map + x = Object.new + k = "foo" + @wm[k] = x + assert_same(x, @wm[k]) + assert_not_same(x, @wm["FOO".downcase]) + end + + def test_aset_const + x = Object.new + assert_raise(ArgumentError) {@wm[true] = x} + assert_raise(ArgumentError) {@wm[false] = x} + assert_raise(ArgumentError) {@wm[nil] = x} + assert_raise(ArgumentError) {@wm[42] = x} + assert_raise(ArgumentError) {@wm[:foo] = x} + assert_raise(ArgumentError) {@wm[x] = true} + assert_raise(ArgumentError) {@wm[x] = false} + assert_raise(ArgumentError) {@wm[x] = nil} + assert_raise(ArgumentError) {@wm[x] = 42} + assert_raise(ArgumentError) {@wm[x] = :foo} + end + + def test_include? + m = __callee__[/test_(.*)/, 1] + k = "foo" + 1.times do + x = Object.new + @wm[k] = x + assert_send([@wm, m, k]) + assert_not_send([@wm, m, "FOO".downcase]) + x = nil + end + GC.start + assert_not_send([@wm, m, k]) + end + alias test_member? test_include? + alias test_key? test_include? + + def test_inspect + x = Object.new + k = BasicObject.new + @wm[k] = x + assert_match(/\A\#<#{@wm.class.name}:[^:]+:\s\#<BasicObject:[^:]*>\s=>\s\#<Object:[^:]*>>\z/, + @wm.inspect) + end + + def test_each + m = __callee__[/test_(.*)/, 1] + x1 = Object.new + k1 = "foo" + @wm[k1] = x1 + x2 = Object.new + k2 = "bar" + @wm[k2] = x2 + n = 0 + @wm.__send__(m) do |k, v| + assert_match(/\A(?:foo|bar)\z/, k) + case k + when /foo/ + assert_same(k1, k) + assert_same(x1, v) + when /bar/ + assert_same(k2, k) + assert_same(x2, v) + end + n += 1 + end + assert_equal(2, n) + end + + def test_each_key + x1 = Object.new + k1 = "foo" + @wm[k1] = x1 + x2 = Object.new + k2 = "bar" + @wm[k2] = x2 + n = 0 + @wm.each_key do |k| + assert_match(/\A(?:foo|bar)\z/, k) + case k + when /foo/ + assert_same(k1, k) + when /bar/ + assert_same(k2, k) + end + n += 1 + end + assert_equal(2, n) + end + + def test_each_value + x1 = "foo" + k1 = Object.new + @wm[k1] = x1 + x2 = "bar" + k2 = Object.new + @wm[k2] = x2 + n = 0 + @wm.each_value do |v| + assert_match(/\A(?:foo|bar)\z/, v) + case v + when /foo/ + assert_same(x1, v) + when /bar/ + assert_same(x2, v) + end + n += 1 + end + assert_equal(2, n) + end + + def test_size + m = __callee__[/test_(.*)/, 1] + assert_equal(0, @wm.__send__(m)) + x1 = "foo" + k1 = Object.new + @wm[k1] = x1 + assert_equal(1, @wm.__send__(m)) + x2 = "bar" + k2 = Object.new + @wm[k2] = x2 + assert_equal(2, @wm.__send__(m)) + end + alias test_length test_size +end diff --git a/jni/ruby/test/ruby/test_whileuntil.rb b/jni/ruby/test/ruby/test_whileuntil.rb new file mode 100644 index 0000000..3d8dbee --- /dev/null +++ b/jni/ruby/test/ruby/test_whileuntil.rb @@ -0,0 +1,82 @@ +require 'test/unit' +require 'tmpdir' + +class TestWhileuntil < Test::Unit::TestCase + def test_while + Dir.mktmpdir("ruby_while_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_while_tmp.#{$$}" + + tmp = open(tmpfilename, "w") + tmp.print "tvi925\n"; + tmp.print "tvi920\n"; + tmp.print "vt100\n"; + tmp.print "Amiga\n"; + tmp.print "paper\n"; + tmp.close + + tmp = open(tmpfilename, "r") + assert_instance_of(File, tmp) + + while line = tmp.gets() + break if /vt100/ =~ line + end + + assert_not_predicate(tmp, :eof?) + assert_match(/vt100/, line) + tmp.close + + tmp = open(tmpfilename, "r") + while line = tmp.gets() + next if /vt100/ =~ line + assert_no_match(/vt100/, line) + end + assert_predicate(tmp, :eof?) + assert_no_match(/vt100/, line) + tmp.close + + tmp = open(tmpfilename, "r") + while line = tmp.gets() + lastline = line + line = line.gsub(/vt100/, 'VT100') + if lastline != line + line.gsub!('VT100', 'Vt100') + redo + end + assert_no_match(/vt100/, line) + assert_no_match(/VT100/, line) + end + assert_predicate(tmp, :eof?) + tmp.close + + sum=0 + for i in 1..10 + sum += i + i -= 1 + if i > 0 + redo + end + end + assert_equal(220, sum) + + tmp = open(tmpfilename, "r") + while line = tmp.gets() + break if 3 + assert_no_match(/vt100/, line) + assert_no_match(/Amiga/, line) + assert_no_match(/paper/, line) + end + tmp.close + + File.unlink tmpfilename or `/bin/rm -f "#{tmpfilename}"` + assert_file.not_exist?(tmpfilename) + } + end + + def test_until + i = 0 + until i>4 + i+=1 + end + assert_operator(i, :>, 4) + end +end diff --git a/jni/ruby/test/ruby/test_yield.rb b/jni/ruby/test/ruby/test_yield.rb new file mode 100644 index 0000000..82378d4 --- /dev/null +++ b/jni/ruby/test/ruby/test_yield.rb @@ -0,0 +1,393 @@ +require 'test/unit' +require 'stringio' + +class TestRubyYield < Test::Unit::TestCase + + def test_ary_each + ary = [1] + ary.each {|a, b, c, d| assert_equal [1,nil,nil,nil], [a,b,c,d] } + ary.each {|a, b, c| assert_equal [1,nil,nil], [a,b,c] } + ary.each {|a, b| assert_equal [1,nil], [a,b] } + ary.each {|a| assert_equal 1, a } + end + + def test_hash_each + h = {:a => 1} + h.each do |k, v| + assert_equal :a, k + assert_equal 1, v + end + h.each do |kv| + assert_equal [:a, 1], kv + end + end + + def test_yield_0 + assert_equal 1, iter0 { 1 } + assert_equal 2, iter0 { 2 } + end + + def iter0 + yield + end + + def test_yield_1 + iter1([]) {|a, b| assert_equal [nil,nil], [a, b] } + iter1([1]) {|a, b| assert_equal [1,nil], [a, b] } + iter1([1, 2]) {|a, b| assert_equal [1,2], [a,b] } + iter1([1, 2, 3]) {|a, b| assert_equal [1,2], [a,b] } + + iter1([]) {|a| assert_equal [], a } + iter1([1]) {|a| assert_equal [1], a } + iter1([1, 2]) {|a| assert_equal [1,2], a } + iter1([1, 2, 3]) {|a| assert_equal [1,2,3], a } + end + + def iter1(args) + yield args + end + + def test_yield2 + def iter2_1() yield 1, *[2, 3] end + iter2_1 {|a, b, c| assert_equal [1,2,3], [a,b,c] } + def iter2_2() yield 1, *[] end + iter2_2 {|a, b, c| assert_equal [1,nil,nil], [a,b,c] } + def iter2_3() yield 1, *[2] end + iter2_3 {|a, b, c| assert_equal [1,2,nil], [a,b,c] } + end + + def test_yield_nested + [[1, [2, 3]]].each {|a, (b, c)| + assert_equal [1,2,3], [a,b,c] + } + [[1, [2, 3]]].map {|a, (b, c)| + assert_equal [1,2,3], [a,b,c] + } + end + + def test_with_enum + obj = Object.new + def obj.each + yield(*[]) + end + obj.each{|*v| assert_equal([], [], '[ruby-dev:32392]')} + obj.to_enum.each{|*v| assert_equal([], [], '[ruby-dev:32392]')} + end + + def block_args_unleashed + yield(1,2,3,4,5) + end + + def test_block_args_unleashed + r = block_args_unleashed {|a,b=1,*c,d,e| + [a,b,c,d,e] + } + assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]") + end +end + +require_relative 'sentence' +class TestRubyYieldGen < Test::Unit::TestCase + Syntax = { + :exp => [["0"], + ["nil"], + ["false"], + ["[]"], + ["[",:exps,"]"]], + :exps => [[:exp], + [:exp,",",:exps]], + :opt_block_param => [[], + [:block_param_def]], + :block_param_def => [['|', '|'], + ['|', :block_param, '|']], + :block_param => [[:f_arg, ",", :f_rest_arg, :opt_f_block_arg], + [:f_arg, ","], + [:f_arg, ',', :f_rest_arg, ",", :f_arg, :opt_f_block_arg], + [:f_arg, :opt_f_block_arg], + [:f_rest_arg, :opt_f_block_arg], + [:f_rest_arg, ',', :f_arg, :opt_f_block_arg], + [:f_block_arg]], + :f_arg => [[:f_arg_item], + [:f_arg, ',', :f_arg_item]], + :f_rest_arg => [['*', "var"], + ['*']], + :opt_f_block_arg => [[',', :f_block_arg], + []], + :f_block_arg => [['&', 'var']], + :f_arg_item => [[:f_norm_arg], + ['(', :f_margs, ')']], + :f_margs => [[:f_marg_list], + [:f_marg_list, ',', '*', :f_norm_arg], + [:f_marg_list, ',', '*', :f_norm_arg, ',', :f_marg_list], + [:f_marg_list, ',', '*'], + [:f_marg_list, ',', '*', ',', :f_marg_list], + [ '*', :f_norm_arg], + [ '*', :f_norm_arg, ',', :f_marg_list], + [ '*'], + [ '*', ',', :f_marg_list]], + :f_marg_list => [[:f_marg], + [:f_marg_list, ',', :f_marg]], + :f_marg => [[:f_norm_arg], + ['(', :f_margs, ')']], + :f_norm_arg => [['var']], + + :command_args => [[:open_args]], + :open_args => [[' ',:call_args], + ['(', ')'], + ['(', :call_args2, ')']], + :call_args => [[:command], + [ :args, :opt_block_arg], + [ :assocs, :opt_block_arg], + [ :args, ',', :assocs, :opt_block_arg], + [ :block_arg]], + :call_args2 => [[:arg, ',', :args, :opt_block_arg], + [:arg, ',', :block_arg], + [ :assocs, :opt_block_arg], + [:arg, ',', :assocs, :opt_block_arg], + [:arg, ',', :args, ',', :assocs, :opt_block_arg], + [ :block_arg]], + + :command_args_noblock => [[:open_args_noblock]], + :open_args_noblock => [[' ',:call_args_noblock], + ['(', ')'], + ['(', :call_args2_noblock, ')']], + :call_args_noblock => [[:command], + [ :args], + [ :assocs], + [ :args, ',', :assocs]], + :call_args2_noblock => [[:arg, ',', :args], + [ :assocs], + [:arg, ',', :assocs], + [:arg, ',', :args, ',', :assocs]], + + :command => [], + :args => [[:arg], + ["*",:arg], + [:args,",",:arg], + [:args,",","*",:arg]], + :arg => [[:exp]], + :assocs => [[:assoc], + [:assocs, ',', :assoc]], + :assoc => [[:arg, '=>', :arg], + ['label', ':', :arg]], + :opt_block_arg => [[',', :block_arg], + []], + :block_arg => [['&', :arg]], + #:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']] + :test_proc => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']], + :test_lambda => [['def m() yield', :command_args_noblock, ' end; r = m(&lambda {', :block_param_def, 'vars', '}); undef m; r']], + :test_enum => [['o = Object.new; def o.each() yield', :command_args_noblock, ' end; r1 = r2 = nil; o.each {|*x| r1 = x }; o.to_enum.each {|*x| r2 = x }; [r1, r2]']] + } + + def rename_var(obj) + vars = [] + r = obj.subst('var') { + var = "v#{vars.length}" + vars << var + var + } + return r, vars + end + + def split_by_comma(ary) + return [] if ary.empty? + result = [[]] + ary.each {|e| + if e == ',' + result << [] + else + result.last << e + end + } + result + end + + def emu_return_args(*vs) + vs + end + + def emu_eval_args(args) + if args.last == [] + args = args[0...-1] + end + code = "emu_return_args(#{args.map {|a| a.join('') }.join(",")})" + eval code, nil, 'generated_code_in_emu_eval_args' + end + + def emu_bind_single(arg, param, result_binding) + #p [:emu_bind_single, arg, param] + if param.length == 1 && String === param[0] && /\A[a-z0-9]+\z/ =~ param[0] + result_binding[param[0]] = arg + elsif param.length == 1 && Array === param[0] && param[0][0] == '(' && param[0][-1] == ')' + arg = [arg] unless Array === arg + emu_bind_params(arg, split_by_comma(param[0][1...-1]), false, result_binding) + else + raise "unexpected param: #{param.inspect}" + end + result_binding + end + + def emu_bind_params(args, params, islambda, result_binding={}) + #p [:emu_bind_params, args, params] + if params.last == [] # extra comma + params.pop + end + + star_index = nil + params.each_with_index {|par, i| + star_index = i if par[0] == '*' + } + + if islambda + if star_index + if args.length < params.length - 1 + throw :emuerror, ArgumentError + end + else + if args.length != params.length and !(args.length == 1 and Array === args[0] and args[0].length == params.length) + throw :emuerror, ArgumentError + end + end + end + + # TRICK #2 : adjust mismatch on number of arguments + if star_index + pre_params = params[0...star_index] + rest_param = params[star_index] + post_params = params[(star_index+1)..-1] + pre_params.each {|par| emu_bind_single(args.shift, par, result_binding) } + if post_params.length <= args.length + post_params.reverse_each {|par| emu_bind_single(args.pop, par, result_binding) } + else + post_params.each {|par| emu_bind_single(args.shift, par, result_binding) } + end + if rest_param != ['*'] + emu_bind_single(args, rest_param[1..-1], result_binding) + end + else + params.each_with_index {|par, i| + emu_bind_single(args[i], par, result_binding) + } + end + + #p [args, params, result_binding] + + result_binding + end + + def emu_bind(t, islambda) + #puts + #p t + command_args_noblock = t[1] + block_param_def = t[3] + command_args_noblock = command_args_noblock.expand {|a| !(a[0] == '[' && a[-1] == ']') } + block_param_def = block_param_def.expand {|a| !(a[0] == '(' && a[-1] == ')') } + + if command_args_noblock.to_a[0] == ' ' + args = command_args_noblock.to_a[1..-1] + elsif command_args_noblock.to_a[0] == '(' && command_args_noblock.to_a[-1] == ')' + args = command_args_noblock.to_a[1...-1] + else + raise "unexpected command_args_noblock: #{command_args_noblock.inspect}" + end + args = emu_eval_args(split_by_comma(args)) + + params = block_param_def.to_a[1...-1] + params = split_by_comma(params) + + #p [:emu0, args, params] + + result_binding = {} + + if params.last && params.last[0] == '&' + result_binding[params.last[1]] = nil + params.pop + end + + if !islambda + # TRICK #1 : single array argument is expanded if there are two or more params. + # * block parameter is not counted. + # * extra comma after single param forces the expansion. + if args.length == 1 && Array === args[0] && 1 < params.length + args = args[0] + end + end + + emu_bind_params(args, params, islambda, result_binding) + #p result_binding + result_binding + end + + def emu(t, vars, islambda) + catch(:emuerror) { + emu_binding = emu_bind(t, islambda) + vars.map {|var| emu_binding.fetch(var, "NOVAL") } + } + end + + def disable_stderr + begin + save_stderr = $stderr + $stderr = StringIO.new + yield + ensure + $stderr = save_stderr + end + end + + def check_nofork(t, islambda=false) + t, vars = rename_var(t) + t = t.subst('vars') { " [#{vars.join(",")}]" } + emu_values = emu(t, vars, islambda) + s = t.to_s + #print "#{s}\t\t" + #STDOUT.flush + eval_values = disable_stderr { + begin + eval(s, nil, 'generated_code_in_check_nofork') + rescue ArgumentError + ArgumentError + end + } + #success = emu_values == eval_values ? 'succ' : 'fail' + #puts "eval:#{vs_ev.inspect[1...-1].delete(' ')}\temu:#{vs_emu.inspect[1...-1].delete(' ')}\t#{success}" + assert_equal(emu_values, eval_values, s) + end + + def test_yield + syntax = Sentence.expand_syntax(Syntax) + Sentence.each(syntax, :test_proc, 4) {|t| + check_nofork(t) + } + end + + def test_yield_lambda + syntax = Sentence.expand_syntax(Syntax) + Sentence.each(syntax, :test_lambda, 4) {|t| + check_nofork(t, true) + } + end + + def test_yield_enum + syntax = Sentence.expand_syntax(Syntax) + Sentence.each(syntax, :test_enum, 4) {|t| + code = t.to_s + r1, r2 = disable_stderr { + eval(code, nil, 'generated_code_in_test_yield_enum') + } + assert_equal(r1, r2, "#{t}") + } + end + + def test_block_with_mock + y = Object.new + def y.s(a) + yield(a) + end + m = Object.new + def m.method_missing(*a) + super + end + assert_equal [m, nil], y.s(m){|a,b|[a,b]} + end +end diff --git a/jni/ruby/test/ruby/ut_eof.rb b/jni/ruby/test/ruby/ut_eof.rb new file mode 100644 index 0000000..83325f2 --- /dev/null +++ b/jni/ruby/test/ruby/ut_eof.rb @@ -0,0 +1,128 @@ +require 'test/unit' + +module TestEOF + def test_eof_0 + open_file("") {|f| + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("") {|f| + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("") {|f| + s = "x" + assert_equal("", f.read(nil, s)) + assert_equal("", s) + } + open_file("") {|f| + s = "x" + assert_nil(f.read(10, s)) + assert_equal("", s) + } + end + + def test_eof_0_rw + return unless respond_to? :open_file_rw + open_file_rw("") {|f| + assert_equal("", f.read) + assert_equal("", f.read) + assert_equal(0, f.syswrite("")) + assert_equal("", f.read) + } + end + + def test_eof_1 + open_file("a") {|f| + assert_equal("", f.read(0)) + assert_equal("a", f.read(1)) + assert_equal("" , f.read(0)) + assert_equal("" , f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + assert_equal("a", f.read(1)) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + s = "x" + assert_equal("a", f.read(nil, s)) + assert_equal("a", s) + } + open_file("a") {|f| + s = "x" + assert_equal("a", f.read(10, s)) + assert_equal("a", s) + } + end + + def test_eof_2 + open_file("") {|f| + assert_equal("", f.read) + assert_predicate(f, :eof?) + } + end + + def test_eof_3 + open_file("") {|f| + assert_predicate(f, :eof?) + } + end + + module Seek + def open_file_seek(content, pos) + open_file(content) do |f| + f.seek(pos) + yield f + end + end + + def test_eof_0_seek + open_file_seek("", 10) {|f| + assert_equal(10, f.pos) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read) + } + end + + def test_eof_1_seek + open_file_seek("a", 10) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file_seek("a", 1) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + end + end +end |