diff options
Diffstat (limited to 'test/ruby')
118 files changed, 46754 insertions, 997 deletions
diff --git a/test/ruby/allpairs.rb b/test/ruby/allpairs.rb new file mode 100644 index 0000000000..6cb2729b19 --- /dev/null +++ b/test/ruby/allpairs.rb @@ -0,0 +1,103 @@ +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 + prime = make_prime(max_v) + 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/test/ruby/beginmainend.rb b/test/ruby/beginmainend.rb index 646140dd22..6cdfb15ea6 100644 --- a/test/ruby/beginmainend.rb +++ b/test/ruby/beginmainend.rb @@ -16,7 +16,7 @@ BEGIN { } # for scope check -raise if defined?(local_begin1) +#raise if defined?(local_begin1) raise unless defined?($global_begin1) raise unless defined?(::ConstBegin1) local_for_end2 = "e2" diff --git a/test/ruby/enc/test_big5.rb b/test/ruby/enc/test_big5.rb new file mode 100644 index 0000000000..e8fe0270a8 --- /dev/null +++ b/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/test/ruby/enc/test_cp949.rb b/test/ruby/enc/test_cp949.rb new file mode 100644 index 0000000000..e675c7b80c --- /dev/null +++ b/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/test/ruby/enc/test_emoji.rb b/test/ruby/enc/test_emoji.rb new file mode 100644 index 0000000000..90144cffff --- /dev/null +++ b/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 Encoding.name_list.include?(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 Encoding.name_list.include?(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 Encoding.name_list.include?(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/test/ruby/enc/test_euc_jp.rb b/test/ruby/enc/test_euc_jp.rb new file mode 100644 index 0000000000..1ccc55ccb9 --- /dev/null +++ b/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_no_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/test/ruby/enc/test_euc_kr.rb b/test/ruby/enc/test_euc_kr.rb new file mode 100644 index 0000000000..087bc795f7 --- /dev/null +++ b/test/ruby/enc/test_euc_kr.rb @@ -0,0 +1,28 @@ +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 +end diff --git a/test/ruby/enc/test_euc_tw.rb b/test/ruby/enc/test_euc_tw.rb new file mode 100644 index 0000000000..f36d86b088 --- /dev/null +++ b/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/test/ruby/enc/test_gb18030.rb b/test/ruby/enc/test_gb18030.rb new file mode 100644 index 0000000000..f379504d48 --- /dev/null +++ b/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/test/ruby/enc/test_gbk.rb b/test/ruby/enc/test_gbk.rb new file mode 100644 index 0000000000..d6dc5d6d1b --- /dev/null +++ b/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/test/ruby/enc/test_iso_8859.rb b/test/ruby/enc/test_iso_8859.rb new file mode 100644 index 0000000000..64cc7cd76d --- /dev/null +++ b/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/test/ruby/enc/test_koi8.rb b/test/ruby/enc/test_koi8.rb new file mode 100644 index 0000000000..ce2d8925ea --- /dev/null +++ b/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/test/ruby/enc/test_shift_jis.rb b/test/ruby/enc/test_shift_jis.rb new file mode 100644 index 0000000000..54ef67dd44 --- /dev/null +++ b/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_no_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/test/ruby/enc/test_utf16.rb b/test/ruby/enc/test_utf16.rb new file mode 100644 index 0000000000..90a8314067 --- /dev/null +++ b/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_block(full_message) { expected == actual } + 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(s.intern != :aa, "#{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(s.succ.valid_encoding?, "#{encdump s}.succ.valid_encoding?") + + s = "\xdb\xff\xdf\xff".force_encoding("utf-16be") + assert(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(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/test/ruby/enc/test_utf32.rb b/test/ruby/enc/test_utf32.rb new file mode 100644 index 0000000000..3d4a458512 --- /dev/null +++ b/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_block(full_message) { expected == actual } + 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/test/ruby/enc/test_windows_1251.rb b/test/ruby/enc/test_windows_1251.rb new file mode 100644 index 0000000000..6fbf3159a1 --- /dev/null +++ b/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/test/ruby/endblockwarn.rb b/test/ruby/endblockwarn_rb index 7b7f97f597..7b7f97f597 100644 --- a/test/ruby/endblockwarn.rb +++ b/test/ruby/endblockwarn_rb diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb index c481326288..6998842259 100644 --- a/test/ruby/envutil.rb +++ b/test/ruby/envutil.rb @@ -1,5 +1,11 @@ +require "open3" +require "timeout" + module EnvUtil def rubybin + unless ENV["RUBYOPT"] + + end if ruby = ENV["RUBY"] return ruby end @@ -10,19 +16,222 @@ module EnvUtil return File.expand_path(ruby) end if File.exist? rubyexe and File.executable? rubyexe - return File.expand_path(ruby) + return File.expand_path(rubyexe) end ruby = File.join("..", ruby) end - begin - require "rbconfig" - File.join( - Config::CONFIG["bindir"], - Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"] - ) - rescue LoadError + if defined?(RbConfig.ruby) + RbConfig.ruby + else "ruby" end end module_function :rubybin + + LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" + + def invoke_ruby(args, stdin_data="", capture_stdout=false, capture_stderr=false, opt={}) + in_c, in_p = IO.pipe + out_p, out_c = IO.pipe if capture_stdout + err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout + opt = opt.dup + opt[:in] = in_c + opt[:out] = out_c if capture_stdout + opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr + if enc = opt.delete(:encoding) + out_p.set_encoding(enc) if out_p + err_p.set_encoding(enc) if err_p + end + timeout = opt.delete(:timeout) || 10 + c = "C" + child_env = {} + LANG_ENVS.each {|lc| child_env[lc] = c} + if Array === args and Hash === args.first + child_env.update(args.shift) + end + args = [args] if args.kind_of?(String) + pid = spawn(child_env, EnvUtil.rubybin, *args, opt) + in_c.close + out_c.close if capture_stdout + err_c.close if capture_stderr && capture_stderr != :merge_to_stdout + if block_given? + return yield in_p, out_p, err_p, pid + else + th_stdout = Thread.new { out_p.read } if capture_stdout + th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout + in_p.write stdin_data.to_str + in_p.close + if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) + stdout = th_stdout.value if capture_stdout + stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout + else + raise Timeout::Error + end + out_p.close if capture_stdout + err_p.close if capture_stderr && capture_stderr != :merge_to_stdout + Process.wait pid + status = $? + return stdout, stderr, status + end + ensure + [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| + io.close if io && !io.closed? + end + [th_stdout, th_stderr].each do |th| + (th.kill; th.join) if th + end + end + module_function :invoke_ruby + + alias rubyexec invoke_ruby + class << self + alias rubyexec invoke_ruby + end + + def verbose_warning + class << (stderr = "") + alias write << + end + stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true + yield stderr + ensure + stderr, $stderr, $VERBOSE = $stderr, stderr, verbose + return stderr + end + module_function :verbose_warning + + def suppress_warning + verbose, $VERBOSE = $VERBOSE, nil + yield + ensure + $VERBOSE = verbose + end + module_function :suppress_warning + + def under_gc_stress + stress, GC.stress = GC.stress, true + yield + ensure + GC.stress = stress + end + module_function :under_gc_stress +end + +module Test + module Unit + module Assertions + public + def assert_normal_exit(testsrc, message = '', opt = {}) + if opt.include?(:child_env) + opt = opt.dup + child_env = [opt.delete(:child_env)] || [] + else + child_env = [] + end + out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt) + pid = status.pid + faildesc = proc do + signo = status.termsig + signame = Signal.list.invert[signo] + sigdesc = "signal #{signo}" + if signame + sigdesc = "SIG#{signame} (#{sigdesc})" + end + if status.coredump? + sigdesc << " (core dumped)" + end + full_message = '' + if !message.empty? + full_message << message << "\n" + end + full_message << "pid #{pid} killed by #{sigdesc}" + if !out.empty? + out << "\n" if /\n\z/ !~ out + full_message << "\n#{out.gsub(/^/, '| ')}" + end + full_message + end + assert !status.signaled?, faildesc + end + + def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, opt={}) + stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt) + if block_given? + yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }) + else + if test_stdout.is_a?(Regexp) + assert_match(test_stdout, stdout, message) + else + assert_equal(test_stdout, stdout.lines.map {|l| l.chomp }, message) + end + if test_stderr.is_a?(Regexp) + assert_match(test_stderr, stderr, message) + else + assert_equal(test_stderr, stderr.lines.map {|l| l.chomp }, message) + end + status + end + end + + def assert_ruby_status(args, test_stdin="", message=nil, opt={}) + _, _, status = EnvUtil.invoke_ruby(args, test_stdin, false, false, opt) + m = message ? "#{message} (#{status.inspect})" : "ruby exit status is not success: #{status.inspect}" + assert(status.success?, m) + end + + def assert_warn(msg) + stderr = EnvUtil.verbose_warning { yield } + assert(msg === stderr, "warning message #{stderr.inspect} is expected to match #{msg.inspect}") + end + + def assert_no_memory_leak(args, prepare, code, message=nil, opt = {}) + limit = opt.delete(:limit) || 1.5 + token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m" + token_dump = token.dump + token_re = Regexp.quote(token) + envs = args.shift if Array === args and Hash === args.first + args = [ + "--disable=gems", + "-r", File.expand_path("../memory_status", __FILE__), + *args, + "-v", "-", + ] + args.unshift(envs) if envs + cmd = [ + 'END {STDERR.puts '"#{token_dump}"'"FINAL=#{Memory::Status.new.size}"}', + prepare, + 'STDERR.puts('"#{token_dump}"'"START=#{$initial_size = Memory::Status.new.size}")', + code, + ].join("\n") + _, err, status = EnvUtil.invoke_ruby(args, cmd, true, true, opt) + before = err.sub!(/^#{token_re}START=(\d+)\n/, '') && $1.to_i + after = err.sub!(/^#{token_re}FINAL=(\d+)\n/, '') && $1.to_i + assert_equal([true, ""], [status.success?, err], message) + assert_operator(after.fdiv(before), :<, limit, message) + end + + def assert_is_minus_zero(f) + assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0") + end + end + end +end + +begin + require 'rbconfig' +rescue LoadError +else + module RbConfig + @ruby = EnvUtil.rubybin + class << self + undef ruby if method_defined?(:ruby) + attr_reader :ruby + end + dir = File.dirname(ruby) + name = File.basename(ruby, CONFIG['EXEEXT']) + CONFIG['bindir'] = dir + CONFIG['ruby_install_name'] = name + CONFIG['RUBY_INSTALL_NAME'] = name + Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap) + end end diff --git a/test/ruby/lbtest.rb b/test/ruby/lbtest.rb new file mode 100644 index 0000000000..df7872dc76 --- /dev/null +++ b/test/ruby/lbtest.rb @@ -0,0 +1,48 @@ +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) / 10.0) + puts "#{i}: done" + lb.sync + puts "#{i}: cont" + end +end + +lb.sync +puts "#{n-1}: cone" + +puts "exit." diff --git a/test/ruby/marshaltestlib.rb b/test/ruby/marshaltestlib.rb index 891f43b1f7..39471aac64 100644 --- a/test/ruby/marshaltestlib.rb +++ b/test/ruby/marshaltestlib.rb @@ -1,3 +1,4 @@ +# coding: utf-8 module MarshalTestLib # include this module to a Test::Unit::TestCase and definde encode(o) and # decode(s) methods. e.g. @@ -17,7 +18,7 @@ module MarshalTestLib def marshaltest(o1) str = encode(o1) - print str, "\n" if $DEBUG + print str.dump, "\n" if $DEBUG o2 = decode(str) o2 end @@ -29,8 +30,8 @@ module MarshalTestLib iv1 = o1.instance_variables.sort iv2 = o2.instance_variables.sort assert_equal(iv1, iv2) - val1 = iv1.map {|var| o1.instance_eval {eval var}} - val2 = iv1.map {|var| o2.instance_eval {eval var}} + 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) @@ -128,7 +129,7 @@ module MarshalTestLib def test_hash_default_proc h = Hash.new {} - assert_raises(TypeError) { marshaltest(h) } + assert_raise(TypeError) { marshaltest(h) } end def test_hash_ivar @@ -245,6 +246,12 @@ module MarshalTestLib 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 @@ -279,8 +286,8 @@ module MarshalTestLib o = "abc" o.extend(Mod1) str = MyString.new(o, "c") - marshal_equal(str) { |o| - assert(o.instance_eval { @v }).kind_of?(Mod1) + marshal_equal(str) { |v| + assert(v.instance_eval { @v }.kind_of?(Mod1)) } end @@ -290,7 +297,7 @@ module MarshalTestLib class MyStruct def ==(rhs) return true if __id__ == rhs.__id__ - return false unless rhs.is_a?(::Struct) + return false unless rhs.is_a?(::Struct) return false if self.class != rhs.class members.each do |member| return false if self.__send__(member) != rhs.__send__(member) @@ -383,6 +390,11 @@ module MarshalTestLib 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 @@ -413,16 +425,16 @@ module MarshalTestLib def test_singleton o = Object.new def o.m() end - assert_raises(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(o) } o = Object.new c = class << o @v = 1 class C; self; end end - assert_raises(TypeError) { marshaltest(o) } - assert_raises(TypeError) { marshaltest(c) } - assert_raises(TypeError) { marshaltest(ARGF) } - assert_raises(TypeError) { marshaltest(ENV) } + assert_raise(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(c) } + assert_raise(TypeError) { marshaltest(ARGF) } + assert_raise(TypeError) { marshaltest(ENV) } end def test_extend @@ -435,7 +447,7 @@ module MarshalTestLib marshal_equal(o) {|obj| class << obj; ancestors end} o = Object.new o.extend Module.new - assert_raises(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(o) } end def test_extend_string @@ -448,16 +460,16 @@ module MarshalTestLib marshal_equal(o) {|obj| class << obj; ancestors end} o = "" o.extend Module.new - assert_raises(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(o) } end def test_anonymous c = Class.new - assert_raises(TypeError) { marshaltest(c) } + assert_raise(TypeError) { marshaltest(c) } o = c.new - assert_raises(TypeError) { marshaltest(o) } + assert_raise(TypeError) { marshaltest(o) } m = Module.new - assert_raises(TypeError) { marshaltest(m) } + assert_raise(TypeError) { marshaltest(m) } end def test_string_empty @@ -478,7 +490,7 @@ module MarshalTestLib class MyStruct2 def ==(rhs) return true if __id__ == rhs.__id__ - return false unless rhs.is_a?(::Struct) + return false unless rhs.is_a?(::Struct) return false if self.class != rhs.class members.each do |member| return false if self.__send__(member) != rhs.__send__(member) diff --git a/test/ruby/memory_status.rb b/test/ruby/memory_status.rb new file mode 100644 index 0000000000..cd4a62c1c0 --- /dev/null +++ b/test/ruby/memory_status.rb @@ -0,0 +1,96 @@ +module Memory + keys = [] + vals = [] + + case + when File.exist?(procfile = "/proc/self/status") + PROC_FILE = procfile + VM_PAT = /^Vm(\w+):\s+(\d+)/ + def self.read_status + IO.foreach(PROC_FILE, encoding: Encoding::ASCII_8BIT) do |l| + yield($1.downcase.intern, $2.to_i * 1024) if VM_PAT =~ l + end + end + + read_status {|k, v| keys << k; vals << v} + + when /mswin|mingw/ =~ RUBY_PLATFORM + require 'dl/import' + require 'dl/types' + + module Win32 + extend DL::Importer + dlload "kernel32.dll", "psapi.dll" + include DL::Win32Types + if [nil].pack('p').bytesize == 8 + typealias "SIZE_T", "DWORD64" + else + typealias "SIZE_T", "DWORD32" + end + + PROCESS_MEMORY_COUNTERS = struct [ + "DWORD cb", + "DWORD PageFaultCount", + "SIZE_T PeakWorkingSetSize", + "SIZE_T WorkingSetSize", + "SIZE_T QuotaPeakPagedPoolUsage", + "SIZE_T QuotaPagedPoolUsage", + "SIZE_T QuotaPeakNonPagedPoolUsage", + "SIZE_T QuotaNonPagedPoolUsage", + "SIZE_T PagefileUsage", + "SIZE_T PeakPagefileUsage", + ] + + typealias "PPROCESS_MEMORY_COUNTERS", "PROCESS_MEMORY_COUNTERS*" + + extern "HANDLE GetCurrentProcess()", :stdcall + extern "BOOL GetProcessMemoryInfo(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD)", :stdcall + + module_function + def memory_info + size = PROCESS_MEMORY_COUNTERS.size + data = PROCESS_MEMORY_COUNTERS.malloc + data.cb = size + data if GetProcessMemoryInfo(GetCurrentProcess(), data, size) + end + end + + keys << :peak << :size + def self.read_status + if info = Win32.memory_info + yield :peak, info.PeakPagefileUsage + yield :size, info.PagefileUsage + end + end + else + PSCMD = ["ps", "-ovsz=","-orss=", "-p"] + PAT = /^\s*(\d+)\s+(\d+)$/ + + keys << :size << :rss + def self.read_status + if PAT =~ IO.popen(PSCMD + [$$.to_s], "r", err: [:child, :out], &:read) + yield :size, $1.to_i*1024 + yield :rss, $2.to_i*1024 + end + end + end + + Status = Struct.new(*keys) + + class Status + def _update + Memory.read_status do |key, val| + self[key] = val + end + end + end + + class Status + Header = members.map {|k| k.to_s.upcase.rjust(6)}.join('') + Format = "%6d" + + def initialize + _update + end + end +end diff --git a/test/ruby/sentence.rb b/test/ruby/sentence.rb new file mode 100644 index 0000000000..50f42d6885 --- /dev/null +++ b/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/test/ruby/suicide.rb b/test/ruby/suicide.rb deleted file mode 100644 index 2687ed04cd..0000000000 --- a/test/ruby/suicide.rb +++ /dev/null @@ -1,2 +0,0 @@ -STDERR.reopen(STDOUT) -at_exit{Process.kill(:INT, $$)} diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb index 83f897fb00..6320121bce 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -2,39 +2,106 @@ require 'test/unit' class TestAlias < Test::Unit::TestCase class Alias0 - def foo; "foo" end + def foo + "foo" + end end - class Alias1<Alias0 + + class Alias1 < Alias0 alias bar foo - def foo; "foo+" + super end + + def foo + "foo+#{super}" + end end - class Alias2<Alias1 + + class Alias2 < Alias1 alias baz foo undef foo end - class Alias3<Alias2 + + class Alias3 < Alias2 def foo - defined? super + super end + def bar - defined? super + super end + def quux - defined? super + super end end def test_alias x = Alias2.new - assert_equal("foo", x.bar) - assert_equal("foo+foo", x.baz) - - # test_check for cache - assert_equal("foo+foo", x.baz) + 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(!x.foo) - assert(x.bar) - assert(!x.quux) + 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_JVN_83768862 + d = lambda { + $SAFE = 4 + dclass = Class.new(C) + dclass.send(:alias_method, :mm, :m) + dclass.new + }.call + assert_raise(SecurityError) { d.mm } + 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 end diff --git a/test/ruby/test_argf.rb b/test/ruby/test_argf.rb new file mode 100644 index 0000000000..1f824152e0 --- /dev/null +++ b/test/ruby/test_argf.rb @@ -0,0 +1,783 @@ +require 'test/unit' +require 'timeout' +require 'tmpdir' +require 'tempfile' +require_relative 'envutil' + +class TestArgf < Test::Unit::TestCase + def setup + @t1 = Tempfile.new("argf-foo") + @t1.binmode + @t1.puts "1" + @t1.puts "2" + @t1.close + @t2 = Tempfile.new("argf-bar") + @t2.binmode + @t2.puts "3" + @t2.puts "4" + @t2.close + @t3 = Tempfile.new("argf-baz") + @t3.binmode + @t3.puts "5" + @t3.puts "6" + @t3.close + @tmps = [@t1, @t2, @t3] + end + + def teardown + @tmps.each {|t| + bak = t.path + ".bak" + File.unlink bak if File.file? bak + t.close(true) + } + end + + def make_tempfile + t = Tempfile.new("argf-qux") + t.puts "foo" + t.puts "bar" + t.puts "baz" + t.close + @tmps << t + t + end + + 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 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 + 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 + t = make_tempfile + + 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 + t = make_tempfile + + 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 = Tempfile.new("argf-foo") + t1.binmode + t1.puts "foo" + t1.close + t2 = Tempfile.new("argf-bar") + 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_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 + 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_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| + e = assert_raise(Errno::ENOENT) {argf.gets} + assert_match(/- #{Regexp.quote(path)}\z/, e.message) + 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_bytes + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + print Marshal.dump(ARGF.bytes.to_a) + SRC + assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read)) + end + end + + def test_chars + ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + print [Marshal.dump(ARGF.chars.to_a)].pack('m') + SRC + 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('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f| + print Marshal.dump(ARGF.codepoints.to_a) + SRC + assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read)) + end + end +end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index c56f06c3b2..4350e0578f 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1,7 +1,18 @@ require 'test/unit' +require_relative 'envutil' class TestArray < Test::Unit::TestCase - def test_array + def setup + @verbose = $VERBOSE + $VERBOSE = nil + @cls = Array + end + + def teardown + $VERBOSE = @verbose + 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] * ":") @@ -27,29 +38,32 @@ class TestArray < Test::Unit::TestCase assert(x[-1] == 20 && x.pop == 20) end - def test_array_andor + 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 - x = [nil, 1, nil, nil, 5, nil, nil] - x.compact! - assert_equal([1, 5], x) + 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 + def test_uniq_0 x = [1, 1, 4, 2, 5, 4, 5, 1, 2] x.uniq! assert_equal([1, 4, 2, 5], x) + end - # empty? - assert(!x.empty?) - x = [] - assert(x.empty?) + 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 + def test_sort_0 x = ["it", "came", "to", "pass", "that", "..."] x = x.sort.join(" ") assert_equal("... came it pass that to", x) @@ -60,8 +74,8 @@ class TestArray < Test::Unit::TestCase assert_equal([7,5,3,2,1], x) end - def test_split - x = "The Boassert of Mormon" + 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(":")) @@ -70,7 +84,7 @@ class TestArray < Test::Unit::TestCase assert_equal(['a', 'b', 'c', 'd'], x.split(' ')) end - def test_misc + def test_misc_0 assert(defined? "a".chomp) assert_equal(["a", "b", "c"], "abc".scan(/./)) assert_equal([["1a"], ["2b"], ["3c"]], "1a2b3c".scan(/(\d.)/)) @@ -110,7 +124,35 @@ class TestArray < Test::Unit::TestCase assert_equal([1,2,3,5], y) end - def test_find_all + 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"}) @@ -120,7 +162,7 @@ class TestArray < Test::Unit::TestCase assert_equal([3,3], x.find_all{ |obj| obj == 3 }) end - def test_fill + 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)) @@ -142,4 +184,2029 @@ class TestArray < Test::Unit::TestCase 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(@cls[] == @cls[]) + assert(@cls[1] == @cls[1]) + assert(@cls[1, 1, 2, 2] == @cls[1, 1, 2, 2]) + assert(@cls[1.0, 1.0, 2.0, 2.0] == @cls[1, 1, 2, 2]) + end + + def test_VERY_EQUAL # '===' + assert(@cls[] === @cls[]) + assert(@cls[1] === @cls[1]) + assert(@cls[1, 1, 2, 2] === @cls[1, 1, 2, 2]) + assert(@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) + 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 untrust in [ false, true ] + for frozen in [ false, true ] + a = @cls[*(0..99).to_a] + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end + 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) + 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(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(@cls[].empty?) + assert(!@cls[1].empty?) + end + + def test_eql? + assert(@cls[].eql?(@cls[])) + assert(@cls[1].eql?(@cls[1])) + assert(@cls[1, 1, 2, 2].eql?(@cls[1, 1, 2, 2])) + assert(!@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 + a6.untrust + a7 = a6.flatten + assert_equal(true, a7.tainted?) + assert_equal(true, a7.untrusted?) + + 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_equal(@cls[], @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 + respond_to?(:callcc, true) or require '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 + respond_to?(:callcc, true) or require '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 + respond_to?(:callcc, true) or require '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 + respond_to?(:callcc, true) or require '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 + respond_to?(:callcc, true) or require '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 + respond_to?(:callcc, true) or require '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(a1.hash == a2.hash) + assert(a1.hash != a3.hash) + end + + def test_include? + a = @cls[ 'cat', 99, /a/, @cls[ 1, 2, 3] ] + assert(a.include?('cat')) + assert(a.include?(99)) + assert(a.include?(/a/)) + assert(a.include?([1,2,3])) + assert(!a.include?('ca')) + assert(!a.include?([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("1,2", a.join(',')) + + $, = "" + a = @cls[1, 2, 3] + assert_equal("123", a.join) + 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(',')) + + $, = "" + a = @cls[1, 2, 3] + a.taint + a.untrust + s = a.join + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + + 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| + 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 + respond_to?(:callcc, true) or require '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_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_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) + 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) + 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 + 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) + 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]) + 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 } + assert(a.all?{|x| !x.include?(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) + 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(a.all?{|x| !x.include?(0) }) + 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(a.all?{|x| !x.include?(0) }) + 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 + + def test_modify_check + a = [] + a.freeze + assert_raise(RuntimeError) { a.shift } + a = [1, 2] + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + a.shift + end.value + end + 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_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([], a.values_at(7..8)) + 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_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(NoMethodError){ %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_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 + + def test_hash2 + a = [] + a << a + assert_equal([[a]].hash, a.hash) + assert_not_equal([a, a].hash, a.hash) # Implementation dependent + 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 + 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)} + end + + def test_sample + 100.times do + assert([0, 1, 2].include?([2, 1, 0].sample)) + samples = [2, 1, 0].sample(2) + samples.each{|sample| + assert([0, 1, 2].include?(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 + end + + def test_sample_random + ary = (0...10000).to_a + assert_raise(ArgumentError) {ary.sample(1, 2, random: nil)} + gen0 = proc do + 0.5 + end + class << gen0 + alias rand call + end + gen1 = proc do + ary.replace([]) + 0.5 + 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) + 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_nothing_raised do + (0..100).to_a.combination(50) { break } + 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 + a.untrust + s = a.inspect + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + 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 + e = assert_raise(RuntimeError) {a.rotate!} + assert_match(/can't modify frozen/, e.message) + a = [1,2,3] + assert_raise(ArgumentError) { a.rotate!(1, 1) } + end end diff --git a/test/ruby/test_assignment.rb b/test/ruby/test_assignment.rb index 63f37a9d73..e38b20b285 100644 --- a/test/ruby/test_assignment.rb +++ b/test/ruby/test_assignment.rb @@ -29,30 +29,26 @@ class TestAssignment < Test::Unit::TestCase a = [*[1]]; assert_equal([1], a) a = [*[1,2]]; assert_equal([1,2], a) - a = *nil; assert_nil(a) - a = *1; assert_equal(1, a) - a = *[]; assert_nil(a) - a = *[1]; assert_equal(1, a) - a = *[nil]; assert_nil(a) - a = *[[]]; assert_equal([], 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_nil(a) - a = *[*[1]]; assert_equal(1, a) + a = *[*[]]; assert_equal([], a) + a = *[*[1]]; assert_equal([1], a) a = *[*[1,2]]; assert_equal([1,2], a) *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) - - *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) + *a = *[]; assert_equal([], a) *a = *[1]; assert_equal([1], a) *a = *[nil]; assert_equal([nil], a) @@ -73,8 +69,6 @@ class TestAssignment < Test::Unit::TestCase a,b,*c = [*[1]]; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = [*[1,2]]; assert_equal([1,2,[]], [a,b,c]) - 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]) @@ -83,158 +77,144 @@ class TestAssignment < Test::Unit::TestCase 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]) + + 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_yield - def f; yield nil; end; f {|a| assert_nil(a)} - def f; yield 1; end; f {|a| assert_equal(1, a)} - def f; yield []; end; f {|a| assert_equal([], a)} - def f; yield [1]; end; f {|a| assert_equal([1], a)} - def f; yield [nil]; end; f {|a| assert_equal([nil], a)} - def f; yield [[]]; end; f {|a| assert_equal([[]], a)} - def f; yield [*[]]; end; f {|a| assert_equal([], a)} - def f; yield [*[1]]; end; f {|a| assert_equal([1], a)} - def f; yield [*[1,2]]; end; f {|a| assert_equal([1,2], a)} - - def f; yield *nil; end; f {|a| assert_nil(a)} - def f; yield *1; end; f {|a| assert_equal(1, a)} - def f; yield *[1]; end; f {|a| assert_equal(1, a)} - def f; yield *[nil]; end; f {|a| assert_nil(a)} - def f; yield *[[]]; end; f {|a| assert_equal([], a)} - def f; yield *[*[1]]; end; f {|a| assert_equal(1, a)} - - def f; yield; end; f {|*a| assert_equal([], a)} - def f; yield nil; end; f {|*a| assert_equal([nil], a)} - def f; yield 1; end; f {|*a| assert_equal([1], a)} - def f; yield []; end; f {|*a| assert_equal([[]], a)} - def f; yield [1]; end; f {|*a| assert_equal([[1]], a)} - def f; yield [nil]; end; f {|*a| assert_equal([[nil]], a)} - def f; yield [[]]; end; f {|*a| assert_equal([[[]]], a)} - def f; yield [1,2]; end; f {|*a| assert_equal([[1,2]], a)} - def f; yield [*[]]; end; f {|*a| assert_equal([[]], a)} - def f; yield [*[1]]; end; f {|*a| assert_equal([[1]], a)} - def f; yield [*[1,2]]; end; f {|*a| assert_equal([[1,2]], a)} - - def f; yield *nil; end; f {|*a| assert_equal([nil], a)} - def f; yield *1; end; f {|*a| assert_equal([1], a)} - def f; yield *[]; end; f {|*a| assert_equal([], a)} - def f; yield *[1]; end; f {|*a| assert_equal([1], a)} - def f; yield *[nil]; end; f {|*a| assert_equal([nil], a)} - def f; yield *[[]]; end; f {|*a| assert_equal([[]], a)} - def f; yield *[*[]]; end; f {|*a| assert_equal([], a)} - def f; yield *[*[1]]; end; f {|*a| assert_equal([1], a)} - def f; yield *[*[1,2]]; end; f {|*a| assert_equal([1,2], a)} - - def f; yield; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield nil; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield 1; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield []; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield [1]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield [nil]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield [[]]; end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])} - def f; yield [*[]]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield [*[1]]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield [*[1,2]]; end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])} - - def f; yield *nil; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield *1; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield *[]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield *[1]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield *[nil]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield *[[]]; end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])} - def f; yield *[*[]]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} - def f; yield *[*[1]]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} - def f; yield *[*[1,2]]; end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])} + 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) - def r; return nil; end; a = r(); assert_nil(a) - def r; return 1; end; a = r(); assert_equal(1, a) - def r; return []; end; a = r(); assert_equal([], a) - def r; return [1]; end; a = r(); assert_equal([1], a) - def r; return [nil]; end; a = r(); assert_equal([nil], a) - def r; return [[]]; end; a = r(); assert_equal([[]], a) - def r; return [*[]]; end; a = r(); assert_equal([], a) - def r; return [*[1]]; end; a = r(); assert_equal([1], a) - def r; return [*[1,2]]; end; a = r(); assert_equal([1,2], a) - - def r; return *nil; end; a = r(); assert_nil(a) - def r; return *1; end; a = r(); assert_equal(1, a) - def r; return *[]; end; a = r(); assert_nil(a) - def r; return *[1]; end; a = r(); assert_equal(1, a) - def r; return *[nil]; end; a = r(); assert_nil(a) - def r; return *[[]]; end; a = r(); assert_equal([], a) - def r; return *[*[]]; end; a = r(); assert_nil(a) - def r; return *[*[1]]; end; a = r(); assert_equal(1, a) - def r; return *[*[1,2]]; end; a = r(); assert_equal([1,2], a) - - def r; return *nil; end; a = *r(); assert_nil(a) - def r; return *1; end; a = *r(); assert_equal(1, a) - def r; return *[]; end; a = *r(); assert_nil(a) - def r; return *[1]; end; a = *r(); assert_equal(1, a) - def r; return *[nil]; end; a = *r(); assert_nil(a) - def r; return *[[]]; end; a = *r(); assert_nil(a) - def r; return *[*[]]; end; a = *r(); assert_nil(a) - def r; return *[*[1]]; end; a = *r(); assert_equal(1, a) - def r; return *[*[1,2]]; end; a = *r(); assert_equal([1,2], a) - - def r; return; end; *a = r(); assert_equal([nil], a) - def r; return nil; end; *a = r(); assert_equal([nil], a) - def r; return 1; end; *a = r(); assert_equal([1], a) - def r; return []; end; *a = r(); assert_equal([[]], a) - def r; return [1]; end; *a = r(); assert_equal([[1]], a) - def r; return [nil]; end; *a = r(); assert_equal([[nil]], a) - def r; return [[]]; end; *a = r(); assert_equal([[[]]], a) - def r; return [1,2]; end; *a = r(); assert_equal([[1,2]], a) - def r; return [*[]]; end; *a = r(); assert_equal([[]], a) - def r; return [*[1]]; end; *a = r(); assert_equal([[1]], a) - def r; return [*[1,2]]; end; *a = r(); assert_equal([[1,2]], a) - - def r; return *nil; end; *a = r(); assert_equal([nil], a) - def r; return *1; end; *a = r(); assert_equal([1], a) - def r; return *[]; end; *a = r(); assert_equal([nil], a) - def r; return *[1]; end; *a = r(); assert_equal([1], a) - def r; return *[nil]; end; *a = r(); assert_equal([nil], a) - def r; return *[[]]; end; *a = r(); assert_equal([[]], a) - def r; return *[1,2]; end; *a = r(); assert_equal([[1,2]], a) - def r; return *[*[]]; end; *a = r(); assert_equal([nil], a) - def r; return *[*[1]]; end; *a = r(); assert_equal([1], a) - def r; return *[*[1,2]]; end; *a = r(); assert_equal([[1,2]], a) - - def r; return *nil; end; *a = *r(); assert_equal([nil], a) - def r; return *1; end; *a = *r(); assert_equal([1], a) - def r; return *[]; end; *a = *r(); assert_equal([nil], a) - def r; return *[1]; end; *a = *r(); assert_equal([1], a) - def r; return *[nil]; end; *a = *r(); assert_equal([nil], a) - def r; return *[[]]; end; *a = *r(); assert_equal([], a) - def r; return *[1,2]; end; *a = *r(); assert_equal([1,2], a) - def r; return *[*[]]; end; *a = *r(); assert_equal([nil], a) - def r; return *[*[1]]; end; *a = *r(); assert_equal([1], a) - def r; return *[*[1,2]]; end; *a = *r(); assert_equal([1,2], a) - - def r; return; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return 1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return []; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return [1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return [nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return [[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]) - def r; return [1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) - def r; return [*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return [*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return [*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) - - def r; return *nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return *1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return *[]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return *[1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return *[nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return *[[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return *[1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) - def r; return *[*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) - def r; return *[*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) - def r; return *[*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) + 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 @@ -292,48 +272,37 @@ class TestAssignment < Test::Unit::TestCase 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 *nil; end; assert_nil(a) - a = loop do break *1; end; assert_equal(1, a) - a = loop do break *[]; end; assert_nil(a) - a = loop do break *[1]; end; assert_equal(1, a) - a = loop do break *[nil]; end; assert_nil(a) - a = loop do break *[[]]; end; assert_equal([], a) - a = loop do break *[*[]]; 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([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 *nil; end; assert_equal([nil], a) - *a = loop do break *1; end; assert_equal([1], a) - *a = loop do break *[]; end; assert_equal([nil], 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([nil], 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 *nil; end; assert_equal([nil], a) - *a = *loop do break *1; end; assert_equal([1], a) - *a = *loop do break *[]; end; assert_equal([nil], 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,2]; end; assert_equal([1,2], a) - *a = *loop do break *[*[]]; end; assert_equal([nil], a) - *a = *loop do break *[*[1]]; end; assert_equal([1], 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]) @@ -348,12 +317,10 @@ class TestAssignment < Test::Unit::TestCase 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 *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,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]) @@ -373,40 +340,34 @@ class TestAssignment < Test::Unit::TestCase r([1]){next [*[1]]} r([1,2]){next [*[1,2]]} - r(nil){next *nil} - r(1){next *1} - r(nil){next *[]} - r(1){next *[1]} - r(nil){next *[nil]} - r([]){next *[[]]} - r(nil){next *[*[]]} - 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]]} + 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]]} + 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([nil]){next *nil} - r([1]){next *1} - r([nil]){next *[]} - r([1]){next *[1]} - r([nil]){next *[nil]} - r([]){next *[[]]} + r([[]]){next *[[]]} r([1,2]){next *[1,2]} - r([nil]){next *[*[]]} - r([1]){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,nil,[]]){next} @@ -420,40 +381,66 @@ class TestAssignment < Test::Unit::TestCase 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,nil,[]]){next *nil} - r([1,nil,[]]){next *1} - r([nil,nil,[]]){next *[]} - r([1,nil,[]]){next *[1]} - r([nil,nil,[]]){next *[nil]} - r([nil,nil,[]]){next *[[]]} + 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 end - def test_assign2 + def test_massign a = nil assert(defined?(a)) assert_nil(a) # multiple asignment a, b = 1, 2 - assert(a == 1 && b == 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(a == 2 && b == 1) + assert_equal 2, a + assert_equal 1, b - a, = 1,2 - assert_equal(1, a) + 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(a == 1 && b == [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(a == 1 && b == 2 && c == 3 && d == 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) @@ -463,5 +450,246 @@ class TestAssignment < Test::Unit::TestCase *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 end diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb new file mode 100644 index 0000000000..e175e57006 --- /dev/null +++ b/test/ruby/test_autoload.rb @@ -0,0 +1,56 @@ +require 'test/unit' +require_relative 'envutil' + +class TestAutoload < Test::Unit::TestCase + def test_autoload_so + # Continuation is always available, unless excluded intentionally. + assert_in_out_err([], <<-INPUT, [], []) + autoload :Continuation, "continuation" + begin Continuation; 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 +end diff --git a/test/ruby/test_basicinstructions.rb b/test/ruby/test_basicinstructions.rb new file mode 100644 index 0000000000..7e57530d72 --- /dev/null +++ b/test/ruby/test_basicinstructions.rb @@ -0,0 +1,685 @@ +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 + assert_equal prev.object_id, (prev ||= /#{s}/o).object_id if prev + 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 + 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_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/test/ruby/test_beginendblock.rb b/test/ruby/test_beginendblock.rb index ae96eacad3..121d116c35 100644 --- a/test/ruby/test_beginendblock.rb +++ b/test/ruby/test_beginendblock.rb @@ -1,7 +1,7 @@ require 'test/unit' require 'tempfile' -$:.replace([File.dirname(File.expand_path(__FILE__))] | $:) -require 'envutil' +require 'timeout' +require_relative 'envutil' class TestBeginEndBlock < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) @@ -13,21 +13,41 @@ class TestBeginEndBlock < Test::Unit::TestCase def test_beginendblock ruby = EnvUtil.rubybin target = File.join(DIR, 'beginmainend.rb') - io = IO.popen("#{q(ruby)} #{q(target)}") - assert_equal(%w(b1 b2-1 b2 main b3-1 b3 b4 e1 e4 e3 e2 e4-2 e4-1 e1-1 e4-1-1), io.read.split) - io.close + 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) + + input = Tempfile.new(self.class.name) + inputpath = input.path + input.close + 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.open + 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_raises(SyntaxError) do + assert_raise(SyntaxError) do eval("def foo; BEGIN {}; end") end - assert_raises(SyntaxError) do + assert_raise(SyntaxError) do eval('eval("def foo; BEGIN {}; end")') end end + def test_begininclass + assert_raise(SyntaxError) do + eval("class TestBeginEndBlock; BEGIN {}; end") + end + end + def test_endblockwarn ruby = EnvUtil.rubybin # Use Tempfile to create temporary file path. @@ -35,20 +55,20 @@ class TestBeginEndBlock < Test::Unit::TestCase errout = Tempfile.new(self.class.name) launcher << <<EOF +# -*- coding: #{ruby.encoding.name} -*- errout = ARGV.shift STDERR.reopen(File.open(errout, "w")) STDERR.sync = true Dir.chdir(#{q(DIR)}) -cmd = "\\"#{ruby}\\" \\"endblockwarn.rb\\"" -system(cmd) +system("#{ruby}", "endblockwarn_rb") EOF launcher.close launcherpath = launcher.path errout.close erroutpath = errout.path - system("#{q(ruby)} #{q(launcherpath)} #{q(erroutpath)}") + system(ruby, launcherpath, erroutpath) expected = <<EOW -endblockwarn.rb:2: warning: END in method; use at_exit +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)) @@ -56,15 +76,14 @@ EOW end def test_raise_in_at_exit - # [ruby-core:09675] ruby = EnvUtil.rubybin - out = IO.popen("#{q(ruby)} -e 'STDERR.reopen(STDOUT);" \ - "at_exit{raise %[SomethingBad]};" \ - "raise %[SomethingElse]'") {|f| + out = IO.popen([ruby, '-e', 'STDERR.reopen(STDOUT)', + '-e', 'at_exit{raise %[SomethingBad]}', + '-e', 'raise %[SomethingElse]']) {|f| f.read } - assert_match /SomethingBad/, out - assert_match /SomethingElse/, out + assert_match(/SomethingBad/, out, "[ruby-core:9675]") + assert_match(/SomethingElse/, out, "[ruby-core:9675]") end def test_should_propagate_exit_code @@ -76,23 +95,78 @@ EOW def test_should_propagate_signaled ruby = EnvUtil.rubybin - out = IO.popen("#{ruby} #{File.dirname(__FILE__)}/suicide.rb"){|f| - f.read + out = IO.popen( + [ruby, + '-e', 'STDERR.reopen(STDOUT)', + '-e', 'at_exit{Process.kill(:INT, $$); sleep 5 }']) {|f| + timeout(10) { + f.read + } } - assert_match /Interrupt$/, out + 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_begin_and_eval - $test_begin_and_eval = :ok - begin - eval("BEGIN{$test_begin_and_eval = :ng}\n_/a:a") - rescue SyntaxError - x1 = x2 = $test_begin_and_eval - eval("x2 = $test_begin_and_eval") + def test_endblock_raise + ruby = EnvUtil.rubybin + 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| + Thread.new {sleep 5; Process.kill :KILL, f.pid} + f.read + } + assert_match(/e1/, out) + assert_match(/e6/, out) + end + + def test_nested_at_exit + t = Tempfile.new(["test_nested_at_exit_", ".rb"]) + 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]") + t.close + 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 - assert_equal(:ok, x1) - assert_equal(:ok, x2) + 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/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb index e070a9c866..582a7b2366 100644 --- a/test/ruby/test_bignum.rb +++ b/test/ruby/test_bignum.rb @@ -1,6 +1,18 @@ 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 @@ -85,6 +97,421 @@ class TestBignum < Test::Unit::TestCase 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)) + end + + + T_ZERO = (2**32).coerce(0).first + T_ONE = (2**32).coerce(1).first + T_MONE = (2**32).coerce(-1).first + T31 = 2**31 # 2147483648 + T31P = T31 - 1 # 2147483647 + T32 = 2**32 # 4294967296 + T32P = T32 - 1 # 4294967295 + T64 = 2**64 # 18446744073709551616 + T64P = T64 - 1 # 18446744073709551615 + + 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(T31P > 1) + assert(T31P < 2147483648.0) + assert(T31P < T64P) + assert(T64P > T31P) + assert_raise(ArgumentError) { T31P < "foo" } + assert(T64 < (1.0/0.0)) + assert(!(T64 > (1.0/0.0))) + end + + def test_eq + assert(T31P != 1) + assert(T31P == 2147483647.0) + assert(T31P != "foo") + assert(2**77889 != (1.0/0.0), '[ruby-core:31603]') + end + + def test_eql + assert(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_div + assert_equal(T32.to_f, T32 / 1.0) + assert_raise(TypeError) { T32 / "foo" } + assert_equal(0x20000000, 0x40000001.div(2.0), "[ruby-dev:34553]") + 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_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(1024**1024, (1024**1024).quo(1.0)) + assert_equal(1024**1024*2, (1024**1024*2).quo(1)) + inf = 1 / 0.0; nan = inf / inf + + assert((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) + 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 + + 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_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(T31P.size.is_a?(Integer)) + 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 assert_interrupt + time = Time.now + start_flag = false + end_flag = false + thread = Thread.new do + start_flag = true + yield + end_flag = true + end + Thread.pass until start_flag + thread.raise + thread.join rescue nil + time = Time.now - time + assert_equal([true, false], [start_flag, end_flag]) + assert_operator(time, :<, 10) + end + + def test_interrupt + assert_interrupt {(65536 ** 65536).to_s} + end + def test_too_big_to_s if (big = 2**31-1).is_a?(Fixnum) return @@ -92,4 +519,31 @@ class TestBignum < Test::Unit::TestCase e = assert_raise(RangeError) {(1 << big).to_s} assert_match(/too big to convert/, e.message) 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(@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 end diff --git a/test/ruby/test_call.rb b/test/ruby/test_call.rb index da7ee93c73..8f861d96a1 100644 --- a/test/ruby/test_call.rb +++ b/test/ruby/test_call.rb @@ -8,8 +8,8 @@ class TestCall < Test::Unit::TestCase end def test_call - assert_raises(ArgumentError) {aaa()} - assert_raises(ArgumentError) {aaa} + assert_raise(ArgumentError) {aaa()} + assert_raise(ArgumentError) {aaa} assert_equal([1, 100], aaa(1)) assert_equal([1, 2], aaa(1, 2)) diff --git a/test/ruby/test_case.rb b/test/ruby/test_case.rb index 41a22038a0..0067b74e2b 100644 --- a/test/ruby/test_case.rb +++ b/test/ruby/test_case.rb @@ -1,4 +1,5 @@ require 'test/unit' +require_relative 'envutil.rb' class TestCase < Test::Unit::TestCase def test_case @@ -45,5 +46,61 @@ class TestCase < Test::Unit::TestCase 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 end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb new file mode 100644 index 0000000000..3d894da03c --- /dev/null +++ b/test/ruby/test_class.rb @@ -0,0 +1,276 @@ +require 'test/unit' +require_relative 'envutil' + +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_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) + + stderr = EnvUtil.verbose_warning do + Class.new do + def foo; end + alias bar foo + def foo; end + end + end + assert_equal("", stderr) + + stderr = EnvUtil.verbose_warning do + Class.new do + def foo; end + alias bar foo + alias bar foo + end + end + assert_equal("", stderr) + + 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) + + stderr = EnvUtil.verbose_warning do + Class.new do + define_method(:foo) do end + alias bar foo + alias bar foo + end + end + assert_equal("", stderr) + + stderr = EnvUtil.verbose_warning do + Class.new do + def foo; end + undef foo + end + end + assert_equal("", stderr) + 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) { :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 } + 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 + + def test_cannot_reinitialize_class_with_initialize_copy # [ruby-core:50869] + assert_in_out_err([], <<-RUBY, ["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 + RUBY + end +end diff --git a/test/ruby/test_clone.rb b/test/ruby/test_clone.rb index 43c0cffa1d..c5e2469d10 100644 --- a/test/ruby/test_clone.rb +++ b/test/ruby/test_clone.rb @@ -21,7 +21,7 @@ class TestClone < Test::Unit::TestCase assert_equal("test", bar.test) assert_equal("test", foo.test) - assert_raises(NoMethodError) {foo.test2} + assert_raise(NoMethodError) {foo.test2} assert_equal([M003, M002, M001], M003.ancestors) end diff --git a/test/ruby/test_comparable.rb b/test/ruby/test_comparable.rb new file mode 100644 index 0000000000..3526c73add --- /dev/null +++ b/test/ruby/test_comparable.rb @@ -0,0 +1,79 @@ +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; end + assert_equal(false, @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 } + end + + def test_no_cmp + bug9003 = '[ruby-core:57736] [Bug #9003]' + assert_nothing_raised(SystemStackError, bug9003) { + @o <=> @o.dup + } + end +end diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb new file mode 100644 index 0000000000..b2f9e8dff0 --- /dev/null +++ b/test/ruby/test_complex.rb @@ -0,0 +1,1151 @@ +require 'test/unit' + +class ComplexSub < Complex; end + +class Complex_Test < Test::Unit::TestCase + + def setup + @rational = defined?(Rational) + if @rational + @keiju = Rational.instance_variables.include?(:@RCS_ID) + end + seps = [File::SEPARATOR, File::ALT_SEPARATOR].compact.map{|x| Regexp.escape(x)}.join("|") + @unify = $".grep(/(?:^|#{seps})mathn(?:\.(?:rb|so))?/).size != 0 + end + + 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) + + if @unify + assert_instance_of(Fixnum, c) + else + 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) + end + + 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)) + + if @unify + assert_equal(true, c.eql?(0)) + else + assert_equal(false, c.eql?(0)) + end + 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 + unless @unify + assert_equal(true, c.frozen?) + end + 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')) + if @rational && !@keiju + assert_equal(Complex(1,1),Complex('3/3','3/3')) + end + 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) + + if @unify +=begin + assert_equal(true, c.finite?) + assert_equal(false, c.infinite?) + assert_equal(false, c.nan?) + assert_equal(true, c.integer?) + assert_equal(false, c.float?) + assert_equal(true, c.rational?) +=end + assert_equal(true, c.real?) +=begin + assert_equal(false, c.complex?) + assert_equal(true, c.exact?) + assert_equal(false, c.inexact?) +=end + else +=begin + assert_equal(true, c.finite?) + assert_equal(false, c.infinite?) + assert_equal(false, c.nan?) + assert_equal(false, c.integer?) + assert_equal(false, c.float?) + assert_equal(false, c.rational?) +=end + assert_equal(false, c.real?) +=begin + assert_equal(true, c.complex?) + assert_equal(true, c.exact?) + assert_equal(false, c.inexact?) +=end + end + +=begin + assert_equal(0, Complex(0).sign) + assert_equal(1, Complex(2).sign) + assert_equal(-1, Complex(-2).sign) +=end + + 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 + +=begin + assert_equal(0, Complex(0).negate) + assert_equal(-2, Complex(2).negate) + assert_equal(2, Complex(-2).negate) +=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) + + if @rational + assert_equal(Complex(Rational(3,1),Rational(2)), c + Rational(2)) + assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3)) + end + 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) + + if @rational + assert_equal(Complex(Rational(-1,1),Rational(2)), c - Rational(2)) + assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3)) + end + 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) + + if @rational + 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 + + end + + def test_div + c = Complex(1,2) + c2 = Complex(2,3) + + if @rational + assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2) + else + r = c / c2 + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + end + + 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) + + if @rational + assert_equal(Complex(Rational(1,2),1), c / 2) + else + assert_equal(Complex(0.5,1.0), c / 2) + end + assert_equal(Complex(0.5,1.0), c / 2.0) + + if @rational + assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2)) + assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3)) + end + end + + def test_quo + c = Complex(1,2) + c2 = Complex(2,3) + + if @rational + assert_equal(Complex(Rational(8,13),Rational(1,13)), c.quo(c2)) + else + r = c.quo(c2) + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.imag, 0.001) + end + + 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) + + if @rational + assert_equal(Complex(Rational(1,2),1), c.quo(2)) + else + assert_equal(Complex(0.5,1.0), c.quo(2)) + end + assert_equal(Complex(0.5,1.0), c.quo(2.0)) + + if @rational + assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2)) + assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3)) + end + 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) + if @rational && !@keiju + assert_equal(Complex(Rational(-3,25),Rational(-4,25)), c ** -2) + else + r = c ** -2 + assert_in_delta(-0.12, r.real, 0.001) + assert_in_delta(-0.16, r.imag, 0.001) + end + 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) + + if @rational && !@keiju + assert_equal(Complex(-3,4), c ** Rational(2)) +#=begin + assert_equal(Complex(Rational(-3,25),Rational(-4,25)), + c ** Rational(-2)) # why failed? +#=end + + 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 + 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(Complex(1,0) == Complex(1)) + assert(Complex(-1,0) == Complex(-1)) + + assert_equal(false, Complex(2,1) == Complex(1)) + assert_equal(true, Complex(2,1) != Complex(1)) + assert_equal(false, Complex(1) == nil) + assert_equal(false, Complex(1) == '') + + nan = 0.0 / 0 + if nan.nan? && nan != nan + assert_equal(false, Complex(nan, 0) == Complex(nan, 0)) + assert_equal(false, Complex(0, nan) == Complex(0, nan)) + assert_equal(false, 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_unify + if @unify + assert_instance_of(Fixnum, Complex(1,2) + Complex(-1,-2)) + assert_instance_of(Fixnum, Complex(1,2) - Complex(1,2)) + assert_instance_of(Fixnum, Complex(1,2) * 0) + assert_instance_of(Fixnum, Complex(1,2) / Complex(1,2)) +# assert_instance_of(Fixnum, Complex(1,2).div(Complex(1,2))) + assert_instance_of(Fixnum, Complex(1,2).quo(Complex(1,2))) +# assert_instance_of(Fixnum, Complex(1,2) ** 0) # mathn's bug + 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) +# assert_equal(5, c * ~c) + + 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) + + if @rational && !@unify && !@keiju + 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) + end + + 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) + + if @rational + 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) + end + + bug3656 = '[ruby-core:31622]' + assert_raise(TypeError, bug3656) { + Complex(1,2).marshal_load(0) + } + 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')} + + if @rational && defined?(''.to_r) + 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 + + 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 + if @rational && !@keiju + 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 + 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]) + + if @rational + c = Rational(1,2).to_c + assert_equal([Rational(1,2), 0], [c.real, c.imag]) + end + + 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(nan.arg.equal?(nan)) + assert(nan.angle.equal?(nan)) + assert(nan.phase.equal?(nan)) + 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) + + if @rational + assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) + else + assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) + end + +=begin + if @rational && !@keiju + assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) + end +=end + + assert_equal(0.5, 1.fdiv(2)) + assert_equal(5000000000.0, 10000000000.fdiv(2)) + assert_equal(0.5, 1.0.fdiv(2)) + if @rational + assert_equal(0.25, Rational(1,2).fdiv(2)) + end + assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) + + unless $".grep(/(\A|\/)complex/).empty? + assert_equal(Complex(0,2), Math.sqrt(-4.0)) +# assert_equal(true, Math.sqrt(-4.0).inexact?) + assert_equal(Complex(0,2), Math.sqrt(-4)) +# assert_equal(true, Math.sqrt(-4).exact?) + if @rational + assert_equal(Complex(0,2), Math.sqrt(Rational(-4))) +# assert_equal(true, Math.sqrt(Rational(-4)).exact?) + end + + assert_equal(Complex(0,3), Math.sqrt(-9.0)) +# assert_equal(true, Math.sqrt(-9.0).inexact?) + assert_equal(Complex(0,3), Math.sqrt(-9)) +# assert_equal(true, Math.sqrt(-9).exact?) + if @rational + assert_equal(Complex(0,3), Math.sqrt(Rational(-9))) +# assert_equal(true, Math.sqrt(Rational(-9)).exact?) + end + + c = Math.sqrt(Complex(1, 2)) + assert_in_delta(1.272, c.real, 0.001) + assert_in_delta(0.786, c.imag, 0.001) + + c = Math.sqrt(-9) + assert_in_delta(0.0, c.real, 0.001) + assert_in_delta(3.0, c.imag, 0.001) + + c = Math.exp(Complex(1, 2)) + assert_in_delta(-1.131, c.real, 0.001) + assert_in_delta(2.471, c.imag, 0.001) + + c = Math.sin(Complex(1, 2)) + assert_in_delta(3.165, c.real, 0.001) + assert_in_delta(1.959, c.imag, 0.001) + + c = Math.cos(Complex(1, 2)) + assert_in_delta(2.032, c.real, 0.001) + assert_in_delta(-3.051, c.imag, 0.001) + + c = Math.tan(Complex(1, 2)) + assert_in_delta(0.033, c.real, 0.001) + assert_in_delta(1.014, c.imag, 0.001) + + c = Math.sinh(Complex(1, 2)) + assert_in_delta(-0.489, c.real, 0.001) + assert_in_delta(1.403, c.imag, 0.001) + + c = Math.cosh(Complex(1, 2)) + assert_in_delta(-0.642, c.real, 0.001) + assert_in_delta(1.068, c.imag, 0.001) + + c = Math.tanh(Complex(1, 2)) + assert_in_delta(1.166, c.real, 0.001) + assert_in_delta(-0.243, c.imag, 0.001) + + c = Math.log(Complex(1, 2)) + assert_in_delta(0.804, c.real, 0.001) + assert_in_delta(1.107, c.imag, 0.001) + + c = Math.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 = Math.log(-1) + assert_in_delta(0.0, c.real, 0.001) + assert_in_delta(Math::PI, c.imag, 0.001) + + c = Math.log(8, 2) + assert_in_delta(3.0, c.real, 0.001) + assert_in_delta(0.0, c.imag, 0.001) + + c = Math.log(-8, -2) + assert_in_delta(1.092, c.real, 0.001) + assert_in_delta(-0.420, c.imag, 0.001) + + c = Math.log10(Complex(1, 2)) + assert_in_delta(0.349, c.real, 0.001) + assert_in_delta(0.480, c.imag, 0.001) + + c = Math.asin(Complex(1, 2)) + assert_in_delta(0.427, c.real, 0.001) + assert_in_delta(1.528, c.imag, 0.001) + + c = Math.acos(Complex(1, 2)) + assert_in_delta(1.143, c.real, 0.001) + assert_in_delta(-1.528, c.imag, 0.001) + + c = Math.atan(Complex(1, 2)) + assert_in_delta(1.338, c.real, 0.001) + assert_in_delta(0.402, c.imag, 0.001) + + c = Math.atan2(Complex(1, 2), 1) + assert_in_delta(1.338, c.real, 0.001) + assert_in_delta(0.402, c.imag, 0.001) + + c = Math.asinh(Complex(1, 2)) + assert_in_delta(1.469, c.real, 0.001) + assert_in_delta(1.063, c.imag, 0.001) + + c = Math.acosh(Complex(1, 2)) + assert_in_delta(1.528, c.real, 0.001) + assert_in_delta(1.143, c.imag, 0.001) + + c = Math.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 + if @rational && !@keiju + assert_equal(Complex(1), 1 ** Complex(1)) + end + 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) + end + + def test_known_bug + end + +end diff --git a/test/ruby/test_complex2.rb b/test/ruby/test_complex2.rb new file mode 100644 index 0000000000..3ee7810dc6 --- /dev/null +++ b/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/test/ruby/test_complexrational.rb b/test/ruby/test_complexrational.rb new file mode 100644 index 0000000000..99f54e4e97 --- /dev/null +++ b/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(Rational(2,3) == SimpleRat(2,3)) + assert(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(Complex(SimpleRat(2,3),SimpleRat(3,2)) == + Complex(Rational(2,3),Rational(3,2))) + assert(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/test/ruby/test_const.rb b/test/ruby/test_const.rb index 8d01379dbd..3708a5a0ca 100644 --- a/test/ruby/test_const.rb +++ b/test/ruby/test_const.rb @@ -15,19 +15,34 @@ class TestConst < Test::Unit::TestCase 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_equal([1,2,3,4], [TEST1,TEST2,TEST3,TEST4]) + 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_equal([1,2,6,8], [TEST1,TEST2,TEST3,TEST4]) - - assert_equal(-1, (String <=> Object)) - assert_equal(1, (Object <=> String)) - assert_equal(nil, (Array <=> String)) + 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 end diff --git a/test/ruby/test_continuation.rb b/test/ruby/test_continuation.rb new file mode 100644 index 0000000000..64390d8177 --- /dev/null +++ b/test/ruby/test_continuation.rb @@ -0,0 +1,124 @@ +require 'test/unit' +require 'continuation' +require 'fiber' +require_relative 'envutil' + +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 + cont = nil + func = lambda do |*args| + @memo += 1 + cont.call(nil) + 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| + @memo += 1 + cont.call(nil) + 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/test/ruby/test_defined.rb b/test/ruby/test_defined.rb index 8a7fcf45a9..2552626b9e 100644 --- a/test/ruby/test_defined.rb +++ b/test/ruby/test_defined.rb @@ -10,6 +10,12 @@ class TestDefined < Test::Unit::TestCase 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 @@ -30,14 +36,104 @@ class TestDefined < Test::Unit::TestCase 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)) + 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 + 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) + 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 end diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 09685bee8f..b688cc4dd0 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -2,28 +2,31 @@ require 'test/unit' require 'tmpdir' require 'fileutils' +require 'pathname' class TestDir < Test::Unit::TestCase - ROOT = File.join(Dir.tmpdir, "__test_dir__#{$$}") - def setup - Dir.mkdir(ROOT) + @verbose = $VERBOSE + $VERBOSE = nil + @root = Pathname.new(Dir.mktmpdir('__test_dir__')).realpath.to_s + @nodir = File.join(@root, "dummy") for i in ?a..?z - if i % 2 == 0 - FileUtils.touch(File.join(ROOT, i.chr)) + if i.ord % 2 == 0 + FileUtils.touch(File.join(@root, i)) else - FileUtils.mkdir(File.join(ROOT, i.chr)) + FileUtils.mkdir(File.join(@root, i)) end end end def teardown - FileUtils.rm_rf ROOT if File.directory?(ROOT) + $VERBOSE = @verbose + FileUtils.remove_entry_secure @root if File.directory?(@root) end def test_seek - dir = Dir.open(ROOT) + dir = Dir.open(@root) begin cache = [] loop do @@ -31,12 +34,195 @@ class TestDir < Test::Unit::TestCase break unless name = dir.read cache << [pos, name] end - for x in cache.sort_by {|x| x[0] % 3 } # shuffle - dir.seek(x[0]) - assert_equal(x[1], dir.read) + 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_JVN_13947696 + b = lambda { + d = Dir.open('.') + $SAFE = 4 + d.close + } + assert_raise(SecurityError) { b.call } + 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) + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + d.rewind + end.join + end + 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) + + 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) + + 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_recursive + bug6977 = '[ruby-core:47418]' + Dir.chdir(@root) do + 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) + 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_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 + end diff --git a/test/ruby/test_dir_m17n.rb b/test/ruby/test_dir_m17n.rb new file mode 100644 index 0000000000..2cf1c15441 --- /dev/null +++ b/test/ruby/test_dir_m17n.rb @@ -0,0 +1,265 @@ +require 'test/unit' +require 'tmpdir' +require_relative 'envutil' + +class TestDir_M17N < Test::Unit::TestCase + def with_tmpdir + Dir.mktmpdir {|dir| + Dir.chdir(dir) { + yield dir + } + } + end + + def create_and_check_raw_file_name(code, encoding) + with_tmpdir { |dir| + create_file_program = %Q[ + 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) + exit ents.include?(filename) + ] + assert_ruby_status(["-E#{encoding}"], create_file_program, nil, :chdir=>dir) + + test_file_program = %Q[ + 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") + result = ents.include?(filename) || (/mswin|mingw/ =~ RUBY_PLATFORM && ents.include?(expected_filename)) + if !result && /mswin|mingw/ =~ RUBY_PLATFORM + exit Dir.entries(".", {:encoding => Encoding.find("filesystem")}).include?(expected_filename) + end + exit result + ] + assert_ruby_status(%w[-EASCII-8BIT], test_file_program, nil, :chdir=>dir) + } + end + + ## UTF-8 default_external, no default_internal + + def test_filename_extutf8 + with_tmpdir {|d| + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d) + filename = "\u3042" + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + exit ents.include?(filename) + EOS + } + end + + def test_filename_extutf8_invalid + with_tmpdir {|d| + assert_ruby_status(%w[-EASCII-8BIT], <<-'EOS', nil, :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) + exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%FF")) + EOS + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :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) + exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%FF")) + EOS + } + end unless /mswin|mingw/ =~ RUBY_PLATFORM + + def test_filename_as_bytes_extutf8 + with_tmpdir {|d| + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :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) + exit ents.include?(filename) + EOS + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d) + if /mswin|mingw/ =~ RUBY_PLATFORM + filename = "\x8f\xa2\xc2".force_encoding("euc-jp") + else + filename = "\xc2\xa1".force_encoding("euc-jp") + end + begin + open(filename) {} + exit true + rescue Errno::ENOENT + exit false + end + EOS + # no meaning test on windows + unless /mswin|mingw/ =~ RUBY_PLATFORM + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :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") + s1 = File.stat(filename1) rescue nil + s2 = File.stat(filename2) rescue nil + s3 = File.stat(filename3) rescue nil + s4 = File.stat(filename4) rescue nil + exit((s1 && s2 && !s3 && !s4) ? true : false) + EOS + end + } + end + + ## UTF-8 default_external, EUC-JP default_internal + + def test_filename_extutf8_inteucjp_representable + with_tmpdir {|d| + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d) + filename = "\u3042" + File.open(filename, "w") {} + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + exit ents.include?(filename) + EOS + assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + exit ents.include?(filename) + EOS + assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d) + filename = "\xA4\xA2".force_encoding("euc-jp") + begin + open(filename) {} + exit true + rescue Errno::ENOENT + exit false + end + EOS + } + end + + def test_filename_extutf8_inteucjp_unrepresentable + with_tmpdir {|d| + assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :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) + exit ents.include?(filename1) && ents.include?(filename2) + EOS + assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :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) + exit ents.include?(filename1) && ents.include?(filename2) + EOS + assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :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 + s1 = File.stat(filename1) rescue nil + s2 = File.stat(filename2) rescue nil + s3 = File.stat(filename3) rescue nil + exit((s1 && s2 && s3) ? true : false) + EOS + } + end + + ## others + + def test_filename_bytes_euc_jp + with_tmpdir {|d| + assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :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") } + exit ents.include?(filename.force_encoding("ASCII-8BIT")) || + (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("ASCII-8BIT"))) + EOS + } + end + + def test_filename_euc_jp + with_tmpdir {|d| + assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :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) + exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("euc-jp"))) + EOS + assert_ruby_status(%w[-EASCII-8BIT], <<-'EOS', nil, :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) + result = ents.include?(filename) || + (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("ASCII-8BIT"))) || + (/mswin|mingw/ =~ RUBY_PLATFORM && ents.include?(win_expected_filename.force_encoding("ASCII-8BIT"))) + if !result && /mswin|mingw/ =~ RUBY_PLATFORM + exit Dir.entries(".", {:encoding => Encoding.find("filesystem")}).include?(win_expected_filename) + end + exit result + EOS + } + end + + def test_filename_utf8_raw_jp_name + create_and_check_raw_file_name(0x3042, "UTF-8") + end + + def test_filename_utf8_raw_windows_1251_name + create_and_check_raw_file_name(0x0424, "UTF-8") + end + + def test_filename_utf8_raw_windows_1252_name + create_and_check_raw_file_name(0x00c6, "UTF-8") + end + + def test_filename_ext_euc_jp_and_int_utf_8 + with_tmpdir {|d| + assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :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) + exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("euc-jp"))) + EOS + assert_ruby_status(%w[-EEUC-JP:UTF-8], <<-'EOS', nil, :chdir=>d) + filename = "\u3042" + opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM + ents = Dir.entries(".", opts) + exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2")) + 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 +end diff --git a/test/ruby/test_econv.rb b/test/ruby/test_econv.rb new file mode 100644 index 0000000000..f667d733a0 --- /dev/null +++ b/test/ruby/test_econv.rb @@ -0,0 +1,931 @@ +require 'test/unit' +require 'envutil' + +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~~\(B".force_encoding("iso-2022-jp") + str2 = str.encode(acenc) + str3 = str.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(!encoding_list.include?(name1)) + assert(!encoding_list.include?(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, dst="", 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(src="\xff", dst="", 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(src="\xff", dst="", 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(src="\xa4\xa2", dst="", 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(src="\xa4", dst="", 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(src="\xa4", dst="", 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@", dst="", 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", dst="", 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(src="\x00\xd8\x21\x00", dst="", 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(src="fo\x81", dst="", 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(src="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(src="\u{3042}", dst="") + 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(src="\u{3042}", dst="") + 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) + end + + def test_default_external + cmd = <<EOS + Encoding.default_external = ext = ARGV[0] + Encoding.default_internal = int ='utf-8' + begin + Encoding::Converter.new(ext, int) + ensure + Marshal.dump($!, STDOUT) + STDOUT.flush + end +EOS + Encoding.list.grep(->(enc) {/^ISO-8859-\d(?:[0-5])?\z/i =~ enc.name}) do |enc| + error = IO.popen([EnvUtil.rubybin, "-e", cmd, enc.name]) do |child| + Marshal.load(child) + end + assert_nil(error) + end + end +end diff --git a/test/ruby/test_encoding.rb b/test/ruby/test_encoding.rb new file mode 100644 index 0000000000..ef2dc39c4d --- /dev/null +++ b/test/ruby/test_encoding.rb @@ -0,0 +1,116 @@ +require 'test/unit' +require_relative 'envutil' + +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(e.names.include?(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(Encoding.name_list.include?(k)) + assert(Encoding.name_list.include?(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_unsafe + bug5279 = '[ruby-dev:44469]' + assert_ruby_status([], '$SAFE=4; "a".encode("utf-16be")', bug5279) + 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)) + end +end diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb new file mode 100644 index 0000000000..d5353f680c --- /dev/null +++ b/test/ruby/test_enum.rb @@ -0,0 +1,388 @@ +require 'test/unit' +require 'continuation' + +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 + end + end + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + 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) + 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 }) + 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 }) + end + + def test_reject + assert_equal([2, 3, 2], @obj.reject {|x| x < 2 }) + end + + def test_to_a + assert_equal([1, 2, 3, 1, 2], @obj.to_a) + 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 }) + end + + def test_partition + assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 }) + end + + def test_group_by + h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] } + assert_equal(h, @obj.group_by {|x| x }) + end + + def test_first + assert_equal(1, @obj.first) + assert_equal([1, 2, 3], @obj.first(3)) + 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 }) + 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 }) + 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) + end + + def test_max + assert_equal(3, @obj.max) + assert_equal(1, @obj.max {|a,b| b <=> a }) + 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 }) + 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 }) + a = %w(albatross dog horse) + assert_equal("dog", a.min_by {|x| x.length }) + assert_equal(3, [2,3,1].min_by {|x| -x }) + end + + def test_max_by + assert_equal(1, @obj.max_by {|x| -x }) + a = %w(albatross dog horse) + assert_equal("albatross", a.max_by {|x| x.length }) + assert_equal(1, [2,3,1].max_by {|x| -x }) + end + + def test_minmax_by + assert_equal([3, 1], @obj.minmax_by {|x| -x }) + 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) + 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 = [] + @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(NoMethodError){ %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}) + 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}) + end + + def test_cycle + assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10)) + 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) + end + +end diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb new file mode 100644 index 0000000000..feaa2de698 --- /dev/null +++ b/test/ruby/test_enumerator.rb @@ -0,0 +1,408 @@ +require 'test/unit' +require_relative "envutil" + +class TestEnumerator < Test::Unit::TestCase + def setup + @obj = Object.new + class << @obj + include Enumerable + def foo(*a) + a.each {|x| yield x } + end + end + end + + def enum_test obj + i = 0 + 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}) + 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) + assert_equal([1, 2, 3], Enumerator.new(@obj, :foo, 1, 2, 3).to_a) + assert_equal([1, 2, 3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)) + assert_raise(ArgumentError) { Enumerator.new } + 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_in_out_err([], <<-"end;", ["Enumerator", "[false, [1]]"], [], bug9178) + bug = "#{bug9178}" + e = [1].to_enum(:chunk).with_index {|c,i| i == 5} + puts e.class + p e.to_a[0] + 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_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| x = 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_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) + 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 +end + diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index 3a65f91fa4..9166f4df6c 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -1,16 +1,21 @@ require 'test/unit' class TestEnv < Test::Unit::TestCase - IGNORE_CASE = /djgpp|bccwin|mswin|mingw/ =~ RUBY_PLATFORM + IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM + PATH_ENV = "PATH" def setup - @backup = ENV.delete('test') - @BACKUP = ENV.delete('TEST') + @verbose = $VERBOSE + $VERBOSE = nil + @backup = ENV.to_hash + ENV.delete('test') + ENV.delete('TEST') end def teardown - ENV['test'] = @backup if @backup - ENV['TEST'] = @BACKUP if @BACKUP + $VERBOSE = @verbose + ENV.clear + @backup.each {|k, v| ENV[k] = v } end def test_bracket @@ -31,20 +36,20 @@ class TestEnv < Test::Unit::TestCase assert_equal('foo', ENV['test']) end - assert_raises(TypeError) { + assert_raise(TypeError) { tmp = ENV[1] } - assert_raises(TypeError) { + assert_raise(TypeError) { ENV[1] = 'foo' } - assert_raises(TypeError) { + 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) + val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) ENV['test'] = val[0...-1] assert_equal(false, ENV.has_value?(val)) @@ -57,26 +62,345 @@ class TestEnv < Test::Unit::TestCase assert_equal(true, ENV.has_value?(val.upcase)) end - def test_index + def test_key val = 'a' - val.succ! while ENV.has_value?(val) && ENV.has_value?(val.upcase) + 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.index(val.upcase)) + assert_nil(ENV.key(val.upcase)) ENV['test'] = val if IGNORE_CASE - assert_equal('TEST', ENV.index(val).upcase) + assert_equal('TEST', ENV.key(val).upcase) else - assert_equal('test', ENV.index(val)) + assert_equal('test', ENV.key(val)) end - assert_nil(ENV.index(val.upcase)) + assert_nil(ENV.key(val.upcase)) ENV['test'] = val.upcase - assert_nil(ENV.index(val)) + 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") + assert_raise(KeyError) { ENV.fetch("test") } + 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_raise(SecurityError) do + Thread.new do + $SAFE = 4 + ENV["test"] = "foo" + end.join + end + 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 = nil + assert_block { 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 = nil + assert_block { 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 - assert_equal('TEST', ENV.index(val.upcase).upcase) + s = s.upcase + assert(s == '{"FOO"=>"BAR", "BAZ"=>"QUX"}' || s == '{"BAZ"=>"QUX", "FOO"=>"BAR"}') else - assert_equal('test', ENV.index(val.upcase)) + 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(ENV.empty?) + ENV["test"] = "foo" + assert(!ENV.empty?) + end + + def test_has_key + assert(!ENV.has_key?("test")) + ENV["test"] = "foo" + assert(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(!ENV.has_value?("foo")) + ENV["test"] = "foo" + assert(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_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 + len = 32767 - ENV.to_a.flatten.inject(0) {|r,e| r + e.size + 2 } + val = "bar" * 1000 + key = nil + 1.upto(12) {|i| + ENV[key] = val while (len -= val.size + (key="foo#{len}").size + 2) > 0 + assert_raise(Errno::EINVAL) { ENV[key] = val } + } end end end diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb index 6b3fea7bb4..299165fb34 100644 --- a/test/ruby/test_eval.rb +++ b/test/ruby/test_eval.rb @@ -1,7 +1,213 @@ require 'test/unit' +require_relative 'envutil' class TestEval < Test::Unit::TestCase - # eval with binding + + @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(mid) + objects = [Object.new, [], nil, true, false, 77, :sym] # TODO: check + objects.each do |obj| + obj.instance_variable_set :@ivar, 12 + send mid, obj + end + end + + def test_instance_eval_string_basic + forall_TYPE :instance_eval_string_basic_i + end + + def instance_eval_string_basic_i(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") + 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") + assert_equal 13, o.instance_eval("@@cvar") + assert_equal 14, o.instance_eval("$gvar__eval") + assert_equal 15, o.instance_eval("Const") + } + end + + def test_instance_eval_block_basic + forall_TYPE :instance_eval_block_basic_i + end + + def instance_eval_block_basic_i(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 } + 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 } + assert_equal 13, o.instance_eval { @@cvar } + assert_equal 14, o.instance_eval { $gvar__eval } + assert_equal 15, o.instance_eval { Const } + } + 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 + + # + # From ruby/test/ruby/test_eval.rb + # + def test_ev local1 = "local1" lambda { @@ -10,7 +216,7 @@ class TestEval < Test::Unit::TestCase }.call end - def test_eval + def test_eval_orig assert_nil(eval("")) $bad=false eval 'while false; $bad = true; print "foo\n" end' @@ -66,16 +272,19 @@ class TestEval < Test::Unit::TestCase end assert(!$bad) - 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)) - $x = [] - x = proc{proc{}}.call - eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x - assert_equal(8, $x[4].call) + 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)) + $x = [] + x = proc{proc{}}.call + eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x + assert_equal(8, $x[4].call) + end x = binding eval "i = 1", x @@ -98,55 +307,62 @@ class TestEval < Test::Unit::TestCase 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("foo11"), eval("foo11", p)) + # assert_equal(1, eval("foo11")) assert_equal(eval("foo22"), eval("foo22", p)) assert_equal(55, eval("foo22")) }.call - p1 = proc{i7 = 0; proc{i7}}.call - assert_equal(0, p1.call) - eval "i7=5", p1 - assert_equal(5, p1.call) - assert(!defined?(i7)) + 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 - 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) + 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 # [ruby-dev:24103] + def test_nil_instance_eval_cvar def nil.test_binding binding end bb = eval("nil.instance_eval \"binding\"", nil.test_binding) - assert_raise(NameError) { eval("@@a", bb) } + assert_raise(NameError, "[ruby-dev:24103]") { eval("@@a", bb) } class << nil remove_method :test_binding end end - def test_fixnum_instance_eval_cvar # [ruby-dev:24213] - assert_raise(NameError) { 1.instance_eval "@@a" } + def test_fixnum_instance_eval_cvar + assert_raise(NameError, "[ruby-dev:24213]") { 1.instance_eval "@@a" } end - def test_cvar_scope_with_instance_eval # [ruby-dev:24223] + 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")) + 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 # [ruby-dev:24228] - assert_nothing_raised { + 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) + class << Object.new; self end.send(:define_method, :zzz, &block) } end v = eval("temporally_method_for_test_eval_and_define_method {}") @@ -154,4 +370,64 @@ class TestEval < Test::Unit::TestCase 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_eval_using_integer_as_binding + assert_raise(TypeError) { eval("", 1) } + end + + def test_eval_raise + assert_raise(RuntimeError) { eval("raise ''") } + end + + def test_eval_using_untainted_binding_under_safe4 + assert_raise(SecurityError) do + Thread.new do + b = binding + $SAFE = 4 + eval("", b) + end.join + end + 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 end diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 4c27c52f3c..281dc70fbe 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -1,4 +1,6 @@ require 'test/unit' +require 'tempfile' +require_relative 'envutil' class TestException < Test::Unit::TestCase def test_exception @@ -23,7 +25,7 @@ class TestException < Test::Unit::TestCase # exception in rescue clause $string = "this must be handled no.3" - e = assert_raises(RuntimeError) do + e = assert_raise(RuntimeError) do begin raise "exception in rescue clause" rescue @@ -35,7 +37,7 @@ class TestException < Test::Unit::TestCase # exception in ensure clause $string = "exception in ensure clause" - e = assert_raises(RuntimeError) do + e = assert_raise(RuntimeError) do begin raise "this must be handled no.4" ensure @@ -90,7 +92,16 @@ class TestException < Test::Unit::TestCase end false }) + end + def test_catch_throw_in_require + bug7185 = '[ruby-dev:46234]' + t = Tempfile.open(["dep", ".rb"]) + t.puts("throw :extdep, 42") + t.close + assert_equal(42, catch(:extdep) {require t.path}, bug7185) + ensure + t.close! if t end def test_else @@ -184,4 +195,201 @@ class TestException < Test::Unit::TestCase 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_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_safe4 + cmd = proc{raise SystemExit} + safe0_p = proc{|*args| args} + + test_proc = proc { + $SAFE = 4 + begin + cmd.call + rescue SystemExit => e + safe0_p["SystemExit: #{e.inspect}"] + raise e + rescue Exception => e + safe0_p["Exception (NOT SystemExit): #{e.inspect}"] + raise e + end + } + assert_raise(SystemExit, '[ruby-dev:38760]') {test_proc.call} + end + + def test_thread_signal_location + stdout, stderr, status = EnvUtil.invoke_ruby("-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_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(e.success?) + + begin + abort + rescue SystemExit => e + end + assert(!e.success?) + end + + def test_nomethoderror + bug3237 = '[ruby-core:29948]' + str = "\u2600" + id = :"\u2604" + e = assert_raise(NoMethodError) {str.__send__(id)} + assert_equal("undefined method `#{id}' for #{str.inspect}:String", e.message, bug3237) + end + + def test_errno + assert_equal(Encoding.find("locale"), Errno::EINVAL.new.message.encoding) + end + + def test_exception_in_name_error_to_str + bug5575 = '[ruby-core:41612]' + t = Tempfile.new(["test_exception_in_name_error_to_str", ".rb"]) + t.puts <<-EOC + begin + BasicObject.new.inspect + rescue + $!.inspect + end + EOC + t.close + assert_nothing_raised(NameError, bug5575) do + load(t.path) + 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 test_exception_to_s_should_not_propagate_untrustedness + favorite_lang = "Ruby" + + for exc in [Exception, NameError] + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + exc.new(favorite_lang).to_s + favorite_lang.replace("Python") + }.call + end + end + + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + o = Object.new + o.singleton_class.send(:define_method, :to_str) { + favorite_lang + } + NameError.new(o).to_s + favorite_lang.replace("Python") + }.call + end + + assert_equal("Ruby", favorite_lang) + end end diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb new file mode 100644 index 0000000000..49736f5a89 --- /dev/null +++ b/test/ruby/test_fiber.rb @@ -0,0 +1,240 @@ +require 'test/unit' +require 'fiber' +require 'continuation' +require_relative './envutil' + +class TestFiber < Test::Unit::TestCase + def test_normal + f = Fiber.current + 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 = 10000 + assert_equal(max, max.times{ + Fiber.new{} + }) + assert_equal(max, + max.times{|i| + Fiber.new{ + }.resume + } + ) + end + + def test_many_fibers_with_threads + max = 1000 + @cnt = 0 + (1..100).map{|ti| + Thread.new{ + max.times{|i| + Fiber.new{ + @cnt += 1 + }.resume + } + } + }.each{|t| + t.join + } + assert_equal(:ok, :ok) + 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){ + f = 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(ArgumentError){ + 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]' + 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]' + error = assert_raise(RuntimeError) do + Fiber.new(&Module.method(:nesting)).resume + end + assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083) + error = assert_raise(RuntimeError) do + Fiber.new(&Module.method(:undef_method)).resume(:to_s) + end + assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083) + end + + def test_fork_from_fiber + begin + Process.fork{} + rescue NotImplementedError + return + end + bug5700 = '[ruby-core:41456]' + pid = nil + 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 +end + diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb index 2458dde347..b888233bbe 100644 --- a/test/ruby/test_file.rb +++ b/test/ruby/test_file.rb @@ -1,34 +1,29 @@ require 'test/unit' require 'tempfile' -$:.replace([File.dirname(File.expand_path(__FILE__))] | $:) -require 'ut_eof' +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 - filename = 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 - begin - File.unlink(filename) - assert(false) - rescue Errno::EACCES - assert(true) - end - else - File.unlink(filename) - assert(true) + 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 - ensure - r.close - File.unlink(filename) if File.exist?(filename) - end + } end include TestEOF @@ -42,22 +37,68 @@ class TestFile < Test::Unit::TestCase include TestEOF::Seek - def test_fnmatch - # from [ruby-dev:22815] and [ruby-dev:22819] - assert(true, File.fnmatch('\[1\]' , '[1]')) - assert(true, File.fnmatch('*?', 'a')) + def test_empty_file_bom + bug6487 = '[ruby-core:45203]' + f = Tempfile.new(__method__.to_s) + f.close + 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')} + f.close(true) + end + + def assert_bom(bytes, name) + bug6487 = '[ruby-core:45203]' + + f = Tempfile.new(name.to_s) + 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" + f.close(true) + 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_truncate_wbuf # [ruby-dev:24191] + def test_bom_32le + assert_bom(["\xFF\xFE\0", "\0"], __method__) + end + + def test_truncate_wbuf f = Tempfile.new("test-truncate") f.print "abc" f.truncate(0) f.print "def" + f.flush + assert_equal("\0\0\0def", File.read(f.path), "[ruby-dev:24191]") f.close - assert_equal("\0\0\0def", File.read(f.path)) end - def test_truncate_rbuf # [ruby-dev:24197] + def test_truncate_rbuf f = Tempfile.new("test-truncate") f.puts "abc" f.puts "def" @@ -65,44 +106,168 @@ class TestFile < Test::Unit::TestCase f.open assert_equal("abc\n", f.gets) f.truncate(3) - assert_equal(nil, f.gets) + assert_equal(nil, f.gets, "[ruby-dev:24197]") + end + + def test_truncate_beyond_eof + f = Tempfile.new("test-truncate") + f.print "abc" + f.truncate 10 + assert_equal("\0" * 7, f.read(100), "[ruby-dev:24532]") end def test_read_all_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal("a", f.read) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + f.print "a" + f.rewind + assert_equal("a", f.read, "mode = <#{mode}>") + end end def test_gets_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal("a", f.gets("a")) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + 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 - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "\na" } - assert_equal("a", f.gets("")) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + 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| + f = Tempfile.new("test-extended-file", mode) + 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 - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - result = [] - f.each_byte {|b| result << b } - assert_equal([?a], result) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + 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 - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal(?a, f.getc) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + 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| + f = Tempfile.new("test-extended-file", mode) + 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.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0') + 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.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0') + assert_equal(realdir, File.realdirpath(tst)) + assert_equal(realdir, File.realdirpath(".", tst)) + assert_equal(File.join(realdir, "foo"), File.realdirpath("foo", tst)) + } + 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_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_open_nul + Dir.mktmpdir(__method__.to_s) do |tmpdir| + path = File.join(tmpdir, "foo") + assert_raise(ArgumentError) do + open(path + "\0bar", "w") {} + end + refute File.exist?(path) + end + end end diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb new file mode 100644 index 0000000000..df7140f24a --- /dev/null +++ b/test/ruby/test_file_exhaustive.rb @@ -0,0 +1,1048 @@ +# -*- coding: us-ascii -*- +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) + @hardlinkfile = @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(n.is_a?(Integer), n.inspect + " is not Fixnum.") + end + + def assert_integer_or_nil(n) + assert(n.is_a?(Integer) || n.equal?(nil), n.inspect + " is neither Fixnum nor nil.") + 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_directory_p + assert(File.directory?(@dir)) + assert(!(File.directory?(@dir+"/..."))) + assert(!(File.directory?(@file))) + assert(!(File.directory?(@nofile))) + end + + def test_pipe_p ## xxx + assert(!(File.pipe?(@dir))) + assert(!(File.pipe?(@file))) + assert(!(File.pipe?(@nofile))) + end + + def test_symlink_p + assert(!(File.symlink?(@dir))) + assert(!(File.symlink?(@file))) + assert(File.symlink?(@symlinkfile)) if @symlinkfile + assert(!(File.symlink?(@hardlinkfile))) if @hardlinkfile + assert(!(File.symlink?(@nofile))) + end + + def test_socket_p ## xxx + assert(!(File.socket?(@dir))) + assert(!(File.socket?(@file))) + assert(!(File.socket?(@nofile))) + end + + def test_blockdev_p ## xxx + assert(!(File.blockdev?(@dir))) + assert(!(File.blockdev?(@file))) + assert(!(File.blockdev?(@nofile))) + end + + def test_chardev_p ## xxx + assert(!(File.chardev?(@dir))) + assert(!(File.chardev?(@file))) + assert(!(File.chardev?(@nofile))) + end + + def test_exist_p + assert(File.exist?(@dir)) + assert(File.exist?(@file)) + assert(!(File.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.readable?(@file))) + File.chmod(0600, @file) + assert(File.readable?(@file)) + assert(!(File.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.readable_real?(@file))) + File.chmod(0600, @file) + assert(File.readable_real?(@file)) + assert(!(File.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.world_readable?(@file))) + File.chmod(0600, @file) + assert(!(File.world_readable?(@file))) + assert(!(File.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.writable?(@file))) + File.chmod(0600, @file) + assert(File.writable?(@file)) + assert(!(File.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.writable_real?(@file))) + File.chmod(0600, @file) + assert(File.writable_real?(@file)) + assert(!(File.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.world_writable?(@file))) + File.chmod(0600, @file) + assert(!(File.world_writable?(@file))) + assert(!(File.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.executable?(@file))) + assert(!(File.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.executable_real?(@file))) + assert(!(File.executable_real?(@nofile))) + end + + def test_file_p + assert(!(File.file?(@dir))) + assert(File.file?(@file)) + assert(!(File.file?(@nofile))) + end + + def test_zero_p + assert_nothing_raised { File.zero?(@dir) } + assert(!(File.zero?(@file))) + assert(File.zero?(@zerofile)) + assert(!(File.zero?(@nofile))) + end + + def test_size_p + assert_nothing_raised { File.size?(@dir) } + assert_equal(3, File.size?(@file)) + assert(!(File.size?(@zerofile))) + assert(!(File.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.setuid?(@file))) + assert(!(File.setgid?(@file))) + assert(!(File.sticky?(@file))) + end + + def test_identical_p + assert(File.identical?(@file, @file)) + assert(!(File.identical?(@file, @zerofile))) + assert(!(File.identical?(@file, @nofile))) + assert(!(File.identical?(@nofile, @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_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.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))) + if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM + 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(%r'\Ac:/bar/foo\z'i, File.expand_path('c:foo', 'c:/bar')) + 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 + + 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 + + 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) + skip "FIXME" + 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_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_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")) + 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")) + 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_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_find_file + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + load(@file) + end.join + end + 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/test/ruby/test_fixnum.rb b/test/ruby/test_fixnum.rb new file mode 100644 index 0000000000..2aee65c211 --- /dev/null +++ b/test/ruby/test_fixnum.rb @@ -0,0 +1,232 @@ +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)) + 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(r.abs < b.abs) + assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0)) + assert_equal(q, a/b) + assert_equal(q, a.div(b)) + assert_equal(r, a%b) + assert_equal(r, a.modulo(b)) + } + } + 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_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(1 != nil) + + assert_equal(0, 1 <=> 1) + assert_equal(-1, 1 <=> 4294967296) + assert_equal(0, 1 <=> 1.0) + assert_nil(1 <=> nil) + + assert(1.send(:>, 0)) + assert(!(1.send(:>, 1))) + assert(!(1.send(:>, 2))) + assert(!(1.send(:>, 4294967296))) + assert(1.send(:>, 0.0)) + assert_raise(ArgumentError) { 1.send(:>, nil) } + + assert(1.send(:>=, 0)) + assert(1.send(:>=, 1)) + assert(!(1.send(:>=, 2))) + assert(!(1.send(:>=, 4294967296))) + assert(1.send(:>=, 0.0)) + assert_raise(ArgumentError) { 1.send(:>=, nil) } + + assert(!(1.send(:<, 0))) + assert(!(1.send(:<, 1))) + assert(1.send(:<, 2)) + assert(1.send(:<, 4294967296)) + assert(!(1.send(:<, 0.0))) + assert_raise(ArgumentError) { 1.send(:<, nil) } + + assert(!(1.send(:<=, 0))) + assert(1.send(:<=, 1)) + assert(1.send(:<=, 2)) + assert(1.send(:<=, 4294967296)) + assert(!(1.send(:<=, 0.0))) + assert_raise(ArgumentError) { 1.send(:<=, nil) } + end +end diff --git a/test/ruby/test_flip.rb b/test/ruby/test_flip.rb new file mode 100644 index 0000000000..bd14228a8c --- /dev/null +++ b/test/ruby/test_flip.rb @@ -0,0 +1,21 @@ +require 'test/unit' +require_relative 'envutil' + +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 +end diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index d559ce5cab..301aeecf0f 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -1,6 +1,9 @@ require 'test/unit' +require_relative 'envutil' class TestFloat < Test::Unit::TestCase + include EnvUtil + def test_float assert_equal(2, 2.6.floor) assert_equal(-3, (-2.6).floor) @@ -11,6 +14,8 @@ class TestFloat < Test::Unit::TestCase assert_equal(3, 2.6.round) assert_equal(-2, (-2.4).truncate) assert((13.4 % 1 - 0.4).abs < 0.0001) + assert_equal(36893488147419111424, + 36893488147419107329.0.to_i) end def nan_test(x,y) @@ -22,7 +27,7 @@ class TestFloat < Test::Unit::TestCase assert_equal(false, (x >= y)) end def test_nan - nan = 0.0/0 + nan = Float::NAN nan_test(nan, nan) nan_test(nan, 0) nan_test(nan, 1) @@ -73,14 +78,38 @@ class TestFloat < Test::Unit::TestCase assert(a.abs < Float::EPSILON) a = Float("-.0") assert(a.abs < Float::EPSILON) - assert(a.abs < 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")) + 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 def test_divmod @@ -110,4 +139,396 @@ class TestFloat < Test::Unit::TestCase assert_equal(-3.5, (-11.5).remainder(4)) assert_equal(-3.5, (-11.5).remainder(-4)) 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_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_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_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_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 + bug6044 = '[ruby-core:42726]' + assert_equal(4.2, 4.2.send(:%, Float::INFINITY)) + assert_equal(4.2, 4.2 % Float::INFINITY) + assert_is_minus_zero(-0.0 % 4.2) + assert_is_minus_zero(-0.0.send :%, 4.2) + assert_raise(ZeroDivisionError) { 4.2.send(:%, 0.0) } + assert_raise(ZeroDivisionError) { 4.2 % 0.0 } + assert_raise(ZeroDivisionError) { 42.send(:%, 0) } + assert_raise(ZeroDivisionError) { 42 % 0 } + 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(1.0.eql?(1.0)) + assert(inf.eql?(inf)) + assert(!(nan.eql?(nan))) + assert(!(1.0.eql?(nil))) + + assert(1.0 == 1) + assert(1.0 != 2**32) + assert(1.0 != nan) + assert(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(0.0.zero?) + assert(!(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(!(inf.finite?)) + assert(!((-inf).finite?)) + assert(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| + i = f.round + if f < 0 + assert_operator(i, :<, 0) + else + assert_operator(i, :>, 0) + end + d = f - i + assert_operator(-0.5, :<=, d) + assert_operator(d, :<=, 0.5) + } + 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(!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(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(TypeError) 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_long_string + assert_normal_exit(<<-'end;') + assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9) + end; + end + + def test_long_string + assert_normal_exit(<<-'end;') + assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9) + end; + end end diff --git a/test/ruby/test_fnmatch.rb b/test/ruby/test_fnmatch.rb new file mode 100644 index 0000000000..e5f5ba6a4f --- /dev/null +++ b/test/ruby/test_fnmatch.rb @@ -0,0 +1,106 @@ +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.fnmatch('\[1\]' , '[1]'), "[ruby-dev:22819]") + assert(File.fnmatch('*?', 'a'), "[ruby-dev:22815]") + 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.fnmatch('cat', 'category')) + assert(!File.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.fnmatch('c??t', 'cat')) + assert(!File.fnmatch('??at', 'cat')) + assert(!File.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.fnmatch('c*t', 'cats')) + assert(!File.fnmatch('*abc', 'abcabz')) + assert(File.fnmatch('*abz', 'abcabz')) + assert(!File.fnmatch('a*abc', 'abc')) + assert(File.fnmatch('a*bc', 'abc')) + assert(!File.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.fnmatch('\?', '\?')) + assert(!File.fnmatch('\?', 'a')) + assert(!File.fnmatch('\?', '\a')) + assert(File.fnmatch('\*', '*')) + assert(!File.fnmatch('\*', '\*')) + assert(!File.fnmatch('\*', 'cats')) + assert(!File.fnmatch('\*', '\cats')) + assert(File.fnmatch('\a', 'a')) + assert(!File.fnmatch('\a', '\a')) + assert(File.fnmatch('[a\-c]', 'a')) + assert(File.fnmatch('[a\-c]', '-')) + assert(File.fnmatch('[a\-c]', 'c')) + assert(!File.fnmatch('[a\-c]', 'b')) + assert(!File.fnmatch('[a\-c]', '\\')) + # escaping character loses its meaning if FNM_NOESCAPE is set + assert(!File.fnmatch('\?', '?', File::FNM_NOESCAPE)) + assert(File.fnmatch('\?', '\?', File::FNM_NOESCAPE)) + assert(!File.fnmatch('\?', 'a', File::FNM_NOESCAPE)) + assert(File.fnmatch('\?', '\a', File::FNM_NOESCAPE)) + assert(!File.fnmatch('\*', '*', File::FNM_NOESCAPE)) + assert(File.fnmatch('\*', '\*', File::FNM_NOESCAPE)) + assert(!File.fnmatch('\*', 'cats', File::FNM_NOESCAPE)) + assert(File.fnmatch('\*', '\cats', File::FNM_NOESCAPE)) + assert(!File.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.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.fnmatch('cat', 'CAT')) + assert(File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD)) + assert(!File.fnmatch('[a-z]', 'D')) + assert(File.fnmatch('[a-z]', 'D', File::FNM_CASEFOLD)) + assert(!File.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.fnmatch('foo?boo', 'foo/boo', File::FNM_PATHNAME)) + assert(!File.fnmatch('foo*', 'foo/boo', File::FNM_PATHNAME)) + # wildcard matches leading period if FNM_DOTMATCH is set + assert(!File.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.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.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 + +end diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index d0b4e3df77..381fcd4d18 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -1,5 +1,7 @@ require 'test/unit' +require_relative "envutil" + class TestGc < Test::Unit::TestCase class S def initialize(a) @@ -8,6 +10,9 @@ class TestGc < Test::Unit::TestCase 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] @@ -26,5 +31,99 @@ class TestGc < Test::Unit::TestCase } GC.start assert true # reach here or dumps core + + GC.stress = prev_stress + 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_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]) + end + + def test_singleton_method + prev_stress = GC.stress + assert_nothing_raised("[ruby-dev:42832]") do + 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 + end + ensure + GC.stress = prev_stress + end + + def test_gc_parameter + env = { + "RUBY_GC_MALLOC_LIMIT" => "60000000", + "RUBY_HEAP_MIN_SLOTS" => "100000" + } + assert_normal_exit("exit", "[ruby-core:39777]", :child_env => env) + + env = { + "RUBYOPT" => "", + "RUBY_HEAP_MIN_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"], "", [], /heap_min_slots=100000/, "[ruby-core:39795]") + 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_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_sweep_in_finalizer + bug9205 = '[ruby-core:58833] [Bug #9205]' + 2.times do + assert_ruby_status([], <<-'end;', bug9205) + raise_proc = proc do |id| + GC.start + end + 1000.times do + ObjectSpace.define_finalizer(Object.new, raise_proc) + end + end; + end end end diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 38d72f701b..019196bd2e 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1,10 +1,12 @@ require 'test/unit' +require 'continuation' +require_relative "envutil" class TestHash < Test::Unit::TestCase def test_hash x = {1=>2, 2=>4, 3=>6} - y = {1, 2, 2, 4, 3, 6} + y = {1=>2, 2=>4, 3=>6} # y = {1, 2, 2, 4, 3, 6} # 1.9 doesn't support assert_equal(2, x[1]) @@ -50,7 +52,7 @@ class TestHash < Test::Unit::TestCase assert_equal([], x[22]) assert_not_same(x[22], x[22]) - x = Hash.new{|h,k| z = k; h[k] = k*2} + x = Hash.new{|h,kk| z = kk; h[kk] = kk*2} z = 0 assert_equal(44, x[22]) assert_equal(22, z) @@ -82,6 +84,12 @@ class TestHash < Test::Unit::TestCase self => 'self', true => 'true', nil => 'nil', 'nil' => nil ] + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose end def test_s_AREF @@ -106,7 +114,13 @@ class TestHash < Test::Unit::TestCase assert_instance_of(@cls, h) assert_equal('default', h.default) assert_equal('default', h['spurious']) - + + end + + def test_self_initialize_copy + h = @cls[1=>2] + h.instance_eval {initialize_copy(h)} + assert_equal(2, h[1]) end def test_AREF # '[]' @@ -137,8 +151,6 @@ class TestHash < Test::Unit::TestCase assert_equal('nil', h1[nil]) assert_equal(nil, h1['nil']) assert_equal(:default, h1['koala']) - - end def test_ASET # '[]=' @@ -199,16 +211,20 @@ class TestHash < Test::Unit::TestCase 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(a.__id__ != b.__id__) - assert_equal(a.frozen?, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = @h.clone + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end end end end @@ -279,18 +295,28 @@ class TestHash < Test::Unit::TestCase assert_equal(base.size, n) end + def test_keep_if + h = {1=>2,3=>4,5=>6} + assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 }) + h = {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(a.__id__ != b.__id__) - assert_equal(false, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust 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(a.__id__ != b.__id__) + assert_equal(false, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + assert_equal(a.untrusted?, b.untrusted?) + end end end end @@ -352,8 +378,6 @@ class TestHash < Test::Unit::TestCase end def test_fetch - assert_raise(IndexError) { @cls[].fetch(1) } - assert_raise(IndexError) { @h.fetch('gumby') } assert_equal('gumbygumby', @h.fetch('gumby') {|k| k * 2 }) assert_equal('pokey', @h.fetch('gumby', 'pokey')) @@ -362,7 +386,15 @@ class TestHash < Test::Unit::TestCase assert_equal('nil', @h.fetch(nil)) end - def test_key? + 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(!@cls[].key?(1)) assert(!@cls[].key?(nil)) assert(@h.key?(nil)) @@ -386,6 +418,15 @@ class TestHash < Test::Unit::TestCase assert(!@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(res.length == 3) @@ -516,7 +557,7 @@ class TestHash < Test::Unit::TestCase def test_shift h = @h.dup - + @h.length.times { k, v = h.shift assert(@h.key?(k)) @@ -583,6 +624,13 @@ class TestHash < Test::Unit::TestCase 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 + h.untrust + a = h.to_a + assert_equal(true, a.tainted?) + assert_equal(true, a.untrusted?) end def test_to_hash @@ -592,11 +640,12 @@ class TestHash < Test::Unit::TestCase def test_to_s h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ] - assert_equal(h.to_a.join, h.to_s) + assert_equal(h.inspect, h.to_s) $, = ":" - assert_equal(h.to_a.join, h.to_s) + assert_equal(h.inspect, h.to_s) h = @cls[] - assert_equal(h.to_a.join, h.to_s) + assert_equal(h.inspect, h.to_s) + ensure $, = nil end @@ -617,7 +666,7 @@ class TestHash < Test::Unit::TestCase assert_equal(hb, h2) end - def test_value? + def test_value2? assert(!@cls[].value?(1)) assert(!@cls[].value?(nil)) assert(@h.value?(nil)) @@ -635,4 +684,273 @@ class TestHash < Test::Unit::TestCase assert_equal([], expected - vals) end + def test_security_check + h = {} + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + h[1] = 1 + end.join + end + end + + def test_intialize_wrong_arguments + assert_raise(ArgumentError) do + Hash.new(0) { } + end + end + + def test_create + assert_equal({1=>2, 3=>4}, Hash[[[1,2],[3,4]]]) + assert_raise(ArgumentError) { Hash[0, 1, 2] } + assert_equal({1=>2, 3=>4}, Hash[1,2,3,4]) + o = Object.new + def o.to_hash() {1=>2} end + assert_equal({1=>2}, Hash[o], "[ruby-dev:34555]") + end + + def test_rehash2 + h = {1 => 2, 3 => 4} + assert_equal(h.dup, h.rehash) + assert_raise(RuntimeError) { h.each { h.rehash } } + assert_equal({}, {}.rehash) + end + + def test_fetch2 + assert_equal(:bar, @h.fetch(0, :foo) { :bar }) + end + + def test_default_proc + h = Hash.new {|hh, k| hh + k + "baz" } + assert_equal("foobarbaz", h.default_proc.call("foo", "bar")) + h = {} + assert_nil(h.default_proc) + end + + def test_shift2 + h = Hash.new {|hh, k| :foo } + h[1] = 2 + assert_equal([1, 2], h.shift) + assert_equal(:foo, h.shift) + assert_equal(:foo, h.shift) + + h = Hash.new(:foo) + h[1] = 2 + assert_equal([1, 2], h.shift) + assert_equal(:foo, h.shift) + assert_equal(:foo, h.shift) + + h = {1=>2} + h.each { assert_equal([1, 2], h.shift) } + end + + def test_reject_bang2 + assert_equal({1=>2}, {1=>2,3=>4}.reject! {|k, v| k + v == 7 }) + assert_nil({1=>2,3=>4}.reject! {|k, v| k == 5 }) + assert_nil({}.reject! { }) + end + + def test_select + assert_equal({3=>4,5=>6}, {1=>2,3=>4,5=>6}.select {|k, v| k + v >= 7 }) + end + + def test_select! + h = {1=>2,3=>4,5=>6} + assert_equal(h, h.select! {|k, v| k + v >= 7 }) + assert_equal({3=>4,5=>6}, h) + h = {1=>2,3=>4,5=>6} + assert_equal(nil, h.select!{true}) + end + + def test_clear2 + assert_equal({}, {1=>2,3=>4,5=>6}.clear) + h = {1=>2,3=>4,5=>6} + h.each { h.clear } + assert_equal({}, h) + end + + def test_replace2 + h1 = Hash.new { :foo } + h2 = {} + 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, {}.size) + end + + def test_equal2 + assert({} != 0) + o = Object.new + def o.to_hash; {}; end + def o.==(x); true; end + assert({} == o) + def o.==(x); false; end + assert({} != o) + + h1 = {1=>2}; h2 = {3=>4} + assert(h1 != h2) + h1 = {1=>2}; h2 = {1=>4} + assert(h1 != h2) + end + + def test_eql + assert(!({}.eql?(0))) + o = Object.new + def o.to_hash; {}; end + def o.eql?(x); true; end + assert({}.eql?(o)) + def o.eql?(x); false; end + assert(!({}.eql?(o))) + end + + def test_hash2 + assert_kind_of(Integer, {}.hash) + h = {1=>2} + h.shift + assert_equal({}.hash, h.hash, '[ruby-core:38650]') + end + + def test_update2 + h1 = {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 = {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], {1=>2, 3=>4, 5=>6}.assoc(3)) + assert_nil({1=>2, 3=>4, 5=>6}.assoc(4)) + end + + def test_rassoc + assert_equal([3,4], {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]], {[1] => [2]}.flatten) + end + + def test_callcc + h = {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 = {1=>2} + c = nil + assert_raise(RuntimeError) do + h.each { callcc {|c2| c = c2 } } + h.clear + c.call + end + end + + def test_compare_by_identity + a = "foo" + assert(!{}.compare_by_identity?) + h = { a => "bar" } + assert(!h.compare_by_identity?) + h.compare_by_identity + assert(h.compare_by_identity?) + #assert_equal("bar", h[a]) + assert_nil(h["foo"]) + 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, {11=>1,0=>2}.hash) + o1 = ObjWithHash.new(0,1) + o2 = ObjWithHash.new(11,1) + assert_equal({o1=>1,o2=>2}.hash, {o2=>2,o1=>1}.hash) + end + + def test_hash_bignum_hash + x = 2<<(32-3)-1 + assert_equal({x=>1}.hash, {x=>1}.hash) + x = 2<<(64-3)-1 + assert_equal({x=>1}.hash, {x=>1}.hash) + + o = Object.new + def o.hash; 2 << 100; end + assert_equal({x=>1}.hash, {x=>1}.hash) + end + + def test_hash_poped + assert_nothing_raised { eval("a = 1; {a => a}; a") } + end + + def test_recursive_key + h = {} + assert_nothing_raised { h[h] = :foo } + h.rehash + assert_equal(:foo, h[h]) + end + + def test_inverse_hash + feature4262 = '[ruby-core:34334]' + [{1=>2}, {123=>"abc"}].each do |h| + assert_not_equal(h.hash, h.invert.hash, feature4262) + end + end + + def test_exception_in_rehash + 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 + EOS + + code = <<-EOS + h = {Foo.new => true} + 10_0000.times do + h.rehash rescue nil + end + GC.start + EOS + + assert_no_memory_leak([], prepare, code, bug9187) + end end diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb new file mode 100644 index 0000000000..7f8212ebf0 --- /dev/null +++ b/test/ruby/test_integer.rb @@ -0,0 +1,201 @@ +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((1 >> 0x80000000).zero?) + assert((1 >> 0xffffffff).zero?) + assert((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) } + end + + def test_int_p + assert(!(1.0.integer?)) + assert(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(1.odd?) + assert(!(2.odd?)) + assert(!(1.even?)) + assert(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 +end diff --git a/test/ruby/test_integer_comb.rb b/test/ruby/test_integer_comb.rb new file mode 100644 index 0000000000..c057deb36f --- /dev/null +++ b/test/ruby/test_integer_comb.rb @@ -0,0 +1,622 @@ +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] } + + 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, 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(r.abs < b.abs) + assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0)) + 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/test/ruby/test_io.rb b/test/ruby/test_io.rb index 642c8f4430..5e3a12c999 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1,11 +1,2247 @@ require 'test/unit' +require 'tmpdir' +require "fcntl" +require 'io/nonblock' +require 'socket' +require 'stringio' +require 'timeout' +require 'tempfile' +require 'weakref' +require_relative 'envutil' class TestIO < Test::Unit::TestCase + def have_close_on_exec? + begin + $stdin.close_on_exec? + true + rescue NotImplementedError + false + end + end + + def have_nonblock? + IO.method_defined?("nonblock=") + end + + 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(!r.closed?) + assert(w.closed?) + :foooo + } + assert_equal(:foooo, ret) + assert(x[0].closed?) + assert(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(x[0].closed?) + assert(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 + t = make_tempfile + 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 + t = make_tempfile + 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 + t = make_tempfile + 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_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 test_copy_stream + mkcdtmpdir { + + content = "foobar" + File.open("src", "w") {|f| f << content } + ret = IO.copy_stream("src", "dst") + assert_equal(content.bytesize, ret) + assert_equal(content, File.read("dst")) + + # overwrite by smaller file. + content = "baz" + File.open("src", "w") {|f| f << content } + 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")) + + assert_raise(Errno::ENOENT) { + IO.copy_stream("nodir/foo", "dst") + } + + assert_raise(Errno::ENOENT) { + IO.copy_stream("src", "nodir/bar") + } + + 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) + + with_pipe {|r, w| + w.close + assert_raise(IOError) { IO.copy_stream("src", w) } + } + + pipe_content = "abc" + 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")) + } + + with_read_pipe("abc") {|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("abc") {|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("abc") {|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("abc") {|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("abc") {|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) + + 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) + + if have_nonblock? + 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 + + bigcontent = "abc" * 123456 + File.open("bigsrc", "w") {|f| f << bigcontent } + ret = IO.copy_stream("bigsrc", "bigdst") + assert_equal(bigcontent.bytesize, ret) + assert_equal(bigcontent, File.read("bigdst")) + + File.unlink("bigdst") + ret = IO.copy_stream("bigsrc", "bigdst", nil, 100) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(bigcontent[100..-1], File.read("bigdst")) + + File.unlink("bigdst") + ret = IO.copy_stream("bigsrc", "bigdst", 30000, 100) + assert_equal(30000, ret) + assert_equal(bigcontent[100, 30000], File.read("bigdst")) + + 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 + } + + with_pipe {|r, w| + w.close + assert_raise(IOError) { IO.copy_stream("src", w) } + } + + megacontent = "abc" * 1234567 + File.open("megasrc", "w") {|f| f << megacontent } + + if have_nonblock? + 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 } + ret = IO.copy_stream(r1, w2) + assert_equal(megacontent.bytesize, ret) + w2.close + t1.join + assert_equal(megacontent, t2.value) + } + } + end + + with_pipe {|r1, w1| + with_pipe {|r2, w2| + t1 = Thread.new { w1 << megacontent; w1.close } + t2 = Thread.new { r2.read } + ret = IO.copy_stream(r1, w2) + assert_equal(megacontent.bytesize, ret) + w2.close + t1.join + assert_equal(megacontent, t2.value) + } + } + + with_pipe {|r, w| + t = Thread.new { r.read } + ret = IO.copy_stream("megasrc", w) + assert_equal(megacontent.bytesize, ret) + w.close + assert_equal(megacontent, t.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_socket + return unless defined? UNIXSocket + mkcdtmpdir { + + content = "foobar" + File.open("src", "w") {|f| f << content } + + with_socketpair {|s1, s2| + ret = IO.copy_stream("src", s1) + assert_equal(content.bytesize, ret) + s1.close + assert_equal(content, s2.read) + } + + bigcontent = "abc" * 123456 + File.open("bigsrc", "w") {|f| f << bigcontent } + + with_socketpair {|s1, s2| + t = Thread.new { s2.read } + ret = IO.copy_stream("bigsrc", s1) + assert_equal(bigcontent.bytesize, ret) + s1.close + result = t.value + assert_equal(bigcontent, result) + } + + with_socketpair {|s1, s2| + t = Thread.new { s2.read } + ret = IO.copy_stream("bigsrc", s1, 10000) + assert_equal(10000, ret) + s1.close + result = t.value + assert_equal(bigcontent[0,10000], result) + } + + File.open("bigsrc") {|f| + assert_equal(0, f.pos) + with_socketpair {|s1, s2| + t = Thread.new { s2.read } + ret = IO.copy_stream(f, s1, nil, 100) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(0, f.pos) + s1.close + result = t.value + assert_equal(bigcontent[100..-1], result) + } + } + + File.open("bigsrc") {|f| + assert_equal(bigcontent[0,100], f.read(100)) + assert_equal(100, f.pos) + with_socketpair {|s1, s2| + t = Thread.new { s2.read } + ret = IO.copy_stream(f, s1) + assert_equal(bigcontent.bytesize-100, ret) + assert_equal(bigcontent.length, f.pos) + s1.close + result = t.value + assert_equal(bigcontent[100..-1], result) + } + } + + megacontent = "abc" * 1234567 + File.open("megasrc", "w") {|f| f << megacontent } + + if have_nonblock? + with_socketpair {|s1, s2| + begin + s1.nonblock = true + rescue Errno::EBADF + skip "nonblocking IO for pipe is not implemented" + end + t = Thread.new { s2.read } + ret = IO.copy_stream("megasrc", s1) + assert_equal(megacontent.bytesize, ret) + s1.close + result = t.value + assert_equal(megacontent, result) + } + 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 status.success?, status.inspect + end + } + end + } + end + + 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 + + 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) + t = Thread.new { + w.close + } + assert_equal("zzabcd", r.read) + t.join + } + 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 + + 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 safe_4 + t = Thread.new do + $SAFE = 4 + yield + end + unless t.join(10) + t.kill + flunk("timeout in safe_4") + end + end + + 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_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| + 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) + 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) + assert_raise(SecurityError) do + safe_4 { r.inspect } + end + 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 s.size == 5 + 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_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 s.size == 5 + assert_raise(RuntimeError) { s.clear } + w.write "foobarbaz" + w.close + assert_equal("fooba", t.value) + end + end + + def test_write_nonblock + skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + 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_error + return if !have_nonblock? + skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + with_pipe {|r, w| + begin + r.read_nonblock 4096 + rescue Errno::EWOULDBLOCK + assert_kind_of(IO::WaitReadable, $!) + end + } + end + + def test_write_nonblock_error + return if !have_nonblock? + skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + with_pipe {|r, w| + begin + loop { + w.write_nonblock "a"*100000 + } + rescue Errno::EWOULDBLOCK + assert_kind_of(IO::WaitWritable, $!) + 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", s = 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_close_read_security_error + with_pipe do |r, w| + assert_raise(SecurityError) do + safe_4 { r.close_read } + end + 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_security_error + with_pipe do |r, w| + assert_raise(SecurityError) do + safe_4 { r.close_write } + end + 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 r, w = IO.pipe - w.print "\377xyz" - w.close - assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]") - r.close + assert_equal(nil, r.pid) + assert_equal(nil, w.pid) + + 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) + pipe.close + assert_raise(IOError) { pipe.pid } + end + + def tesst_pid_after_close_read + pid1 = pid2 = nil + IO.popen(["echo", ""], "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 + t + end + + def test_set_lineno + t = make_tempfile + + 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 + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + 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) + end + + def test_bytes + pipe(proc do |w| + w.binmode + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + 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) + end + + def test_chars + pipe(proc do |w| + w.puts "foo" + w.puts "bar" + w.puts "baz" + w.close + end, proc do |r| + 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) + 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(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(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(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_close_security_error + with_pipe do |r, w| + assert_raise(SecurityError) do + safe_4 { r.close } + end + end + end + + def test_pos + t = make_tempfile + + 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]' + t = make_tempfile + ["", "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 test_sysseek + t = make_tempfile + + 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 + t = make_tempfile + + 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 + t = make_tempfile + + 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_flag + t = make_tempfile + + assert_raise(ArgumentError) do + open(t.path, "z") { } + end + + assert_raise(ArgumentError) do + open(t.path, "rr") { } + end + end + + def test_sysopen + t = make_tempfile + + 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 = 100) + if level > 0 + f = try_fdopen(fd, autoclose, level - 1) + GC.start + f + else + WeakRef.new(IO.for_fd(fd, autoclose: autoclose)) + end + end + + def test_autoclose + feature2250 = '[ruby-core:26222]' + pre = 'ft2250' + + t = Tempfile.new(pre) + 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 + 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 + 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 + 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 + t = make_tempfile + + with_pipe do |r, w| + assert_raise(SecurityError) do + safe_4 { r.reopen(t.path) } + end + end + + 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_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) + + t = make_tempfile + + 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]' + e = assert_raise(IOError, bug6054) {IO.foreach(t.path, mode:"w").next} + assert_match(/not opened for reading/, e.message, bug6054) + end + + def test_s_readlines + t = make_tempfile + + 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 + t = make_tempfile + + 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)) + end + + def test_initialize + return unless defined?(Fcntl::F_GETFL) + + t = make_tempfile + + 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 + t = make_tempfile + 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; IO.new(r) {}", [], /^.+$/) + 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 + t = make_tempfile + + 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 + t = make_tempfile + assert(File.read(t.path, 4).tainted?, '[ruby-dev:38826]') + assert(File.open(t.path) {|f| f.read(4)}.tainted?, '[ruby-dev:38826]') + end + + def test_binmode_after_closed + t = make_tempfile + 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) + } + end + end.each {|th| th.join} + end + + def test_flush_in_finalizer1 + require 'tempfile' + bug3910 = '[ruby-dev:42341]' + t = Tempfile.new("bug3910") + path = t.path + t.close + fds = [] + assert_nothing_raised(TypeError, bug3910) do + 500.times { + f = File.open(path, "w") + fds << f.fileno + f.print "hoge" + } + end + ensure + GC.start + end + + def test_flush_in_finalizer2 + require 'tempfile' + bug3910 = '[ruby-dev:42341]' + t = Tempfile.new("bug3910") + path = t.path + t.close + 1.times do + io = open(path,"w") + io.print "hoge" + end + assert_nothing_raised(TypeError, bug3910) do + GC.start + end + end + + def test_readlines_limit_0 + bug4024 = '[ruby-dev:42538]' + t = make_tempfile + 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]' + t = make_tempfile + open(t.path, "r") do |io| + assert_raise(ArgumentError, bug4024) do + io.each_line(0).next + end + end + end + + def test_advise + t = make_tempfile + assert_raise(ArgumentError, "no arguments") { t.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(make_tempfile.path) do |t| + assert_equal(t.advise(adv, offset, len), nil) + 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.advise(adv.to_sym, offset, len) + end + end + end + end + + def test_invalid_advise + feature4204 = '[ruby-dev:42887]' + t = make_tempfile + %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(make_tempfile.path) do |t| + assert_raise(NotImplementedError, feature4204) { t.advise(adv, offset, len) } + end + end + end + end + + def test_fcntl_lock + return if /x86_64-linux/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform + + pad=0 + Tempfile.open(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_cross_thread_close_fd + skip "cross thread close causes hung-up if pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + 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 + with_pipe do |r,w| + pid = fork do + $stdin.reopen(r) + r.close + read_thread = Thread.new do + begin + $stdin.read(1) + rescue => e + e + end + end + sleep(0.1) until read_thread.stop? + $stdin.close + read_thread.join + exit(IOError === read_thread.value) + end + assert Process.waitpid2(pid)[1].success? + end + rescue NotImplementedError + 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)) + 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 + file = Tempfile.new("test") + 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 + threads.each {|t| t.join} + assert(true, "[ruby-core:37197]") + ensure + read_file.close + write_file.close + file.close! + end + + def test_ioctl_linux + return if /linux/ !~ RUBY_PLATFORM + + assert_nothing_raised do + File.open('/dev/urandom'){|f1| + entropy_count = "" + # 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", "w") {|f| + f.puts "a" + f.puts "bc" + f.puts "def" + } + pos1 = pos2 = pos3 = nil + File.open("tmp.txt") {|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") {|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") {|f| + f.pos = pos2 + assert_equal("def\n", f.gets) + assert_equal(nil, f.gets) + } + File.open("tmp.txt") {|f| + f.pos = pos3 + assert_equal(nil, f.gets) + } + } + 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_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 + 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| + 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') + rescue SystemCallError + else + assert_equal(0x1_0000_0000, f.tell, msg) + end + end; + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + r, = IO.pipe + 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 } + ensure + t.kill + end + + def test_readpartial_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + r, = IO.pipe + 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 } + ensure + t.kill + end + + def test_sysread_unlocktmp_ensure + bug8669 = '[ruby-core:56121] [Bug #8669]' + + str = "" + r, = IO.pipe + 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 } + ensure + t.kill end end diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb new file mode 100644 index 0000000000..c22f665286 --- /dev/null +++ b/test/ruby/test_io_m17n.rb @@ -0,0 +1,2407 @@ +require 'test/unit' +require 'tmpdir' +require 'timeout' +require_relative 'envutil' + +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_block(full_message) { expected == actual } + 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_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_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) + defext = Encoding.default_external + Encoding.default_external = Encoding::UTF_8 + open("tmp", "rt") {|f| + s = f.getc + assert_equal(true, s.valid_encoding?) + assert_equal("\u3042", s) + } + Encoding.default_external = defext + } + end + + def test_getc_newlineconv_invalid + with_tmpdir { + src = "\xE3\x81" + generate_file('tmp', src) + defext = Encoding.default_external + Encoding.default_external = Encoding::UTF_8 + 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) + } + Encoding.default_external = defext + } + 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) + + e = assert_raise(ArgumentError) {with_pipe("UTF-8", "UTF-8".encode("UTF-32BE")) {}} + assert_match(/invalid name encoding/, e.message) + e = assert_raise(ArgumentError) {with_pipe("UTF-8".encode("UTF-32BE")) {}} + assert_match(/invalid name encoding/, e.message) + + 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_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") + } + } + 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 + assert_raise(ArgumentError) { open("not-exist", "r", :textmode=>true, :binmode=>true) } + 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 + un = 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" + %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")) + end + + bug3407 = '[ruby-core:30641]' + result = File.read('UTF-8-bom.txt', encoding: 'BOM|UTF-8') + assert_equal("a", result.force_encoding("ascii-8bit"), bug3407) + } + 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(!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]'] + r, w = IO.pipe + [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]'] + r, w = IO.pipe + 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(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} + } + refute(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 +end diff --git a/test/ruby/test_iterator.rb b/test/ruby/test_iterator.rb index 2cd48b29a4..362becc0e0 100644 --- a/test/ruby/test_iterator.rb +++ b/test/ruby/test_iterator.rb @@ -5,8 +5,8 @@ class Array collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]} end def iter_test2 - a = collect{|e| [e, yield(e)]} - a.sort{|a,b|a[1]<=>b[1]} + ary = collect{|e| [e, yield(e)]} + ary.sort{|a,b|a[1]<=>b[1]} end end @@ -51,10 +51,10 @@ class TestIterator < Test::Unit::TestCase def test_nested_iterator i = 0 - tt{|i| break if i == 5} - assert_equal(5, i) + tt{|j| break if j == 5} + assert_equal(0, i) - assert_raises(ArgumentError) do + assert_raise(ArgumentError) do tt3{} end end @@ -64,12 +64,12 @@ class TestIterator < Test::Unit::TestCase end def test_block_argument_without_paren - assert_raises(ArgumentError) do + assert_raise(ArgumentError) do tt4{} end end - # iterator break/redo/next/retry + # iterator break/redo/next def test_break done = true loop{ @@ -104,18 +104,6 @@ class TestIterator < Test::Unit::TestCase end assert_equal(7, $x.size) assert_equal([1, 2, 3, 4, 5, 6, 7], $x) - - $done = false - $x = [] - for i in 1 .. 7 # see how retry works in iterator loop - if i == 4 and not $done - $done = true - retry - end - $x.push(i) - end - assert_equal(10, $x.size) - assert_equal([1, 2, 3, 1, 2, 3, 4, 5, 6, 7], $x) end def test_append_method_to_built_in_class @@ -149,11 +137,9 @@ class TestIterator < Test::Unit::TestCase 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]]).each0 {|x| assert_equal([0], x)} @@ -166,8 +152,8 @@ class TestIterator < Test::Unit::TestCase 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)} + 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) @@ -230,10 +216,10 @@ class TestIterator < Test::Unit::TestCase def test_argument assert_nothing_raised {lambda{||}.call} - assert_raises(ArgumentError) {lambda{||}.call(1)} + assert_raise(ArgumentError) {lambda{||}.call(1)} assert_nothing_raised {lambda{|a,|}.call(1)} - assert_raises(ArgumentError) {lambda{|a,|}.call()} - assert_raises(ArgumentError) {lambda{|a,|}.call(1,2)} + assert_raise(ArgumentError) {lambda{|a,|}.call()} + assert_raise(ArgumentError) {lambda{|a,|}.call(1,2)} end def get_block(&block) @@ -249,9 +235,9 @@ class TestIterator < Test::Unit::TestCase assert_nothing_raised {get_block{|a,|}.call(1,2)} assert_nothing_raised {get_block(&lambda{||}).call()} - assert_raises(ArgumentError) {get_block(&lambda{||}).call(1)} + assert_raise(ArgumentError) {get_block(&lambda{||}).call(1)} assert_nothing_raised {get_block(&lambda{|a,|}).call(1)} - assert_raises(ArgumentError) {get_block(&lambda{|a,|}).call(1,2)} + assert_raise(ArgumentError) {get_block(&lambda{|a,|}).call(1,2)} block = get_block{11} assert_instance_of(Proc, block) @@ -259,11 +245,11 @@ class TestIterator < Test::Unit::TestCase assert_equal(block.clone.call, 11) assert_instance_of(Proc, get_block(&block)) - lambda = lambda{44} - assert_instance_of(Proc, lambda) - assert_instance_of(Proc, lambda.to_proc) - assert_equal(lambda.clone.call, 44) - assert_instance_of(Proc, get_block(&lambda)) + 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)} @@ -312,14 +298,21 @@ class TestIterator < Test::Unit::TestCase end def test_ljump - block = get_block{11} - lambda = lambda{44} - assert_raises(LocalJumpError) {get_block{break}.call} - assert_nothing_raised {lambda{break}.call} - assert_instance_of(LocalJumpError, (get_block{break}.call rescue $!)) + 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 - assert_equal(-1, block.arity) - assert_equal(-1, lambda.arity) + 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) @@ -327,8 +320,8 @@ class TestIterator < Test::Unit::TestCase end def marity_test(m) - method = method(m) - assert_equal(method.arity, method.to_proc.arity) + mobj = method(m) + assert_equal(mobj.arity, mobj.to_proc.arity) end def test_marity @@ -341,10 +334,10 @@ class TestIterator < Test::Unit::TestCase end def foo - yield([:key, :value]) + yield(:key, :value) end def bar(&blk) - blk.call([:key, :value]) + blk.call(:key, :value) end def test_yield_vs_call @@ -356,13 +349,19 @@ class TestIterator < Test::Unit::TestCase 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, :value]], a)} - h.each{|k,v| assert_equal([:key, :value], [k,v])} + [{: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 @@ -474,4 +473,25 @@ class TestIterator < Test::Unit::TestCase 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/test/ruby/test_lambda.rb b/test/ruby/test_lambda.rb new file mode 100644 index 0000000000..ae12c6d609 --- /dev/null +++ b/test/ruby/test_lambda.rb @@ -0,0 +1,73 @@ +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(a, 2) + assert_raise(ArgumentError) {1.times(&->(){ a += 1 })} + 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 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 +end diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb new file mode 100644 index 0000000000..e7a7c76891 --- /dev/null +++ b/test/ruby/test_literal.rb @@ -0,0 +1,293 @@ +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_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 + +end diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb new file mode 100644 index 0000000000..e92b85dbb8 --- /dev/null +++ b/test/ruby/test_m17n.rb @@ -0,0 +1,1431 @@ +require 'test/unit' +require 'stringio' + +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_warning(pat, mesg=nil) + begin + org_stderr = $stderr + $stderr = StringIO.new(warn = '') + yield + ensure + $stderr = org_stderr + end + assert_match(pat, warn, mesg) + end + + def assert_regexp_generic_encoding(r) + assert(!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(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([s1.encoding, s2.encoding].include?(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 + 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 + + def test_utf_16_32_inspect + str = "\u3042" + %w/UTF-16 UTF-32/.each do |enc| + %w/BE LE/.each do |endian| + s = str.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) + end + end + + str = "\uFEFF\u3042" + %w/UTF-16 UTF-32/.each do |enc| + %w/BE LE/.each do |endian| + s = str.encode(enc + endian) + # When a UTF-16/32 string doesn't have a BOM, + # inspect as a dummy encoding string. + assert_equal(s.inspect, + s.dup.force_encoding(enc).inspect) + end + end + 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(s.valid_encoding?, "#{pat2}") + else + assert(!s.valid_encoding?, "#{pat2}") + end + } + if / / =~ pat0 + pat3 = pat1.gsub(/X/, "0") + s = [pat3.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + assert(!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(!s.valid_encoding?, "#{pat1}") + } + } + pats.values_at(0,3).each {|pat| + s = [pat.gsub(/ /, "")].pack("B*").force_encoding("utf-8") + assert(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/}))) + + 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(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\p{Hiragana}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = /\p{Hiragana}/e + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = /\p{AsciI}/e + assert(r.fixed_encoding?) + assert_match(r, "a".force_encoding("euc-jp")) + + r = /\p{hiraganA}/e + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\u{3042}\p{Hiragana}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + + r = eval('/\p{Hiragana}\u{3042}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + end + + def test_regexp_embed_preprocess + r1 = /\xa4\xa2/e + r2 = /#{r1}/ + assert(r2.source.include?(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(r !~ a("")) + assert(r !~ e("")) + assert(r !~ s("")) + assert(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(a("a") < a("\xa1")) + assert(a("a") < s("\xa1")) + assert(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_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_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(s2.empty?) + assert(s2.ascii_only?) + end + + def test_sub3 + repl = "\x81".force_encoding("sjis") + assert_equal(false, repl.valid_encoding?) + s = "a@".sub(/a/, repl) + assert(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 + assert_equal(u("\xf0jihgfedcba"), u("abcdefghij\xf0").reverse) + 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 + 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) + assert_equal(locale_encoding, v.encoding) + } + 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(("".center(1, "\x80".force_encoding("utf-8")); true), + "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]') + end + + def test_combchar_codepoint + 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 +end diff --git a/test/ruby/test_m17n_comb.rb b/test/ruby/test_m17n_comb.rb new file mode 100644 index 0000000000..6eec6a6bea --- /dev/null +++ b/test/ruby/test_m17n_comb.rb @@ -0,0 +1,1633 @@ +require 'test/unit' +require 'stringio' +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("ASCII-8BIT") end + def e(str) str.dup.force_encoding("EUC-JP") end + def s(str) str.dup.force_encoding("Shift_JIS") 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_warning(pat, mesg=nil) + begin + org_stderr = $stderr + $stderr = StringIO.new(warn = '') + yield + ensure + $stderr = org_stderr + end + assert_match(pat, warn, mesg) + end + + def assert_regexp_generic_encoding(r) + assert(!r.fixed_encoding?) + %w[ASCII-8BIT EUC-JP Shift_JIS UTF-8].each {|ename| + # "\xc2\xa1" is a valid sequence for ASCII-8BIT, EUC-JP, Shift_JIS and UTF-8. + assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(ename) } + } + end + + def assert_regexp_fixed_encoding(r) + assert(r.fixed_encoding?) + %w[ASCII-8BIT EUC-JP Shift_JIS UTF-8].each {|ename| + enc = Encoding.find(ename) + if enc == r.encoding + assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(enc) } + else + assert_raise(ArgumentError) { r =~ "\xc2\xa1".force_encoding(enc) } + end + } + end + + def assert_regexp_generic_ascii(r) + assert_encoding("ASCII-8BIT", 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("Shift_JIS", 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 + + STRINGS = [ + a(""), e(""), s(""), u(""), + a("a"), e("a"), s("a"), u("a"), + a("."), e("."), s("."), u("."), + + # single character + a("\x80"), a("\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 + a("\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"), a("\xa1\xa1"), s("\xa1\xa1"), # [ruby-dev:36484] + + #"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 enccall(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 + result = nil + assert_nothing_raised(desc) { + result = recv.send(meth, *args, &block) + } + result + 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([s1.encoding, s2.encoding].include?(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(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(a(s1) + a(s2), a(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(t.valid_encoding?) if s.valid_encoding? + assert_strenc(a(s) * n, s.encoding, t) + } + } + end + + def test_sprintf_s + STRINGS.each {|s| + assert_strenc(a(s), s.encoding, "%s".force_encoding(s.encoding) % s) + if !s.empty? # xxx + t = enccall(a("%s"), :%, s) + assert_strenc(a(s), (a('')+s).encoding, t) + end + } + end + + def test_str_eq_reflexive + STRINGS.each {|s| + assert(s == s, "#{encdump s} == #{encdump s}") + } + end + + def test_str_eq_symmetric + combination(STRINGS, STRINGS) {|s1, s2| + if s1 == s2 + assert(s2 == s1, "#{encdump s2} == #{encdump s1}") + else + assert(!(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(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 a(s1) == a(s2) and + (s1.ascii_only? && s2.ascii_only? or + s1.encoding == s2.encoding) then + assert(s1 == s2, desc_eq) + assert(!(s1 != s2)) + assert_equal(0, s1 <=> s2) + assert(s1.eql?(s2), desc_eq) + else + assert(!(s1 == s2), "!(#{desc_eq})") + assert(s1 != s2) + assert_not_equal(0, s1 <=> s2) + assert(!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(s.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(a(s), a(s1) + a(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(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(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(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert_equal(s2, t) + assert_match(/#{Regexp.escape(a(s2))}/, a(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(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(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + t[i,len] = s2 + assert(a(t).index(a(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(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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(!s.valid_encoding?) + next + end + assert(t1.valid_encoding?) if s.valid_encoding? + assert(t1.casecmp(s)) + t2 = s.dup + t2.capitalize! + assert_equal(t1, t2) + r = s.downcase + r = enccall(r, :sub, /\A[a-z]/) {|ch| a(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(a(t).index(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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(a(t).index(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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(a(t).index(a(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(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? + assert(a(t).index(a(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) { s1.chomp(s2) } + end + next + end + t = enccall(s1, :chomp, s2) + assert(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_chop + STRINGS.each {|s| + s = s.dup + desc = "#{encdump s}.chop" + t = nil + assert_nothing_raised(desc) { t = s.chop } + assert(t.valid_encoding?) if s.valid_encoding? + assert(a(s).index(a(t))) + t2 = s.dup + t2.chop! + assert_equal(t, t2) + } + end + + def test_str_clear + STRINGS.each {|s| + t = s.dup + t.clear + assert(t.valid_encoding?) + assert(t.empty?) + } + end + + def test_str_clone + STRINGS.each {|s| + t = s.clone + assert_equal(s, t) + assert_equal(s.encoding, t.encoding) + assert_equal(a(s), a(t)) + } + end + + def test_str_dup + STRINGS.each {|s| + t = s.dup + assert_equal(s, t) + assert_equal(s.encoding, t.encoding) + assert_equal(a(s), a(t)) + } + end + + def test_str_count + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.valid_encoding? || !s2.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.count(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + assert_raise(Encoding::CompatibilityError) { s1.count(s2) } + next + end + n = enccall(s1, :count, s2) + n0 = a(s1).count(a(s2)) + assert_operator(n, :<=, n0) + } + end + + def test_str_crypt + begin + # glibc 2.16 or later denies salt contained other than [0-9A-Za-z./] #7312 + glibcver = `#{RbConfig::CONFIG["libdir"]}/libc.so.6`[/\AGNU C Library.*version ([0-9.]+)/, 1].split('.').map(&:to_i) + strict_crypt = (glibcver <=> [2, 16]) > -1 + rescue + end + + combination(STRINGS, STRINGS) {|str, salt| + if strict_crypt + next unless salt.ascii_only? && /\A[0-9a-zA-Z.\/]+\z/ =~ salt + end + if a(salt).length < 2 + assert_raise(ArgumentError) { str.crypt(salt) } + next + end + t = str.crypt(salt) + assert_equal(a(str).crypt(a(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(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(t.valid_encoding?) + assert_equal(t.encoding, s.encoding) + assert(t.casecmp(s)) + t2 = s.dup + t2.downcase! + assert_equal(t, t2) + } + end + + def test_str_dump + STRINGS.each {|s| + t = s.dump + assert(t.valid_encoding?) + assert(t.ascii_only?) + u = eval(t) + assert_equal(a(s), a(u)) + } + end + + def test_str_each_line + combination(STRINGS, STRINGS) {|s1, s2| + if !s1.valid_encoding? || !s2.valid_encoding? + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.each_line(s2) {} } + next + end + 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(line.valid_encoding?) + 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 + } + a(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(s.empty?) + else + assert(!s.empty?) + end + } + end + + def test_str_hex + STRINGS.each {|s| + t = s.hex + t2 = a(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(a(s1).include?(a(s2))) + assert(s1.index(s2)) + assert(s1.rindex(s2)) + else + assert(!s1.index(s2)) + assert(!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(a(s1).index(a(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/ =~ a(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 = a(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| + if !s2.valid_encoding? + assert_raise(RegexpError) { s1.scan(s2) } + next + end + if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding + if s1.valid_encoding? + assert_raise(Encoding::CompatibilityError) { s1.scan(s2) } + else + assert_match(/invalid byte sequence/, assert_raise(ArgumentError) { s1.scan(s2) }.message) + end + next + end + if !s1.valid_encoding? + assert_raise(ArgumentError) { s1.scan(s2) } + next + end + r = enccall(s1, :scan, s2) + r.each {|t| + assert_equal(s2, t) + } + } + 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(r.valid_encoding?) + assert(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(a(s1).include?(a(r))) + assert_equal(s1.encoding, r.encoding) + } + assert(a(s1).include?(t.map {|u| a(u) }.join(a(s2)))) + if s1.valid_encoding? && s2.valid_encoding? + t.each {|r| + assert(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(a(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(t1.valid_encoding?) if s.valid_encoding? + assert(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_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(t1.valid_encoding?) + assert(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(t.valid_encoding?, "#{encdump s}.succ.valid_encoding?") + end + s = t + } + } + 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/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 11f3583076..0f3f794572 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -1,16 +1,19 @@ require 'test/unit' -dir = File.dirname(File.expand_path(__FILE__)) -orgpath = $:.dup -begin - $:.push(dir) - require 'marshaltestlib' -ensure - $:.replace(orgpath) -end +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 @@ -29,20 +32,39 @@ class TestMarshal < Test::Unit::TestCase return f end - StrClone=String.clone; - def test_marshal - $x = [1,2,3,[4,5,"foo"],{1=>"bar"},2.5,fact(30)] - $y = Marshal.dump($x) - assert_equal($x, Marshal.load($y)) + 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 - [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z| - a = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f)) - ma = Marshal.dump(a) - b = Marshal.load(ma) - assert_equal(a, b) + 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) + Marshal.load("\004\bIc&TestMarshal::StructInvalidMembers\006:\020__members__\"\bfoo") + assert_raise(TypeError, "[ruby-dev:31759]") { + TestMarshal::StructInvalidMembers.members } end @@ -50,6 +72,7 @@ class TestMarshal < Test::Unit::TestCase def initialize(str) @str = str end + attr_reader :str def _dump(limit) @str end @@ -59,10 +82,423 @@ class TestMarshal < Test::Unit::TestCase end def test_too_long_string - (data = Marshal.dump(C.new("a")))[-2, 1] = "\003\377\377\377" + data = Marshal.dump(C.new("a".force_encoding("ascii-8bit"))) + data[-2, 1] = "\003\377\377\377" e = assert_raise(ArgumentError, "[ruby-dev:32054]") { Marshal.load(data) } assert_equal("marshal data too short", e.message) 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) + + r, w = IO.pipe + t = Thread.new { Marshal.load(r) } + Marshal.dump(o1, w) + o2 = t.value + assert_equal(o1.str, o2.str) + + r, w = IO.pipe + t = Thread.new { Marshal.load(r) } + Marshal.dump(o1, w, 2) + o2 = t.value + assert_equal(o1.str, o2.str) + + 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_and_untrust + x = Object.new + x.taint + x.untrust + s = Marshal.dump(x) + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + y = Marshal.load(s) + assert_equal(true, y.tainted?) + assert_equal(true, y.untrusted?) + end + + def test_taint_and_untrust_each_object + x = Object.new + obj = [[x]] + + # clean object causes crean stream + assert_equal(false, obj.tainted?) + assert_equal(false, obj.untrusted?) + assert_equal(false, obj.first.tainted?) + assert_equal(false, obj.first.untrusted?) + assert_equal(false, obj.first.first.tainted?) + assert_equal(false, obj.first.first.untrusted?) + s = Marshal.dump(obj) + assert_equal(false, s.tainted?) + assert_equal(false, s.untrusted?) + + # tainted/untrusted object causes tainted/untrusted stream + x.taint + x.untrust + assert_equal(false, obj.tainted?) + assert_equal(false, obj.untrusted?) + assert_equal(false, obj.first.tainted?) + assert_equal(false, obj.first.untrusted?) + assert_equal(true, obj.first.first.tainted?) + assert_equal(true, obj.first.first.untrusted?) + t = Marshal.dump(obj) + assert_equal(true, t.tainted?) + assert_equal(true, t.untrusted?) + + # clean stream causes clean objects + assert_equal(false, s.tainted?) + assert_equal(false, s.untrusted?) + y = Marshal.load(s) + assert_equal(false, y.tainted?) + assert_equal(false, y.untrusted?) + assert_equal(false, y.first.tainted?) + assert_equal(false, y.first.untrusted?) + assert_equal(false, y.first.first.tainted?) + assert_equal(false, y.first.first.untrusted?) + + # tainted/untrusted stream causes tainted/untrusted objects + assert_equal(true, t.tainted?) + assert_equal(true, t.untrusted?) + y = Marshal.load(t) + assert_equal(true, y.tainted?) + assert_equal(true, y.untrusted?) + assert_equal(true, y.first.tainted?) + assert_equal(true, y.first.untrusted?) + assert_equal(true, y.first.first.tainted?) + assert_equal(true, y.first.first.untrusted?) + + # same tests by different senario + s.taint + s.untrust + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + y = Marshal.load(s) + assert_equal(true, y.tainted?) + assert_equal(true, y.untrusted?) + assert_equal(true, y.first.tainted?) + assert_equal(true, y.first.untrusted?) + assert_equal(true, y.first.first.tainted?) + assert_equal(true, y.first.first.untrusted?) + end + + def test_symbol + [: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 + + 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_regexp + 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.open("marshal_regexp") do |f| + f.binmode.write("\x04\bI/\x00\x00\x06:\rencoding\"\rUS-ASCII") + f.close + Marshal.load(f.open.binmode) + 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 + + 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 + + class TestClass + end + + module TestModule + end + + def test_marshal_load_should_not_taint_classes + bug7325 = '[ruby-core:49198]' + for c in [TestClass, TestModule] + assert(!c.tainted?) + assert(!c.untrusted?) + c2 = Marshal.load(Marshal.dump(c).taint.untrust) + assert_same(c, c2) + assert(!c.tainted?, bug7325) + assert(!c.untrusted?, bug7325) + end + end end diff --git a/test/ruby/test_math.rb b/test/ruby/test_math.rb index e1e49dba01..3895eec7f5 100644 --- a/test/ruby/test_math.rb +++ b/test/ruby/test_math.rb @@ -1,12 +1,281 @@ require 'test/unit' class TestMath < Test::Unit::TestCase - def test_math - assert_equal(2, Math.sqrt(4)) + def assert_infinity(a, *rest) + rest = ["not infinity: #{a.inspect}"] if rest.empty? + assert(!a.finite?, *rest) + end + + def assert_nan(a, *rest) + rest = ["not nan: #{a.inspect}"] if rest.empty? + assert(a.nan?, *rest) + end + + def check(a, b) + err = [Float::EPSILON * 4, [a.abs, b.abs].max * Float::EPSILON * 256].max + assert_in_delta(a, b, err) + end + + 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)) + assert_raise(Math::DomainError) { Math.atan2(Float::INFINITY, Float::INFINITY) } + assert_raise(Math::DomainError) { Math.atan2(Float::INFINITY, -Float::INFINITY) } + assert_raise(Math::DomainError) { Math.atan2(-Float::INFINITY, Float::INFINITY) } + assert_raise(Math::DomainError) { Math.atan2(-Float::INFINITY, -Float::INFINITY) } + 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(Math.tan(2 * Math::PI / 4).abs > 1024) + check(0.0, Math.tan(4 * Math::PI / 4)) + assert(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)) + 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) } + end + + def test_log2 + check(0, Math.log2(1)) + check(1, Math.log2(2)) + check(2, Math.log2(4)) + 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)) + 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 - self.class.class_eval { - include Math - } - assert_equal(2, sqrt(4)) + 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/test/ruby/test_metaclass.rb b/test/ruby/test_metaclass.rb new file mode 100644 index 0000000000..6386a02dfa --- /dev/null +++ b/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/test/ruby/test_method.rb b/test/ruby/test_method.rb index ef28098dce..889c50efbe 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -1,6 +1,16 @@ require 'test/unit' +require_relative 'envutil' 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 @@ -8,18 +18,40 @@ class TestMethod < Test::Unit::TestCase 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) end class Base def foo() :base end - def bar() :bar end - end - module SuperBar - def bar() super end end class Derived < Base - include SuperBar def foo() :derived end end + class T + def initialize; end + def normal_method; end + end + module M + def func; end + module_function :func + def 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) @@ -29,6 +61,12 @@ class TestMethod < Test::Unit::TestCase 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) + end + + def test_arity_special + assert_equal(-1, method(:__send__).arity) end def test_unbind @@ -45,9 +83,407 @@ class TestMethod < Test::Unit::TestCase end end - def test_method_super - assert_nothing_raised do - assert_equal(:bar, Derived.new.method(:bar).call) + 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")) + 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) + 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) + 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) } + 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 + + 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 + + assert_raise(TypeError) do + Class.new.class_eval {define_method(:meth, M.instance_method(:meth))} + 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_call + o = Object.new + def o.foo; p 1; end + def o.bar(x); x; end + m = o.method(:foo) + m.taint + assert_raise(SecurityError) { m.call } + 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) + 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 + assert T.public_instance_methods.include?(:normal_method), 'normal methods are public by default' + assert !T.public_instance_methods.include?(:initialize), '#initialize is private' + assert !M.public_instance_methods.include?(:func), 'module methods are private by default' + assert M.public_instance_methods.include?(: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|} + + 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) + 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) + 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) + 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) + 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(true, 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(true, 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 + 1000.times {p = Bug6171.new('test'); 10000.times {p.reverse}} + EOC + 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 end diff --git a/test/ruby/test_mixed_unicode_escapes.rb b/test/ruby/test_mixed_unicode_escapes.rb new file mode 100644 index 0000000000..982b57e286 --- /dev/null +++ b/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/test/ruby/test_module.rb b/test/ruby/test_module.rb new file mode 100644 index 0000000000..1fe67df2be --- /dev/null +++ b/test/ruby/test_module.rb @@ -0,0 +1,1267 @@ +require 'test/unit' +require 'pp' +require_relative 'envutil' + +$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 + + def remove_pp_mixins(list) + list.reject {|c| c == PP::ObjectMixin } + end + + def remove_json_mixins(list) + list.reject {|c| c.to_s.start_with?("JSON") } + end + + def remove_rake_mixins(list) + list.reject {|c| + name = c.name + name.start_with?("Rake") or name.start_with?("FileUtils") + } + end + + def remove_minitest_mixins(list) + list.reject {|c| c.to_s.start_with?("MiniTest") } + end + + 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(Mixin >= User) + assert(Mixin >= Mixin) + assert(!(User >= Mixin)) + + assert(Object >= String) + assert(String >= String) + assert(!(String >= Object)) + end + + def test_GT # '>' + assert(Mixin > User) + assert(!(Mixin > Mixin)) + assert(!(User > Mixin)) + + assert(Object > String) + assert(!(String > String)) + assert(!(String > Object)) + end + + def test_LE # '<=' + assert(User <= Mixin) + assert(Mixin <= Mixin) + assert(!(Mixin <= User)) + + assert(String <= Object) + assert(String <= String) + assert(!(Object <= String)) + end + + def test_LT # '<' + assert(User < Mixin) + assert(!(Mixin < Mixin)) + assert(!(Mixin < User)) + + assert(String < Object) + assert(!(String < String)) + assert(!(Object < String)) + end + + def test_VERY_EQUAL # '===' + assert(Object === self) + assert(Test::Unit::TestCase === self) + assert(TestModule === self) + assert(!(String === self)) + end + + def test_ancestors + assert_equal([User, Mixin], User.ancestors) + assert_equal([Mixin], Mixin.ancestors) + + assert_equal([Object, Kernel, BasicObject], + remove_minitest_mixins(remove_rake_mixins(remove_json_mixins(remove_pp_mixins(Object.ancestors))))) + assert_equal([String, Comparable, Object, Kernel, BasicObject], + remove_minitest_mixins(remove_rake_mixins(remove_json_mixins(remove_pp_mixins(String.ancestors))))) + end + + CLASS_EVAL = 2 + @@class_eval = 'b' + + def test_class_eval + Other.class_eval("CLASS_EVAL = 1") + assert_equal(1, Other::CLASS_EVAL) + assert(Other.constants.include?(: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(Math.const_defined?(:PI)) + assert(Math.const_defined?("PI")) + assert(!Math.const_defined?(:IP)) + assert(!Math.const_defined?("IP")) + end + + def test_const_get + assert_equal(Math::PI, Math.const_get("PI")) + assert_equal(Math::PI, Math.const_get(:PI)) + end + + def test_const_set + assert(!Other.const_defined?(:KOALA)) + Other.const_set(:KOALA, 99) + assert(Other.const_defined?(:KOALA)) + assert_equal(99, Other::KOALA) + Other.const_set("WOMBAT", "Hi") + assert_equal("Hi", Other::WOMBAT) + 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_included_modules + assert_equal([], Mixin.included_modules) + assert_equal([Mixin], User.included_modules) + assert_equal([Kernel], + remove_minitest_mixins(remove_rake_mixins(remove_json_mixins(remove_pp_mixins(Object.included_modules))))) + assert_equal([Comparable, Kernel], + remove_minitest_mixins(remove_rake_mixins(remove_json_mixins(remove_pp_mixins(String.included_modules))))) + 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(User.constants.include?(:MODULE_EVAL)) + User.instance_eval("remove_const(:MODULE_EVAL)") + assert(!User.constants.include?(: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_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) } + + 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_raise(NameError) { c1.const_get(:foo) } + end + + def test_const_set_invalid_name + c1 = Class.new + assert_raise(NameError) { c1.const_set(:foo, :foo) } + end + + def test_const_get_invalid_name + c1 = Class.new + assert_raise(NameError) { c1.const_defined?(:foo) } + 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(:foo) } + 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(:foo, 1) } + 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?(:foo) } + 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 + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + Class.instance_eval { undef_method(:foo) } + end.join + end + + 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, [], /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_class + m = Module.new + m.freeze + assert_raise(RuntimeError) do + m.instance_eval { undef_method(:foo) } + end + + c = Class.new + c.freeze + assert_raise(RuntimeError) do + c.instance_eval { undef_method(:foo) } + end + + o = Object.new + c = class << o; self; end + c.freeze + assert_raise(RuntimeError) do + c.instance_eval { undef_method(:foo) } + 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_change_visibility_under_safe4 + c = Class.new + c.class_eval do + def foo; end + end + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + c.class_eval { private :foo } + end.join + end + 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_include_under_safe4 + m = Module.new + c1 = Class.new + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + c1.instance_eval { include(m) } + }.call + end + assert_nothing_raised do + lambda { + $SAFE = 4 + c2 = Class.new + c2.instance_eval { include(m) } + }.call + end + 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) + + stderr = EnvUtil.verbose_warning do + Module.new do + def foo; end + alias bar foo + def foo; end + end + end + assert_equal("", stderr) + + stderr = EnvUtil.verbose_warning do + Module.new do + def foo; end + alias bar foo + alias bar foo + end + end + assert_equal("", stderr) + + 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) + + stderr = EnvUtil.verbose_warning do + Module.new do + define_method(:foo) do end + alias bar foo + alias barf oo + end + end + assert_equal("", stderr) + + stderr = EnvUtil.verbose_warning do + Module.new do + module_function + def foo; end + module_function :foo + end + end + assert_equal("", stderr, '[ruby-dev:39397]') + + stderr = EnvUtil.verbose_warning do + Module.new do + def foo; end + undef foo + end + end + assert_equal("", stderr) + 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_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 + + 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(!(::TestModule).constants.include?(: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 + + 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 +end diff --git a/test/ruby/test_notimp.rb b/test/ruby/test_notimp.rb new file mode 100644 index 0000000000..c29119eac9 --- /dev/null +++ b/test/ruby/test_notimp.rb @@ -0,0 +1,64 @@ +require 'test/unit' +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 + if Process.respond_to?(:fork) + assert_nothing_raised { + pid = fork {} + Process.wait pid + } + end + end + + 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/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb new file mode 100644 index 0000000000..9667046916 --- /dev/null +++ b/test/ruby/test_numeric.rb @@ -0,0 +1,235 @@ +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 } + 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(1 <= a) + + DummyNumeric.class_eval do + remove_method :coerce + def coerce(x); [x, 1]; end + end + assert_equal(-1, -a) + + ensure + DummyNumeric.class_eval do + remove_method :coerce + end + end + + def test_numeric + a = Numeric.new + assert_raise(TypeError) { def a.foo; end } + assert_raise(TypeError) { eval("def a.\u3042; end") } + assert_raise(TypeError) { a.dup } + end + + def test_quo + assert_raise(ArgumentError) {DummyNumeric.new.quo(1)} + 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(Numeric.new.real?) + end + + def test_integer_p + assert(!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(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 test_step + a = [] + 1.step(10) {|x| a << x } + assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a) + + a = [] + 1.step(10, 2) {|x| a << x } + assert_equal([1, 3, 5, 7, 9], a) + + assert_raise(ArgumentError) { 1.step(10, 1, 0) { } } + assert_raise(ArgumentError) { 1.step(10, 0) { } } + + a = [] + 10.step(1, -2) {|x| a << x } + assert_equal([10, 8, 6, 4, 2], a) + + a = [] + 1.0.step(10.0, 2.0) {|x| a << x } + assert_equal([1.0, 3.0, 5.0, 7.0, 9.0], a) + + a = [] + 1.step(10, 2**32) {|x| a << x } + assert_equal([1], a) + + a = [] + 10.step(1, -(2**32)) {|x| a << x } + assert_equal([10], a) + + a = [] + 1.step(0, Float::INFINITY) {|x| a << x } + assert_equal([], a) + + a = [] + 0.step(1, -Float::INFINITY) {|x| a << x } + assert_equal([], a) + 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_equal(1, 1 & o) + end + + def test_eql + assert(1 == 1.0) + assert(!(1.eql?(1.0))) + assert(!(1.eql?(2))) + end +end diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb new file mode 100644 index 0000000000..3705df21c1 --- /dev/null +++ b/test/ruby/test_object.rb @@ -0,0 +1,687 @@ +require 'test/unit' +require_relative 'envutil' + +class TestObject < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + 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_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_under_safe_4 + o = Object.new + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + o.freeze + end.join + end + end + + def test_freeze_immediate + assert_equal(false, 1.frozen?) + 1.freeze + assert_equal(true, 1.frozen?) + assert_equal(false, 2.frozen?) + 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_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(:foo) } + 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(:foo, 1) } + 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?(:foo) } + end + + def test_remove_instance_variable + o = Object.new + o.instance_eval { @foo = :foo } + o.instance_eval { 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_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_add_method_under_safe4 + o = Object.new + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + def o.foo + end + end.join + end + 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, [], /warning: redefining `object_id' may cause serious problems$/) + $VERBOSE = false + def (Object.new).object_id; end + INPUT + + assert_in_out_err([], <<-INPUT, [], /warning: redefining `__send__' may cause serious problems$/) + $VERBOSE = false + def (Object.new).__send__; end + INPUT + end + + def test_remove_method + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + Object.instance_eval { remove_method(:foo) } + end.join + end + + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + Class.instance_eval { remove_method(:foo) } + end.join + end + + 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), /warning: removing `#{m}' may cause serious problems$/) + $VERBOSE = false + begin + Class.new.instance_eval { remove_method(:#{m}) } + rescue NameError + p :ok + end + INPUT + 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 + c = Class.new do + def respond_to_missing?(id, priv=false) + 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(foo.respond_to?(:foobar)) + assert_equal(false, foo.respond_to?(: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_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_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 + obj = lambda { + $SAFE = 4 + x = Object.new + x.instance_eval { @foo = 1 } + x + }.call + assert_equal(true, obj.untrusted?) + assert_equal(true, obj.tainted?) + + x = Object.new + assert_equal(false, x.untrusted?) + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x = Object.new + x.taint + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x.untrust + assert_equal(true, x.untrusted?) + assert_nothing_raised do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x.trust + assert_equal(false, x.untrusted?) + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + a = Object.new + a.untrust + assert_equal(true, a.untrusted?) + b = a.dup + assert_equal(true, b.untrusted?) + c = a.clone + assert_equal(true, c.untrusted?) + + a = Object.new + b = lambda { + $SAFE = 4 + a.dup + }.call + assert_equal(true, b.untrusted?) + + a = Object.new + b = lambda { + $SAFE = 4 + a.clone + }.call + assert_equal(true, b.untrusted?) + end + + def test_to_s + x = Object.new + x.taint + x.untrust + s = x.to_s + assert_equal(true, s.untrusted?) + assert_equal(true, s.tainted?) + end + + def test_exec_recursive + Thread.current[:__recursive_key__] = nil + a = [[]] + a.inspect + + assert_nothing_raised do + -> do + $SAFE = 4 + begin + a.hash + rescue ArgumentError + end + end.call + end + + -> do + assert_nothing_raised do + $SAFE = 4 + a.inspect + end + end.call + + -> do + o = Object.new + def o.to_ary(x); end + def o.==(x); $SAFE = 4; false; end + a = [[o]] + b = [] + b << b + + assert_nothing_raised do + b == a + end + end.call + 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 +end diff --git a/test/ruby/test_objectspace.rb b/test/ruby/test_objectspace.rb index a2d0164954..24731a7a50 100644 --- a/test/ruby/test_objectspace.rb +++ b/test/ruby/test_objectspace.rb @@ -1,4 +1,5 @@ require 'test/unit' +require_relative 'envutil' class TestObjectSpace < Test::Unit::TestCase def self.deftest_id2ref(obj) @@ -33,4 +34,35 @@ End deftest_id2ref(true) deftest_id2ref(false) deftest_id2ref(nil) + + def test_count_objects + h = {} + ObjectSpace.count_objects(h) + assert_kind_of(Hash, h) + assert(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert(h.values.all? {|x| x.is_a?(Integer) }) + + h = ObjectSpace.count_objects + assert_kind_of(Hash, h) + assert(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert(h.values.all? {|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) } + end end diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb new file mode 100644 index 0000000000..ed604e7bc3 --- /dev/null +++ b/test/ruby/test_optimization.rb @@ -0,0 +1,163 @@ +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 redefine_method(klass, method) + (@redefine_method_seq ||= 0) + seq = (@redefine_method_seq += 1) + eval(<<-End, ::TOPLEVEL_BINDING) + class #{klass} + alias redefine_method_orig_#{seq} #{method} + undef #{method} + def #{method}(*args) + args[0] + end + end + End + begin + return yield + ensure + eval(<<-End, ::TOPLEVEL_BINDING) + class #{klass} + undef #{method} + alias #{method} redefine_method_orig_#{seq} + end + End + 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_equal 11, redefine_method('Fixnum', '+') { 10 + 11 } + assert_equal 21, 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_equal 3, redefine_method('Fixnum', '-') { 8 - 3 } + assert_equal 5, 8 - 3 + end + + def test_fixnum_mul + assert_equal 15, 3 * 5 + end + + def test_fixnum_div + assert_equal 3, 15 / 5 + end + + def test_fixnum_mod + assert_equal 1, 8 % 7 + end + + def test_float_plus + assert_equal 4.0, 2.0 + 2.0 + assert_equal 2.0, redefine_method('Float', '+') { 2.0 + 2.0 } + assert_equal 4.0, 2.0 + 2.0 + end + + def test_string_length + assert_equal 6, "string".length + assert_nil redefine_method('String', 'length') { "string".length } + assert_equal 6, "string".length + end + + def test_string_plus + assert_equal "", "" + "" + assert_equal "x", "x" + "" + assert_equal "x", "" + "x" + assert_equal "ab", "a" + "b" + assert_equal 'b', redefine_method('String', '+') { "a" + "b" } + assert_equal "ab", "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 + end + + def test_array_plus + assert_equal [1,2], [1]+[2] + end + + def test_array_minus + assert_equal [2], [1,2] - [1] + end + + def test_array_length + assert_equal 0, [].length + assert_equal 3, [1,2,3].length + end + + def test_hash_length + assert_equal 0, {}.length + assert_equal 1, {1=>1}.length + 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, + } + iseq = 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 +end diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb index e67465b33a..52beb9f8d4 100644 --- a/test/ruby/test_pack.rb +++ b/test/ruby/test_pack.rb @@ -20,6 +20,31 @@ class TestPack < Test::Unit::TestCase 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') @@ -40,21 +65,591 @@ class TestPack < Test::Unit::TestCase 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 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_raises(RangeError) { [-0x40000001].pack("U") } - assert_raises(RangeError) { [-0x40000000].pack("U") } - assert_raises(RangeError) { [-1].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", [0x3fffffff].pack("U") - assert_equal "\375\200\200\200\200\200", [0x40000000].pack("U") - assert_equal "\375\277\277\277\277\277", [0x7fffffff].pack("U") - assert_raises(RangeError) { [0x80000000].pack("U") } - assert_raises(RangeError) { [0x100000000].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_raise(ArgumentError) { (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")) + 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")) + 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*")) + + assert_equal(8, [1].pack("q").bytesize) + assert_equal(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(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([""], "".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(["\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")) + 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".unpack("M")) + assert_equal([""], "=\r\n".unpack("M")) + assert_equal([""], "=\r\n".unpack("M")) + assert_equal(["\xC6\xF7"], "=C6=F7".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_pack_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_modify_under_safe4 + s = "foo" + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + s.clear + end.join + end + 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 end diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb new file mode 100644 index 0000000000..6de57c1a22 --- /dev/null +++ b/test/ruby/test_parse.rb @@ -0,0 +1,841 @@ +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 + begin + else + 42 + end + END + assert_equal(42, x) + end + + def test_alias_backref + assert_raise(SyntaxError) do + eval <<-END + 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 + 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 + 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 + 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 + $1 ||= t.foo 42 + END + end + + def t.bar(x); x + yield; end + + a = b = nil + assert_nothing_raised do + eval <<-END + 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 + a = bar "foo" do "bar" end + END + end + assert_equal("foobar", a) + + a = nil + assert_nothing_raised do + eval <<-END + 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 + 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 + def foo + self::FOO, self::BAR = 1, 2 + ::FOO, ::BAR = 1, 2 + end + END + end + + assert_raise(SyntaxError) do + eval <<-END + $1, $2 = 1, 2 + END + end + + assert_raise(SyntaxError) do + Object.new.instance_eval <<-END + def foo + ::FOO = 1 + end + END + end + + c = Class.new + assert_raise(SyntaxError) do + eval <<-END + c::FOO &= 1 + ::FOO &= 1 + END + end + + c = Class.new + assert_raise(SyntaxError) do + eval <<-END + $1 &= 1 + END + end + end + + def test_class_module + assert_raise(SyntaxError) do + eval <<-END + class foo; end + END + end + + assert_raise(SyntaxError) do + eval <<-END + def foo + class Foo; end + module Bar; end + end + END + end + + assert_raise(SyntaxError) do + eval <<-END + class Foo Bar; end + END + end + end + + def test_op_name + o = Object.new + def o.>(x); x; end + def o./(x); x; end + + a = nil + assert_nothing_raised do + o.instance_eval <<-END + 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 + 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 + 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 + o.foo 1 do|; a| a = 42 end + END + end + assert_nil(a) + end + + def test_bad_arg + assert_raise(SyntaxError) do + eval <<-END + def foo(FOO); end + END + end + + assert_raise(SyntaxError) do + eval <<-END + def foo(@foo); end + END + end + + assert_raise(SyntaxError) do + eval <<-END + def foo($foo); end + END + end + + assert_raise(SyntaxError) do + eval <<-END + def foo(@@foo); end + END + end + + o = Object.new + def o.foo(*r); yield(*r); end + + assert_raise(SyntaxError) do + eval <<-END + o.foo 1 {|; @a| @a = 42 } + END + end + end + + def test_do_lambda + a = b = nil + assert_nothing_raised do + eval <<-END + 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 + 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 + 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_disallowd_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 + 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 + 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 + 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 + 1.times {|&b?| } + END + end + + assert_raise(SyntaxError) do + eval <<-END + 1.times {|a, a|} + END + end + + assert_raise(SyntaxError) do + eval <<-END + def foo(a, a); end + END + end + end + + def test_define_singleton_error + assert_raise(SyntaxError) do + eval <<-END + def ("foo").foo; end + END + end + end + + def test_backquote + t = Object.new + + assert_nothing_raised do + eval <<-END + def t.`(x); "foo" + x + "bar"; end + END + end + a = b = nil + assert_nothing_raised do + eval <<-END + a = t.` "zzz" + 1.times {|;z| t.` ("zzz") } + END + t.instance_eval <<-END + 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 +/ + 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 +# coding = utf-8 +x = __ENCODING__ + END + end + assert_equal(Encoding.find("UTF-8"), x) + + assert_raise(ArgumentError) do + eval <<-END +# 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 + 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 +=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('@#') } + end + + def test_invalid_class_variable + assert_raise(SyntaxError) { eval('@@1') } + end + + def test_invalid_char + x = 1 + assert_equal(1, eval("\x01x")) + 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 + def foo + FOO = 1 + end + END + end + end + + def test_block_dup + assert_raise(SyntaxError) do + eval <<-END + foo(&proc{}) {} + END + end + end + + def test_set_backref + assert_raise(SyntaxError) do + eval <<-END + $& = 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 + 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 + + o = Object.new + assert_nothing_raised do + eval <<-END + x = def o.foo; end + END + end + assert_equal($stderr.string.lines.to_a.size, 14) + $stderr = stderr + end + + def test_assign_in_conditional + assert_raise(SyntaxError) do + eval <<-END + (x, y = 1, 2) ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END + if @x = true + 1 + else + 2 + end + END + end + end + + def test_literal_in_conditional + assert_nothing_raised do + eval <<-END + "foo" ? 1 : 2 + END + end + + assert_nothing_raised do + x = "bar" + eval <<-END + /foo#{x}baz/ ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END + (true..false) ? 1 : 2 + END + end + + assert_nothing_raised do + eval <<-END + ("foo".."bar") ? 1 : 2 + END + end + + assert_nothing_raised do + x = "bar" + eval <<-END + :"foo#{"x"}baz" ? 1 : 2 + END + end + end + + def test_no_blockarg + assert_raise(SyntaxError) do + eval <<-END + 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(x.all? {|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 +end diff --git a/test/ruby/test_path.rb b/test/ruby/test_path.rb index 63dbd07346..2db7be0b76 100644 --- a/test/ruby/test_path.rb +++ b/test/ruby/test_path.rb @@ -35,22 +35,24 @@ class TestPath < Test::Unit::TestCase assert_equal("/sub", File.expand_path("sub", "/")) end if dosish - assert_equal("//machine/share", File.expand_path("/", "//machine/share/sub")) - assert_equal("//machine/share/dir", File.expand_path("/dir", "//machine/share/sub")) + 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 # [ruby-dev:27738] - if /(bcc|ms)win\d|mingw|cygwin|djgpp|human|emx/ =~ RUBY_PLATFORM + 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')) + 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')) @@ -62,7 +64,7 @@ class TestPath < Test::Unit::TestCase 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:///'), "[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')) @@ -101,7 +103,7 @@ class TestPath < Test::Unit::TestCase assert_equal('/', File.dirname('/a/')) assert_equal('/a', File.dirname('/a/b')) - if /(bcc|ms|cyg)win|mingw|djgpp|human|emx/ =~ RUBY_PLATFORM + if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM # DOSISH_UNC assert_equal('//', File.dirname('//')) assert_equal('//a', File.dirname('//a')) @@ -134,8 +136,8 @@ class TestPath < Test::Unit::TestCase end end - def test_basename # [ruby-dev:27766] - if /(bcc|ms)win\d|mingw|cygwin|djgpp|human|emx/ =~ RUBY_PLATFORM + 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')) @@ -189,12 +191,14 @@ class TestPath < Test::Unit::TestCase assert_equal('a', File.basename('/a/')) assert_equal('b', File.basename('/a/b')) - if /(bcc|ms|cyg)win|mingw|djgpp|human|emx/ =~ RUBY_PLATFORM + 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')) + assert_equal('/', File.basename('//a/b'), "[ruby-dev:27776]") assert_equal('/', File.basename('//a/b/')) assert_equal('c', File.basename('//a/b/c')) @@ -221,4 +225,35 @@ class TestPath < Test::Unit::TestCase 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/test/ruby/test_pipe.rb b/test/ruby/test_pipe.rb index c3b4d29c0a..34f231ad8c 100644 --- a/test/ruby/test_pipe.rb +++ b/test/ruby/test_pipe.rb @@ -1,7 +1,5 @@ require 'test/unit' -$:.replace([File.dirname(File.expand_path(__FILE__))] | $:) -require 'ut_eof' -require 'envutil' +require_relative 'ut_eof' class TestPipe < Test::Unit::TestCase include TestEOF diff --git a/test/ruby/test_primitive.rb b/test/ruby/test_primitive.rb new file mode 100644 index 0000000000..02dab78233 --- /dev/null +++ b/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(x.to_a_called, bug3658) + x.to_a_called = false + [0, *x, 2] + assert(x.to_a_called, bug3658) + end +end diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index f0b78ffb23..7560ce94ef 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -1,6 +1,16 @@ require 'test/unit' +require_relative 'envutil' 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)) @@ -50,40 +60,812 @@ class TestProc < Test::Unit::TestCase end def test_arity - assert_equal(-1, proc{}.arity) + assert_equal(0, proc{}.arity) assert_equal(0, proc{||}.arity) assert_equal(1, proc{|x|}.arity) assert_equal(2, proc{|x, y|}.arity) assert_equal(-2, proc{|x, *y|}.arity) assert_equal(-1, proc{|*x|}.arity) assert_equal(-1, proc{|*|}.arity) + assert_equal(-3, proc{|x, *y, z|}.arity) + assert_equal(-4, proc{|x, *y, z, a|}.arity) - assert_arity(-1) {} + 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) {|*|} end - # [ruby-dev:22592] def m(x) lambda { x } end + def test_eq - # [ruby-dev:22592] a = m(1) b = m(2) - assert_not_equal(a, b) - assert_not_equal(a.call, b.call) + assert_not_equal(a, b, "[ruby-dev:22592]") + assert_not_equal(a.call, b.call, "[ruby-dev:22592]") - # [ruby-dev:22599] - assert_not_equal(proc {||}, proc {|x,y|}) + assert_not_equal(proc {||}, proc {|x,y|}, "[ruby-dev:22599]") - # [ruby-dev:22601] a = lambda {|x| lambda {} }.call(1) b = lambda {} - assert_not_equal(a, b) + 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 + assert_instance_of(Binding, b.binding, '[ruby-core:25589]') + 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_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; 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 + end + + def test_eq2 + b1 = proc { } + b2 = b1.dup + assert(b1 == b2) + end + + def test_to_proc + b = proc { :foo } + assert_equal(:foo, b.to_proc.call) + end + + def test_localjump_error + 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_rest_and_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_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_and_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_and_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_and_rest_and_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_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, 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_rest_and_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_and_post_and_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_opt_and_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_and_post_and_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_and_block2 + 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_and_rest_and_post_and_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_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|}.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) 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([], "".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(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 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_overriden_lambda + bug8345 = '[ruby-core:54687] [Bug #8345]' + assert_normal_exit('def lambda; end; method(:puts).to_proc', bug8345) + end + + def test_overriden_proc + bug8345 = '[ruby-core:54688] [Bug #8345]' + assert_normal_exit('def proc; end; ->{}.curry', bug8345) end end diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 93eb871edc..83ff379ca9 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -1,6 +1,46 @@ require 'test/unit' +require 'tmpdir' +require 'pathname' +require 'timeout' +require_relative 'envutil' +require 'rbconfig' class TestProcess < Test::Unit::TestCase + RUBY = EnvUtil.rubybin + + def setup + Process.waitall + end + + def teardown + Process.waitall + end + + def 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 = Pathname.new(d).realpath.to_s + 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) @@ -21,21 +61,1285 @@ class TestProcess < Test::Unit::TestCase def test_rlimit_nofile return unless rlimit_exist? - pid = fork { - cur_nofile, max_nofile = Process.getrlimit(Process::RLIMIT_NOFILE) - begin - Process.setrlimit(Process::RLIMIT_NOFILE, 0, max_nofile) - rescue Errno::EINVAL - exit 0 + with_tmpchdir { + write_file 's', <<-"End" + # if limit=0, this test freeze pn OpenBSD + limit = /openbsd/ =~ RUBY_PLATFORM ? 1 : 0 + 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") } + end + + def test_rlimit_value + return unless rlimit_exist? + assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) } + 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_equal(0, s.exitstatus) + 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_equal(0, s.exitstatus) + 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]) + 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_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 + + 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 + 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(!File.read("out").empty?) # 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")) + + 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 + + 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_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 + return if /freebsd/ =~ RUBY_PLATFORM # this test freeze in FreeBSD + 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.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}) + End + 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')"]) + w.close + errmsg = io.read + assert_equal("", r.read) + assert_not_equal("", errmsg) + Process.wait + } + 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| + 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]) + w.close + errmsg = io.read + assert_equal("", r.read) + assert_not_equal("", errmsg) + Process.wait + } + with_pipe {|r, w| + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>false]) + w.close + errmsg = io.read + assert_equal("mo\n", r.read) + assert_equal("", errmsg) + Process.wait + } + with_pipe {|r, w| + io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>nil]) + w.close + errmsg = io.read + assert_equal("mo\n", r.read) + assert_equal("", errmsg) + Process.wait + } + + } + 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_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(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(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(status.exited?) + assert_equal(7, status.exitstatus) + assert_equal("fufu 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(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(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(status.exited?) + assert(!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(status.exited?) + assert(status.success?) + assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]') + pid = spawn(%[#{bat.dump} "foo 'bar'"]) + Process.wait pid + status = $? + assert(status.exited?) + assert(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(status.exited?) + assert(!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(status.exited?) + assert(!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"]).read) + Process.wait + + 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 - IO.pipe - rescue Errno::EMFILE - exit 0 + old = STDIN.dup + begin + STDIN.reopen(filename) + yield + ensure + STDIN.reopen(old) + end + ensure + old.close end - exit 1 } + 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($?.success?) + with_stdin("f") { Process.wait spawn([RUBY, "rfv"]) } + assert(!$?.success?) + + with_stdin("t") { IO.popen([[RUBY, "tgb"]]) {|io| assert_equal("", io.read) } } + assert($?.success?) + with_stdin("f") { IO.popen([[RUBY, "yhn"]]) {|io| assert_equal("", io.read) } } + assert(!$?.success?) + + status = run_in_child "STDIN.reopen('t'); exec([#{RUBY.dump}, 'ujm'])" + assert(status.success?) + status = run_in_child "STDIN.reopen('f'); exec([#{RUBY.dump}, 'ik,'])" + assert(!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?("QUIT") + + with_tmpchdir do + write_file("foo", "sleep 30") + pid = spawn(RUBY, "foo") + Thread.new { sleep 1; Process.kill(:SIGQUIT, pid) } + Process.wait(pid) + s = $? + assert_equal([false, true, false], + [s.exited?, s.signaled?, s.stopped?], + "[s.exited?, s.signaled?, s.stopped?]") + 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]) + assert_equal(false, s.exited?) + assert_equal(nil, s.success?) + 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_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.egid) + end + + def test_uid_re_exchangeable_p + r = Process::UID.re_exchangeable? + assert(true == r || false == r) + end + + def test_gid_re_exchangeable_p + r = Process::GID.re_exchangeable? + assert(true == r || false == r) + end + + def test_uid_sid_available? + r = Process::UID.sid_available? + assert(true == r || false == r) + end + + def test_gid_sid_available? + r = Process::GID.sid_available? + assert(true == r || 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 = fork { sleep 0.1; exit } + Thread.start { raise } Process.wait pid - assert_equal(0, $?.to_i) + sleep 0.1 + 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}") + system({"RUBYLIB"=>nil}, RUBY, "--disable-gems", "-e", "exit true") + status = $? + } + assert(status.success?, "[ruby-dev:38105]") + } + end unless /mswin|bccwin|mingw/ =~ RUBY_PLATFORM + + 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) + end + end if File.executable?("/bin/sh") + + def test_too_long_path + bug4314 = '[ruby-core:34842]' + exs = [Errno::ENOENT] + exs << Errno::E2BIG if defined?(Errno::E2BIG) + assert_raise(*exs, bug4314) {Process.spawn("a" * 10_000_000)} + end + + def test_too_long_path2 + skip + bug4315 = '[ruby-core:34833]' + exs = [Errno::ENOENT] + exs << Errno::E2BIG if defined?(Errno::E2BIG) + assert_raise(*exs, bug4315) {Process.spawn('"a"|'*10_000_000)} + 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 + + if File.directory?("/proc/self/task") + 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_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 end diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb index e2fd127f9c..c7139818de 100644 --- a/test/ruby/test_rand.rb +++ b/test/ruby/test_rand.rb @@ -1,131 +1,487 @@ 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 - srand(0x00000456_00000345_00000234_00000123) - %w(1067595299 955945823 477289528 4107218783 4228976476).each {|w| - assert_equal(w.to_i, rand(0x100000000)) - } + assert_random_int(%w(1067595299 955945823 477289528 4107218783 4228976476), + 0x100000000, 0x00000456_00000345_00000234_00000123) end def test_0x3fffffff - srand(0) - %w(209652396 398764591 924231285 404868288 441365315).each {|w| - assert_equal(w.to_i, rand(0x3fffffff)) - } + assert_random_int(%w(209652396 398764591 924231285 404868288 441365315), + 0x3fffffff) end def test_0x40000000 - srand(0) - %w(209652396 398764591 924231285 404868288 441365315).each {|w| - assert_equal(w.to_i, rand(0x40000000)) - } + assert_random_int(%w(209652396 398764591 924231285 404868288 441365315), + 0x40000000) end def test_0x40000001 - srand(0) - %w(209652396 398764591 924231285 441365315 192771779).each {|w| - assert_equal(w.to_i, rand(0x40000001)) - } + assert_random_int(%w(209652396 398764591 924231285 441365315 192771779), + 0x40000001) end def test_0xffffffff - srand(0) - %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w| - assert_equal(w.to_i, rand(0xffffffff)) - } + assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963), + 0xffffffff) end def test_0x100000000 - srand(0) - %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w| - assert_equal(w.to_i, rand(0x100000000)) - } + assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963), + 0x100000000) end def test_0x100000001 - srand(0) - %w(2546248239 1277901399 243580376 1171049868 2051556033).each {|w| - assert_equal(w.to_i, rand(0x100000001)) - } + assert_random_int(%w(2546248239 1277901399 243580376 1171049868 2051556033), + 0x100000001) end def test_rand_0x100000000 - srand(311702798) - %w(4119812344 3870378946 80324654 4294967296 410016213).each {|w| - assert_equal(w.to_i, rand(0x100000001)) - } + assert_random_int(%w(4119812344 3870378946 80324654 4294967296 410016213), + 0x100000001, 311702798) end def test_0x1000000000000 - srand(0) - %w(11736396900911 - 183025067478208 - 197104029029115 - 130583529618791 - 180361239846611).each {|w| - assert_equal(w.to_i, rand(0x1000000000000)) - } + assert_random_int(%w(11736396900911 + 183025067478208 + 197104029029115 + 130583529618791 + 180361239846611), + 0x1000000000000) end def test_0x1000000000001 - srand(0) - %w(187121911899765 - 197104029029115 - 180361239846611 - 236336749852452 - 208739549485656).each {|w| - assert_equal(w.to_i, rand(0x1000000000001)) - } + assert_random_int(%w(187121911899765 + 197104029029115 + 180361239846611 + 236336749852452 + 208739549485656), + 0x1000000000001) end def test_0x3fffffffffffffff - srand(0) - %w(900450186894289455 - 3969543146641149120 - 1895649597198586619 - 827948490035658087 - 3203365596207111891).each {|w| - assert_equal(w.to_i, rand(0x3fffffffffffffff)) - } + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 3203365596207111891), + 0x3fffffffffffffff) end def test_0x4000000000000000 - srand(0) - %w(900450186894289455 - 3969543146641149120 - 1895649597198586619 - 827948490035658087 - 3203365596207111891).each {|w| - assert_equal(w.to_i, rand(0x4000000000000000)) - } + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 3203365596207111891), + 0x4000000000000000) end def test_0x4000000000000001 - srand(0) - %w(900450186894289455 - 3969543146641149120 - 1895649597198586619 - 827948490035658087 - 2279347887019741461).each {|w| - assert_equal(w.to_i, rand(0x4000000000000001)) - } + assert_random_int(%w(900450186894289455 + 3969543146641149120 + 1895649597198586619 + 827948490035658087 + 2279347887019741461), + 0x4000000000000001) end - def test_neg_0x10000000000 + def test_0x10000000000 ws = %w(455570294424 1073054410371 790795084744 2445173525 1088503892627) - srand(3) - ws.each {|w| assert_equal(w.to_i, rand(0x10000000000)) } - srand(3) - ws.each {|w| assert_equal(w.to_i, rand(-0x10000000000)) } + assert_random_int(ws, 0x10000000000, 3) end - def test_neg_0x10000 + 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) + assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle) + assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle(random: Random.new(0))) + end + + def test_big_seed + assert_random_int(%w(1143843490), 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) } + assert_raise(ArgumentError, bug3027 = '[ruby-core:29075]') { 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) - ws.each {|w| assert_equal(w.to_i, rand(0x10000)) } + 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) - ws.each {|w| assert_equal(w.to_i, rand(-0x10000)) } + 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(r == r) + assert(r == r.dup) + r1 = r.dup + r2 = r.dup + r1.rand(0x100) + assert(r1 != r2) + r2.rand(0x100) + assert(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 + p2, st = Process.waitpid2(pid) + assert(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 + 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.marshal_load(0) + } + end end diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 455175087d..738c7cdb85 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -1,4 +1,6 @@ require 'test/unit' +require 'delegate' +require 'timeout' class TestRange < Test::Unit::TestCase def test_range_string @@ -9,9 +11,340 @@ class TestRange < Test::Unit::TestCase 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) + 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) + end + + def test_initialize_twice + r = eval("1..2") + assert_raise(NameError) { r.instance_eval { initialize 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(!((0..1).exclude_end?)) + assert((0...1).exclude_end?) + end + + def test_eq + r = (0..1) + assert(r == r) + assert(r == (0..1)) + assert(r != 0) + assert(r != (1..2)) + assert(r != (0..2)) + assert(r != (0...1)) + subclass = Class.new(Range) + assert(r == subclass.new(0,1)) + end + + def test_eql + r = (0..1) + assert(r.eql?(r)) + assert(r.eql?(0..1)) + assert(!r.eql?(0)) + assert(!r.eql?(1..2)) + assert(!r.eql?(0..2)) + assert(!r.eql?(0...1)) + subclass = Class.new(Range) + assert(r.eql?(subclass.new(0,1))) + end + + def test_hash + assert((0..1).hash.is_a?(Fixnum)) + 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)) + 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((0..10) === 5) + assert(!((0..10) === 11)) + end + + def test_include + assert(("a".."z").include?("c")) + assert(!(("a".."z").include?("5"))) + assert(("a"..."z").include?("y")) + assert(!(("a"..."z").include?("z"))) + assert(!(("a".."z").include?("cc"))) + assert((0...10).include?(5)) + end + + def test_cover + assert(("a".."z").cover?("c")) + assert(!(("a".."z").cover?("5"))) + assert(("a"..."z").cover?("y")) + assert(!(("a"..."z").cover?("z"))) + assert(("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 x == y + assert x.eql? y + } + + z = CyclicRange.allocate; z.send(:initialize, z, :another) + Timeout.timeout(1) { + assert x != z + assert !x.eql?(z) + } + + x = CyclicRange.allocate + y = CyclicRange.allocate + x.send(:initialize, y, 1) + y.send(:initialize, x, 1) + Timeout.timeout(1) { + assert x == y + assert x.eql?(y) + } + + x = CyclicRange.allocate + z = CyclicRange.allocate + x.send(:initialize, z, 1) + z.send(:initialize, x, :other) + Timeout.timeout(1) { + assert x != z + assert !x.eql?(z) + } + end end diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb new file mode 100644 index 0000000000..70aab03c38 --- /dev/null +++ b/test/ruby/test_rational.rb @@ -0,0 +1,1139 @@ +require 'test/unit' + +class RationalSub < Rational; end + +class Rational_Test < Test::Unit::TestCase + + def setup + @complex = defined?(Complex) + if @complex + @keiju = Complex.instance_variables.include?(:@RCS_ID) + end + seps = [File::SEPARATOR, File::ALT_SEPARATOR].compact.map{|x| Regexp.escape(x)}.join("|") + @unify = $".grep(/(?:^|#{seps})mathn(?:\.(?:rb|so))?/).size != 0 + end + + def test_ratsub + c = RationalSub.__send__(:convert, 1) + + assert_kind_of(Numeric, c) + + if @unify + assert_instance_of(Fixnum, c) + else + 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) + end + + 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)) + + if @unify + assert_equal(true, c.eql?(0)) + else + assert_equal(false, c.eql?(0)) + end + 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 + unless @unify + assert_equal(true, c.frozen?) + end + 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) + + if @complex && !@keiju + 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) + end + + 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) + + if @unify +=begin + assert_equal(true, c.finite?) + assert_equal(false, c.infinite?) + assert_equal(false, c.nan?) + assert_equal(true, c.integer?) + assert_equal(false, c.float?) + assert_equal(true, c.rational?) +=end + assert_equal(true, c.real?) +=begin + assert_equal(false, c.complex?) + assert_equal(true, c.exact?) + assert_equal(false, c.inexact?) +=end + else +=begin + assert_equal(true, c.finite?) + assert_equal(false, c.infinite?) + assert_equal(false, c.nan?) + assert_equal(false, c.integer?) + assert_equal(false, c.float?) + assert_equal(true, c.rational?) +=end + assert_equal(true, c.real?) +=begin + assert_equal(false, c.complex?) + assert_equal(true, c.exact?) + assert_equal(false, c.inexact?) +=end + end + +=begin + assert_equal(true, Rational(0).positive?) + assert_equal(true, Rational(1).positive?) + assert_equal(false, Rational(-1).positive?) + assert_equal(false, Rational(0).negative?) + assert_equal(false, Rational(1).negative?) + assert_equal(true, Rational(-1).negative?) + + assert_equal(0, Rational(0).sign) + assert_equal(1, Rational(2).sign) + assert_equal(-1, Rational(-2).sign) +=end + + 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)) + +=begin + assert_equal(0, Rational(0).negate) + assert_equal(-2, Rational(2).negate) + assert_equal(2, Rational(-2).negate) +=end + 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((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)) + + unless @unify + 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 + 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)) + + unless @unify + 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 + 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)) + + unless @unify + 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 + end + +=begin + def test_quot + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql(0, c.quot(c2)) + assert_eql(0, c.quot(2)) + assert_eql(0, c.quot(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal(2, c.quot(c2)) + assert_equal(-2, c.quot(-c2)) + assert_equal(-2, (-c).quot(c2)) + assert_equal(2, (-c).quot(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal(1, c.quot(c2)) + assert_equal(-1, c.quot(-c2)) + assert_equal(-1, (-c).quot(c2)) + assert_equal(1, (-c).quot(-c2)) + + unless @unify + c = Rational(11) + c2 = Rational(3) + + assert_equal(3, c.quot(c2)) + assert_equal(-3, c.quot(-c2)) + assert_equal(-3, (-c).quot(c2)) + assert_equal(3, (-c).quot(-c2)) + end + end +=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)) + + unless @unify + 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 + end + +=begin + def test_quotrem + c = Rational(1,2) + c2 = Rational(2,3) + + assert_eql([0, Rational(1,2)], c.quotrem(c2)) + assert_eql([0, Rational(1,2)], c.quotrem(2)) + assert_eql([0, 0.5], c.quotrem(2.0)) + + c = Rational(301,100) + c2 = Rational(7,5) + + assert_equal([2, Rational(21,100)], c.quotrem(c2)) + assert_equal([-2, Rational(21,100)], c.quotrem(-c2)) + assert_equal([-2, Rational(-21,100)], (-c).quotrem(c2)) + assert_equal([2, Rational(-21,100)], (-c).quotrem(-c2)) + + c = Rational(301,100) + c2 = Rational(2) + + assert_equal([1, Rational(101,100)], c.quotrem(c2)) + assert_equal([-1, Rational(101,100)], c.quotrem(-c2)) + assert_equal([-1, Rational(-101,100)], (-c).quotrem(c2)) + assert_equal([1, Rational(-101,100)], (-c).quotrem(-c2)) + + unless @unify + c = Rational(11) + c2 = Rational(3) + + assert_equal([3,2], c.quotrem(c2)) + assert_equal([-3,2], c.quotrem(-c2)) + assert_equal([-3,-2], (-c).quotrem(c2)) + assert_equal([3,-2], (-c).quotrem(-c2)) + end + end +=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(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) + unless @unify + assert_instance_of(Rational, x) + end + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(2) ** 2 + assert_equal(Rational(4), x) + unless @unify + assert_instance_of(Rational, x) + end + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(2) ** Rational(2) + assert_equal(Rational(4), x) + unless @unify + assert_instance_of(Rational, x) + end + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + # -p ** p + x = (-2) ** Rational(2) + assert_equal(Rational(4), x) + unless @unify + assert_instance_of(Rational, x) + end + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(-2) ** 2 + assert_equal(Rational(4), x) + unless @unify + assert_instance_of(Rational, x) + end + assert_equal(4, x.numerator) + assert_equal(1, x.denominator) + + x = Rational(-2) ** Rational(2) + assert_equal(Rational(4), x) + unless @unify + assert_instance_of(Rational, x) + end + 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) + + unless @unify # maybe bug mathn + assert_raise(ZeroDivisionError){0 ** -1} + end + 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(Rational(1,1) == Rational(1)) + assert(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_unify + if @unify + assert_instance_of(Fixnum, Rational(1,2) + Rational(1,2)) + assert_instance_of(Fixnum, Rational(1,2) - Rational(1,2)) + assert_instance_of(Fixnum, Rational(1,2) * 2) + assert_instance_of(Fixnum, Rational(1,2) / Rational(1,2)) + assert_instance_of(Fixnum, Rational(1,2).div(Rational(1,2))) + assert_instance_of(Fixnum, Rational(1,2).quo(Rational(1,2))) + assert_instance_of(Fixnum, Rational(1,2) ** -2) + end + end + + def test_math + assert_equal(Rational(1,2), Rational(1,2).abs) + assert_equal(Rational(1,2), Rational(-1,2).abs) + if @complex && !@keiju + assert_equal(Rational(1,2), Rational(1,2).magnitude) + assert_equal(Rational(1,2), Rational(-1,2).magnitude) + end + + 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) + + if @unify + assert_equal('0', Rational(0,2).to_s) + assert_equal('0', Rational(0,-2).to_s) + else + assert_equal('0/1', Rational(0,2).to_s) + assert_equal('0/1', Rational(0,-2).to_s) + end + 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]' + assert_raise(TypeError, bug3656) { + Rational(1,2).marshal_load(0) + } + 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,-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,-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(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(5e1,-3), '5e1/-3'.to_r) +# assert_equal(Rational(-5e2,-3), '-5e2/-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,-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,-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(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(5e1,-3), Rational('5e1/-3')) +# assert_equal(Rational(-5e2,-3), Rational('-5e2/-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 + +=begin + def test_reciprocal + assert_equal(Rational(1,9), Rational(9,1).reciprocal) + assert_equal(Rational(9,1), Rational(1,9).reciprocal) + assert_equal(Rational(-1,9), Rational(-9,1).reciprocal) + assert_equal(Rational(-9,1), Rational(-1,9).reciprocal) + assert_equal(Rational(1,9), Rational(9,1).inverse) + assert_equal(Rational(9,1), Rational(1,9).inverse) + assert_equal(Rational(-1,9), Rational(-9,1).inverse) + assert_equal(Rational(-9,1), Rational(-1,9).inverse) + end +=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 + if @complex && !@keiju + if @unify + assert_equal(Rational(3,2), Rational(3,2).to_c) + assert_equal(Rational(3,2), Complex(Rational(3,2))) + else + assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c) + assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2))) + end + end + 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]) + + if @complex + if @keiju + assert_raise(NoMethodError){Complex(1,2).to_r} + else + assert_raise(RangeError){Complex(1,2).to_r} + end + end + + 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)) + + if @complex + if @keiju + else + assert_raise(RangeError){Complex(1,2).rationalize} + end + end + + 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) + +=begin + assert_equal(Rational(1,9), 9.reciprocal) + assert_in_delta(0.1111, 9.0.reciprocal, 0.001) + assert_equal(Rational(1,9), 9.inverse) + assert_in_delta(0.1111, 9.0.inverse, 0.001) +=end + + 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(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 + if @unify + assert_instance_of(Fixnum, Rational(1,2) ** 0) # mathn's bug + end + + n = Float::MAX.to_i * 2 + assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]') + end + + def test_known_bug + end + +end diff --git a/test/ruby/test_rational2.rb b/test/ruby/test_rational2.rb new file mode 100644 index 0000000000..3b6a985bc6 --- /dev/null +++ b/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/test/ruby/test_readpartial.rb b/test/ruby/test_readpartial.rb index 3877e21f85..b969c38692 100644 --- a/test/ruby/test_readpartial.rb +++ b/test/ruby/test_readpartial.rb @@ -5,6 +5,8 @@ require 'fcntl' class TestReadPartial < Test::Unit::TestCase def make_pipe r, w = IO.pipe + r.binmode + w.binmode begin yield r, w ensure @@ -38,18 +40,17 @@ class TestReadPartial < Test::Unit::TestCase w.close assert_equal('ab', r.readpartial(2)) assert_equal('c', r.readpartial(2)) - assert_raises(EOFError) { r.readpartial(2) } - assert_raises(EOFError) { r.readpartial(2) } + assert_raise(EOFError) { r.readpartial(2) } + assert_raise(EOFError) { r.readpartial(2) } } end - if !File::ALT_SEPARATOR # read on pipe cannot timeout on Windows. def test_open_pipe pipe {|r, w| w << 'abc' assert_equal('ab', r.readpartial(2)) assert_equal('c', r.readpartial(2)) - assert_raises(TimeoutError) { + assert_raise(TimeoutError) { timeout(0.1) { r.readpartial(2) } } } @@ -63,12 +64,9 @@ class TestReadPartial < Test::Unit::TestCase assert_equal("de", r.readpartial(2)) assert_equal("f\n", r.readpartial(4096)) assert_equal("ghi\n", r.readpartial(4096)) - assert_raises(TimeoutError) { + assert_raise(TimeoutError) { timeout(0.1) { r.readpartial(2) } } } end - end - end - diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb new file mode 100644 index 0000000000..3073a98b89 --- /dev/null +++ b/test/ruby/test_regexp.rb @@ -0,0 +1,876 @@ +require 'test/unit' +require_relative 'envutil' + +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 + 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_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_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(!local_variables.include?(: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 + assert_equal('', //.source) + 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)) + re = /foo/ + assert_raise(SecurityError) do + Thread.new { $SAFE = 4; re.instance_eval { initialize(re) } }.join + end + re.taint + assert_raise(SecurityError) do + Thread.new { $SAFE = 4; re.instance_eval { initialize(re) } }.join + end + + 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}/)) } + + 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 + assert_equal(true, /abc/ == /abc/) + assert_equal(false, /abc/ == /abc/m) + assert_equal(false, /abc/ == /abd/) + 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_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_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 = 4 + /foo/.match("foo") + end.value + assert(m.tainted?) + assert_nothing_raised('[ruby-core:26137]') { + m = proc {$SAFE = 4; %r"#{ }"o}.call + } + assert(m.tainted?) + end + + def check(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 + + def failcheck(re) + assert_raise(RegexpError) { %r"#{ re }" } + end + + 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(/\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(/\A[[:^alpha:]0]\z/, %w(0 1 .), "a") + check(/\A[[:alpha\:]]\z/, %w(a l p h a :), %w(b 0 1 .)) + check(/\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 + + 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]') + 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_warn(/duplicated/) { Regexp.new('[\u3042\u3043\u3042]') } + assert_warn(/duplicated/) { Regexp.new('[\u3042\u3043\u3043]') } + assert_warn(/\A\z/) { Regexp.new('[\u3042\u3044\u3043]') } + assert_warn(/\A\z/) { Regexp.new('[\u3042\u3045\u3043]') } + assert_warn(/\A\z/) { Regexp.new('[\u3042\u3045\u3044]') } + assert_warn(/\A\z/) { Regexp.new('[\u3042\u3045\u3043-\u3044]') } + assert_warn(/duplicated/) { Regexp.new('[\u3042\u3045\u3042-\u3043]') } + assert_warn(/duplicated/) { Regexp.new('[\u3042\u3045\u3044-\u3045]') } + assert_warn(/\A\z/) { Regexp.new('[\u3042\u3046\u3044]') } + assert_warn(/duplicated/) { Regexp.new('[\u1000-\u2000\u3042-\u3046\u3044]') } + assert_warn(/duplicated/) { Regexp.new('[\u3044\u3041-\u3047]') } + assert_warn(/duplicated/) { Regexp.new('[\u3042\u3044\u3046\u3041-\u3047]') } + 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 +end diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb new file mode 100644 index 0000000000..58a9ee26b6 --- /dev/null +++ b/test/ruby/test_require.rb @@ -0,0 +1,359 @@ +require 'test/unit' + +require 'tempfile' +require_relative 'envutil' +require 'tmpdir' + +class TestRequire < Test::Unit::TestCase + def test_require_invalid_shared_object + t = Tempfile.new(["test_ruby_test_require", ".so"]) + t.puts "dummy" + t.close + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + begin + require \"#{ t.path }\" + rescue LoadError + p :ok + end + INPUT + end + + def test_require_too_long_filename + assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), []) + begin + require '#{ "foo/" * 10000 }foo' + rescue LoadError + p :ok + 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]' + e = assert_raise(LoadError, bug3758) {require "\u{221e}"} + assert_match(/\u{221e}\z/, e.message, bug3758) + 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"] + + t = Tempfile.new(["test_ruby_test_require", ".rb"]) + 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 + assert(system(File.expand_path(EnvUtil.rubybin).sub(/\A(\w):/, '//127.0.0.1/\1$/'), "-rabbrev", "-e0")) + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_define_class + begin + require "socket" + rescue LoadError + return + end + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + BasicSocket = 1 + begin + require 'socket' + p :ng + rescue TypeError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + class BasicSocket; end + begin + require 'socket' + p :ng + rescue TypeError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + class BasicSocket < IO; end + begin + require 'socket' + p :ok + rescue Exception + p :ng + end + INPUT + end + + def test_define_class_under + begin + require "zlib" + rescue LoadError + return + end + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + module Zlib; end + Zlib::Error = 1 + begin + require 'zlib' + p :ng + rescue TypeError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + module Zlib; end + class Zlib::Error; end + begin + require 'zlib' + p :ng + rescue NameError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + module Zlib; end + class Zlib::Error < StandardError; end + begin + require 'zlib' + p :ok + rescue Exception + p :ng + end + INPUT + end + + def test_define_module + begin + require "zlib" + rescue LoadError + return + end + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + Zlib = 1 + begin + require 'zlib' + p :ng + rescue TypeError + p :ok + end + INPUT + end + + def test_define_module_under + begin + require "socket" + rescue LoadError + return + end + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + class BasicSocket < IO; end + class Socket < BasicSocket; end + Socket::Constants = 1 + begin + require 'socket' + p :ng + rescue TypeError + p :ok + end + INPUT + end + + def test_load + t = Tempfile.new(["test_ruby_test_require", ".rb"]) + 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_load2 # [ruby-core:25039] + t = Tempfile.new(["test_ruby_test_require", ".rb"]) + t.puts "Hello = 'hello'" + t.puts "class Foo" + t.puts " p Hello" + t.puts "end" + t.close + + assert_in_out_err([], <<-INPUT, %w("hello"), []) + load(#{ t.path.dump }, true) + INPUT + end + + def test_tainted_loadpath + t = Tempfile.new(["test_ruby_test_require", ".rb"]) + abs_dir, file = File.split(t.path) + abs_dir = File.expand_path(abs_dir).untaint + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + abs_dir = "#{ abs_dir }" + $: << abs_dir + require "#{ file }" + p :ok + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + require "#{ file }" + p :ok + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + $SAFE = 1 + begin + require "#{ file }" + rescue SecurityError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + abs_dir = "#{ abs_dir }" + $: << abs_dir.taint + $SAFE = 1 + begin + require "#{ file }" + rescue SecurityError + p :ok + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(:ok), []) + abs_dir = "#{ abs_dir }" + $: << abs_dir << 'elsewhere'.taint + require "#{ file }" + p :ok + 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_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_not_equal(Encoding::ASCII_8BIT, $"[0].encoding, bug6377) + } + ensure + $:.replace(loadpath) + $".replace(features) + end +end diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb new file mode 100644 index 0000000000..5533ac2c8e --- /dev/null +++ b/test/ruby/test_rubyoptions.rb @@ -0,0 +1,568 @@ +require 'test/unit' + +require 'tmpdir' +require 'tempfile' +require 'pathname' + +require_relative 'envutil' + +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 = Pathname.new(d).realpath.to_s + 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) + assert_equal([], e) + end + + assert_in_out_err(%w(--help)) do |r, e| + assert_operator(r.size, :<=, 24) + 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).*? \[#{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 + assert_in_out_err(%w(-KE -e) + [""], "", [], []) + assert_in_out_err(%w(-KS -e) + [""], "", [], []) + assert_in_out_err(%w(-KN -e) + [""], "", [], []) + end + + def test_version + assert_in_out_err(%w(--version)) do |r, e| + assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev).*? \[#{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(-Eutf-8), "p '\u3042'", [], /invalid multibyte char/) + + 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\)/) + + assert_in_out_err(%w(--encoding utf-8), "p '\u3042'", [], /invalid multibyte char/) + 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'] + + t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"]) + 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 + t.close(true) if t + $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([], "#!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 + t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"]) + 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.close + err = ["#{t.path}:1: warning: found = in conditional, should be ==", + "#{t.path}:4: warning: found = in conditional, should be =="] + err = /\A(#{Regexp.quote(t.path)}):1(: warning: found = in conditional, should be ==)\n\1:4\2\Z/ + bug2136 = '[ruby-dev:39363]' + assert_in_out_err(["-w", t.path], "", [], err, bug2136) + assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err, bug2136) + ensure + t.close(true) if t + end + + def test_indentation_check + t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"]) + t.puts "begin" + t.puts " end" + t.close + 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.open + t.puts "# -*- warn-indent: false -*-" + t.puts "begin" + t.puts " end" + t.close + assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]') + + err = ["#{t.path}:4: warning: mismatched indentations at 'end' with 'begin' at 3"] + t.open + t.puts "# -*- warn-indent: false -*-" + t.puts "# -*- warn-indent: true -*-" + t.puts "begin" + t.puts " end" + t.close + 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.open + t.puts "# -*- warn-indent: true -*-" + t.puts "begin" + t.puts "# -*- warn-indent: false -*-" + t.puts " end" + t.close + assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]') + ensure + t.close(true) if t + end + + def test_notfound + notexist = "./notexist.rb" + rubybin = Regexp.quote(EnvUtil.rubybin) + pat = Regexp.quote(notexist) + bug1573 = '[ruby-core:23717]' + assert_equal(false, File.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 + + def test_set_program_name + skip "platform dependent feature" if /linux|freebsd|netbsd|openbsd|darwin/ !~ RUBY_PLATFORM + + with_tmpchdir do + write_file("test-script", "$0 = 'hello world'; sleep 60") + + pid = spawn(EnvUtil.rubybin, "test-script") + sleep 0.1 + ps = `ps -p #{pid} -o command` + assert_match(/hello world/, ps) + Process.kill :KILL, pid + end + end + + def test_segv_test + opts = {} + if /mswin|mingw/ =~ RUBY_PLATFORM + additional = '[\s\w\.\']*' + else + opts[:rlimit_core] = 0 + additional = "" + end + assert_in_out_err(["-e", "Process.kill :SEGV, $$"], "", [], + %r(\A + -e:(?:1:)?\s\[BUG\]\sSegmentation\sfault\n + #{ Regexp.quote(RUBY_DESCRIPTION) }\n\n + --\sControl\sframe\sinformation\s-+\n + (?:c:.*\n)* + (?: + --\sRuby\slevel\sbacktrace\sinformation\s----------------------------------------\n + -e:1:in\s\`<main>\'\n + -e:1:in\s\`kill\'\n + )? + \n + (?: + --\sC\slevel\sbacktrace\sinformation\s-------------------------------------------\n + (?:(?:.*\s)?\[0x\h+\]\n)*\n + )? + (?m:.*) + \[NOTE\]\n + You\smay\shave\sencountered\sa\sbug\sin\sthe\sRuby\sinterpreter\sor\sextension\slibraries.\n + Bug\sreports\sare\swelcome.\n + For\sdetails:\shttp:\/\/www.ruby-lang.org/bugreport.html\n + \n + (?:#{additional}) + \z + )x, + nil, + opts) + end + + def test_DATA + t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"]) + t.puts "puts DATA.read.inspect" + t.puts "__END__" + t.puts "foo" + t.puts "bar" + t.puts "baz" + t.close + assert_in_out_err([t.path], "", %w("foo\\nbar\\nbaz\\n"), []) + ensure + t.close(true) if t + 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"], "", [], []) + 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) + 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) + 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 + + 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 +end diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 39e1b035d8..d6c6d06f38 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -1,138 +1,395 @@ require 'test/unit' class TestSetTraceFunc < Test::Unit::TestCase - def foo; end; + def setup + @original_compile_option = RubyVM::InstructionSequence.compile_option + RubyVM::InstructionSequence.compile_option = { + :trace_instruction => true, + :specialized_instruction => false + } + end + + def teardown + set_trace_func(nil) + RubyVM::InstructionSequence.compile_option = @original_compile_option + end - def bar + def test_c_call events = [] - set_trace_func(Proc.new { |event, file, lineno, mid, bidning, klass| - events << [event, lineno, mid, klass] - }) - return events + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 3: }) + 4: x = 1 + 1 + 5: set_trace_func(nil) + EOF + assert_equal(["c-return", 3, :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_event + def test_call events = [] - set_trace_func(Proc.new { |event, file, lineno, mid, bidning, klass| - events << [event, lineno, mid, klass] - }) - a = 1 - foo - a - b = 1 + 2 - if b == 3 - case b - when 2 - c = "b == 2" - when 3 - c = "b == 3" - end - end - begin - raise "error" - rescue - end - eval("class Foo; end") - set_trace_func nil - - assert_equal(["line", 19, :test_event, TestSetTraceFunc], - events.shift) # a = 1 - assert_equal(["line", 20, :test_event, TestSetTraceFunc], - events.shift) # foo - assert_equal(["call", 4, :foo, TestSetTraceFunc], - events.shift) # foo - assert_equal(["return", 4, :foo, TestSetTraceFunc], - events.shift) # foo - assert_equal(["line", 21, :test_event, TestSetTraceFunc], - events.shift) # a - assert_equal(["line", 22, :test_event, TestSetTraceFunc], - events.shift) # b = 1 + 2 - assert_equal(["c-call", 22, :+, Fixnum], - events.shift) # 1 + 2 - assert_equal(["c-return", 22, :+, Fixnum], - events.shift) # 1 + 2 - assert_equal(["line", 23, :test_event, TestSetTraceFunc], - events.shift) # if b == 3 - assert_equal(["line", 23, :test_event, TestSetTraceFunc], - events.shift) # if b == 3 - assert_equal(["c-call", 23, :==, Fixnum], - events.shift) # b == 3 - assert_equal(["c-return", 23, :==, Fixnum], - events.shift) # b == 3 - assert_equal(["line", 24, :test_event, TestSetTraceFunc], - events.shift) # case b - assert_equal(["line", 25, :test_event, TestSetTraceFunc], - events.shift) # when 2 - assert_equal(["c-call", 25, :===, Kernel], - events.shift) # when 2 - assert_equal(["c-call", 25, :==, Fixnum], - events.shift) # when 2 - assert_equal(["c-return", 25, :==, Fixnum], - events.shift) # when 2 - assert_equal(["c-return", 25, :===, Kernel], - events.shift) # when 2 - assert_equal(["line", 27, :test_event, TestSetTraceFunc], - events.shift) # when 3 - assert_equal(["c-call", 27, :===, Kernel], - events.shift) # when 3 - assert_equal(["c-return", 27, :===, Kernel], - events.shift) # when 3 - assert_equal(["line", 28, :test_event, TestSetTraceFunc], - events.shift) # c = "b == 3" - assert_equal(["line", 31, :test_event, TestSetTraceFunc], - events.shift) # begin - assert_equal(["line", 32, :test_event, TestSetTraceFunc], - events.shift) # raise "error" - assert_equal(["c-call", 32, :raise, Kernel], - events.shift) # raise "error" - assert_equal(["c-call", 32, :new, Class], - events.shift) # raise "error" - assert_equal(["c-call", 32, :initialize, Exception], - events.shift) # raise "error" - assert_equal(["c-return", 32, :initialize, Exception], - events.shift) # raise "error" - assert_equal(["c-return", 32, :new, Class], - events.shift) # raise "error" - assert_equal(["c-call", 32, :backtrace, Exception], - events.shift) # raise "error" - assert_equal(["c-return", 32, :backtrace, Exception], - events.shift) # raise "error" - assert_equal(["c-call", 32, :set_backtrace, Exception], - events.shift) # raise "error" - assert_equal(["c-return", 32, :set_backtrace, Exception], - events.shift) # raise "error" - assert_equal(["raise", 32, :test_event, TestSetTraceFunc], - events.shift) # raise "error" - assert_equal(["c-return", 32, :raise, Kernel], - events.shift) # raise "error" - assert_equal(["line", 35, :test_event, TestSetTraceFunc], - events.shift) # eval(<<EOF) - assert_equal(["c-call", 35, :eval, Kernel], - events.shift) # eval(<<EOF) - assert_equal(["line", 1, :test_event, TestSetTraceFunc], - events.shift) # class Foo - assert_equal(["c-call", 1, :inherited, Class], - events.shift) # class Foo - assert_equal(["c-return", 1, :inherited, Class], - events.shift) # class Foo - assert_equal(["class", 1, :test_event, TestSetTraceFunc], - events.shift) # class Foo - assert_equal(["end", 1, :test_event, TestSetTraceFunc], - events.shift) # class Foo - assert_equal(["c-return", 35, :eval, Kernel], - events.shift) # eval(<<EOF) - assert_equal(["line", 36, :test_event, TestSetTraceFunc], - events.shift) # set_trace_func nil - assert_equal(["c-call", 36, :set_trace_func, Kernel], - events.shift) # set_trace_func nil + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 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", 3, :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 - events = bar - set_trace_func(nil) - assert_equal(["line", 11, :bar, TestSetTraceFunc], events.shift) - assert_equal(["return", 7, :bar, TestSetTraceFunc], events.shift) - assert_equal(["line", 131, :test_event, TestSetTraceFunc], events.shift) - assert_equal(["c-call", 131, :set_trace_func, Kernel], events.shift) + def test_class + events = [] + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 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", 3, :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 = [] + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 3: }) + 4: def foo(a) + 5: return if a + 6: return + 7: end + 8: foo(true) + 9: foo(false) + 10: set_trace_func(nil) + EOF + assert_equal(["c-return", 3, :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, :foo, self.class], + events.shift) + assert_equal(["line", 5, :foo, self.class], + events.shift) + assert_equal(["return", 5, :foo, self.class], + events.shift) + assert_equal(["line", 9, :test_return, self.class], + events.shift) + assert_equal(["call", 4, :foo, self.class], + events.shift) + assert_equal(["line", 5, :foo, self.class], + events.shift) + assert_equal(["return", 7, :foo, 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 = [] + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 3: }) + 4: def foo + 5: a = 5 + 6: return a + 7: end + 8: foo + 9: set_trace_func(nil) + EOF + assert_equal(["c-return", 3, :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, :foo, self.class], + events.shift) + assert_equal(["line", 5, :foo, self.class], + events.shift) + assert_equal(["line", 6, :foo, self.class], + events.shift) + assert_equal(["return", 7, :foo, 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 = [] + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 3: }) + 4: begin + 5: raise TypeError, "error" + 6: rescue TypeError + 7: end + 8: set_trace_func(nil) + EOF + assert_equal(["c-return", 3, :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-call", 5, :backtrace, Exception], + events.shift) + assert_equal(["c-return", 5, :backtrace, Exception], + events.shift) + assert_equal(["c-call", 5, :set_backtrace, Exception], + events.shift) + assert_equal(["c-return", 5, :set_backtrace, Exception], + events.shift) + assert_equal(["raise", 5, :test_raise, TestSetTraceFunc], + events.shift) + assert_equal(["c-return", 5, :raise, Kernel], + 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 = [] + eval <<-EOF.gsub(/^.*?: /, "") + 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass| + 2: events << [event, lineno, mid, klass] + 3: }) + 4: [1,2,3].any? {|n| n} + 8: set_trace_func(nil) + EOF + + [["c-return", 3, :set_trace_func, Kernel], + ["line", 4, __method__, self.class], + ["c-call", 4, :any?, Enumerable], + ["c-call", 4, :each, Array], + ["line", 4, __method__, self.class], + ["c-return", 4, :each, Array], + ["c-return", 4, :any?, Enumerable], + ["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] + } + prc2 = Proc.new { |event, file, lineno, mid, binding, klass| + events[:add] << [event, lineno, mid, klass, :add] + } + + th = Thread.new do + th = Thread.current + eval <<-EOF.gsub(/^.*?: /, "") + 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 = [] + eval <<-EOF.gsub(/^.*?: /, "") + 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] + 5: }) + 6: fb.foobar + 7: set_trace_func(nil) + EOF + + [["c-return", 5, :set_trace_func, Kernel], + ["line", 6, __method__, self.class], + ["call", 6, :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 end diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb index 43e16b8c79..c226fdd611 100644 --- a/test/ruby/test_signal.rb +++ b/test/ruby/test_signal.rb @@ -1,56 +1,75 @@ require 'test/unit' require 'timeout' +require 'tempfile' +require_relative 'envutil' class TestSignal < Test::Unit::TestCase def have_fork? begin - fork{} - true + Process.fork {} + return true rescue NotImplementedError - false + return false end end def test_signal - defined?(Process.kill) or return + return unless Process.respond_to?(:kill) begin - $x = 0 - oldtrap = trap "SIGINT", proc{|sig| $x = 2} - Process.kill "SIGINT", $$ - sleep 0.1 - assert_equal(2, $x) - - trap "SIGINT", proc{raise "Interrupt"} - - x = assert_raises(RuntimeError) do - Process.kill "SIGINT", $$ + 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(x) - assert_match(/Interrupt/, x.message) + assert_equal 2, x + + Signal.trap(:INT) { raise "Interrupt" } + ex = assert_raise(RuntimeError) { + Process.kill :INT, Process.pid + sleep 0.1 + } + assert_kind_of Exception, ex + assert_match(/Interrupt/, ex.message) ensure - trap "SIGINT", oldtrap + Signal.trap :INT, oldtrap if oldtrap + end + end + + def test_signal_process_group + return unless Process.respond_to?(:kill) + return unless Process.respond_to?(:pgroup) # for mswin32 + + 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 def test_exit_action - return unless have_fork? # snip this test + return unless have_fork? # skip this test begin r, w = IO.pipe r0, w0 = IO.pipe - pid = fork { - trap(:USR1, "EXIT") - w0.close + pid = Process.spawn(EnvUtil.rubybin, '-e', <<-'End', 3=>w, 4=>r0) + w = IO.new(3, "w") + r0 = IO.new(4, "r") + Signal.trap(:USR1, "EXIT") w.syswrite("a") - Thread.start { Thread.pass } + Thread.start { sleep(2) } r0.sysread(4096) - } + End r.sysread(1) sleep 0.1 assert_nothing_raised("[ruby-dev:26128]") { Process.kill(:USR1, pid) begin - Timeout.timeout(10) { + Timeout.timeout(3) { Process.waitpid pid } rescue Timeout::Error @@ -65,4 +84,140 @@ class TestSignal < Test::Unit::TestCase w0.close end end + + def test_invalid_signal_name + return unless Process.respond_to?(:kill) + + assert_raise(ArgumentError) { Process.kill(:XXXXXXXXXX, $$) } + end + + def test_signal_exception + assert_raise(ArgumentError) { SignalException.new } + assert_raise(ArgumentError) { SignalException.new(-1) } + assert_raise(ArgumentError) { SignalException.new(:XXXXXXXXXX) } + 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 + return unless Process.respond_to?(:kill) + 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 + + def test_trap + return unless Process.respond_to?(:kill) + 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") } + + ensure + Signal.trap(:INT, oldtrap) if oldtrap + end + end + + def test_kill_immediately_before_termination + return unless have_fork? # skip this test + + r, w = IO.pipe + pid = Process.fork do + r.close + Signal.trap(:USR1) { w.syswrite("foo") } + Process.kill :USR1, $$ + end + w.close + assert_equal(r.read, "foo") + end + + def test_signal_requiring + t = Tempfile.new(%w"require_ensure_test .rb") + t.puts "sleep" + t.close + error = IO.popen([EnvUtil.rubybin, "-e", <<EOS, t.path, :err => File::NULL]) do |child| +trap(:INT, "DEFAULT") +th = Thread.new do + begin + require ARGV[0] + ensure + Marshal.dump($!, STDOUT) + STDOUT.flush + end +end +Thread.pass while th.running? +Process.kill(:INT, $$) +th.join +EOS + Marshal.load(child) + end + t.close! + assert_nil(error) + end end diff --git a/test/ruby/test_sleep.rb b/test/ruby/test_sleep.rb new file mode 100644 index 0000000000..989ced92c7 --- /dev/null +++ b/test/ruby/test_sleep.rb @@ -0,0 +1,15 @@ +require 'test/unit' + +class TestSleep < Test::Unit::TestCase + def test_sleep_5sec + GC.disable + start = Time.now + sleep 5 + slept = Time.now-start + bottom = /linux/ =~ RUBY_PLATFORM && /Linux ([\d.]+)/ =~ `uname -sr` && ($1.split('.')<=>%w/2 6 18/)<1 ? 4.99 : 5.0 + assert_operator(bottom, :<=, slept) + assert_operator(slept, :<=, 6.0, "[ruby-core:18015]: longer than expected") + ensure + GC.enable + end +end diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb new file mode 100644 index 0000000000..218d2188b7 --- /dev/null +++ b/test/ruby/test_sprintf.rb @@ -0,0 +1,334 @@ +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_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%") } + 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]") + 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)) + 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(b1 == b2, "[ruby-dev:33224]") + end + + def test_named + assert_equal("value", sprintf("%<key>s", :key => "value")) + assert_raise(ArgumentError) {sprintf("%1$<key2>s", :key => "value")} + assert_raise(ArgumentError) {sprintf("%<key><key2>s", :key => "value")} + assert_equal("value", sprintf("%{key}", :key => "value")) + assert_raise(ArgumentError) {sprintf("%1${key2}", :key => "value")} + assert_equal("value{key2}", sprintf("%{key}{key2}", :key => "value")) + end +end diff --git a/test/ruby/test_sprintf_comb.rb b/test/ruby/test_sprintf_comb.rb new file mode 100644 index 0000000000..c58ddf4f15 --- /dev/null +++ b/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/test/ruby/test_string.rb b/test/ruby/test_string.rb index f8938cad84..6185e23c90 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -1,13 +1,1401 @@ require 'test/unit' +require_relative 'envutil' + +# use of $= is deprecated after 1.7.1 +def pre_1_7_1 +end class TestString < Test::Unit::TestCase + + 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_nil("foo" <=> o) + + 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(-(2**100), "foo" <=> o) + end + + def test_EQUAL # '==' + assert_equal(false, S("foo") == :foo) + assert(S("abcdef") == S("abcdef")) + + pre_1_7_1 do + $= = true + assert(S("CAT") == S('cat')) + assert(S("CaT") == S('cAt')) + $= = false + end + + assert(S("CAT") != S('cat')) + assert(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) + case a + when b + assert(!rev) + else + assert(rev) + 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 untrust in [ false, true ] + for frozen in [ false, true ] + a = S("Cool") + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end + 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('!'))) + 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(5, "abc\u{3042 3044 3046}".count("^\u3042")) + assert_equal(2, "abc\u{3042 3044 3046}".count("a-z", "^a")) + + assert_raise(ArgumentError) { "foo".count } + end + + def test_crypt + assert_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("aa"))) + assert(S('aaGUC/JkO9/Sc') != S("mypassword").crypt(S("ab"))) + 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")) + 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 untrust in [ false, true ] + for frozen in [ false, true ] + a = S("hello") + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert(!b.frozen?) + assert_equal(a.tainted?, b.tainted?) + assert_equal(a.untrusted?, b.untrusted?) + end + 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 + res = [] + S("ABC").each_byte {|x| res << x } + assert_equal(65, res[0]) + assert_equal(66, res[1]) + assert_equal(67, res[2]) + end + + def test_each_line + 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 + + s = nil + "foo\nbar".each_line(nil) {|s2| s = s2 } + assert_equal("foo\nbar", s) + end + + def test_empty? + assert(S("").empty?) + assert(!S("not").empty?) + end + + def test_eql? + a = S("hello") + assert(a.eql?(S("hello"))) + assert(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 }) + + a = S("hello") + a.taint + a.untrust + assert(a.gsub(/./, S('X')).tainted?) + assert(a.gsub(/./, S('X')).untrusted?) + + 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 + 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 + r.untrust + a.gsub!(/./, r) + assert(a.tainted?) + assert(a.untrusted?) + + 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(S("hello").hash != S("helLO").hash) + bug4104 = '[ruby-core:33500]' + assert_not_equal(S("a").hash, S("a\0").hash, bug4104) + 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( S("foobar").include?(?f)) + assert( S("foobar").include?(S("foo"))) + assert(!S("foobar").include?(S("baz"))) + assert(!S("foobar").include?(?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./)) + + 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(: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 + a.untrust + b = a.replace(S("xyz")) + assert_equal(S("xyz"), b) + assert(b.tainted?) + assert(b.untrusted?) + + 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 + a.untrust + res = [] + a.scan(/./) { |w| res << w } + assert(res[0].tainted?, '[ruby-core:33338] #4087') + assert(res[0].untrusted?, '[ruby-core:33338] #4087') + 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"))) + 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") + + 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_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_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("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 + a.untrust + x = a.sub(/./, S('X')) + assert(x.tainted?) + assert(x.untrusted?) + + 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 }) + 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 + r.untrust + a.sub!(/./, r) + assert(a.tainted?) + assert(a.untrusted?) + 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(15 != n.sum) + 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 + + def test_sum_2 assert_equal(0, "".sum) assert_equal(294, "abc".sum) check_sum("abc") @@ -16,4 +1404,600 @@ class TestString < Test::Unit::TestCase 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)) + 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?) + 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_end_with? + assert("abc".end_with?("c")) + 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 = /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_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 + 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 + end + + def test_setter + assert_raise(TypeError) { $/ = 1 } + 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 + ext = Encoding.default_external + Encoding.default_external = "us-ascii" + i = "abc\"\\".force_encoding("utf-8").inspect + ensure + Encoding.default_external = ext + 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?) + assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?) + end end diff --git a/test/ruby/test_stringchar.rb b/test/ruby/test_stringchar.rb index 34934e87bd..44c8634c02 100644 --- a/test/ruby/test_stringchar.rb +++ b/test/ruby/test_stringchar.rb @@ -34,11 +34,11 @@ class TestStringchar < Test::Unit::TestCase ABCD ABCD END - $x.gsub!(/((.|\n)*?)B((.|\n)*?)D/){$1+$3} + $x.gsub!(/((.|\n)*?)B((.|\n)*?)D/m ,'\1\3') assert_equal("AC\nAC\n", $x) - assert("foobar" =~ /foo(?=(bar)|(baz))/) - assert("foobaz" =~ /foo(?=(bar)|(baz))/) + assert_match(/foo(?=(bar)|(baz))/, "foobar") + assert_match(/foo(?=(bar)|(baz))/, "foobaz") $foo = "abc" assert_equal("abc = abc", "#$foo = abc") @@ -68,9 +68,9 @@ END # character constants(assumes ASCII) assert_equal(?a, "a"[0]) assert_equal(?a, ?a) - assert_equal(1, ?\C-a) - assert_equal(225, ?\M-a) - assert_equal(129, ?\M-\C-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")) @@ -82,7 +82,7 @@ END $y = [ ?a, ?b, ?c, ?d, ?e, ?f ] $bad = false $x.each_byte {|i| - if i != $y.shift + if i.chr != $y.shift $bad = true break end @@ -163,4 +163,19 @@ EOS 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/test/ruby/test_struct.rb b/test/ruby/test_struct.rb index fa1bb1549a..49dcdb45b2 100644 --- a/test/ruby/test_struct.rb +++ b/test/ruby/test_struct.rb @@ -1,4 +1,5 @@ require 'test/unit' +require 'timeout' class TestStruct < Test::Unit::TestCase def test_struct @@ -21,4 +22,231 @@ class TestStruct < Test::Unit::TestCase 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_modify + klass = Struct.new(:a) + o = klass.new(1) + assert_raise(SecurityError) do + Thread.new do + $SAFE = 4 + o.a = 2 + end.value + end + 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) + 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("#<struct :@a=1>", o.inspect) + 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] } + 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 } + 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_equal + klass1 = Struct.new(:a) + klass2 = Struct.new(:a, :b) + o1 = klass1.new(1) + o2 = klass1.new(1) + o3 = klass2.new(1) + assert(o1.==(o2)) + assert(o1 != o3) + end + + def test_hash + klass = Struct.new(:a) + o = klass.new(1) + assert(o.hash.is_a?(Fixnum)) + 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(o1.eql?(o2)) + assert(!(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_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]') + 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 x == y + assert x.eql? y + } + + z = klass1.new(:something, :other, nil); z.c = z + Timeout.timeout(1) { + assert x != z + assert !x.eql?(z) + } + + x.c = y; y.c = x + Timeout.timeout(1) { + assert x == y + assert x.eql?(y) + } + + x.c = z; z.c = x + Timeout.timeout(1) { + assert x != z + assert !x.eql?(z) + } + end end diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index 900fe997e6..743b71d73f 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -120,15 +120,68 @@ class TestSuper < Test::Unit::TestCase def uu(a) class << self define_method(:tt) do |sym| - super + super(sym) end end end end - def test_define_method # [ruby-core:03856] + def test_define_method a = A.new a.uu(12) - assert_equal("A#tt", a.tt(12)) + assert_equal("A#tt", a.tt(12), "[ruby-core:3856]") + e = assert_raise(RuntimeError, "[ruby-core:24244]") { + lambda { + Class.new do + define_method(:a) {super}.call + end + }.call + } + assert_match(/implicit argument passing of super from method defined by define_method/, e.message) + 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(ary = [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 end diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb index 2ccfe64c92..23c50e6778 100644 --- a/test/ruby/test_symbol.rb +++ b/test/ruby/test_symbol.rb @@ -3,21 +3,25 @@ require 'test/unit' class TestSymbol < Test::Unit::TestCase # [ruby-core:3573] - def assert_eval_inspected(sym) + 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(:"=") - assert_eval_inspected(:"0") + assert_eval_inspected(:"=", false) + assert_eval_inspected(:"0", false) assert_eval_inspected(:"$1") - assert_eval_inspected(:"@1") - assert_eval_inspected(:"@@1") - assert_eval_inspected(:"@") - assert_eval_inspected(:"@@") + assert_eval_inspected(:"@1", false) + assert_eval_inspected(:"@@1", false) + assert_eval_inspected(:"@", false) + assert_eval_inspected(:"@@", false) end def assert_inspect_evaled(n) @@ -29,7 +33,7 @@ class TestSymbol < Test::Unit::TestCase 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(':>=') @@ -69,9 +73,106 @@ class TestSymbol < Test::Unit::TestCase end def test_inspect_number - # 5) Inconsistency between :$0 and :$1? The first one is valid, but the + # 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_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 end diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb new file mode 100644 index 0000000000..a65b567153 --- /dev/null +++ b/test/ruby/test_syntax.rb @@ -0,0 +1,94 @@ +require 'test/unit' + +class TestSyntax < Test::Unit::TestCase + def assert_valid_syntax(code, fname, mesg = fname) + code = code.dup.force_encoding("ascii-8bit") + code.sub!(/\A(?:\xef\xbb\xbf)?(\s*\#.*$)*(\n)?/n) { + "#$&#{"\n" if $1 && !$2}BEGIN{throw tag, :ok}\n" + } + code.force_encoding("us-ascii") + verbose, $VERBOSE = $VERBOSE, nil + assert_nothing_raised(SyntaxError, mesg) do + assert_equal(:ok, catch {|tag| eval(code, binding, fname, 0)}, mesg) + end + ensure + $VERBOSE = verbose + end + + def test_syntax + assert_nothing_raised(Exception) do + for script in Dir[File.expand_path("../../../{lib,sample,ext,test}/**/*.rb", __FILE__)].sort + assert_valid_syntax(IO::read(script), script) + end + end + 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 + f.close! + 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 + f.close! + 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_reserved_method_no_args + bug6403 = '[ruby-dev:45626]' + assert_valid_syntax("def self; :foo; end", __FILE__, bug6403) + end + + private + + 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 +end diff --git a/test/ruby/test_system.rb b/test/ruby/test_system.rb index 3513577ec5..f1372781cf 100644 --- a/test/ruby/test_system.rb +++ b/test/ruby/test_system.rb @@ -1,67 +1,139 @@ require 'test/unit' -$:.replace([File.dirname(File.expand_path(__FILE__))] | $:) -require 'envutil' +require 'tmpdir' +require_relative 'envutil' class TestSystem < Test::Unit::TestCase - def valid_syntax?(code, fname) - code = code.sub(/\A(?:\s*\#.*$)*(\n)?/n) { - "#$&#{"\n" if $1 && !$2}BEGIN{return true}\n" - } - eval(code, nil, fname, 0) - end - def test_system ruby = EnvUtil.rubybin assert_equal("foobar\n", `echo foobar`) assert_equal('foobar', `#{ruby} -e 'print "foobar"'`) - tmp = open("script_tmp", "w") - tmp.print "print $zzz\n"; - tmp.close + Dir.mktmpdir("ruby_script_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}" - assert_equal('true', `#{ruby} -s script_tmp -zzz`) - assert_equal('555', `#{ruby} -s script_tmp -zzz=555`) + tmp = open(tmpfilename, "w") + tmp.print "print $zzz\n"; + tmp.close - tmp = open("script_tmp", "w") - tmp.print "#! /usr/local/bin/ruby -s\n"; - tmp.print "print $zzz\n"; - tmp.close + assert_equal('true', `#{ruby} -s #{tmpfilename} -zzz`) + assert_equal('555', `#{ruby} -s #{tmpfilename} -zzz=555`) - assert_equal('678', `#{ruby} script_tmp -zzz=678`) + tmp = open(tmpfilename, "w") + tmp.print "#! /usr/local/bin/ruby -s\n"; + tmp.print "print $zzz\n"; + tmp.close - tmp = open("script_tmp", "w") - tmp.print "this is a leading junk\n"; - tmp.print "#! /usr/local/bin/ruby -s\n"; - tmp.print "print $zzz\n"; - tmp.print "__END__\n"; - tmp.print "this is a trailing junk\n"; - tmp.close + assert_equal('678', `#{ruby} #{tmpfilename} -zzz=678`) - assert_equal('nil', `#{ruby} -x script_tmp`) - assert_equal('555', `#{ruby} -x script_tmp -zzz=555`) + 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 - tmp = open("script_tmp", "w") - for i in 1..5 - tmp.print i, "\n" - end - tmp.close + assert_equal('', `#{ruby} -x #{tmpfilename}`) + assert_equal('555', `#{ruby} -x #{tmpfilename} -zzz=555`) - `#{ruby} -i.bak -pe 'sub(/^[0-9]+$/){$&.to_i * 5}' script_tmp` - tmp = open("script_tmp", "r") - while tmp.gets - assert_equal(0, $_.to_i % 5) - end - tmp.close + 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`) - File.unlink "script_tmp" or `/bin/rm -f "script_tmp"` - File.unlink "script_tmp.bak" or `/bin/rm -f "script_tmp.bak"` + 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 + end + } end - def test_syntax - assert_nothing_raised(Exception) do - for script in Dir[File.expand_path("../../../{lib,sample,ext}/**/*.rb", __FILE__)] - valid_syntax? IO::read(script), script + 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 + + cmd = "%WINDIR%/system32/ping.exe \"BFI3CHL671\" > out.txt 2>NUL" + assert_equal(false, system(cmd), '[ruby-talk:258939]'); + + cmd = "\"%WINDIR%/system32/ping.exe BFI3CHL671\" > out.txt 2>NUL" + assert_equal(false, system(cmd), '[ruby-talk:258939]'); + 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/test/ruby/test_thread.rb b/test/ruby/test_thread.rb new file mode 100644 index 0000000000..4d99053b2f --- /dev/null +++ b/test/ruby/test_thread.rb @@ -0,0 +1,740 @@ +require 'test/unit' +require 'thread' +require_relative 'envutil' + +class TestThread < Test::Unit::TestCase + class Thread < ::Thread + Threads = [] + def self.new(*) + th = super + th.abort_on_exception = true + 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_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_condvar + mutex = Mutex.new + condvar = ConditionVariable.new + result = [] + mutex.synchronize do + t = Thread.new do + mutex.synchronize do + result << 1 + condvar.signal + end + end + + result << 0 + condvar.wait(mutex) + result << 2 + t.join + end + assert_equal([0, 1, 2], result) + end + + def test_condvar_wait_not_owner + mutex = Mutex.new + condvar = ConditionVariable.new + + assert_raise(ThreadError) { condvar.wait(mutex) } + end + + def test_condvar_wait_exception_handling + # Calling wait in the only thread running should raise a ThreadError of + # 'stopping only thread' + mutex = Mutex.new + condvar = ConditionVariable.new + + locked = false + thread = Thread.new do + Thread.current.abort_on_exception = false + mutex.synchronize do + begin + condvar.wait(mutex) + rescue Exception + locked = mutex.locked? + raise + end + end + end + + until thread.stop? + sleep(0.1) + end + + thread.raise Interrupt, "interrupt a dead condition variable" + assert_raise(Interrupt) { thread.value } + assert(locked) + end + + def test_condvar_wait_and_broadcast + nr_threads = 3 + threads = Array.new + mutex = Mutex.new + condvar = ConditionVariable.new + result = [] + + nr_threads.times do |i| + threads[i] = Thread.new do + mutex.synchronize do + result << "C1" + condvar.wait mutex + result << "C2" + end + end + end + sleep 0.1 + mutex.synchronize do + result << "P1" + condvar.broadcast + result << "P2" + end + nr_threads.times do |i| + threads[i].join + end + + assert_equal ["C1", "C1", "C1", "P1", "P2", "C2", "C2", "C2"], result + end + +# Hmm.. don't we have a way of catch fatal exception? +# +# def test_cv_wait_deadlock +# mutex = Mutex.new +# cv = ConditionVariable.new +# +# assert_raises(fatal) { +# mutex.lock +# cv.wait mutex +# mutex.unlock +# } +# end + + def test_condvar_wait_deadlock_2 + nr_threads = 3 + threads = Array.new + mutex = Mutex.new + condvar = ConditionVariable.new + + nr_threads.times do |i| + if (i != 0) + mutex.unlock + end + threads[i] = Thread.new do + mutex.synchronize do + condvar.wait mutex + end + end + mutex.lock + end + + assert_raise(Timeout::Error) do + Timeout.timeout(0.1) { condvar.wait mutex } + end + mutex.unlock rescue + threads[i].each.join + end + + def test_condvar_timed_wait + mutex = Mutex.new + condvar = ConditionVariable.new + timeout = 0.3 + locked = false + + t0 = Time.now + mutex.synchronize do + begin + condvar.wait(mutex, timeout) + ensure + locked = mutex.locked? + end + end + t1 = Time.now + t = t1-t0 + + assert_block { timeout*0.9 < t && t < timeout*1.1 } + assert(locked) + end + + def test_condvar_nolock + mutex = Mutex.new + condvar = ConditionVariable.new + + assert_raise(ThreadError) { condvar.wait(mutex) } + end + + def test_condvar_nolock_2 + mutex = Mutex.new + condvar = ConditionVariable.new + + Thread.new do + assert_raise(ThreadError) {condvar.wait(mutex)} + end.join + end + + def test_condvar_nolock_3 + mutex = Mutex.new + condvar = ConditionVariable.new + + Thread.new do + assert_raise(ThreadError) {condvar.wait(mutex, 0.1)} + end.join + end + + def test_local_barrier + dir = File.dirname(__FILE__) + lbtest = File.join(dir, "lbtest.rb") + $:.unshift File.join(File.dirname(dir), 'ruby') + require 'envutil' + $:.shift + 3.times { + result = `#{EnvUtil.rubybin} #{lbtest}` + assert(!$?.coredump?, '[ruby-dev:30653]') + assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]') + } + end + + def test_priority + c1 = c2 = 0 + t1 = Thread.new { loop { c1 += 1 } } + t1.priority = -1 + t2 = Thread.new { loop { c2 += 1 } } + t2.priority = -3 + assert_equal(-1, t1.priority) + assert_equal(-3, t2.priority) + sleep 0.5 + 5.times do + break if c1 > c2 + sleep 0.1 + end + 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.5)) + + ensure + t.kill if t + end + + def test_join2 + t1 = Thread.new { sleep(1.5) } + t2 = Thread.new do + t1.join(1) + end + t3 = Thread.new do + sleep 0.5 + t1.join + end + assert_nil(t2.value) + 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 + sleep 0.5 + assert_equal(1, s) + t.wakeup + sleep 0.5 + 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.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 + Thread.new { raise } + sleep 0.5 + 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 + Thread.new { raise } + sleep 0.5 + p 1 + rescue + p 2 + end + INPUT + + assert_in_out_err([], <<-INPUT, %w(false true 2), []) + p Thread.abort_on_exception + begin + t = Thread.new { sleep 0.5; raise } + t.abort_on_exception = true + p t.abort_on_exception + 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 } + d = Thread.new { sleep } + e = Thread.current + sleep 0.5 + + assert_equal(nil, a.status) + assert(a.stop?) + + assert_equal("sleep", b.status) + assert(b.stop?) + + assert_equal(false, c.status) + assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect) + assert(c.stop?) + + d.kill + assert_equal(["aborting", false], [d.status, d.stop?]) + + assert_equal(["run", false], [e.status, e.stop?]) + + ensure + a.kill if a + b.kill if b + c.kill if c + d.kill if d + end + + def test_safe_level + t = Thread.new { $SAFE = 3; sleep } + sleep 0.5 + 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 + t = Thread.new { sleep } + + assert_raise(SecurityError) do + Thread.new { $SAFE = 4; t[:foo] }.join + end + + assert_raise(SecurityError) do + Thread.new { $SAFE = 4; t[:foo] = :baz }.join + end + + assert_raise(RuntimeError) do + Thread.new do + Thread.current[:foo] = :bar + Thread.current.freeze + Thread.current[:foo] = :baz + end.join + end + end + + def test_select_wait + assert_nil(IO.select(nil, nil, nil, 1)) + t = Thread.new do + IO.select(nil, nil, nil, nil) + end + sleep 0.5 + 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 + sleep 0.5 + 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]) + 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]' + error = assert_raise(RuntimeError) do + Thread.new(&Module.method(:nesting)).join + end + assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083) + error = assert_raise(RuntimeError) do + Thread.new(:to_s, &Module.method(:undef_method)).join + end + assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083) + end +end + +class TestThreadGroup < Test::Unit::TestCase + def test_thread_init + thgrp = ThreadGroup.new + Thread.new{ + thgrp.add(Thread.current) + assert_equal(thgrp, Thread.new{sleep 1}.group) + }.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 + + 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 = '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) + unless /mswin|mingw/ =~ RUBY_PLATFORM + # status of signal is not supported on Windows + assert_equal([false, true, false, Signal.list["INT"]], + [s.exited?, s.signaled?, s.stopped?, s.termsig], + "[s.exited?, s.signaled?, s.stopped?, s.termsig]") + end + assert_in_delta(t1 - t0, 1, 1) + end + + 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) +end diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index ad9b64ae0e..03172149ea 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -1,12 +1,60 @@ require 'test/unit' +require 'rational' +require 'delegate' +require 'timeout' +require 'delegate' class TestTime < Test::Unit::TestCase + def setup + @verbose = $VERBOSE + $VERBOSE = nil + end + + def teardown + $VERBOSE = @verbose + 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) + 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((Time.utc(2000, 4, 1) + 24).utc?) + assert(!(Time.local(2000, 4, 1) + 24).utc?) + + t = Time.new(2000, 4, 1, 0, 0, 0, "+01:00") + 24 + assert(!t.utc?) + assert_equal(3600, t.utc_offset) + t = Time.new(2000, 4, 1, 0, 0, 0, "+02:00") + 24 + assert(!t.utc?) + assert_equal(7200, t.utc_offset) end def test_time_subt() @@ -63,12 +111,670 @@ class TestTime < Test::Unit::TestCase end end - def test_huge_difference # [ruby-dev:22619] + 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) + 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) + 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(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_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 + + # Sat Jan 01 00:00:00 UTC 2000 + T2000 = Time.at(946684800).gmtime + + def test_security_error + assert_raise(SecurityError) do + Thread.new do + t = Time.gm(2000) + $SAFE = 4 + t.localtime + end.join + end + end + + def test_at3 + 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 + 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 + assert_equal(946684800.0, T2000.to_f) + end + + def test_cmp + assert_equal(-1, T2000 <=> Time.gm(2001)) + assert_equal(1, T2000 <=> Time.gm(1999)) + assert_nil(T2000 <=> 0) + end + + def test_eql + assert(T2000.eql?(T2000)) + assert(!T2000.eql?(Time.gm(2001))) + end + + def test_utc_p + assert(Time.gm(2000).gmt?) + assert(!Time.local(2000).gmt?) + assert(!Time.at(0).gmt?) + end + + def test_hash + 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 + 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(t.gmt?) + t.localtime + assert(!t.gmt?) + t.localtime + assert(!t.gmt?) + t.gmtime + assert(t.gmt?) + t.gmtime + assert(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) + 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 + assert_equal("Sat Jan 1 00:00:00 2000", T2000.asctime) + assert_kind_of(String, Time.at(0).asctime) + end + + def test_to_s + assert_equal("2000-01-01 00:00:00 UTC", T2000.to_s) + 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 test_plus_minus_succ + # 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 + 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_equal(Encoding.find("locale"), T2000.zone.encoding) + assert_equal(0, T2000.gmt_offset) + assert(!T2000.sunday?) + assert(!T2000.monday?) + assert(!T2000.tuesday?) + assert(!T2000.wednesday?) + assert(!T2000.thursday?) + assert(!T2000.friday?) + assert(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_equal(Encoding.find("locale"), Time.at(946684800).zone.encoding) + 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 + 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")) + + 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")) + assert_equal("000", t.strftime("%3S")) + assert_equal("946684800", t.strftime("%s")) + assert_equal("946684800", t.utc.strftime("%s")) + + t = Time.mktime(2001, 10, 1) + assert_equal("2001-10-01", t.strftime("%F")) + + 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")) + + 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")) + + # [ruby-dev:37155] + t = Time.mktime(1970, 1, 18) + assert_equal("0", t.strftime("%w")) + assert_equal("7", t.strftime("%u")) + + # [ruby-dev:37160] + 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")) + + # [ruby-dev:37162] + 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")) + + 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")) + + # [ruby-core:33985] + assert_equal("3000000000", Time.at(3000000000).strftime('%s')) + + bug4457 = '[ruby-dev:43285]' + assert_raise(Errno::ERANGE, bug4457) {Time.now.strftime('%8192z')} + + bug4458 = '[ruby-dev:43287]' + t = T2000.getlocal("+09:00") + assert_equal(" +900", t.strftime("%_10z"), bug4458) + assert_equal("+000000900", t.strftime("%10z"), bug4458) + assert_equal(" +9:00", t.strftime("%_:10z"), bug4458) + assert_equal("+000009:00", t.strftime("%:10z"), bug4458) + assert_equal(" +9:00:00", t.strftime("%_::10z"), bug4458) + assert_equal("+009:00:00", t.strftime("%::10z"), bug4458) + t = T2000.getlocal("-05:00") + assert_equal(" -500", t.strftime("%_10z"), bug4458) + assert_equal("-000000500", t.strftime("%10z"), bug4458) + assert_equal(" -5:00", t.strftime("%_:10z"), bug4458) + assert_equal("-000005:00", t.strftime("%:10z"), bug4458) + assert_equal(" -5:00:00", t.strftime("%_::10z"), bug4458) + assert_equal("-005:00:00", t.strftime("%::10z"), bug4458) + + 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("%_:10z"), bug6323) + assert_equal("+000000:36", t.strftime("%:10z"), bug6323) + assert_equal(" +0:36:00", t.strftime("%_::10z"), bug6323) + assert_equal("+000:36:00", t.strftime("%::10z"), bug6323) + 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("%_:10z"), bug6323) + assert_equal("-000000:55", t.strftime("%:10z"), bug6323) + assert_equal(" -0:55:00", t.strftime("%_::10z"), bug6323) + assert_equal("-000:55:00", t.strftime("%::10z"), bug6323) + 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 end diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb new file mode 100644 index 0000000000..42c4607bf3 --- /dev/null +++ b/test/ruby/test_time_tz.rb @@ -0,0 +1,338 @@ +require 'test/unit' + +class TestTimeTZ < Test::Unit::TestCase + def with_tz(tz) + if /linux/ =~ RUBY_PLATFORM || ENV["RUBY_FORCE_TIME_TZ_TEST"] == "yes" + old = ENV["TZ"] + begin + ENV["TZ"] = tz + yield + ensure + ENV["TZ"] = old + end + else + if ENV["TZ"] == tz + yield + end + end + end + + module Util + 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 + + def time_to_s(t) + if RUBY_VERSION < "1.9" + t.strftime("%Y-%m-%d %H:%M:%S ") + format_gmtoff(t.gmtoff) + else + t.to_s + end + 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="Canada/Newfoundland") { + 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_lisbon + with_tz(tz="Europe/Lisbon") { + assert_equal("LMT", Time.new(-0x1_0000_0000_0000_0000).zone) + } + end + + 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 + + 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 + + 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.gen_zdump_test + sample = [] + ZDUMP_SAMPLE.each_line {|line| + next if /\A\#/ =~ line || /\A\s*\z/ =~ line + /\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 + 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 + sample << [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] + } + 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")) + } + } + } + group_by(sample) {|tz, _, _, _| tz }.each {|tz, a| + a.each_with_index {|(_, u, 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 + + ZDUMP_SAMPLE = <<'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 +Canada/Newfoundland Sun Mar 11 03:30:59 2007 UTC = Sun Mar 11 00:00:59 2007 NST isdst=0 gmtoff=-12600 +Canada/Newfoundland Sun Mar 11 03:31:00 2007 UTC = Sun Mar 11 01:01:00 2007 NDT isdst=1 gmtoff=-9000 +Canada/Newfoundland Sun Nov 4 02:30:59 2007 UTC = Sun Nov 4 00:00:59 2007 NDT isdst=1 gmtoff=-9000 +Canada/Newfoundland 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 +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 +Europe/Lisbon Mon Jan 1 00:36:31 1912 UTC = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2192 +End + gen_zdump_test +end diff --git a/test/ruby/test_trace.rb b/test/ruby/test_trace.rb index 6adfe0bf64..775c458fb1 100644 --- a/test/ruby/test_trace.rb +++ b/test/ruby/test_trace.rb @@ -7,15 +7,55 @@ class TestTrace < Test::Unit::TestCase 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/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb new file mode 100644 index 0000000000..d6e5852743 --- /dev/null +++ b/test/ruby/test_transcode.rb @@ -0,0 +1,1968 @@ +# 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 + default_default_internal = Encoding.default_internal + Encoding.default_internal = nil + assert_equal("\u3042".encode, "\u3042") + assert_equal("\xE3\x81\x82\x81".force_encoding("utf-8").encode, + "\xE3\x81\x82\x81".force_encoding("utf-8")) + Encoding.default_internal = 'EUC-JP' + 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')) + Encoding.default_internal = default_default_internal + 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) + 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_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("\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("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("\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!", + "\xa1!".encode("utf-8", "euc-jp", :invalid=>:replace)) + assert_equal("\uFFFD!", + "\x8f\xa1!".encode("utf-8", "euc-jp", :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>")) + 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_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 + assert_equal("\u{fb4d}", "\u05DB\u05BF".encode("UTF-8", "UTF8-MAC")) + assert_equal("\u{1ff7}", "\u03C9\u0345\u0342".encode("UTF-8", "UTF8-MAC")) + + assert_equal("\u05DB\u05BF", "\u{fb4d}".encode("UTF8-MAC").force_encoding("UTF-8")) + assert_equal("\u03C9\u0345\u0342", "\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 +end diff --git a/test/ruby/test_undef.rb b/test/ruby/test_undef.rb new file mode 100644 index 0000000000..e1c98076c0 --- /dev/null +++ b/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/test/ruby/test_unicode_escape.rb b/test/ruby/test_unicode_escape.rb new file mode 100644 index 0000000000..088f81ce14 --- /dev/null +++ b/test/ruby/test_unicode_escape.rb @@ -0,0 +1,269 @@ +# -*- 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$/, `echo "\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/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 8726160826..32b3d61573 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -1,4 +1,5 @@ require 'test/unit' +require_relative 'envutil' class TestVariable < Test::Unit::TestCase class Gods @@ -25,17 +26,21 @@ class TestVariable < Test::Unit::TestCase end class Titans < Gods - @@rule = "Cronus" - include Olympians # OK to cause warning (intentional) + @@rule = "Cronus" # modifies @@rule in Gods + include Olympians + def ruler4 + @@rule + end end def test_variable assert_instance_of(Fixnum, $$) - + # read-only variable - assert_raises(NameError) do + assert_raise(NameError) do $$ = 5 end + assert_normal_exit("$*=0; $*", "[ruby-dev:36698]") foobar = "foobar" $_ = foobar @@ -49,5 +54,44 @@ class TestVariable < Test::Unit::TestCase 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]") + end + + def test_local_variables2 + x = 1 + proc do |y| + assert_equal([:x, :y], local_variables.sort) + end.call + 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 + 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 { eval("$foo; 1") } + end + + def test_constant_poped + assert_nothing_raised { eval("TestVariable::Gods; 1") } end end diff --git a/test/ruby/test_whileuntil.rb b/test/ruby/test_whileuntil.rb index 6faed31160..5628317cb8 100644 --- a/test/ruby/test_whileuntil.rb +++ b/test/ruby/test_whileuntil.rb @@ -1,70 +1,75 @@ require 'test/unit' +require 'tmpdir' class TestWhileuntil < Test::Unit::TestCase def test_while - tmp = open("while_tmp", "w") - tmp.print "tvi925\n"; - tmp.print "tvi920\n"; - tmp.print "vt100\n"; - tmp.print "Amiga\n"; - tmp.print "paper\n"; - tmp.close + Dir.mktmpdir("ruby_while_tmp") {|tmpdir| + tmpfilename = "#{tmpdir}/ruby_while_tmp.#{$$}" - tmp = open("while_tmp", "r") - assert_instance_of(File, tmp) - - while line = tmp.gets() - break if /vt100/ =~ line - end + 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(!tmp.eof?) - assert_match(/vt100/, line) - tmp.close + assert(!tmp.eof?) + assert_match(/vt100/, line) + tmp.close - tmp = open("while_tmp", "r") - while line = tmp.gets() - next if /vt100/ =~ line + tmp = open(tmpfilename, "r") + while line = tmp.gets() + next if /vt100/ =~ line + assert_no_match(/vt100/, line) + end + assert(tmp.eof?) assert_no_match(/vt100/, line) - end - assert(tmp.eof?) - assert_no_match(/vt100/, line) - tmp.close + tmp.close - tmp = open("while_tmp", "r") - while tmp.gets() - line = $_ - gsub(/vt100/, 'VT100') - if $_ != line - $_.gsub!('VT100', 'Vt100') - redo + 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_no_match(/vt100/, $_) - assert_no_match(/VT100/, $_) - end - assert(tmp.eof?) - tmp.close + assert(tmp.eof?) + tmp.close - sum=0 - for i in 1..10 - sum += i - i -= 1 - if i > 0 - redo + sum=0 + for i in 1..10 + sum += i + i -= 1 + if i > 0 + redo + end end - end - assert_equal(220, sum) + assert_equal(220, sum) - tmp = open("while_tmp", "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 + 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 "while_tmp" or `/bin/rm -f "while_tmp"` - assert(!File.exist?("while_tmp")) + File.unlink tmpfilename or `/bin/rm -f "#{tmpfilename}"` + assert(!File.exist?(tmpfilename)) + } end def test_until diff --git a/test/ruby/test_yield.rb b/test/ruby/test_yield.rb new file mode 100644 index 0000000000..3337aea078 --- /dev/null +++ b/test/ruby/test_yield.rb @@ -0,0 +1,382 @@ +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 + 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 + 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 + +end diff --git a/test/ruby/ut_eof.rb b/test/ruby/ut_eof.rb index e6f6eddd6f..b7219ddb51 100644 --- a/test/ruby/ut_eof.rb +++ b/test/ruby/ut_eof.rb @@ -6,8 +6,8 @@ module TestEOF assert_equal("", f.read(0)) assert_equal("", f.read(0)) assert_equal("", f.read) - assert_nil(f.read(0)) - assert_nil(f.read(0)) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) } open_file("") {|f| assert_nil(f.read(1)) @@ -43,8 +43,8 @@ module TestEOF assert_equal("" , f.read(0)) assert_equal("" , f.read(0)) assert_equal("", f.read) - assert_nil(f.read(0)) - assert_nil(f.read(0)) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) } open_file("a") {|f| assert_equal("a", f.read(1)) @@ -69,7 +69,7 @@ module TestEOF } open_file("a") {|f| assert_equal("a", f.read) - assert_nil(f.read(0)) + assert_equal("", f.read(0)) } open_file("a") {|f| s = "x" @@ -109,7 +109,7 @@ module TestEOF assert_equal(10, f.pos) assert_equal("", f.read(0)) assert_equal("", f.read) - assert_nil(f.read(0)) + assert_equal("", f.read(0)) assert_equal("", f.read) } end |
