summaryrefslogtreecommitdiff
path: root/jni/ruby/test/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'jni/ruby/test/ruby')
-rw-r--r--jni/ruby/test/ruby/allpairs.rb102
-rw-r--r--jni/ruby/test/ruby/beginmainend.rb80
-rw-r--r--jni/ruby/test/ruby/enc/test_big5.rb28
-rw-r--r--jni/ruby/test/ruby/enc/test_cp949.rb28
-rw-r--r--jni/ruby/test/ruby/enc/test_emoji.rb442
-rw-r--r--jni/ruby/test/ruby/enc/test_euc_jp.rb24
-rw-r--r--jni/ruby/test/ruby/enc/test_euc_kr.rb36
-rw-r--r--jni/ruby/test/ruby/enc/test_euc_tw.rb28
-rw-r--r--jni/ruby/test/ruby/enc/test_gb18030.rb126
-rw-r--r--jni/ruby/test/ruby/enc/test_gbk.rb28
-rw-r--r--jni/ruby/test/ruby/enc/test_iso_8859.rb163
-rw-r--r--jni/ruby/test/ruby/enc/test_koi8.rb22
-rw-r--r--jni/ruby/test/ruby/enc/test_shift_jis.rb27
-rw-r--r--jni/ruby/test/ruby/enc/test_utf16.rb384
-rw-r--r--jni/ruby/test/ruby/enc/test_utf32.rb93
-rw-r--r--jni/ruby/test/ruby/enc/test_windows_1251.rb16
-rw-r--r--jni/ruby/test/ruby/endblockwarn_rb12
-rw-r--r--jni/ruby/test/ruby/lbtest.rb49
-rw-r--r--jni/ruby/test/ruby/marshaltestlib.rb436
-rw-r--r--jni/ruby/test/ruby/sentence.rb668
-rw-r--r--jni/ruby/test/ruby/test_alias.rb196
-rw-r--r--jni/ruby/test/ruby/test_argf.rb859
-rw-r--r--jni/ruby/test/ruby/test_arity.rb69
-rw-r--r--jni/ruby/test/ruby/test_array.rb2533
-rw-r--r--jni/ruby/test/ruby/test_assignment.rb760
-rw-r--r--jni/ruby/test/ruby/test_autoload.rb207
-rw-r--r--jni/ruby/test/ruby/test_backtrace.rb246
-rw-r--r--jni/ruby/test/ruby/test_basicinstructions.rb700
-rw-r--r--jni/ruby/test/ruby/test_beginendblock.rb190
-rw-r--r--jni/ruby/test/ruby/test_bignum.rb711
-rw-r--r--jni/ruby/test/ruby/test_call.rb34
-rw-r--r--jni/ruby/test/ruby/test_case.rb124
-rw-r--r--jni/ruby/test/ruby/test_class.rb402
-rw-r--r--jni/ruby/test/ruby/test_clone.rb28
-rw-r--r--jni/ruby/test/ruby/test_comparable.rb94
-rw-r--r--jni/ruby/test/ruby/test_complex.rb1014
-rw-r--r--jni/ruby/test/ruby/test_complex2.rb735
-rw-r--r--jni/ruby/test/ruby/test_complexrational.rb407
-rw-r--r--jni/ruby/test/ruby/test_condition.rb16
-rw-r--r--jni/ruby/test/ruby/test_const.rb72
-rw-r--r--jni/ruby/test/ruby/test_continuation.rb134
-rw-r--r--jni/ruby/test/ruby/test_defined.rb211
-rw-r--r--jni/ruby/test/ruby/test_dir.rb328
-rw-r--r--jni/ruby/test/ruby/test_dir_m17n.rb389
-rw-r--r--jni/ruby/test/ruby/test_econv.rb926
-rw-r--r--jni/ruby/test/ruby/test_encoding.rb123
-rw-r--r--jni/ruby/test/ruby/test_enum.rb733
-rw-r--r--jni/ruby/test/ruby/test_enumerator.rb628
-rw-r--r--jni/ruby/test/ruby/test_env.rb552
-rw-r--r--jni/ruby/test/ruby/test_eval.rb510
-rw-r--r--jni/ruby/test/ruby/test_exception.rb701
-rw-r--r--jni/ruby/test/ruby/test_fiber.rb347
-rw-r--r--jni/ruby/test/ruby/test_file.rb423
-rw-r--r--jni/ruby/test/ruby/test_file_exhaustive.rb1238
-rw-r--r--jni/ruby/test/ruby/test_fixnum.rb315
-rw-r--r--jni/ruby/test/ruby/test_flip.rb41
-rw-r--r--jni/ruby/test/ruby/test_float.rb683
-rw-r--r--jni/ruby/test/ruby/test_fnmatch.rb131
-rw-r--r--jni/ruby/test/ruby/test_gc.rb379
-rw-r--r--jni/ruby/test/ruby/test_hash.rb1300
-rw-r--r--jni/ruby/test/ruby/test_ifunless.rb14
-rw-r--r--jni/ruby/test/ruby/test_integer.rb280
-rw-r--r--jni/ruby/test/ruby/test_integer_comb.rb631
-rw-r--r--jni/ruby/test/ruby/test_io.rb3171
-rw-r--r--jni/ruby/test/ruby/test_io_m17n.rb2566
-rw-r--r--jni/ruby/test/ruby/test_iseq.rb144
-rw-r--r--jni/ruby/test/ruby/test_iterator.rb497
-rw-r--r--jni/ruby/test/ruby/test_keyword.rb579
-rw-r--r--jni/ruby/test/ruby/test_lambda.rb173
-rw-r--r--jni/ruby/test/ruby/test_lazy_enumerator.rb494
-rw-r--r--jni/ruby/test/ruby/test_literal.rb461
-rw-r--r--jni/ruby/test/ruby/test_m17n.rb1599
-rw-r--r--jni/ruby/test/ruby/test_m17n_comb.rb1638
-rw-r--r--jni/ruby/test/ruby/test_marshal.rb650
-rw-r--r--jni/ruby/test/ruby/test_math.rb292
-rw-r--r--jni/ruby/test/ruby/test_metaclass.rb167
-rw-r--r--jni/ruby/test/ruby/test_method.rb894
-rw-r--r--jni/ruby/test/ruby/test_mixed_unicode_escapes.rb25
-rw-r--r--jni/ruby/test/ruby/test_module.rb2032
-rw-r--r--jni/ruby/test/ruby/test_not.rb12
-rw-r--r--jni/ruby/test/ruby/test_notimp.rb84
-rw-r--r--jni/ruby/test/ruby/test_numeric.rb366
-rw-r--r--jni/ruby/test/ruby/test_object.rb861
-rw-r--r--jni/ruby/test/ruby/test_objectspace.rb112
-rw-r--r--jni/ruby/test/ruby/test_optimization.rb292
-rw-r--r--jni/ruby/test/ruby/test_pack.rb730
-rw-r--r--jni/ruby/test/ruby/test_parse.rb882
-rw-r--r--jni/ruby/test/ruby/test_path.rb259
-rw-r--r--jni/ruby/test/ruby/test_pipe.rb29
-rw-r--r--jni/ruby/test/ruby/test_primitive.rb423
-rw-r--r--jni/ruby/test/ruby/test_proc.rb1323
-rw-r--r--jni/ruby/test/ruby/test_process.rb2023
-rw-r--r--jni/ruby/test/ruby/test_rand.rb527
-rw-r--r--jni/ruby/test/ruby/test_range.rb583
-rw-r--r--jni/ruby/test/ruby/test_rational.rb927
-rw-r--r--jni/ruby/test/ruby/test_rational2.rb1386
-rw-r--r--jni/ruby/test/ruby/test_readpartial.rb72
-rw-r--r--jni/ruby/test/ruby/test_refinement.rb1450
-rw-r--r--jni/ruby/test/ruby/test_regexp.rb1102
-rw-r--r--jni/ruby/test/ruby/test_require.rb704
-rw-r--r--jni/ruby/test/ruby/test_rubyoptions.rb796
-rw-r--r--jni/ruby/test/ruby/test_rubyvm.rb17
-rw-r--r--jni/ruby/test/ruby/test_settracefunc.rb1355
-rw-r--r--jni/ruby/test/ruby/test_signal.rb294
-rw-r--r--jni/ruby/test/ruby/test_sleep.rb16
-rw-r--r--jni/ruby/test/ruby/test_sprintf.rb412
-rw-r--r--jni/ruby/test/ruby/test_sprintf_comb.rb553
-rw-r--r--jni/ruby/test/ruby/test_string.rb2314
-rw-r--r--jni/ruby/test/ruby/test_stringchar.rb181
-rw-r--r--jni/ruby/test/ruby/test_struct.rb374
-rw-r--r--jni/ruby/test/ruby/test_super.rb528
-rw-r--r--jni/ruby/test/ruby/test_symbol.rb289
-rw-r--r--jni/ruby/test/ruby/test_syntax.rb622
-rw-r--r--jni/ruby/test/ruby/test_system.rb162
-rw-r--r--jni/ruby/test/ruby/test_thread.rb1036
-rw-r--r--jni/ruby/test/ruby/test_threadgroup.rb57
-rw-r--r--jni/ruby/test/ruby/test_time.rb1049
-rw-r--r--jni/ruby/test/ruby/test_time_tz.rb415
-rw-r--r--jni/ruby/test/ruby/test_trace.rb61
-rw-r--r--jni/ruby/test/ruby/test_transcode.rb2121
-rw-r--r--jni/ruby/test/ruby/test_undef.rb37
-rw-r--r--jni/ruby/test/ruby/test_unicode_escape.rb270
-rw-r--r--jni/ruby/test/ruby/test_variable.rb121
-rw-r--r--jni/ruby/test/ruby/test_weakmap.rb133
-rw-r--r--jni/ruby/test/ruby/test_whileuntil.rb82
-rw-r--r--jni/ruby/test/ruby/test_yield.rb393
-rw-r--r--jni/ruby/test/ruby/ut_eof.rb128
127 files changed, 66551 insertions, 0 deletions
diff --git a/jni/ruby/test/ruby/allpairs.rb b/jni/ruby/test/ruby/allpairs.rb
new file mode 100644
index 0000000..27b6f59
--- /dev/null
+++ b/jni/ruby/test/ruby/allpairs.rb
@@ -0,0 +1,102 @@
+module AllPairs
+ module_function
+
+ def make_prime(v)
+ return 2 if v < 2
+ ary = [true] * (v*2)
+ 2.upto(Math.sqrt(ary.length).ceil) {|i|
+ return i if ary[i] && v <= i
+ (i*2).step(ary.length, i) {|j|
+ ary[j] = false
+ }
+ }
+ v.upto(ary.length-1) {|i|
+ return i if ary[i]
+ }
+ raise "[bug] prime not found greater than #{v}"
+ end
+
+ def make_basic_block(prime)
+ prime.times {|i|
+ prime.times {|j|
+ row = [i]
+ 0.upto(prime-1) {|m|
+ row << (i*m + j) % prime
+ }
+ yield row
+ }
+ }
+ end
+
+ def combine_block(tbl1, tbl2)
+ result = []
+ tbl2.each {|row|
+ result << row * tbl1.first.length
+ }
+ tbl1.each_with_index {|row, k|
+ next if k == 0
+ result << row.map {|i| [i] * tbl2.first.length }.flatten
+ }
+ result
+ end
+
+ def make_large_block(v, prime)
+ if prime <= v+1
+ make_basic_block(v) {|row|
+ yield row
+ }
+ else
+ tbl = []
+ make_basic_block(v) {|row|
+ tbl << row
+ }
+ tbls = [tbl]
+ while tbl.first.length ** 2 < prime
+ tbl = combine_block(tbl, tbl)
+ tbls << tbl
+ end
+ tbl1 = tbls.find {|t| prime <= t.first.length * tbl.first.length }
+ tbl = combine_block(tbl, tbl1)
+ tbl.each {|row|
+ yield row
+ }
+ end
+ end
+
+ def each_index(*vs)
+ n = vs.length
+ max_v = vs.max
+ h = {}
+ make_large_block(max_v, n) {|row|
+ row = vs.zip(row).map {|v, i| i % v }
+ next if h[row]
+ h[row] = true
+ yield row
+ }
+ end
+
+ # generate all pairs test.
+ def each(*args)
+ args.map! {|a| a.to_a }
+ each_index(*args.map {|a| a.length}) {|is|
+ yield is.zip(args).map {|i, a| a[i] }
+ }
+ end
+
+ # generate all combination in cartesian product. (not all-pairs test)
+ def exhaustive_each(*args)
+ args = args.map {|a| a.to_a }
+ i = 0
+ while true
+ n = i
+ as = []
+ args.reverse_each {|a|
+ n, m = n.divmod(a.length)
+ as.unshift a[m]
+ }
+ break if 0 < n
+ yield as
+ i += 1
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/beginmainend.rb b/jni/ruby/test/ruby/beginmainend.rb
new file mode 100644
index 0000000..6cdfb15
--- /dev/null
+++ b/jni/ruby/test/ruby/beginmainend.rb
@@ -0,0 +1,80 @@
+errout = ARGV.shift
+
+BEGIN {
+ puts "b1"
+ local_begin1 = "local_begin1"
+ $global_begin1 = "global_begin1"
+ ConstBegin1 = "ConstBegin1"
+}
+
+BEGIN {
+ puts "b2"
+
+ BEGIN {
+ puts "b2-1"
+ }
+}
+
+# for scope check
+#raise if defined?(local_begin1)
+raise unless defined?($global_begin1)
+raise unless defined?(::ConstBegin1)
+local_for_end2 = "e2"
+$global_for_end1 = "e1"
+
+puts "main"
+
+END {
+ puts local_for_end2 # e2
+}
+
+eval <<EOE
+ BEGIN {
+ puts "b3"
+
+ BEGIN {
+ puts "b3-1"
+ }
+ }
+
+ BEGIN {
+ puts "b4"
+ }
+
+ END {
+ puts "e3"
+ }
+
+ END {
+ puts "e4"
+
+ END {
+ puts "e4-1"
+
+ END {
+ puts "e4-1-1"
+ }
+ }
+
+ END {
+ puts "e4-2"
+ }
+ }
+EOE
+
+END {
+ exit
+ puts "should not be dumped"
+
+ END {
+ puts "not reached"
+ }
+}
+
+END {
+ puts $global_for_end1 # e1
+
+ END {
+ puts "e1-1"
+ }
+}
diff --git a/jni/ruby/test/ruby/enc/test_big5.rb b/jni/ruby/test/ruby/enc/test_big5.rb
new file mode 100644
index 0000000..e8fe027
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_big5.rb
@@ -0,0 +1,28 @@
+require "test/unit"
+
+class TestBig5 < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("big5")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\xa1\xa1").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0xa1a1, s("\xa1\xa1").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\xa1\xa1"), 0xa1a1.chr("big5"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\xa1\xa1)\\1"), "i")
+ assert_match(r, s("\xa1\xa1\xa1\xa1"))
+ end
+
+ def test_left_adjust_char_head
+ assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_cp949.rb b/jni/ruby/test/ruby/enc/test_cp949.rb
new file mode 100644
index 0000000..e675c7b
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_cp949.rb
@@ -0,0 +1,28 @@
+require "test/unit"
+
+class TestCP949 < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("cp949")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\xa1\xa1").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0xa1a1, s("\xa1\xa1").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\xa1\xa1"), 0xa1a1.chr("cp949"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\xa1\xa1)\\1"), "i")
+ assert_match(r, s("\xa1\xa1\xa1\xa1"))
+ end
+
+ def test_left_adjust_char_head
+ assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_emoji.rb b/jni/ruby/test/ruby/enc/test_emoji.rb
new file mode 100644
index 0000000..1f80c5a
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_emoji.rb
@@ -0,0 +1,442 @@
+require 'test/unit'
+
+module Emoji
+
+ class TestRenameSJIS < Test::Unit::TestCase
+ def test_shift_jis
+ assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-DoCoMo") }
+ assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-KDDI") }
+ assert_raise(ArgumentError) { "".force_encoding("Shift_JIS-SoftBank") }
+ end
+ end
+
+ class TestUTF8_BLACK_SUN_WITH_RAYS < Test::Unit::TestCase
+ include Emoji
+
+ def setup
+ @codes = {
+ "UTF8-DoCoMo" => utf8_docomo("\u{E63E}"),
+ "UTF8-KDDI" => utf8_kddi("\u{E488}"),
+ "UTF8-SoftBank" => utf8_softbank("\u{E04A}"),
+ "UTF-8" => "\u{2600}",
+ }
+ end
+
+ def test_convert
+ @codes.each do |from_enc, from_str|
+ @codes.each do |to_enc, to_str|
+ next if from_enc == to_enc
+ assert_equal to_str, from_str.encode(to_enc), "convert from #{from_enc} to #{to_enc}"
+ end
+ end
+ end
+ end
+
+ class TestDoCoMo < Test::Unit::TestCase
+ include Emoji
+
+ def setup
+ setup_instance_variable(self)
+ end
+
+ def test_encoding_name
+ %w(UTF8-DoCoMo
+ SJIS-DoCoMo).each do |n|
+ assert_include Encoding.name_list, n, "encoding not found: #{n}"
+ end
+ end
+
+ def test_comparison
+ assert_not_equal Encoding::UTF_8, Encoding::UTF8_DoCoMo
+ assert_not_equal Encoding::Windows_31J, Encoding::SJIS_DoCoMo
+ end
+
+ def test_from_utf8
+ assert_nothing_raised { assert_equal utf8_docomo(@aiueo_utf8), to_utf8_docomo(@aiueo_utf8) }
+ assert_nothing_raised { assert_equal sjis_docomo(@aiueo_sjis), to_sjis_docomo(@aiueo_utf8) }
+ end
+
+ def test_from_sjis
+ assert_nothing_raised { assert_equal utf8_docomo(@aiueo_utf8), to_utf8_docomo(@aiueo_sjis) }
+ assert_nothing_raised { assert_equal sjis_docomo(@aiueo_sjis), to_sjis_docomo(@aiueo_sjis) }
+ end
+
+ def test_to_utf8
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_docomo) }
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_docomo) }
+ end
+
+ def test_to_sjis
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_docomo) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_docomo) }
+ end
+
+ def test_to_eucjp
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_docomo) }
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_docomo) }
+ end
+
+ def test_docomo
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_docomo) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_docomo) }
+ end
+
+ def test_to_kddi
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@utf8_docomo) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_docomo) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_docomo) }
+
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_docomo) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_docomo) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_docomo) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@utf8_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@utf8_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@utf8_docomo_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@sjis_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@sjis_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@sjis_docomo_only) }
+ end
+
+ def test_to_softbank
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_docomo) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_docomo) }
+
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_docomo) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_docomo) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_softbank(@utf8_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_softbank(@utf8_docomo_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_softbank(@sjis_docomo_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_softbank(@sjis_docomo_only) }
+ end
+ end
+
+ class TestKDDI < Test::Unit::TestCase
+ include Emoji
+
+ def setup
+ setup_instance_variable(self)
+ end
+
+ def test_encoding_name
+ %w(UTF8-KDDI
+ SJIS-KDDI
+ ISO-2022-JP-KDDI
+ stateless-ISO-2022-JP-KDDI).each do |n|
+ assert_include Encoding.name_list, n, "encoding not found: #{n}"
+ end
+ end
+
+ def test_comparison
+ assert_not_equal Encoding::UTF_8, Encoding::UTF8_KDDI
+ assert_not_equal Encoding::Windows_31J, Encoding::SJIS_KDDI
+ assert_not_equal Encoding::ISO_2022_JP, Encoding::ISO_2022_JP_KDDI
+ assert_not_equal Encoding::Stateless_ISO_2022_JP, Encoding::Stateless_ISO_2022_JP_KDDI
+ end
+
+ def test_from_utf8
+ assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_utf8) }
+ assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_utf8) }
+ assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_utf8) }
+ end
+
+ def test_from_sjis
+ assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_sjis) }
+ assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_sjis) }
+ assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_sjis) }
+ end
+
+ def test_from_iso2022jp
+ assert_nothing_raised { assert_equal utf8_kddi(@aiueo_utf8), to_utf8_kddi(@aiueo_iso2022jp) }
+ assert_nothing_raised { assert_equal sjis_kddi(@aiueo_sjis), to_sjis_kddi(@aiueo_iso2022jp) }
+ assert_nothing_raised { assert_equal iso2022jp_kddi(@aiueo_iso2022jp), to_iso2022jp_kddi(@aiueo_iso2022jp) }
+ end
+
+ def test_to_utf8
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_kddi) }
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_undoc_kddi) }
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@iso2022jp_kddi) }
+ end
+
+ def test_to_sjis
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_undoc_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@iso2022jp_kddi) }
+ end
+
+ def test_to_eucjp
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_undoc_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_kddi) }
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@iso2022jp_kddi) }
+ end
+
+ def test_kddi
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@iso2022jp_kddi) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_undoc_kddi) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@iso2022jp_kddi) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_undoc_kddi) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@iso2022jp_kddi) }
+ end
+
+ def test_to_docomo
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_kddi) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_undoc_kddi) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_undoc_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@iso2022jp_kddi) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@iso2022jp_kddi) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_undoc_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_undoc_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_docomo, to_utf8_docomo(@iso2022jp_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_docomo, to_sjis_docomo(@iso2022jp_kddi_only) }
+ end
+
+ def test_to_softbank
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_kddi) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_undoc_kddi) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_undoc_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_kddi) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_kddi) }
+
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@iso2022jp_kddi) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@iso2022jp_kddi) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@utf8_undoc_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_undoc_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@sjis_kddi_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @utf8_softbank, to_utf8_softbank(@iso2022jp_kddi_only) }
+ assert_raise(Encoding::UndefinedConversionError) { assert_equal @sjis_softbank, to_sjis_softbank(@iso2022jp_kddi_only) }
+ end
+ end
+
+ class TestSoftBank < Test::Unit::TestCase
+ include Emoji
+
+ def setup
+ setup_instance_variable(self)
+ end
+
+ def test_encoding_name
+ %w(UTF8-SoftBank
+ SJIS-SoftBank).each do |n|
+ assert_include Encoding.name_list, n, "encoding not found: #{n}"
+ end
+ end
+
+ def test_comparison
+ assert_not_equal Encoding::UTF_8, Encoding::UTF8_SoftBank
+ assert_not_equal Encoding::Windows_31J, Encoding::SJIS_SoftBank
+ end
+
+ def test_from_utf8
+ assert_nothing_raised { assert_equal utf8_softbank(@aiueo_utf8), to_utf8_softbank(@aiueo_utf8) }
+ assert_nothing_raised { assert_equal sjis_softbank(@aiueo_sjis), to_sjis_softbank(@aiueo_utf8) }
+ end
+
+ def test_from_sjis
+ assert_nothing_raised { assert_equal utf8_softbank(@aiueo_utf8), to_utf8_softbank(@aiueo_sjis) }
+ assert_nothing_raised { assert_equal sjis_softbank(@aiueo_sjis), to_sjis_softbank(@aiueo_sjis) }
+ end
+
+ def test_to_utf8
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@utf8_softbank) }
+ assert_nothing_raised { assert_equal @utf8, to_utf8(@sjis_softbank) }
+ end
+
+ def test_to_sjis
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@utf8_softbank) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis(@sjis_softbank) }
+ end
+
+ def test_to_eucjp
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@utf8_softbank) }
+ assert_raise(Encoding::UndefinedConversionError) { to_eucjp(@sjis_softbank) }
+ end
+
+ def test_softbank
+ assert_nothing_raised { assert_equal @utf8_softbank, to_utf8_softbank(@sjis_softbank) }
+ assert_nothing_raised { assert_equal @sjis_softbank, to_sjis_softbank(@utf8_softbank) }
+ end
+
+ def test_to_docomo
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@utf8_softbank) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@utf8_softbank) }
+
+ assert_nothing_raised { assert_equal @utf8_docomo, to_utf8_docomo(@sjis_softbank) }
+ assert_nothing_raised { assert_equal @sjis_docomo, to_sjis_docomo(@sjis_softbank) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_docomo(@utf8_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_docomo(@utf8_softbank_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_docomo(@sjis_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_docomo(@sjis_softbank_only) }
+ end
+
+ def test_to_kddi
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@utf8_softbank) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@utf8_softbank) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@utf8_softbank) }
+
+ assert_nothing_raised { assert_equal @utf8_kddi, to_utf8_kddi(@sjis_softbank) }
+ assert_nothing_raised { assert_equal @sjis_kddi, to_sjis_kddi(@sjis_softbank) }
+ assert_nothing_raised { assert_equal @iso2022jp_kddi, to_iso2022jp_kddi(@sjis_softbank) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@utf8_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@utf8_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@utf8_softbank_only) }
+
+ assert_raise(Encoding::UndefinedConversionError) { to_utf8_kddi(@sjis_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_sjis_kddi(@sjis_softbank_only) }
+ assert_raise(Encoding::UndefinedConversionError) { to_iso2022jp_kddi(@sjis_softbank_only) }
+ end
+ end
+
+ private
+
+ def setup_instance_variable(obj)
+ obj.instance_eval do
+ @aiueo_utf8 = "\u{3042}\u{3044}\u{3046}\u{3048}\u{304A}"
+ @aiueo_sjis = to_sjis(@aiueo_utf8)
+ @aiueo_iso2022jp = to_iso2022jp(@aiueo_utf8)
+
+ @utf8 = "\u{2600}"
+
+ @utf8_docomo = utf8_docomo("\u{E63E}")
+ @sjis_docomo = sjis_docomo("\xF8\x9F")
+ @utf8_docomo_only = utf8_docomo("\u{E6B1}")
+ @sjis_docomo_only = sjis_docomo("\xF9\x55")
+
+ @utf8_kddi = utf8_kddi("\u{E488}")
+ @utf8_undoc_kddi = utf8_kddi("\u{EF60}")
+ @sjis_kddi = sjis_kddi("\xF6\x60")
+ @iso2022jp_kddi = iso2022jp_kddi("\x1B$B\x75\x41\x1B(B")
+ @stateless_iso2022jp_kddi = stateless_iso2022jp_kddi("\x92\xF5\xC1")
+ @utf8_kddi_only = utf8_kddi("\u{E5B3}")
+ @utf8_undoc_kddi_only = utf8_kddi("\u{F0D0}")
+ @sjis_kddi_only = sjis_kddi("\xF7\xD0")
+ @iso2022jp_kddi_only = iso2022jp_kddi("\x1B$B\x78\x52\x1B(B")
+ @stateless_iso2022jp_kddi_only = stateless_iso2022jp_kddi("\x92\xF8\xD2")
+
+ @utf8_softbank = utf8_softbank("\u{E04A}")
+ @sjis_softbank = sjis_softbank("\xF9\x8B")
+ @utf8_softbank_only = utf8_softbank("\u{E524}")
+ @sjis_softbank_only = sjis_softbank("\xFB\xC4")
+ end
+ end
+
+ def utf8(str)
+ str.force_encoding("UTF-8")
+ end
+
+ def to_utf8(str)
+ str.encode("UTF-8")
+ end
+
+ def to_sjis(str)
+ str.encode("Windows-31J")
+ end
+
+ def to_eucjp(str)
+ str.encode("eucJP-ms")
+ end
+
+ def to_iso2022jp(str)
+ str.encode("ISO-2022-JP")
+ end
+
+ def utf8_docomo(str)
+ str.force_encoding("UTF8-DoCoMo")
+ end
+
+ def to_utf8_docomo(str)
+ str.encode("UTF8-DoCoMo")
+ end
+
+ def utf8_kddi(str)
+ str.force_encoding("UTF8-KDDI")
+ end
+
+ def to_utf8_kddi(str)
+ str.encode("UTF8-KDDI")
+ end
+
+ def utf8_softbank(str)
+ str.force_encoding("UTF8-SoftBank")
+ end
+
+ def to_utf8_softbank(str)
+ str.encode("UTF8-SoftBank")
+ end
+
+ def sjis_docomo(str)
+ str.force_encoding("SJIS-DoCoMo")
+ end
+
+ def to_sjis_docomo(str)
+ str.encode("SJIS-DoCoMo")
+ end
+
+ def sjis_kddi(str)
+ str.force_encoding("SJIS-KDDI")
+ end
+
+ def to_sjis_kddi(str)
+ str.encode("SJIS-KDDI")
+ end
+
+ def sjis_softbank(str)
+ str.force_encoding("SJIS-SoftBank")
+ end
+
+ def to_sjis_softbank(str)
+ str.encode("SJIS-SoftBank")
+ end
+
+ def iso2022jp_kddi(str)
+ str.force_encoding("ISO-2022-JP-KDDI")
+ end
+
+ def to_iso2022jp_kddi(str)
+ str.encode("ISO-2022-JP-KDDI")
+ end
+
+ def stateless_iso2022jp_kddi(str)
+ str.force_encoding("stateless-ISO-2022-JP-KDDI")
+ end
+
+ def to_stateless_iso2022jp_kddi(str)
+ str.encode("stateless-ISO-2022-JP-KDDI")
+ end
+
+end
diff --git a/jni/ruby/test/ruby/enc/test_euc_jp.rb b/jni/ruby/test/ruby/enc/test_euc_jp.rb
new file mode 100644
index 0000000..510ee46
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_euc_jp.rb
@@ -0,0 +1,24 @@
+# vim: set fileencoding=euc-jp
+
+require "test/unit"
+
+class TestEUC_JP < Test::Unit::TestCase
+ def test_mbc_case_fold
+ assert_match(/()(a)\1\2/i, "aA")
+ assert_match(/()(a)\1\2/i, "aA")
+ end
+
+ def test_property
+ assert_match(/{0}\p{Hiragana}{4}/, "Ҥ餬")
+ assert_no_match(/{0}\p{Hiragana}{4}/, "")
+ assert_no_match(/{0}\p{Hiragana}{4}/, "")
+ assert_no_match(/{0}\p{Katakana}{4}/, "Ҥ餬")
+ assert_match(/{0}\p{Katakana}{4}/, "")
+ assert_no_match(/{0}\p{Katakana}{4}/, "")
+ assert_raise(RegexpError) { Regexp.new('{0}\p{foobarbaz}') }
+ end
+
+ def test_charboundary
+ assert_nil(/\xA2\xA2/ =~ "\xA1\xA2\xA2\xA3")
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_euc_kr.rb b/jni/ruby/test/ruby/enc/test_euc_kr.rb
new file mode 100644
index 0000000..5413fa6
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_euc_kr.rb
@@ -0,0 +1,36 @@
+require "test/unit"
+
+class TestEucKr < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("euc-kr")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\xa1\xa1").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0xa1a1, s("\xa1\xa1").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\xa1\xa1"), 0xa1a1.chr("euc-kr"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\xa1\xa1)\\1"), "i")
+ assert_match(r, s("\xa1\xa1\xa1\xa1"))
+ end
+
+ def test_left_adjust_char_head
+ assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop)
+ end
+
+ def test_euro_sign
+ assert_equal("\u{20ac}", s("\xa2\xe6").encode("utf-8"))
+ end
+
+ def test_registered_mark
+ assert_equal("\u{00ae}", s("\xa2\xe7").encode("utf-8"))
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_euc_tw.rb b/jni/ruby/test/ruby/enc/test_euc_tw.rb
new file mode 100644
index 0000000..f36d86b
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_euc_tw.rb
@@ -0,0 +1,28 @@
+require "test/unit"
+
+class TestEucTw < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("euc-tw")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\xa1\xa1").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0xa1a1, s("\xa1\xa1").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\xa1\xa1"), 0xa1a1.chr("euc-tw"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\xa1\xa1)\\1"), "i")
+ assert_match(r, s("\xa1\xa1\xa1\xa1"))
+ end
+
+ def test_left_adjust_char_head
+ assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_gb18030.rb b/jni/ruby/test/ruby/enc/test_gb18030.rb
new file mode 100644
index 0000000..f379504
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_gb18030.rb
@@ -0,0 +1,126 @@
+require "test/unit"
+
+class TestGB18030 < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("gb18030")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\x81\x40").size)
+ assert_equal(1, s("\x81\x30\x81\x30").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0x8140, s("\x81\x40").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\x81\x40"), 0x8140.chr("gb18030"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\x81\x40)\\1"), "i")
+ assert_match(r, s("\x81\x40\x81\x40"))
+ end
+
+ def scheck(c, i)
+ assert_equal(s(c.reverse.take(c.size - i).join), s(c.reverse.join).chop)
+ end
+
+ def fcheck(c)
+ c = s(c.reverse.join)
+ assert_raise(ArgumentError, c) { c.chop }
+ end
+
+ def test_left_adjust_char_head
+ # C1: 00-2f, 3a-3f, 7f, ff
+ # C2: 40-7e, 80
+ # C4: 30-39
+ # CM: 81-fe
+ c1 = "\x2f"
+ c2 = "\x40"
+ c4 = "\x30"
+ cm = "\x81"
+
+ # S_START-c1
+ # S_START-c2-S_one_C2-0
+ # S_START-c2-S_one_C2-c1
+ # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-c1
+ # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-cm-S_even_CM_one_CX-c1
+ # S_START-c2-S_one_C2-cm-S_odd_CM_one_CX-cm-S_even_CM_one_CX-cm-S_odd_CM_one_CX(rec)
+ # S_START-c4-S_one_C4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-c4-S_one_C4_odd_CMC4(rec)
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-cm-S_even_CM_odd_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-c4-S_one_C4_even_CMC4-cm-S_odd_CMC4-cm-S_odd_CM_odd_CMC4-cm-S_even_CM_odd_CMC4-cm-S_odd_CM_odd_CMC4(rec)
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-cm-S_even_CM_even_CMC4-c1
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-c4-S_one_C4_odd_CMC4-cm-S_even_CMC4-cm-S_odd_CM_even_CMC4-cm-S_even_CM_even_CMC4-cm-S_odd_CM_even_CMC4(rec)
+ # S_START-c4-S_one_C4-cm-S_one_CMC4-cm-S_even_CM_one_CX(rec)
+ # S_START-cm-S_one_CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-c4-S_odd_C4CM(rec)
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-cm-S_odd_CM_even_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-c4-S_even_C4CM-cm-S_one_CM_even_C4CM-cm-S_even_CM_even_C4CM-cm-S_odd_CM_even_C4CM-cm-S_even_CM_even_C4CM(rec)
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-cm-S_odd_CM_odd_C4CM-c1
+ # S_START-cm-S_one_CM-c4-S_odd_C4CM-cm-S_one_CM_odd_C4CM-cm-S_even_CM_odd_C4CM-cm-S_odd_CM_odd_C4CM-cm-S_even_CM_odd_C4CM(rec)
+ # S_START-cm-S_one_CM-cm-S_odd_CM_one_CX(rec)
+
+ scheck([c1], 1)
+ scheck([c2], 1)
+ scheck([c2, c1], 1)
+ scheck([c2, cm, c1], 2)
+ scheck([c2, cm, cm, c1], 1)
+ scheck([c2, cm, cm, cm], 2)
+ scheck([c4], 1)
+ scheck([c4, c1], 1)
+ scheck([c4, cm], 2)
+ scheck([c4, cm, c1], 2)
+ scheck([c4, cm, c4, c1], 2)
+ scheck([c4, cm, c4, cm], 4)
+ scheck([c4, cm, c4, cm, c1], 4)
+ scheck([c4, cm, c4, cm, c4], 4)
+ scheck([c4, cm, c4, cm, c4, c1], 4)
+ scheck([c4, cm, c4, cm, c4, cm], 2)
+ scheck([c4, cm, c4, cm, c4, cm, c1], 2)
+ scheck([c4, cm, c4, cm, c4, cm, c4], 2)
+ scheck([c4, cm, c4, cm, c4, cm, cm, c1], 4)
+ scheck([c4, cm, c4, cm, c4, cm, cm, cm], 2)
+ scheck([c4, cm, c4, cm, c4, cm, cm, cm, c1], 2)
+ scheck([c4, cm, c4, cm, c4, cm, cm, cm, cm], 4)
+ scheck([c4, cm, c4, cm, cm, c1], 2)
+ scheck([c4, cm, c4, cm, cm, cm], 4)
+ scheck([c4, cm, c4, cm, cm, cm, c1], 4)
+ scheck([c4, cm, c4, cm, cm, cm, cm], 2)
+ scheck([c4, cm, cm], 1)
+ scheck([cm], 1)
+ scheck([cm, c1], 1)
+ scheck([cm, c4, c1], 1)
+ scheck([cm, c4, cm], 3)
+ scheck([cm, c4, cm, c1], 3)
+ scheck([cm, c4, cm, c4], 3)
+ scheck([cm, c4, cm, c4, c1], 3)
+ scheck([cm, c4, cm, c4, cm], 1)
+ scheck([cm, c4, cm, c4, cm, c1], 1)
+ scheck([cm, c4, cm, c4, cm, c4], 1)
+ scheck([cm, c4, cm, c4, cm, cm, c1], 3)
+ scheck([cm, c4, cm, c4, cm, cm, cm], 1)
+ scheck([cm, c4, cm, c4, cm, cm, cm, c1], 1)
+ scheck([cm, c4, cm, c4, cm, cm, cm, cm], 3)
+ scheck([cm, c4, cm, cm, c1], 1)
+ scheck([cm, c4, cm, cm, cm], 3)
+ scheck([cm, c4, cm, cm, cm, c1], 3)
+ scheck([cm, c4, cm, cm, cm, cm], 1)
+ scheck([cm, cm], 2)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_gbk.rb b/jni/ruby/test/ruby/enc/test_gbk.rb
new file mode 100644
index 0000000..d6dc5d6
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_gbk.rb
@@ -0,0 +1,28 @@
+require "test/unit"
+
+class TestGBK < Test::Unit::TestCase
+ def s(s)
+ s.force_encoding("gbk")
+ end
+
+ def test_mbc_enc_len
+ assert_equal(1, s("\x81\x40").size)
+ end
+
+ def test_mbc_to_code
+ assert_equal(0x8140, s("\x81\x40").ord)
+ end
+
+ def test_code_to_mbc
+ assert_equal(s("\x81\x40"), 0x8140.chr("gbk"))
+ end
+
+ def test_mbc_case_fold
+ r = Regexp.new(s("(\x81\x40)\\1"), "i")
+ assert_match(r, s("\x81\x40\x81\x40"))
+ end
+
+ def test_left_adjust_char_head
+ assert_equal(s("\x81\x40"), s("\x81\x40\x81\x40").chop)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_iso_8859.rb b/jni/ruby/test/ruby/enc/test_iso_8859.rb
new file mode 100644
index 0000000..64cc7cd
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_iso_8859.rb
@@ -0,0 +1,163 @@
+require 'test/unit'
+
+class TestISO8859 < Test::Unit::TestCase
+ ASSERTS = %q(
+ assert_match(/^(\xdf)\1$/i, "\xdf\xdf")
+ assert_match(/^(\xdf)\1$/i, "ssss")
+ # assert_match(/^(\xdf)\1$/i, "\xdfss") # this must be bug...
+ assert_match(/^[\xdfz]+$/i, "sszzsszz")
+ assert_match(/^SS$/i, "\xdf")
+ assert_match(/^Ss$/i, "\xdf")
+ ((0xc0..0xde).to_a - [0xd7]).each do |c|
+ c1 = c.chr("ENCODING")
+ c2 = (c + 0x20).chr("ENCODING")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ assert_match(/^\xff$/i, "\xff")
+ )
+
+ def test_iso_8859_1
+ eval("# encoding: iso8859-1\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-1"))
+ end
+
+ def test_iso_8859_2
+ eval("# encoding: iso8859-2\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-2"))
+ end
+
+ def test_iso_8859_3
+ eval(%q(# encoding: iso8859-3
+ assert_match(/^(\xdf)\1$/i, "\xdf\xdf")
+ assert_match(/^(\xdf)\1$/i, "ssss")
+ assert_match(/^[\xdfz]+$/i, "sszzsszz")
+ assert_match(/^SS$/i, "\xdf")
+ assert_match(/^Ss$/i, "\xdf")
+ [0xa1, 0xa6, *(0xa9..0xac), 0xaf].each do |c|
+ c1 = c.chr("iso8859-3")
+ c2 = (c + 0x10).chr("iso8859-3")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ([*(0xc0..0xde)] - [0xc3, 0xd0, 0xd7]).each do |c|
+ c1 = c.chr("iso8859-3")
+ c2 = (c + 0x20).chr("iso8859-3")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ))
+ end
+
+ def test_iso_8859_4
+ eval("# encoding: iso8859-4\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-4"))
+ end
+
+ def test_iso_8859_5
+ eval(%q(# encoding: iso8859-5
+ (0xb0..0xcf).each do |c|
+ c1 = c.chr("iso8859-5")
+ c2 = (c + 0x20).chr("iso8859-5")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ((0xa1..0xaf).to_a - [0xad]).each do |c|
+ c1 = c.chr("iso8859-5")
+ c2 = (c + 0x50).chr("iso8859-5")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ))
+ end
+
+ def test_iso_8859_6
+ eval(%q(# encoding: iso8859-6
+ [0xa4, 0xac, 0xbb, 0xbf, *(0xc1..0xda), *(0xe0..0xf2)].each do |c|
+ c1 = c.chr("iso8859-6")
+ assert_match(/^(#{ c1 })\1$/i, c1 * 2)
+ end
+ ))
+ end
+
+ def test_iso_8859_7
+ eval(%q(# encoding: iso8859-7
+ ((0xa0..0xfe).to_a - [0xae, 0xd2]).each do |c|
+ c1 = c.chr("iso8859-7")
+ assert_match(/^(#{ c1 })\1$/i, c1 * 2)
+ end
+ ((0xc1..0xd9).to_a - [0xd2]).each do |c|
+ c1 = c.chr("iso8859-7")
+ c2 = (c + 0x20).chr("iso8859-7")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ))
+ end
+
+ def test_iso_8859_8
+ eval(%q(# encoding: iso8859-8
+ [0xa0, *(0xa2..0xbe), *(0xdf..0xfa), 0xfc, 0xfd].each do |c|
+ c1 = c.chr("iso8859-8")
+ assert_match(/^(#{ c1 })\1$/i, c1 * 2)
+ end
+ ))
+ end
+
+ def test_iso_8859_9
+ eval(%q(# encoding: iso8859-9
+ assert_match(/^(\xdf)\1$/i, "\xdf\xdf")
+ assert_match(/^(\xdf)\1$/i, "ssss")
+ assert_match(/^[\xdfz]+$/i, "sszzsszz")
+ assert_match(/^SS$/i, "\xdf")
+ assert_match(/^Ss$/i, "\xdf")
+ ([*(0xc0..0xdc)] - [0xd7]).each do |c|
+ c1 = c.chr("iso8859-9")
+ c2 = (c + 0x20).chr("iso8859-9")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ ))
+ end
+
+ def test_iso_8859_10
+ eval("# encoding: iso8859-10\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-10"))
+ end
+
+ def test_iso_8859_11
+ eval(%q(# encoding: iso8859-11
+ [*(0xa0..0xda), *(0xdf..0xfb)].each do |c|
+ c1 = c.chr("iso8859-11")
+ assert_match(/^(#{ c1 })\1$/i, c1 * 2)
+ end
+ ))
+ end
+
+ def test_iso_8859_13
+ eval("# encoding: iso8859-13\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-13"))
+ end
+
+ def test_iso_8859_14
+ eval("# encoding: iso8859-14\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-14"))
+ end
+
+ def test_iso_8859_15
+ eval("# encoding: iso8859-15\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-15"))
+ end
+
+ def test_iso_8859_16
+ eval("# encoding: iso8859-16\n" + ASSERTS.gsub(/ENCODING/m, "iso8859-16"))
+ end
+end
+
diff --git a/jni/ruby/test/ruby/enc/test_koi8.rb b/jni/ruby/test/ruby/enc/test_koi8.rb
new file mode 100644
index 0000000..ce2d892
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_koi8.rb
@@ -0,0 +1,22 @@
+require "test/unit"
+
+class TestKOI8 < Test::Unit::TestCase
+ ASSERTS = %q(
+ (0xc0..0xdf).each do |c|
+ c1 = c.chr("ENCODING")
+ c2 = (c + 0x20).chr("ENCODING")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ )
+
+ def test_koi8_r
+ eval("# encoding: koi8-r\n" + ASSERTS.gsub("ENCODING", "koi8-r"))
+ end
+
+ def test_koi8_u
+ eval("# encoding: koi8-u\n" + ASSERTS.gsub("ENCODING", "koi8-u"))
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_shift_jis.rb b/jni/ruby/test/ruby/enc/test_shift_jis.rb
new file mode 100644
index 0000000..1bd47fa
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_shift_jis.rb
@@ -0,0 +1,27 @@
+# vim: set fileencoding=shift_jis
+
+require "test/unit"
+
+class TestShiftJIS < Test::Unit::TestCase
+ def test_mbc_case_fold
+ assert_match(/()(a)\1\2/i, "aA")
+ assert_match(/()(a)\1\2/i, "a`A")
+ end
+
+ def test_property
+ assert_match(/{0}\p{Hiragana}{4}/, "Ђ炪")
+ assert_no_match(/{0}\p{Hiragana}{4}/, "J^Ji")
+ assert_no_match(/{0}\p{Hiragana}{4}/, "")
+ assert_no_match(/{0}\p{Katakana}{4}/, "Ђ炪")
+ assert_match(/{0}\p{Katakana}{4}/, "J^Ji")
+ assert_no_match(/{0}\p{Katakana}{4}/, "")
+ assert_raise(RegexpError) { Regexp.new('{0}\p{foobarbaz}') }
+ end
+
+ def test_code_to_mbclen
+ s = ""
+ s << 0x82a9
+ assert_equal("", s)
+ assert_raise(RangeError) { s << 0x82 }
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_utf16.rb b/jni/ruby/test/ruby/enc/test_utf16.rb
new file mode 100644
index 0000000..63929c6
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_utf16.rb
@@ -0,0 +1,384 @@
+require 'test/unit'
+
+class TestUTF16 < Test::Unit::TestCase
+ def encdump(obj)
+ case obj
+ when String
+ d = obj.dump
+ if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d
+ d
+ else
+ "#{d}.force_encoding(#{obj.encoding.name.dump})"
+ end
+ when Regexp
+ "Regexp.new(#{encdump(obj.source)}, #{obj.options})"
+ else
+ raise Argument, "unexpected: #{obj.inspect}"
+ end
+ end
+
+ def enccall(recv, meth, *args)
+ desc = ''
+ if String === recv
+ desc << encdump(recv)
+ else
+ desc << recv.inspect
+ end
+ desc << '.' << meth.to_s
+ if !args.empty?
+ desc << '('
+ args.each_with_index {|a, i|
+ desc << ',' if 0 < i
+ if String === a
+ desc << encdump(a)
+ else
+ desc << a.inspect
+ end
+ }
+ desc << ')'
+ end
+ result = nil
+ assert_nothing_raised(desc) {
+ result = recv.send(meth, *args)
+ }
+ result
+ end
+
+ def assert_str_equal(expected, actual, message=nil)
+ full_message = build_message(message, <<EOT)
+#{encdump expected} expected but not equal to
+#{encdump actual}.
+EOT
+ assert_equal(expected, actual, full_message)
+ end
+
+ # tests start
+
+ def test_utf16be_valid_encoding
+ [
+ "\x00\x00",
+ "\xd7\xff",
+ "\xd8\x00\xdc\x00",
+ "\xdb\xff\xdf\xff",
+ "\xe0\x00",
+ "\xff\xff",
+ ].each {|s|
+ s.force_encoding("utf-16be")
+ assert_equal(true, s.valid_encoding?, "#{encdump s}.valid_encoding?")
+ }
+ [
+ "\x00",
+ "\xd7",
+ "\xd8\x00",
+ "\xd8\x00\xd8\x00",
+ "\xdc\x00",
+ "\xdc\x00\xd8\x00",
+ "\xdc\x00\xdc\x00",
+ "\xe0",
+ "\xff",
+ ].each {|s|
+ s.force_encoding("utf-16be")
+ assert_equal(false, s.valid_encoding?, "#{encdump s}.valid_encoding?")
+ }
+ end
+
+ def test_utf16le_valid_encoding
+ [
+ "\x00\x00",
+ "\xff\xd7",
+ "\x00\xd8\x00\xdc",
+ "\xff\xdb\xff\xdf",
+ "\x00\xe0",
+ "\xff\xff",
+ ].each {|s|
+ s.force_encoding("utf-16le")
+ assert_equal(true, s.valid_encoding?, "#{encdump s}.valid_encoding?")
+ }
+ [
+ "\x00",
+ "\xd7",
+ "\x00\xd8",
+ "\x00\xd8\x00\xd8",
+ "\x00\xdc",
+ "\x00\xdc\x00\xd8",
+ "\x00\xdc\x00\xdc",
+ "\xe0",
+ "\xff",
+ ].each {|s|
+ s.force_encoding("utf-16le")
+ assert_equal(false, s.valid_encoding?, "#{encdump s}.valid_encoding?")
+ }
+ end
+
+ def test_strftime
+ s = "aa".force_encoding("utf-16be")
+ assert_raise(ArgumentError, "Time.now.strftime(#{encdump s})") { Time.now.strftime(s) }
+ end
+
+ def test_intern
+ s = "aaaa".force_encoding("utf-16be")
+ assert_equal(s.encoding, s.intern.to_s.encoding, "#{encdump s}.intern.to_s.encoding")
+ end
+
+ def test_sym_eq
+ s = "aa".force_encoding("utf-16le")
+ assert_not_equal(:aa, s.intern, "#{encdump s}.intern != :aa")
+ end
+
+ def test_compatible
+ s1 = "aa".force_encoding("utf-16be")
+ s2 = "z".force_encoding("us-ascii")
+ assert_nil(Encoding.compatible?(s1, s2), "Encoding.compatible?(#{encdump s1}, #{encdump s2})")
+ end
+
+ def test_casecmp
+ s1 = "aa".force_encoding("utf-16be")
+ s2 = "AA"
+ assert_not_equal(0, s1.casecmp(s2), "#{encdump s1}.casecmp(#{encdump s2})")
+ end
+
+ def test_end_with
+ s1 = "ab".force_encoding("utf-16be")
+ s2 = "b".force_encoding("utf-16be")
+ assert_equal(false, s1.end_with?(s2), "#{encdump s1}.end_with?(#{encdump s2})")
+ end
+
+ def test_hex
+ assert_raise(Encoding::CompatibilityError) {
+ "ff".encode("utf-16le").hex
+ }
+ assert_raise(Encoding::CompatibilityError) {
+ "ff".encode("utf-16be").hex
+ }
+ end
+
+ def test_oct
+ assert_raise(Encoding::CompatibilityError) {
+ "77".encode("utf-16le").oct
+ }
+ assert_raise(Encoding::CompatibilityError) {
+ "77".encode("utf-16be").oct
+ }
+ end
+
+ def test_count
+ s1 = "aa".force_encoding("utf-16be")
+ s2 = "aa"
+ assert_raise(Encoding::CompatibilityError, "#{encdump s1}.count(#{encdump s2})") {
+ s1.count(s2)
+ }
+ end
+
+ def test_plus
+ s1 = "a".force_encoding("us-ascii")
+ s2 = "aa".force_encoding("utf-16be")
+ assert_raise(Encoding::CompatibilityError, "#{encdump s1} + #{encdump s2}") {
+ s1 + s2
+ }
+ end
+
+ def test_encoding_find
+ assert_raise(ArgumentError) {
+ Encoding.find("utf-8".force_encoding("utf-16be"))
+ }
+ end
+
+ def test_interpolation
+ s = "aa".force_encoding("utf-16be")
+ assert_raise(Encoding::CompatibilityError, "\"a\#{#{encdump s}}\"") {
+ "a#{s}"
+ }
+ end
+
+ def test_slice!
+ enccall("aa".force_encoding("UTF-16BE"), :slice!, -1)
+ end
+
+ def test_plus_empty1
+ s1 = ""
+ s2 = "aa".force_encoding("utf-16be")
+ assert_nothing_raised("#{encdump s1} << #{encdump s2}") {
+ s1 + s2
+ }
+ end
+
+ def test_plus_empty2
+ s1 = "aa"
+ s2 = "".force_encoding("utf-16be")
+ assert_nothing_raised("#{encdump s1} << #{encdump s2}") {
+ s1 + s2
+ }
+ end
+
+ def test_plus_nonempty
+ s1 = "aa"
+ s2 = "bb".force_encoding("utf-16be")
+ assert_raise(Encoding::CompatibilityError, "#{encdump s1} << #{encdump s2}") {
+ s1 + s2
+ }
+ end
+
+ def test_concat_empty1
+ s1 = ""
+ s2 = "aa".force_encoding("utf-16be")
+ assert_nothing_raised("#{encdump s1} << #{encdump s2}") {
+ s1 << s2
+ }
+ end
+
+ def test_concat_empty2
+ s1 = "aa"
+ s2 = "".force_encoding("utf-16be")
+ assert_nothing_raised("#{encdump s1} << #{encdump s2}") {
+ s1 << s2
+ }
+ end
+
+ def test_concat_nonempty
+ s1 = "aa"
+ s2 = "bb".force_encoding("utf-16be")
+ assert_raise(Encoding::CompatibilityError, "#{encdump s1} << #{encdump s2}") {
+ s1 << s2
+ }
+ end
+
+ def test_chomp
+ s = "\1\n".force_encoding("utf-16be")
+ assert_equal(s, s.chomp, "#{encdump s}.chomp")
+ s = "\0\n".force_encoding("utf-16be")
+ assert_equal("", s.chomp, "#{encdump s}.chomp")
+ s = "\0\r\0\n".force_encoding("utf-16be")
+ assert_equal("", s.chomp, "#{encdump s}.chomp")
+ end
+
+ def test_succ
+ s = "\xff\xff".force_encoding("utf-16be")
+ assert_predicate(s.succ, :valid_encoding?, "#{encdump s}.succ.valid_encoding?")
+
+ s = "\xdb\xff\xdf\xff".force_encoding("utf-16be")
+ assert_predicate(s.succ, :valid_encoding?, "#{encdump s}.succ.valid_encoding?")
+ end
+
+ def test_regexp_union
+ enccall(Regexp, :union, "aa".force_encoding("utf-16be"), "bb".force_encoding("utf-16be"))
+ end
+
+ def test_empty_regexp
+ s = "".force_encoding("utf-16be")
+ assert_equal(Encoding.find("utf-16be"), Regexp.new(s).encoding,
+ "Regexp.new(#{encdump s}).encoding")
+ end
+
+ def test_regexp_match
+ assert_raise(Encoding::CompatibilityError) { Regexp.new("aa".force_encoding("utf-16be")) =~ "aa" }
+ end
+
+ def test_gsub
+ s = "abcd".force_encoding("utf-16be")
+ assert_nothing_raised {
+ s.gsub(Regexp.new(".".encode("utf-16be")), "xy")
+ }
+ s = "ab\0\ncd".force_encoding("utf-16be")
+ assert_raise(Encoding::CompatibilityError) {
+ s.gsub(Regexp.new(".".encode("utf-16be")), "xy")
+ }
+ end
+
+ def test_split_awk
+ s = " ab cd ".encode("utf-16be")
+ r = s.split(" ".encode("utf-16be"))
+ assert_equal(2, r.length)
+ assert_str_equal("ab".encode("utf-16be"), r[0])
+ assert_str_equal("cd".encode("utf-16be"), r[1])
+ end
+
+ def test_count2
+ e = "abc".count("^b")
+ assert_equal(e, "abc".encode("utf-16be").count("^b".encode("utf-16be")))
+ assert_equal(e, "abc".encode("utf-16le").count("^b".encode("utf-16le")))
+ end
+
+ def test_header
+ assert_raise(ArgumentError) { eval("# encoding:utf-16le\nfoo") }
+ assert_raise(ArgumentError) { eval("# encoding:utf-16be\nfoo") }
+ end
+
+
+ def test_is_mbc_newline
+ sl = "f\0o\0o\0\n\0b\0a\0r\0\n\0b\0a\0z\0\n\0".force_encoding("utf-16le")
+ sb = "\0f\0o\0o\0\n\0b\0a\0r\0\n\0b\0a\0z\0\n".force_encoding("utf-16be")
+ al = sl.lines.to_a
+ ab = sb.lines.to_a
+ assert_equal("f\0o\0o\0\n\0".force_encoding("utf-16le"), al.shift)
+ assert_equal("b\0a\0r\0\n\0".force_encoding("utf-16le"), al.shift)
+ assert_equal("b\0a\0z\0\n\0".force_encoding("utf-16le"), al.shift)
+ assert_equal("\0f\0o\0o\0\n".force_encoding("utf-16be"), ab.shift)
+ assert_equal("\0b\0a\0r\0\n".force_encoding("utf-16be"), ab.shift)
+ assert_equal("\0b\0a\0z\0\n".force_encoding("utf-16be"), ab.shift)
+
+ sl = "f\0o\0o\0\n\0".force_encoding("utf-16le")
+ sb = "\0f\0o\0o\0\n".force_encoding("utf-16be")
+ sl2 = "f\0o\0o\0".force_encoding("utf-16le")
+ sb2 = "\0f\0o\0o".force_encoding("utf-16be")
+ assert_equal(sl2, sl.chomp)
+ assert_equal(sl2, sl.chomp.chomp)
+ assert_equal(sb2, sb.chomp)
+ assert_equal(sb2, sb.chomp.chomp)
+
+ sl = "f\0o\0o\0\n".force_encoding("utf-16le")
+ sb = "\0f\0o\0o\n".force_encoding("utf-16be")
+ assert_equal(sl, sl.chomp)
+ assert_equal(sb, sb.chomp)
+ end
+
+ def test_code_to_mbc
+ assert_equal("a\0".force_encoding("utf-16le"), "a".ord.chr("utf-16le"))
+ assert_equal("\0a".force_encoding("utf-16be"), "a".ord.chr("utf-16be"))
+ end
+
+ def utf8_to_utf16(s, e)
+ s.chars.map {|c| c.ord.chr(e) }.join
+ end
+
+ def test_mbc_case_fold
+ rl = Regexp.new(utf8_to_utf16("^(\u3042)(a)\\1\\2$", "utf-16le"), "i")
+ rb = Regexp.new(utf8_to_utf16("^(\u3042)(a)\\1\\2$", "utf-16be"), "i")
+ assert_equal(Encoding.find("utf-16le"), rl.encoding)
+ assert_equal(Encoding.find("utf-16be"), rb.encoding)
+ assert_match(rl, utf8_to_utf16("\u3042a\u3042a", "utf-16le"))
+ assert_match(rb, utf8_to_utf16("\u3042a\u3042a", "utf-16be"))
+ end
+
+ def test_surrogate_pair
+ sl = "\x42\xd8\xb7\xdf".force_encoding("utf-16le")
+ sb = "\xd8\x42\xdf\xb7".force_encoding("utf-16be")
+
+ assert_equal(1, sl.size)
+ assert_equal(1, sb.size)
+ assert_equal(0x20bb7, sl.ord)
+ assert_equal(0x20bb7, sb.ord)
+ assert_equal(sl, 0x20bb7.chr("utf-16le"))
+ assert_equal(sb, 0x20bb7.chr("utf-16be"))
+ assert_equal("", sl.chop)
+ assert_equal("", sb.chop)
+ end
+
+ def test_regexp_escape
+ s = "\0*".force_encoding("UTF-16BE")
+ r = Regexp.new(Regexp.escape(s))
+ assert_match(r, s, "#{encdump(r)} =~ #{encdump(s)}")
+ end
+
+ def test_casecmp2
+ assert_equal(0, "\0A".force_encoding("UTF-16BE").casecmp("\0a".force_encoding("UTF-16BE")))
+ assert_not_equal(0, "\0A".force_encoding("UTF-16LE").casecmp("\0a".force_encoding("UTF-16LE")))
+ assert_not_equal(0, "A\0".force_encoding("UTF-16BE").casecmp("a\0".force_encoding("UTF-16BE")))
+ assert_equal(0, "A\0".force_encoding("UTF-16LE").casecmp("a\0".force_encoding("UTF-16LE")))
+
+ ary = ["01".force_encoding("UTF-16LE"),
+ "10".force_encoding("UTF-16LE")]
+ e = ary.sort {|x,y| x <=> y }
+ a = ary.sort {|x,y| x.casecmp(y) }
+ assert_equal(e, a)
+ end
+end
diff --git a/jni/ruby/test/ruby/enc/test_utf32.rb b/jni/ruby/test/ruby/enc/test_utf32.rb
new file mode 100644
index 0000000..29a2240
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_utf32.rb
@@ -0,0 +1,93 @@
+require 'test/unit'
+
+class TestUTF32 < Test::Unit::TestCase
+ def encdump(str)
+ d = str.dump
+ if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d
+ d
+ else
+ "#{d}.force_encoding(#{str.encoding.name.dump})"
+ end
+ end
+
+ def assert_str_equal(expected, actual, message=nil)
+ full_message = build_message(message, <<EOT)
+#{encdump expected} expected but not equal to
+#{encdump actual}.
+EOT
+ assert_equal(expected, actual, full_message)
+ end
+
+ def test_substr
+ assert_str_equal(
+ "abcdefgh".force_encoding("utf-32le"),
+ "abcdefgh".force_encoding("utf-32le")[0,3])
+ assert_str_equal(
+ "abcdefgh".force_encoding("utf-32be"),
+ "abcdefgh".force_encoding("utf-32be")[0,3])
+ end
+
+ def test_mbc_len
+ al = "abcdefghijkl".force_encoding("utf-32le").each_char.to_a
+ ab = "abcdefghijkl".force_encoding("utf-32be").each_char.to_a
+ assert_equal("abcd".force_encoding("utf-32le"), al.shift)
+ assert_equal("efgh".force_encoding("utf-32le"), al.shift)
+ assert_equal("ijkl".force_encoding("utf-32le"), al.shift)
+ assert_equal("abcd".force_encoding("utf-32be"), ab.shift)
+ assert_equal("efgh".force_encoding("utf-32be"), ab.shift)
+ assert_equal("ijkl".force_encoding("utf-32be"), ab.shift)
+ end
+
+ def ascii_to_utf16le(s)
+ s.unpack("C*").map {|x| [x,0,0,0] }.flatten.pack("C*").force_encoding("utf-32le")
+ end
+
+ def ascii_to_utf16be(s)
+ s.unpack("C*").map {|x| [0,0,0,x] }.flatten.pack("C*").force_encoding("utf-32be")
+ end
+
+ def test_mbc_newline
+ al = ascii_to_utf16le("foo\nbar\nbaz\n").lines.to_a
+ ab = ascii_to_utf16be("foo\nbar\nbaz\n").lines.to_a
+
+ assert_equal(ascii_to_utf16le("foo\n"), al.shift)
+ assert_equal(ascii_to_utf16le("bar\n"), al.shift)
+ assert_equal(ascii_to_utf16le("baz\n"), al.shift)
+ assert_equal(ascii_to_utf16be("foo\n"), ab.shift)
+ assert_equal(ascii_to_utf16be("bar\n"), ab.shift)
+ assert_equal(ascii_to_utf16be("baz\n"), ab.shift)
+
+ sl = "a\0".force_encoding("utf-32le")
+ sb = "a\0".force_encoding("utf-32be")
+ assert_equal(sl, sl.chomp)
+ assert_equal(sb, sb.chomp)
+ end
+
+ def test_mbc_to_code
+ sl = "a\0\0\0".force_encoding("utf-32le")
+ sb = "\0\0\0a".force_encoding("utf-32be")
+ assert_equal("a".ord, sl.ord)
+ assert_equal("a".ord, sb.ord)
+ end
+
+ def utf8_to_utf32(s, e)
+ s.chars.map {|c| c.ord.chr(e) }.join
+ end
+
+ def test_mbc_case_fold
+ rl = Regexp.new(utf8_to_utf32("^(\u3042)(a)\\1\\2$", "utf-32le"), "i")
+ rb = Regexp.new(utf8_to_utf32("^(\u3042)(a)\\1\\2$", "utf-32be"), "i")
+ assert_equal(Encoding.find("utf-32le"), rl.encoding)
+ assert_equal(Encoding.find("utf-32be"), rb.encoding)
+ assert_match(rl, utf8_to_utf32("\u3042a\u3042a", "utf-32le"))
+ assert_match(rb, utf8_to_utf32("\u3042a\u3042a", "utf-32be"))
+ end
+
+ def test_code_to_mbc
+ sl = "a\0\0\0".force_encoding("utf-32le")
+ sb = "\0\0\0a".force_encoding("utf-32be")
+ assert_equal(sl, "a".ord.chr("utf-32le"))
+ assert_equal(sb, "a".ord.chr("utf-32be"))
+ end
+end
+
diff --git a/jni/ruby/test/ruby/enc/test_windows_1251.rb b/jni/ruby/test/ruby/enc/test_windows_1251.rb
new file mode 100644
index 0000000..6fbf315
--- /dev/null
+++ b/jni/ruby/test/ruby/enc/test_windows_1251.rb
@@ -0,0 +1,16 @@
+# encoding:windows-1251
+
+require "test/unit"
+
+class TestWindows1251 < Test::Unit::TestCase
+ def test_windows_1251
+ (0xc0..0xdf).each do |c|
+ c1 = c.chr("windows-1251")
+ c2 = (c + 0x20).chr("windows-1251")
+ assert_match(/^(#{ c1 })\1$/i, c2 + c1)
+ assert_match(/^(#{ c2 })\1$/i, c1 + c2)
+ assert_match(/^[#{ c1 }]+$/i, c2 + c1)
+ assert_match(/^[#{ c2 }]+$/i, c1 + c2)
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/endblockwarn_rb b/jni/ruby/test/ruby/endblockwarn_rb
new file mode 100644
index 0000000..7b7f97f
--- /dev/null
+++ b/jni/ruby/test/ruby/endblockwarn_rb
@@ -0,0 +1,12 @@
+def end1
+ END {}
+end
+
+end1
+
+eval <<EOE
+ def end2
+ END {}
+ end
+EOE
+
diff --git a/jni/ruby/test/ruby/lbtest.rb b/jni/ruby/test/ruby/lbtest.rb
new file mode 100644
index 0000000..ae047fb
--- /dev/null
+++ b/jni/ruby/test/ruby/lbtest.rb
@@ -0,0 +1,49 @@
+require 'thread'
+
+class LocalBarrier
+ def initialize(n)
+ @wait = Queue.new
+ @done = Queue.new
+ @keeper = begin_keeper(n)
+ end
+
+ def sync
+ @done.push(true)
+ @wait.pop
+ end
+
+ def join
+ @keeper.join
+ end
+
+ private
+ def begin_keeper(n)
+ Thread.start do
+ n.times do
+ @done.pop
+ end
+ n.times do
+ @wait.push(true)
+ end
+ end
+ end
+end
+
+n = 10
+
+lb = LocalBarrier.new(n)
+
+(n - 1).times do |i|
+ Thread.start do
+ sleep((rand(n) + 1) / 100.0)
+ print "#{i}: done\n"
+ lb.sync
+ print "#{i}: cont\n"
+ end
+end
+
+lb.sync
+print "#{n-1}: cont\n"
+# lb.join # [ruby-dev:30653]
+
+print "exit.\n"
diff --git a/jni/ruby/test/ruby/marshaltestlib.rb b/jni/ruby/test/ruby/marshaltestlib.rb
new file mode 100644
index 0000000..665d365
--- /dev/null
+++ b/jni/ruby/test/ruby/marshaltestlib.rb
@@ -0,0 +1,436 @@
+# coding: utf-8
+module MarshalTestLib
+ # include this module to a Test::Unit::TestCase and define encode(o) and
+ # decode(s) methods. e.g.
+ #
+ # def encode(o)
+ # SOAPMarshal.dump(o)
+ # end
+ #
+ # def decode(s)
+ # SOAPMarshal.load(s)
+ # end
+
+ NegativeZero = (-1.0 / (1.0 / 0.0))
+
+ module Mod1; end
+ module Mod2; end
+
+ def marshaltest(o1)
+ str = encode(o1)
+ print str.dump, "\n" if $DEBUG
+ o2 = decode(str)
+ o2
+ end
+
+ def marshal_equal(o1, msg = nil)
+ msg = msg ? msg + "(#{ caller[0] })" : caller[0]
+ o2 = marshaltest(o1)
+ assert_equal(o1.class, o2.class, msg)
+ iv1 = o1.instance_variables.sort
+ iv2 = o2.instance_variables.sort
+ assert_equal(iv1, iv2)
+ val1 = iv1.map {|var| o1.instance_eval {eval var.to_s}}
+ val2 = iv1.map {|var| o2.instance_eval {eval var.to_s}}
+ assert_equal(val1, val2, msg)
+ if block_given?
+ assert_equal(yield(o1), yield(o2), msg)
+ else
+ assert_equal(o1, o2, msg)
+ end
+ end
+
+ def marshal_equal_with_ancestry(o1, msg = nil)
+ marshal_equal(o1, msg) do |o|
+ ancestry = o.singleton_class.ancestors
+ ancestry[ancestry.index(o.singleton_class)] = :singleton_class
+ ancestry
+ end
+ end
+
+ class MyObject; def initialize(v) @v = v end; attr_reader :v; end
+ def test_object
+ o1 = Object.new
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_object_subclass
+ marshal_equal(MyObject.new(2)) {|o| o.v}
+ end
+
+ def test_object_extend
+ o1 = Object.new
+ o1.extend(Mod1)
+ marshal_equal_with_ancestry(o1)
+ o1.extend(Mod2)
+ marshal_equal_with_ancestry(o1)
+ end
+
+ def test_object_subclass_extend
+ o1 = MyObject.new(2)
+ o1.extend(Mod1)
+ marshal_equal_with_ancestry(o1)
+ o1.extend(Mod2)
+ marshal_equal_with_ancestry(o1)
+ end
+
+ def test_object_prepend
+ bug8041 = '[ruby-core:53202] [Bug #8041]'
+
+ o1 = MyObject.new(42)
+ o1.singleton_class.class_eval {prepend Mod1}
+ assert_nothing_raised(ArgumentError, bug8041) {
+ marshal_equal_with_ancestry(o1, bug8041)
+ }
+ end
+
+ class MyArray < Array
+ def initialize(v, *args)
+ super(args)
+ @v = v
+ end
+ end
+ def test_array
+ marshal_equal(5)
+ marshal_equal([1,2,3])
+ end
+
+ def test_array_subclass
+ marshal_equal(MyArray.new(0, 1, 2, 3))
+ end
+
+ def test_array_ivar
+ o1 = Array.new
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ class MyException < Exception; def initialize(v, *args) super(*args); @v = v; end; attr_reader :v; end
+ def test_exception
+ marshal_equal(Exception.new('foo')) {|o| o.message}
+ marshal_equal(assert_raise(NoMethodError) {no_such_method()}) {|o| o.message}
+ end
+
+ def test_exception_subclass
+ marshal_equal(MyException.new(20, "bar")) {|o| [o.message, o.v]}
+ end
+
+ def test_false
+ marshal_equal(false)
+ end
+
+ class MyHash < Hash; def initialize(v, *args) super(*args); @v = v; end end
+ def test_hash
+ marshal_equal({1=>2, 3=>4})
+ end
+
+ def test_hash_default
+ h = Hash.new(:default)
+ h[5] = 6
+ marshal_equal(h)
+ end
+
+ def test_hash_subclass
+ h = MyHash.new(7, 8)
+ h[4] = 5
+ marshal_equal(h)
+ end
+
+ def test_hash_default_proc
+ h = Hash.new {}
+ assert_raise(TypeError) { marshaltest(h) }
+ end
+
+ def test_hash_ivar
+ o1 = Hash.new
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_hash_extend
+ o1 = Hash.new
+ o1.extend(Mod1)
+ marshal_equal_with_ancestry(o1)
+ o1.extend(Mod2)
+ marshal_equal_with_ancestry(o1)
+ end
+
+ def test_hash_subclass_extend
+ o1 = MyHash.new(2)
+ o1.extend(Mod1)
+ marshal_equal_with_ancestry(o1)
+ o1.extend(Mod2)
+ marshal_equal_with_ancestry(o1)
+ end
+
+ def test_bignum
+ marshal_equal(-0x4000_0000_0000_0001)
+ marshal_equal(-0x4000_0001)
+ marshal_equal(0x4000_0000)
+ marshal_equal(0x4000_0000_0000_0000)
+ end
+
+ def test_fixnum
+ marshal_equal(-0x4000_0000)
+ marshal_equal(-0x3fff_ffff)
+ marshal_equal(-1)
+ marshal_equal(0)
+ marshal_equal(1)
+ marshal_equal(0x3fff_ffff)
+ end
+
+ def test_float
+ marshal_equal(-1.0)
+ marshal_equal(0.0)
+ marshal_equal(1.0)
+ end
+
+ def test_float_inf_nan
+ marshal_equal(1.0/0.0)
+ marshal_equal(-1.0/0.0)
+ marshal_equal(0.0/0.0) {|o| o.nan?}
+ marshal_equal(NegativeZero) {|o| 1.0/o}
+ end
+
+ class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end
+ def test_range
+ marshal_equal(1..2)
+ marshal_equal(1...3)
+ end
+
+ def test_range_subclass
+ marshal_equal(MyRange.new(4,5,8, false))
+ end
+
+ class MyRegexp < Regexp; def initialize(v, *args) super(*args); @v = v; end end
+ def test_regexp
+ marshal_equal(/a/)
+ marshal_equal(/A/i)
+ marshal_equal(/A/mx)
+ marshal_equal(/a\u3042/)
+ marshal_equal(/aあ/)
+ assert_equal(Regexp.new("あ".force_encoding("ASCII-8BIT")),
+ Marshal.load("\004\b/\b\343\201\202\000"))
+ assert_equal(/au3042/, Marshal.load("\004\b/\fa\\u3042\000"))
+ #assert_equal(/au3042/u, Marshal.load("\004\b/\fa\\u3042@")) # spec
+ end
+
+ def test_regexp_subclass
+ marshal_equal(MyRegexp.new(10, "a"))
+ end
+
+ class MyString < String; def initialize(v, *args) super(*args); @v = v; end end
+ def test_string
+ marshal_equal("abc")
+ end
+
+ def test_string_ivar
+ o1 = ""
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_string_subclass
+ marshal_equal(MyString.new(10, "a"))
+ end
+
+ def test_string_subclass_cycle
+ str = MyString.new(10, "b")
+ str.instance_eval { @v = str }
+ marshal_equal(str) { |o|
+ assert_same(o, o.instance_eval { @v })
+ o.instance_eval { @v }
+ }
+ end
+
+ def test_string_subclass_extend
+ o = "abc"
+ o.extend(Mod1)
+ str = MyString.new(o, "c")
+ marshal_equal(str) { |v|
+ assert_kind_of(Mod1, v.instance_eval { @v })
+ }
+ end
+
+ MyStruct = Struct.new("MyStruct", :a, :b)
+ class MySubStruct < MyStruct; def initialize(v, *args) super(*args); @v = v; end end
+ def test_struct
+ marshal_equal(MyStruct.new(1,2))
+ end
+
+ def test_struct_subclass
+ marshal_equal(MySubStruct.new(10,1,2))
+ end
+
+ def test_struct_ivar
+ o1 = MyStruct.new
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_struct_subclass_extend
+ o1 = MyStruct.new
+ o1.extend(Mod1)
+ marshal_equal_with_ancestry(o1)
+ o1.extend(Mod2)
+ marshal_equal_with_ancestry(o1)
+ end
+
+ def test_symbol
+ marshal_equal(:a)
+ marshal_equal(:a?)
+ marshal_equal(:a!)
+ marshal_equal(:a=)
+ marshal_equal(:|)
+ marshal_equal(:^)
+ marshal_equal(:&)
+ marshal_equal(:<=>)
+ marshal_equal(:==)
+ marshal_equal(:===)
+ marshal_equal(:=~)
+ marshal_equal(:>)
+ marshal_equal(:>=)
+ marshal_equal(:<)
+ marshal_equal(:<=)
+ marshal_equal(:<<)
+ marshal_equal(:>>)
+ marshal_equal(:+)
+ marshal_equal(:-)
+ marshal_equal(:*)
+ marshal_equal(:/)
+ marshal_equal(:%)
+ marshal_equal(:**)
+ marshal_equal(:~)
+ marshal_equal(:+@)
+ marshal_equal(:-@)
+ marshal_equal(:[])
+ marshal_equal(:[]=)
+ marshal_equal(:`) #`
+ marshal_equal("a b".intern)
+ end
+
+ class MyTime < Time; def initialize(v, *args) super(*args); @v = v; end end
+ def test_time
+ # once there was a bug caused by usec overflow. try a little harder.
+ 10.times do
+ t = Time.now
+ marshal_equal(t, t.usec.to_s)
+ end
+ end
+
+ def test_time_subclass
+ marshal_equal(MyTime.new(10))
+ end
+
+ def test_time_ivar
+ o1 = Time.now
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_time_in_array
+ t = Time.now
+ assert_equal([t,t], Marshal.load(Marshal.dump([t, t])), "[ruby-dev:34159]")
+ end
+
+ def test_true
+ marshal_equal(true)
+ end
+
+ def test_nil
+ marshal_equal(nil)
+ end
+
+ def test_share
+ o = [:share]
+ o1 = [o, o]
+ o2 = marshaltest(o1)
+ assert_same(o2.first, o2.last)
+ end
+
+ class CyclicRange < Range
+ def <=>(other); true; end
+ end
+ def test_range_cyclic
+ return unless CyclicRange.respond_to?(:allocate) # test for 1.8
+ o1 = CyclicRange.allocate
+ o1.instance_eval { initialize(o1, o1) }
+ o2 = marshaltest(o1)
+ assert_same(o2, o2.begin)
+ assert_same(o2, o2.end)
+ end
+
+ def test_singleton
+ o = Object.new
+ def o.m() end
+ assert_raise(TypeError) { marshaltest(o) }
+
+ bug8043 = '[ruby-core:53206] [Bug #8043]'
+ class << o; prepend Mod1; end
+ assert_raise(TypeError, bug8043) {marshaltest(o)}
+
+ o = Object.new
+ c = class << o
+ @v = 1
+ class C; self; end
+ end
+ assert_raise(TypeError) { marshaltest(o) }
+ assert_raise(TypeError) { marshaltest(c) }
+ assert_raise(TypeError) { marshaltest(ARGF) }
+ assert_raise(TypeError) { marshaltest(ENV) }
+ end
+
+ def test_extend
+ o = Object.new
+ o.extend Mod1
+ marshal_equal(o) { |obj| obj.kind_of? Mod1 }
+ o = Object.new
+ o.extend Mod1
+ o.extend Mod2
+ marshal_equal_with_ancestry(o)
+ o = Object.new
+ o.extend Module.new
+ assert_raise(TypeError) { marshaltest(o) }
+ end
+
+ def test_extend_string
+ o = ""
+ o.extend Mod1
+ marshal_equal(o) { |obj| obj.kind_of? Mod1 }
+ o = ""
+ o.extend Mod1
+ o.extend Mod2
+ marshal_equal_with_ancestry(o)
+ o = ""
+ o.extend Module.new
+ assert_raise(TypeError) { marshaltest(o) }
+ end
+
+ def test_anonymous
+ c = Class.new
+ assert_raise(TypeError) { marshaltest(c) }
+ o = c.new
+ assert_raise(TypeError) { marshaltest(o) }
+ m = Module.new
+ assert_raise(TypeError) { marshaltest(m) }
+ end
+
+ def test_string_empty
+ marshal_equal("")
+ end
+
+ def test_string_crlf
+ marshal_equal("\r\n")
+ end
+
+ def test_string_escape
+ marshal_equal("\0<;;>\1;;")
+ end
+
+ MyStruct2 = Struct.new(:a, :b)
+ def test_struct_toplevel
+ o = MyStruct2.new(1,2)
+ marshal_equal(o)
+ end
+end
diff --git a/jni/ruby/test/ruby/sentence.rb b/jni/ruby/test/ruby/sentence.rb
new file mode 100644
index 0000000..50f42d6
--- /dev/null
+++ b/jni/ruby/test/ruby/sentence.rb
@@ -0,0 +1,668 @@
+# == sentence library
+#
+# = Features
+#
+# * syntax based sentences generation
+# * sentence operations such as substitution.
+#
+# = Example
+#
+# Some arithmetic expressions using "+", "-", "*" and "/" are generated as follows.
+#
+# require 'sentence'
+# Sentence.each({
+# :exp => [["num"],
+# [:exp, "+", :exp],
+# [:exp, "-", :exp],
+# [:exp, "*", :exp],
+# [:exp, "/", :exp]]
+# }, :exp, 2) {|sent| p sent }
+# #=>
+# #<Sentence: "num">
+# #<Sentence: ("num") "+" ("num")>
+# #<Sentence: ("num") "+" (("num") "+" ("num"))>
+# #<Sentence: ("num") "+" (("num") "-" ("num"))>
+# #<Sentence: ("num") "+" (("num") "*" ("num"))>
+# #<Sentence: ("num") "+" (("num") "/" ("num"))>
+# #<Sentence: (("num") "+" ("num")) "+" ("num")>
+# ...
+#
+# Sentence.each takes 3 arguments.
+# The first argument is the syntax for the expressions.
+# The second argument, :exp, is a generating nonterminal.
+# The third argument, 2, limits derivation to restrict results finitely.
+#
+# Some arithmetic expressions including parenthesis can be generated as follows.
+#
+# syntax = {
+# :factor => [["n"],
+# ["(", :exp, ")"]],
+# :term => [[:factor],
+# [:term, "*", :factor],
+# [:term, "/", :factor]],
+# :exp => [[:term],
+# [:exp, "+", :term],
+# [:exp, "-", :term]]
+# }
+# Sentence.each(syntax, :exp, 2) {|sent| p sent }
+# #=>
+# #<Sentence: (("n"))>
+# #<Sentence: (("(" ((("n"))) ")"))>
+# #<Sentence: (("(" ((("(" ((("n"))) ")"))) ")"))>
+# #<Sentence: (("(" (((("n")) "*" ("n"))) ")"))>
+# #<Sentence: (("(" (((("n")) "/" ("n"))) ")"))>
+# #<Sentence: (("(" (((("n"))) "+" (("n"))) ")"))>
+# #<Sentence: (("(" (((("n"))) "-" (("n"))) ")"))>
+# #<Sentence: ((("n")) "*" ("n"))>
+# #<Sentence: ((("n")) "*" ("(" ((("n"))) ")"))>
+# ...
+#
+# Sentence#to_s can be used to concatenate strings
+# in a sentence:
+#
+# Sentence.each(syntax, :exp, 2) {|sent| p sent.to_s }
+# #=>
+# "n"
+# "(n)"
+# "((n))"
+# "(n*n)"
+# "(n/n)"
+# "(n+n)"
+# "(n-n)"
+# "n*n"
+# "n*(n)"
+# ...
+#
+
+# Sentence() instantiates a sentence object.
+#
+# Sentence("foo", "bar")
+# #=> #<Sentence: "foo" "bar">
+#
+# Sentence("foo", ["bar", "baz"])
+# #=> #<Sentence: "foo" ("bar" "baz")>
+#
+def Sentence(*ary)
+ Sentence.new(ary)
+end
+
+# Sentence class represents a tree with string leaves.
+#
+class Sentence
+ # _ary_ represents a tree.
+ # It should be a possibly nested array which contains strings.
+ #
+ # Note that _ary_ is not copied.
+ # Don't modify _ary_ after the sentence object is instantiated.
+ #
+ # Sentence.new(["a", "pen"])
+ # #<Sentence: "a" "pen">
+ #
+ # Sentence.new(["I", "have", ["a", "pen"]])
+ # #<Sentence: "I" "have" ("a" "pen")>
+ #
+ def initialize(ary)
+ @sent = ary
+ end
+
+ # returns a string which is concatenation of all strings.
+ # No separator is used.
+ #
+ # Sentence("2", "+", "3").to_s
+ # "2+3"
+ #
+ # Sentence("2", "+", ["3", "*", "5"]).to_s
+ # "2+3*5"
+ #
+ def to_s
+ @sent.join('')
+ end
+
+ # returns a string which is concatenation of all strings separated by _sep_.
+ # If _sep_ is not given, single space is used.
+ #
+ # Sentence("I", "have", ["a", "pen"]).join
+ # "I have a pen"
+ #
+ # Sentence("I", "have", ["a", "pen"]).join("/")
+ # "I/have/a/pen"
+ #
+ # Sentence("a", [], "b").join("/")
+ # "a/b"
+ #
+ def join(sep=' ')
+ @sent.flatten.join(sep)
+ end
+
+ # returns a tree as a nested array.
+ #
+ # Note that the result is not copied.
+ # Don't modify the result.
+ #
+ # Sentence(["foo", "bar"], "baz").to_a
+ # #=> [["foo", "bar"], "baz"]
+ #
+ def to_a
+ @sent
+ end
+
+ # returns <i>i</i>th element as a sentence or string.
+ #
+ # s = Sentence(["foo", "bar"], "baz")
+ # s #=> #<Sentence: ("foo" "bar") "baz">
+ # s[0] #=> #<Sentence: "foo" "bar">
+ # s[1] #=> "baz"
+ #
+ def [](i)
+ e = @sent[i]
+ e.respond_to?(:to_ary) ? Sentence.new(e) : e
+ end
+
+ # returns the number of top level elements.
+ #
+ # Sentence.new(%w[foo bar]).length
+ # #=> 2
+ #
+ # Sentence(%w[2 * 7], "+", %w[3 * 5]).length
+ # #=> 3
+ #
+ def length
+ @sent.length
+ end
+
+ # iterates over children.
+ #
+ # Sentence(%w[2 * 7], "+", %w[3 * 5]).each {|v| p v }
+ # #=>
+ # #<Sentence: "2" "*" "7">
+ # "+"
+ # #<Sentence: "3" "*" "5">
+ #
+ def each # :yield: element
+ @sent.each_index {|i|
+ yield self[i]
+ }
+ end
+ include Enumerable
+
+ def inspect
+ "#<#{self.class}: #{inner_inspect(@sent, '')}>"
+ end
+
+ # :stopdoc:
+ def inner_inspect(ary, r)
+ first = true
+ ary.each {|obj|
+ r << ' ' if !first
+ first = false
+ if obj.respond_to? :to_ary
+ r << '('
+ inner_inspect(obj, r)
+ r << ')'
+ else
+ r << obj.inspect
+ end
+ }
+ r
+ end
+ # :startdoc:
+
+ # returns new sentence object which
+ # _target_ is substituted by the block.
+ #
+ # Sentence#subst invokes <tt>_target_ === _string_</tt> for each
+ # string in the sentence.
+ # The strings which === returns true are substituted by the block.
+ # The block is invoked with the substituting string.
+ #
+ # Sentence.new(%w[2 + 3]).subst("+") { "*" }
+ # #<Sentence: "2" "*" "3">
+ #
+ # Sentence.new(%w[2 + 3]).subst(/\A\d+\z/) {|s| ((s.to_i)*2).to_s }
+ # #=> #<Sentence: "4" "+" "6">
+ #
+ def subst(target, &b) # :yield: string
+ Sentence.new(subst_rec(@sent, target, &b))
+ end
+
+ # :stopdoc:
+ def subst_rec(obj, target, &b)
+ if obj.respond_to? :to_ary
+ a = []
+ obj.each {|e| a << subst_rec(e, target, &b) }
+ a
+ elsif target === obj
+ yield obj
+ else
+ obj
+ end
+ end
+ # :startdoc:
+
+ # find a subsentence and return it.
+ # The block is invoked for each subsentence in preorder manner.
+ # The first subsentence which the block returns true is returned.
+ #
+ # Sentence(%w[2 * 7], "+", %w[3 * 5]).find_subtree {|s| s[1] == "*" }
+ # #=> #<Sentence: "2" "*" "7">
+ #
+ def find_subtree(&b) # :yield: sentence
+ find_subtree_rec(@sent, &b)
+ end
+
+ # :stopdoc:
+ def find_subtree_rec(obj, &b)
+ if obj.respond_to? :to_ary
+ s = Sentence.new(obj)
+ if b.call s
+ return s
+ else
+ obj.each {|e|
+ r = find_subtree_rec(e, &b)
+ return r if r
+ }
+ end
+ end
+ nil
+ end
+ # :startdoc:
+
+ # returns a new sentence object which expands according to the condition
+ # given by the block.
+ #
+ # The block is invoked for each subsentence.
+ # The subsentences which the block returns true are
+ # expanded into parent.
+ #
+ # s = Sentence(%w[2 * 7], "+", %w[3 * 5])
+ # #=> #<Sentence: ("2" "*" "7") "+" ("3" "*" "5")>
+ #
+ # s.expand { true }
+ # #=> #<Sentence: "2" "*" "7" "+" "3" "*" "5">
+ #
+ # s.expand {|s| s[0] == "3" }
+ # #=> #<Sentence: (("2" "*" "7") "+" "3" "*" "5")>
+ #
+ def expand(&b) # :yield: sentence
+ Sentence.new(expand_rec(@sent, &b))
+ end
+
+ # :stopdoc:
+ def expand_rec(obj, r=[], &b)
+ if obj.respond_to? :to_ary
+ obj.each {|o|
+ s = Sentence.new(o)
+ if b.call s
+ expand_rec(o, r, &b)
+ else
+ a = []
+ expand_rec(o, a, &b)
+ r << a
+ end
+ }
+ else
+ r << obj
+ end
+ r
+ end
+ # :startdoc:
+
+ # Sentence.each generates sentences
+ # by deriving the start symbol _sym_ using _syntax_.
+ # The derivation is restricted by an positive integer _limit_ to
+ # avoid infinite generation.
+ #
+ # Sentence.each yields the block with a generated sentence.
+ #
+ # Sentence.each({
+ # :exp => [["n"],
+ # [:exp, "+", :exp],
+ # [:exp, "*", :exp]]
+ # }, :exp, 1) {|sent| p sent }
+ # #=>
+ # #<Sentence: "n">
+ # #<Sentence: ("n") "+" ("n")>
+ # #<Sentence: ("n") "*" ("n")>
+ #
+ # Sentence.each({
+ # :exp => [["n"],
+ # [:exp, "+", :exp],
+ # [:exp, "*", :exp]]
+ # }, :exp, 2) {|sent| p sent }
+ # #=>
+ # #<Sentence: "n">
+ # #<Sentence: ("n") "+" ("n")>
+ # #<Sentence: ("n") "+" (("n") "+" ("n"))>
+ # #<Sentence: ("n") "+" (("n") "*" ("n"))>
+ # #<Sentence: (("n") "+" ("n")) "+" ("n")>
+ # #<Sentence: (("n") "*" ("n")) "+" ("n")>
+ # #<Sentence: ("n") "*" ("n")>
+ # #<Sentence: ("n") "*" (("n") "+" ("n"))>
+ # #<Sentence: ("n") "*" (("n") "*" ("n"))>
+ # #<Sentence: (("n") "+" ("n")) "*" ("n")>
+ # #<Sentence: (("n") "*" ("n")) "*" ("n")>
+ #
+ def Sentence.each(syntax, sym, limit)
+ Gen.new(syntax).each_tree(sym, limit) {|tree|
+ yield Sentence.new(tree)
+ }
+ end
+
+ # Sentence.expand_syntax returns an expanded syntax:
+ # * No rule derives to empty sequence
+ # * Underivable rule simplified
+ # * No channel rule
+ # * Symbols which has zero or one choices are not appered in rhs.
+ #
+ # Note that the rules which can derive empty and non-empty
+ # sequences are modified to derive only non-empty sequences.
+ #
+ # Sentence.expand_syntax({
+ # :underivable1 => [],
+ # :underivable2 => [[:underivable1]],
+ # :underivable3 => [[:underivable3]],
+ # :empty_only1 => [[]],
+ # :empty_only2 => [[:just_empty1, :just_empty1]],
+ # :empty_or_not => [[], ["foo"]],
+ # :empty_or_not_2 => [[:empty_or_not, :empty_or_not]],
+ # :empty_or_not_3 => [[:empty_or_not, :empty_or_not, :empty_or_not]],
+ # :empty_or_not_4 => [[:empty_or_not_2, :empty_or_not_2]],
+ # :channel1 => [[:channeled_data]],
+ # :channeled_data => [["a", "b"], ["c", "d"]],
+ # :single_choice => [["single", "choice"]],
+ # :single_choice_2 => [[:single_choice, :single_choice]],
+ # })
+ # #=>
+ # {
+ # :underivable1=>[], # underivable rules are simplified to [].
+ # :underivable2=>[],
+ # :underivable3=>[],
+ # :empty_only1=>[], # derivation to empty sequence are removed.
+ # :empty_only2=>[],
+ # :empty_or_not=>[["foo"]], # empty sequences are removed too.
+ # :empty_or_not_2=>[["foo"], ["foo", "foo"]],
+ # :empty_or_not_3=>[["foo"], ["foo", "foo"], ["foo", "foo", "foo"]],
+ # :empty_or_not_4=> [["foo"], ["foo", "foo"], [:empty_or_not_2, :empty_or_not_2]],
+ # :channel1=>[["a", "b"], ["c", "d"]], # channel rules are removed.
+ # :channeled_data=>[["a", "b"], ["c", "d"]],
+ # :single_choice=>[["single", "choice"]], # single choice rules are expanded.
+ # :single_choice_2=>[["single", "choice", "single", "choice"]],
+ # }
+ #
+ # Sentence.expand_syntax({
+ # :factor => [["n"],
+ # ["(", :exp, ")"]],
+ # :term => [[:factor],
+ # [:term, "*", :factor],
+ # [:term, "/", :factor]],
+ # :exp => [[:term],
+ # [:exp, "+", :term],
+ # [:exp, "-", :term]]
+ # })
+ # #=>
+ # {:exp=> [["n"],
+ # ["(", :exp, ")"],
+ # [:exp, "+", :term],
+ # [:exp, "-", :term],
+ # [:term, "*", :factor],
+ # [:term, "/", :factor]],
+ # :factor=> [["n"],
+ # ["(", :exp, ")"]],
+ # :term=> [["n"],
+ # ["(", :exp, ")"],
+ # [:term, "*", :factor],
+ # [:term, "/", :factor]]
+ # }
+ #
+ def Sentence.expand_syntax(syntax)
+ Sentence::Gen.expand_syntax(syntax)
+ end
+
+ # :stopdoc:
+ class Gen
+ def Gen.each_tree(syntax, sym, limit, &b)
+ Gen.new(syntax).each_tree(sym, limit, &b)
+ end
+
+ def Gen.each_string(syntax, sym, limit, &b)
+ Gen.new(syntax).each_string(sym, limit, &b)
+ end
+
+ def initialize(syntax)
+ @syntax = syntax
+ end
+
+ def self.expand_syntax(syntax)
+ syntax = simplify_underivable_rules(syntax)
+ syntax = simplify_emptyonly_rules(syntax)
+ syntax = make_rules_no_empseq(syntax)
+ syntax = expand_channel_rules(syntax)
+
+ syntax = expand_noalt_rules(syntax)
+ syntax = reorder_rules(syntax)
+ end
+
+ def self.simplify_underivable_rules(syntax)
+ deribable_syms = {}
+ changed = true
+ while changed
+ changed = false
+ syntax.each {|sym, rules|
+ next if deribable_syms[sym]
+ rules.each {|rhs|
+ if rhs.all? {|e| String === e || deribable_syms[e] }
+ deribable_syms[sym] = true
+ changed = true
+ break
+ end
+ }
+ }
+ end
+ result = {}
+ syntax.each {|sym, rules|
+ if deribable_syms[sym]
+ rules2 = []
+ rules.each {|rhs|
+ rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
+ }
+ result[sym] = rules2.uniq
+ else
+ result[sym] = []
+ end
+ }
+ result
+ end
+
+ def self.simplify_emptyonly_rules(syntax)
+ justempty_syms = {}
+ changed = true
+ while changed
+ changed = false
+ syntax.each {|sym, rules|
+ next if justempty_syms[sym]
+ if !rules.empty? && rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
+ justempty_syms[sym] = true
+ changed = true
+ end
+ }
+ end
+ result = {}
+ syntax.each {|sym, rules|
+ result[sym] = rules.map {|rhs| rhs.reject {|e| justempty_syms[e] } }.uniq
+ }
+ result
+ end
+
+ def self.expand_emptyable_syms(rhs, emptyable_syms)
+ if rhs.empty?
+ yield []
+ else
+ first = rhs[0]
+ rest = rhs[1..-1]
+ if emptyable_syms[first]
+ expand_emptyable_syms(rest, emptyable_syms) {|rhs2|
+ yield [first] + rhs2
+ yield rhs2
+ }
+ else
+ expand_emptyable_syms(rest, emptyable_syms) {|rhs2|
+ yield [first] + rhs2
+ }
+ end
+ end
+ end
+
+ def self.make_rules_no_empseq(syntax)
+ emptyable_syms = {}
+ changed = true
+ while changed
+ changed = false
+ syntax.each {|sym, rules|
+ next if emptyable_syms[sym]
+ rules.each {|rhs|
+ if rhs.all? {|e| emptyable_syms[e] }
+ emptyable_syms[sym] = true
+ changed = true
+ break
+ end
+ }
+ }
+ end
+ result = {}
+ syntax.each {|sym, rules|
+ rules2 = []
+ rules.each {|rhs|
+ expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
+ next if rhs2.empty?
+ rules2 << rhs2
+ }
+ }
+ result[sym] = rules2.uniq
+ }
+ result
+ end
+
+ def self.expand_channel_rules(syntax)
+ channel_rules = {}
+ syntax.each {|sym, rules|
+ channel_rules[sym] = {sym=>true}
+ rules.each {|rhs|
+ if rhs.length == 1 && Symbol === rhs[0]
+ channel_rules[sym][rhs[0]] = true
+ end
+ }
+ }
+ changed = true
+ while changed
+ changed = false
+ channel_rules.each {|sym, set|
+ n1 = set.size
+ set.keys.each {|s|
+ set.update(channel_rules[s])
+ }
+ n2 = set.size
+ changed = true if n1 < n2
+ }
+ end
+ result = {}
+ syntax.each {|sym, rules|
+ rules2 = []
+ channel_rules[sym].each_key {|s|
+ syntax[s].each {|rhs|
+ unless rhs.length == 1 && Symbol === rhs[0]
+ rules2 << rhs
+ end
+ }
+ }
+ result[sym] = rules2.uniq
+ }
+ result
+ end
+
+ def self.expand_noalt_rules(syntax)
+ noalt_syms = {}
+ syntax.each {|sym, rules|
+ if rules.length == 1
+ noalt_syms[sym] = true
+ end
+ }
+ result = {}
+ syntax.each {|sym, rules|
+ rules2 = []
+ rules.each {|rhs|
+ rhs2 = []
+ rhs.each {|e|
+ if noalt_syms[e]
+ rhs2.concat syntax[e][0]
+ else
+ rhs2 << e
+ end
+ }
+ rules2 << rhs2
+ }
+ result[sym] = rules2.uniq
+ }
+ result
+ end
+
+ def self.reorder_rules(syntax)
+ result = {}
+ syntax.each {|sym, rules|
+ result[sym] = rules.sort_by {|rhs|
+ [rhs.find_all {|e| Symbol === e }.length, rhs.length]
+ }
+ }
+ result
+ end
+
+ def each_tree(sym, limit)
+ generate_from_sym(sym, limit) {|_, tree|
+ yield tree
+ }
+ nil
+ end
+
+ def each_string(sym, limit)
+ generate_from_sym(sym, limit) {|_, tree|
+ yield [tree].join('')
+ }
+ nil
+ end
+
+ def generate_from_sym(sym, limit, &b)
+ return if limit < 0
+ if String === sym
+ yield limit, sym
+ else
+ rules = @syntax[sym]
+ raise "undefined rule: #{sym}" if !rules
+ rules.each {|rhs|
+ if rhs.length == 1 || rules.length == 1
+ limit1 = limit
+ else
+ limit1 = limit-1
+ end
+ generate_from_rhs(rhs, limit1, &b)
+ }
+ end
+ nil
+ end
+
+ def generate_from_rhs(rhs, limit)
+ return if limit < 0
+ if rhs.empty?
+ yield limit, []
+ else
+ generate_from_sym(rhs[0], limit) {|limit1, child|
+ generate_from_rhs(rhs[1..-1], limit1) {|limit2, arr|
+ yield limit2, [child, *arr]
+ }
+ }
+ end
+ nil
+ end
+ end
+ # :startdoc:
+
+end
+
diff --git a/jni/ruby/test/ruby/test_alias.rb b/jni/ruby/test/ruby/test_alias.rb
new file mode 100644
index 0000000..8901fc2
--- /dev/null
+++ b/jni/ruby/test/ruby/test_alias.rb
@@ -0,0 +1,196 @@
+require 'test/unit'
+
+class TestAlias < Test::Unit::TestCase
+ class Alias0
+ def foo
+ "foo"
+ end
+ end
+
+ class Alias1 < Alias0
+ alias bar foo
+
+ def foo
+ "foo+#{super}"
+ end
+ end
+
+ class Alias2 < Alias1
+ alias baz foo
+ undef foo
+ end
+
+ class Alias3 < Alias2
+ def foo
+ super
+ end
+
+ def bar
+ super
+ end
+
+ def quux
+ super
+ end
+ end
+
+ def test_alias
+ x = Alias2.new
+ assert_equal "foo", x.bar
+ assert_equal "foo+foo", x.baz
+ assert_equal "foo+foo", x.baz # test_check for cache
+
+ x = Alias3.new
+ assert_raise(NoMethodError) { x.foo }
+ assert_equal "foo", x.bar
+ assert_raise(NoMethodError) { x.quux }
+ end
+
+ class C
+ def m
+ $SAFE
+ end
+ end
+
+ def test_nonexistmethod
+ assert_raise(NameError){
+ Class.new{
+ alias_method :foobarxyzzy, :barbaz
+ }
+ }
+ end
+
+ def test_send_alias
+ x = "abc"
+ class << x
+ alias_method :try, :__send__
+ end
+ assert_equal("ABC", x.try(:upcase), '[ruby-dev:38824]')
+ end
+
+ def test_special_const_alias
+ assert_raise(TypeError) do
+ 1.instance_eval do
+ alias to_string to_s
+ end
+ end
+ end
+
+ def test_alias_with_zsuper_method
+ c = Class.new
+ c.class_eval do
+ def foo
+ :ok
+ end
+ def bar
+ :ng
+ end
+ private :foo
+ end
+ d = Class.new(c)
+ d.class_eval do
+ public :foo
+ alias bar foo
+ end
+ assert_equal(:ok, d.new.bar)
+ end
+
+ module SuperInAliasedModuleMethod
+ module M
+ def foo
+ super << :M
+ end
+
+ alias bar foo
+ end
+
+ class Base
+ def foo
+ [:Base]
+ end
+ end
+
+ class Derived < Base
+ include M
+ end
+ end
+
+ # [ruby-dev:46028]
+ def test_super_in_aliased_module_method # fails in 1.8
+ assert_equal([:Base, :M], SuperInAliasedModuleMethod::Derived.new.bar)
+ end
+
+ def test_alias_wb_miss
+ assert_normal_exit %q{
+ require 'stringio'
+ GC.verify_internal_consistency
+ GC.start
+ class StringIO
+ alias_method :read_nonblock, :sysread
+ end
+ GC.verify_internal_consistency
+ }
+ end
+
+ def test_cyclic_zsuper
+ bug9475 = '[ruby-core:60431] [Bug #9475]'
+
+ a = Module.new do
+ def foo
+ "A"
+ end
+ end
+
+ b = Class.new do
+ include a
+ attr_reader :b
+
+ def foo
+ @b ||= 0
+ raise SystemStackError if (@b += 1) > 1
+ # "foo from B"
+ super + "B"
+ end
+ end
+
+ c = Class.new(b) do
+ alias orig_foo foo
+
+ def foo
+ # "foo from C"
+ orig_foo + "C"
+ end
+ end
+
+ b.class_eval do
+ alias orig_foo foo
+ attr_reader :b2
+
+ def foo
+ @b2 ||= 0
+ raise SystemStackError if (@b2 += 1) > 1
+ # "foo from B (again)"
+ orig_foo + "B2"
+ end
+ end
+
+ assert_nothing_raised(SystemStackError, bug9475) do
+ assert_equal("ABC", c.new.foo, bug9475)
+ end
+ end
+
+ def test_alias_in_module
+ bug9663 = '[ruby-core:61635] [Bug #9663]'
+
+ assert_separately(['-', bug9663], <<-'end;')
+ bug = ARGV[0]
+
+ m = Module.new do
+ alias orig_to_s to_s
+ end
+
+ o = Object.new.extend(m)
+ assert_equal(o.to_s, o.orig_to_s, bug)
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_argf.rb b/jni/ruby/test/ruby/test_argf.rb
new file mode 100644
index 0000000..6975b83
--- /dev/null
+++ b/jni/ruby/test/ruby/test_argf.rb
@@ -0,0 +1,859 @@
+require 'test/unit'
+require 'timeout'
+require 'tmpdir'
+require 'tempfile'
+require 'fileutils'
+
+class TestArgf < Test::Unit::TestCase
+ def setup
+ @tmpdir = Dir.mktmpdir
+ @tmp_count = 0
+ @t1 = make_tempfile0("argf-foo")
+ @t1.binmode
+ @t1.puts "1"
+ @t1.puts "2"
+ @t1.close
+ @t2 = make_tempfile0("argf-bar")
+ @t2.binmode
+ @t2.puts "3"
+ @t2.puts "4"
+ @t2.close
+ @t3 = make_tempfile0("argf-baz")
+ @t3.binmode
+ @t3.puts "5"
+ @t3.puts "6"
+ @t3.close
+ end
+
+ def teardown
+ FileUtils.rmtree(@tmpdir)
+ end
+
+ def make_tempfile0(basename)
+ @tmp_count += 1
+ open("#{@tmpdir}/#{basename}-#{@tmp_count}", "w")
+ end
+
+ def make_tempfile
+ t = make_tempfile0("argf-qux")
+ t.puts "foo"
+ t.puts "bar"
+ t.puts "baz"
+ t.close
+ t
+ end
+
+ def ruby(*args, external_encoding: Encoding::UTF_8)
+ args = ['-e', '$>.write($<.read)'] if args.empty?
+ ruby = EnvUtil.rubybin
+ f = IO.popen([ruby] + args, 'r+', external_encoding: external_encoding)
+ yield(f)
+ ensure
+ f.close unless !f || f.closed?
+ end
+
+ def no_safe_rename
+ /cygwin|mswin|mingw|bccwin/ =~ RUBY_PLATFORM
+ end
+
+ def assert_src_expected(line, src, args = nil)
+ args ||= [@t1.path, @t2.path, @t3.path]
+ expected = src.split(/^/)
+ ruby('-e', src, *args) do |f|
+ expected.each_with_index do |e, i|
+ /#=> *(.*)/ =~ e or next
+ a = f.gets
+ assert_not_nil(a, "[ruby-dev:34445]: remained")
+ assert_equal($1, a.chomp, "[ruby-dev:34445]: line #{line+i}")
+ end
+ end
+ end
+
+ def test_argf
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ a = ARGF
+ b = a.dup
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["1", 1, "1", 1]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["2", 2, "2", 2]
+ a.rewind
+ b.rewind
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["1", 1, "1", 3]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["2", 2, "2", 4]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["3", 3, "3", 5]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["4", 4, "4", 6]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["5", 5, "5", 7]
+ a.rewind
+ b.rewind
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["5", 5, "5", 8]
+ p [a.gets.chomp, a.lineno, b.gets.chomp, b.lineno] #=> ["6", 6, "6", 9]
+ SRC
+ end
+
+ def test_lineno
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ a = ARGF
+ a.gets; p $. #=> 1
+ a.gets; p $. #=> 2
+ a.gets; p $. #=> 3
+ a.rewind; p $. #=> 3
+ a.gets; p $. #=> 3
+ a.gets; p $. #=> 4
+ a.rewind; p $. #=> 4
+ a.gets; p $. #=> 3
+ a.lineno = 1000; p $. #=> 1000
+ a.gets; p $. #=> 1001
+ a.gets; p $. #=> 1002
+ $. = 2000
+ a.gets; p $. #=> 2001
+ a.gets; p $. #=> 2001
+ SRC
+ end
+
+ def test_lineno2
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ a = ARGF.dup
+ a.gets; p $. #=> 1
+ a.gets; p $. #=> 2
+ a.gets; p $. #=> 1
+ a.rewind; p $. #=> 1
+ a.gets; p $. #=> 1
+ a.gets; p $. #=> 2
+ a.gets; p $. #=> 1
+ a.lineno = 1000; p $. #=> 1
+ a.gets; p $. #=> 2
+ a.gets; p $. #=> 2
+ $. = 2000
+ a.gets; p $. #=> 2000
+ a.gets; p $. #=> 2000
+ SRC
+ end
+
+ def test_lineno3
+ assert_in_out_err(["-", @t1.path, @t2.path], <<-INPUT, %w"1 1 1 2 2 2 3 3 1 4 4 2", [], "[ruby-core:25205]")
+ ARGF.each do |line|
+ puts [$., ARGF.lineno, ARGF.file.lineno]
+ end
+ INPUT
+ end
+
+ def test_inplace
+ assert_in_out_err(["-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], [])
+ ARGF.inplace_mode = '.bak'
+ while line = ARGF.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ assert_equal("1.new\n2.new\n", File.read(@t1.path))
+ assert_equal("3.new\n4.new\n", File.read(@t2.path))
+ assert_equal("5.new\n6.new\n", File.read(@t3.path))
+ assert_equal("1\n2\n", File.read(@t1.path + ".bak"))
+ assert_equal("3\n4\n", File.read(@t2.path + ".bak"))
+ assert_equal("5\n6\n", File.read(@t3.path + ".bak"))
+ end
+
+ def test_inplace2
+ assert_in_out_err(["-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], [])
+ ARGF.inplace_mode = '.bak'
+ puts ARGF.gets.chomp + '.new'
+ puts ARGF.gets.chomp + '.new'
+ p ARGF.inplace_mode
+ ARGF.inplace_mode = nil
+ puts ARGF.gets.chomp + '.new'
+ puts ARGF.gets.chomp + '.new'
+ p ARGF.inplace_mode
+ ARGF.inplace_mode = '.bak'
+ puts ARGF.gets.chomp + '.new'
+ p ARGF.inplace_mode
+ ARGF.inplace_mode = nil
+ puts ARGF.gets.chomp + '.new'
+ INPUT
+ assert_equal("1.new\n2.new\n\".bak\"\n3.new\n4.new\nnil\n", File.read(@t1.path))
+ assert_equal("3\n4\n", File.read(@t2.path))
+ assert_equal("5.new\n\".bak\"\n6.new\n", File.read(@t3.path))
+ assert_equal("1\n2\n", File.read(@t1.path + ".bak"))
+ assert_equal(false, File.file?(@t2.path + ".bak"))
+ assert_equal("5\n6\n", File.read(@t3.path + ".bak"))
+ end
+
+ def test_inplace3
+ assert_in_out_err(["-i.bak", "-", @t1.path, @t2.path, @t3.path], <<-INPUT, [], [])
+ puts ARGF.gets.chomp + '.new'
+ puts ARGF.gets.chomp + '.new'
+ p $-i
+ $-i = nil
+ puts ARGF.gets.chomp + '.new'
+ puts ARGF.gets.chomp + '.new'
+ p $-i
+ $-i = '.bak'
+ puts ARGF.gets.chomp + '.new'
+ p $-i
+ $-i = nil
+ puts ARGF.gets.chomp + '.new'
+ INPUT
+ assert_equal("1.new\n2.new\n\".bak\"\n3.new\n4.new\nnil\n", File.read(@t1.path))
+ assert_equal("3\n4\n", File.read(@t2.path))
+ assert_equal("5.new\n\".bak\"\n6.new\n", File.read(@t3.path))
+ assert_equal("1\n2\n", File.read(@t1.path + ".bak"))
+ assert_equal(false, File.file?(@t2.path + ".bak"))
+ assert_equal("5\n6\n", File.read(@t3.path + ".bak"))
+ end
+
+ def test_inplace_rename_impossible
+ t = make_tempfile
+
+ assert_in_out_err(["-", t.path], <<-INPUT) do |r, e|
+ ARGF.inplace_mode = '/\\\\:'
+ while line = ARGF.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ assert_match(/Can't rename .* to .*: .*. skipping file/, e.first) #'
+ assert_equal([], r)
+ assert_equal("foo\nbar\nbaz\n", File.read(t.path))
+ end
+
+ base = "argf-\u{30c6 30b9 30c8}"
+ name = "#{@tmpdir}/#{base}"
+ File.write(name, "foo")
+ argf = ARGF.class.new(name)
+ argf.inplace_mode = '/\\:'
+ assert_warning(/#{base}/) {argf.gets}
+ end
+
+ def test_inplace_no_backup
+ t = make_tempfile
+
+ assert_in_out_err(["-", t.path], <<-INPUT) do |r, e|
+ ARGF.inplace_mode = ''
+ while line = ARGF.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ if no_safe_rename
+ assert_match(/Can't do inplace edit without backup/, e.join) #'
+ else
+ assert_equal([], e)
+ assert_equal([], r)
+ assert_equal("foo.new\nbar.new\nbaz.new\n", File.read(t.path))
+ end
+ end
+ end
+
+ def test_inplace_dup
+ t = make_tempfile
+
+ assert_in_out_err(["-", t.path], <<-INPUT, [], [])
+ ARGF.inplace_mode = '.bak'
+ f = ARGF.dup
+ while line = f.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ assert_equal("foo.new\nbar.new\nbaz.new\n", File.read(t.path))
+ end
+
+ def test_inplace_stdin
+ assert_in_out_err(["-", "-"], <<-INPUT, [], /Can't do inplace edit for stdio; skipping/)
+ ARGF.inplace_mode = '.bak'
+ f = ARGF.dup
+ while line = f.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ end
+
+ def test_inplace_stdin2
+ assert_in_out_err(["-"], <<-INPUT, [], /Can't do inplace edit for stdio/)
+ ARGF.inplace_mode = '.bak'
+ while line = ARGF.gets
+ puts line.chomp + '.new'
+ end
+ INPUT
+ end
+
+ def test_encoding
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ p ARGF.external_encoding.is_a?(Encoding)
+ p ARGF.internal_encoding.is_a?(Encoding)
+ ARGF.gets
+ p ARGF.external_encoding.is_a?(Encoding)
+ p ARGF.internal_encoding
+ SRC
+ assert_equal("true\ntrue\ntrue\nnil\n", f.read)
+ end
+ end
+
+ def test_tell
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ ARGF.binmode
+ loop do
+ p ARGF.tell
+ p ARGF.gets
+ end
+ rescue ArgumentError
+ puts "end"
+ end
+ SRC
+ a = f.read.split("\n")
+ [0, 2, 4, 2, 4, 2, 4].map {|i| i.to_s }.
+ zip((1..6).map {|i| '"' + i.to_s + '\n"' } + ["nil"]).flatten.
+ each do |x|
+ assert_equal(x, a.shift)
+ end
+ assert_equal('end', a.shift)
+ end
+ end
+
+ def test_seek
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ ARGF.seek(4)
+ p ARGF.gets #=> "3\n"
+ ARGF.seek(0, IO::SEEK_END)
+ p ARGF.gets #=> "5\n"
+ ARGF.seek(4)
+ p ARGF.gets #=> nil
+ begin
+ ARGF.seek(0)
+ rescue
+ puts "end" #=> end
+ end
+ SRC
+ end
+
+ def test_set_pos
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ ARGF.pos = 4
+ p ARGF.gets #=> "3\n"
+ ARGF.pos = 4
+ p ARGF.gets #=> "5\n"
+ ARGF.pos = 4
+ p ARGF.gets #=> nil
+ begin
+ ARGF.pos = 4
+ rescue
+ puts "end" #=> end
+ end
+ SRC
+ end
+
+ def test_rewind
+ assert_src_expected(__LINE__+1, <<-'SRC')
+ ARGF.pos = 4
+ ARGF.rewind
+ p ARGF.gets #=> "1\n"
+ ARGF.pos = 4
+ p ARGF.gets #=> "3\n"
+ ARGF.pos = 4
+ p ARGF.gets #=> "5\n"
+ ARGF.pos = 4
+ p ARGF.gets #=> nil
+ begin
+ ARGF.rewind
+ rescue
+ puts "end" #=> end
+ end
+ SRC
+ end
+
+ def test_fileno
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ p ARGF.fileno
+ ARGF.gets
+ ARGF.gets
+ p ARGF.fileno
+ ARGF.gets
+ ARGF.gets
+ p ARGF.fileno
+ ARGF.gets
+ ARGF.gets
+ p ARGF.fileno
+ ARGF.gets
+ begin
+ ARGF.fileno
+ rescue
+ puts "end"
+ end
+ SRC
+ a = f.read.split("\n")
+ fd1, fd2, fd3, fd4, tag = a
+ assert_match(/^\d+$/, fd1)
+ assert_match(/^\d+$/, fd2)
+ assert_match(/^\d+$/, fd3)
+ assert_match(/^\d+$/, fd4)
+ assert_equal('end', tag)
+ end
+ end
+
+ def test_to_io
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ 8.times do
+ p ARGF.to_io
+ ARGF.gets
+ end
+ SRC
+ a = f.read.split("\n")
+ f11, f12, f13, f21, f22, f31, f32, f4 = a
+ assert_equal(f11, f12)
+ assert_equal(f11, f13)
+ assert_equal(f21, f22)
+ assert_equal(f31, f32)
+ assert_match(/\(closed\)/, f4)
+ f4.sub!(/ \(closed\)/, "")
+ assert_equal(f31, f4)
+ end
+ end
+
+ def test_eof
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ 8.times do
+ p ARGF.eof?
+ ARGF.gets
+ end
+ rescue IOError
+ puts "end"
+ end
+ SRC
+ a = f.read.split("\n")
+ (%w(false) + (%w(false true) * 3) + %w(end)).each do |x|
+ assert_equal(x, a.shift)
+ end
+ end
+
+ t1 = open("#{@tmpdir}/argf-hoge", "w")
+ t1.binmode
+ t1.puts "foo"
+ t1.close
+ t2 = open("#{@tmpdir}/argf-moge", "w")
+ t2.binmode
+ t2.puts "bar"
+ t2.close
+ ruby('-e', 'STDERR.reopen(STDOUT); ARGF.gets; ARGF.skip; p ARGF.eof?', t1.path, t2.path) do |f|
+ assert_equal(%w(false), f.read.split(/\n/))
+ end
+ end
+
+ def test_read
+ ruby('-e', "p ARGF.read(8)", @t1.path, @t2.path, @t3.path) do |f|
+ assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read)
+ end
+ end
+
+ def test_read2
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = ""
+ ARGF.read(8, s)
+ p s
+ SRC
+ assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read)
+ end
+ end
+
+ def test_read2_with_not_empty_buffer
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = "0123456789"
+ ARGF.read(8, s)
+ p s
+ SRC
+ assert_equal("\"1\\n2\\n3\\n4\\n\"\n", f.read)
+ end
+ end
+
+ def test_read3
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ nil while ARGF.gets
+ p ARGF.read
+ p ARGF.read(0, "")
+ SRC
+ assert_equal("nil\n\"\"\n", f.read)
+ end
+ end
+
+ def test_readpartial
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = ""
+ begin
+ loop do
+ s << ARGF.readpartial(1)
+ t = ""; ARGF.readpartial(1, t); s << t
+ # not empty buffer
+ u = "abcdef"; ARGF.readpartial(1, u); s << u
+ end
+ rescue EOFError
+ puts s
+ end
+ SRC
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_readpartial2
+ ruby('-e', <<-SRC) do |f|
+ s = ""
+ begin
+ loop do
+ s << ARGF.readpartial(1)
+ t = ""; ARGF.readpartial(1, t); s << t
+ end
+ rescue EOFError
+ $stdout.binmode
+ puts s
+ end
+ SRC
+ f.binmode
+ f.puts("foo")
+ f.puts("bar")
+ f.puts("baz")
+ f.close_write
+ assert_equal("foo\nbar\nbaz\n", f.read)
+ end
+ end
+
+ def test_getc
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = ""
+ while c = ARGF.getc
+ s << c
+ end
+ puts s
+ SRC
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_getbyte
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = []
+ while c = ARGF.getbyte
+ s << c
+ end
+ p s
+ SRC
+ assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read)
+ end
+ end
+
+ def test_readchar
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = ""
+ begin
+ while c = ARGF.readchar
+ s << c
+ end
+ rescue EOFError
+ puts s
+ end
+ SRC
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_readbyte
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ s = []
+ while c = ARGF.readbyte
+ s << c
+ end
+ rescue EOFError
+ p s
+ end
+ SRC
+ assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read)
+ end
+ end
+
+ def test_each_line
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = []
+ ARGF.each_line {|l| s << l }
+ p s
+ SRC
+ assert_equal("[\"1\\n\", \"2\\n\", \"3\\n\", \"4\\n\", \"5\\n\", \"6\\n\"]\n", f.read)
+ end
+ end
+
+ def test_each_line_paragraph
+ assert_in_out_err(['-e', 'ARGF.each_line("") {|para| p para}'], "a\n\nb\n",
+ ["\"a\\n\\n\"", "\"b\\n\""], [])
+ end
+
+ def test_each_byte
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = []
+ ARGF.each_byte {|c| s << c }
+ p s
+ SRC
+ assert_equal("[49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10]\n", f.read)
+ end
+ end
+
+ def test_each_char
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ s = ""
+ ARGF.each_char {|c| s << c }
+ puts s
+ SRC
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_filename
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ puts ARGF.filename.dump
+ end while ARGF.gets
+ puts ARGF.filename.dump
+ SRC
+ a = f.read.split("\n")
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ end
+ end
+
+ def test_filename2
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ puts $FILENAME.dump
+ end while ARGF.gets
+ puts $FILENAME.dump
+ SRC
+ a = f.read.split("\n")
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ end
+ end
+
+ def test_file
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ begin
+ puts ARGF.file.path.dump
+ end while ARGF.gets
+ puts ARGF.file.path.dump
+ SRC
+ a = f.read.split("\n")
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t1.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t2.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ assert_equal(@t3.path.dump, a.shift)
+ end
+ end
+
+ def test_binmode
+ bug5268 = '[ruby-core:39234]'
+ open(@t3.path, "wb") {|f| f.write "5\r\n6\r\n"}
+ ruby('-e', "ARGF.binmode; STDOUT.binmode; puts ARGF.read", @t1.path, @t2.path, @t3.path) do |f|
+ f.binmode
+ assert_equal("1\n2\n3\n4\n5\r\n6\r\n", f.read, bug5268)
+ end
+ end
+
+ def test_textmode
+ bug5268 = '[ruby-core:39234]'
+ open(@t3.path, "wb") {|f| f.write "5\r\n6\r\n"}
+ ruby('-e', "STDOUT.binmode; puts ARGF.read", @t1.path, @t2.path, @t3.path) do |f|
+ f.binmode
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read, bug5268)
+ end
+ end unless IO::BINARY.zero?
+
+ def test_skip
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.skip
+ puts ARGF.gets
+ ARGF.skip
+ puts ARGF.read
+ SRC
+ assert_equal("1\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_skip_in_each_line
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.each_line {|l| print l; ARGF.skip}
+ SRC
+ assert_equal("1\n3\n5\n", f.read, '[ruby-list:49185]')
+ end
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.each_line {|l| ARGF.skip; puts [l, ARGF.gets].map {|s| s ? s.chomp : s.inspect}.join("+")}
+ SRC
+ assert_equal("1+3\n4+5\n6+nil\n", f.read, '[ruby-list:49185]')
+ end
+ end
+
+ def test_skip_in_each_byte
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.each_byte {|l| print l; ARGF.skip}
+ SRC
+ assert_equal("135".unpack("C*").join(""), f.read, '[ruby-list:49185]')
+ end
+ end
+
+ def test_skip_in_each_char
+ [[@t1, "\u{3042}"], [@t2, "\u{3044}"], [@t3, "\u{3046}"]].each do |f, s|
+ File.write(f.path, s, mode: "w:utf-8")
+ end
+ ruby('-Eutf-8', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.each_char {|l| print l; ARGF.skip}
+ SRC
+ assert_equal("\u{3042 3044 3046}", f.read, '[ruby-list:49185]')
+ end
+ end
+
+ def test_skip_in_each_codepoint
+ [[@t1, "\u{3042}"], [@t2, "\u{3044}"], [@t3, "\u{3046}"]].each do |f, s|
+ File.write(f.path, s, mode: "w:utf-8")
+ end
+ ruby('-Eutf-8', '-Eutf-8', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.each_codepoint {|l| printf "%x:", l; ARGF.skip}
+ SRC
+ assert_equal("3042:3044:3046:", f.read, '[ruby-list:49185]')
+ end
+ end
+
+ def test_close
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ ARGF.close
+ puts ARGF.read
+ SRC
+ assert_equal("3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_close_replace
+ ruby('-e', <<-SRC) do |f|
+ ARGF.close
+ ARGV.replace ['#{@t1.path}', '#{@t2.path}', '#{@t3.path}']
+ puts ARGF.read
+ SRC
+ assert_equal("1\n2\n3\n4\n5\n6\n", f.read)
+ end
+ end
+
+ def test_closed
+ ruby('-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ 3.times do
+ p ARGF.closed?
+ ARGF.gets
+ ARGF.gets
+ end
+ p ARGF.closed?
+ ARGF.gets
+ p ARGF.closed?
+ SRC
+ assert_equal("false\nfalse\nfalse\nfalse\ntrue\n", f.read)
+ end
+ end
+
+ def test_argv
+ ruby('-e', "p ARGF.argv; p $*", @t1.path, @t2.path, @t3.path) do |f|
+ assert_equal([@t1.path, @t2.path, @t3.path].inspect, f.gets.chomp)
+ assert_equal([@t1.path, @t2.path, @t3.path].inspect, f.gets.chomp)
+ end
+ end
+
+ def test_readlines_limit_0
+ bug4024 = '[ruby-dev:42538]'
+ t = make_tempfile
+ argf = ARGF.class.new(t.path)
+ begin
+ assert_raise(ArgumentError, bug4024) do
+ argf.readlines(0)
+ end
+ ensure
+ argf.close
+ end
+ end
+
+ def test_each_line_limit_0
+ bug4024 = '[ruby-dev:42538]'
+ t = make_tempfile
+ argf = ARGF.class.new(t.path)
+ begin
+ assert_raise(ArgumentError, bug4024) do
+ argf.each_line(0).next
+ end
+ ensure
+ argf.close
+ end
+ end
+
+ def test_unreadable
+ bug4274 = '[ruby-core:34446]'
+ paths = (1..2).map do
+ t = Tempfile.new("bug4274-")
+ path = t.path
+ t.close!
+ path
+ end
+ argf = ARGF.class.new(*paths)
+ paths.each do |path|
+ assert_raise_with_message(Errno::ENOENT, /- #{Regexp.quote(path)}\z/) {argf.gets}
+ end
+ assert_nil(argf.gets, bug4274)
+ end
+
+ def test_readlines_twice
+ bug5952 = '[ruby-dev:45160]'
+ assert_ruby_status(["-e", "2.times {STDIN.tty?; readlines}"], "", bug5952)
+ end
+
+ def test_lines
+ ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ $stderr = $stdout
+ s = []
+ ARGF.lines {|l| s << l }
+ p s
+ SRC
+ assert_match(/deprecated/, f.gets)
+ assert_equal("[\"1\\n\", \"2\\n\", \"3\\n\", \"4\\n\", \"5\\n\", \"6\\n\"]\n", f.read)
+ end
+ end
+
+ def test_bytes
+ ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ $stderr = $stdout
+ print Marshal.dump(ARGF.bytes.to_a)
+ SRC
+ assert_match(/deprecated/, f.gets)
+ assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read))
+ end
+ end
+
+ def test_chars
+ ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ $stderr = $stdout
+ print [Marshal.dump(ARGF.chars.to_a)].pack('m')
+ SRC
+ assert_match(/deprecated/, f.gets)
+ assert_equal(["1", "\n", "2", "\n", "3", "\n", "4", "\n", "5", "\n", "6", "\n"], Marshal.load(f.read.unpack('m').first))
+ end
+ end
+
+ def test_codepoints
+ ruby('-W1', '-e', <<-SRC, @t1.path, @t2.path, @t3.path) do |f|
+ $stderr = $stdout
+ print Marshal.dump(ARGF.codepoints.to_a)
+ SRC
+ assert_match(/deprecated/, f.gets)
+ assert_equal([49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 10], Marshal.load(f.read))
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_arity.rb b/jni/ruby/test/ruby/test_arity.rb
new file mode 100644
index 0000000..e026841
--- /dev/null
+++ b/jni/ruby/test/ruby/test_arity.rb
@@ -0,0 +1,69 @@
+require 'test/unit'
+
+class TestArity < Test::Unit::TestCase
+ def err_mess(method_proc = nil, argc = 0)
+ args = (1..argc).to_a
+ assert_raise_with_message(ArgumentError, /wrong number of arguments \((.*)\)/) do
+ case method_proc
+ when nil
+ yield
+ when Symbol
+ method(method_proc).call(*args)
+ else
+ method_proc.call(*args)
+ end
+ end
+ $1
+ end
+
+ def a
+ end
+
+ def b(a, b, c, d=1, e=2, f, g, h, i, &block)
+ end
+
+ def c(a, b, c, d=1, e=2, *rest)
+ end
+
+ def d(a, b: 42)
+ end
+
+ def e(a, b:42, **c)
+ end
+
+ def f(a, b, c=1, *rest, d: 3)
+ end
+
+ def test_method_err_mess
+ assert_equal "1 for 0", err_mess(:a, 1)
+ assert_equal "10 for 7..9", err_mess(:b, 10)
+ assert_equal "2 for 3+", err_mess(:c, 2)
+ assert_equal "2 for 1", err_mess(:d, 2)
+ assert_equal "0 for 1", err_mess(:d, 0)
+ assert_equal "2 for 1", err_mess(:e, 2)
+ assert_equal "0 for 1", err_mess(:e, 0)
+ assert_equal "1 for 2+", err_mess(:f, 1)
+ end
+
+ def test_proc_err_mess
+ assert_equal "0 for 1..2", err_mess(->(b, c=42){}, 0)
+ assert_equal "1 for 2+", err_mess(->(a, b, c=42, *d){}, 1)
+ assert_equal "3 for 4+", err_mess(->(a, b, *c, d, e){}, 3)
+ assert_equal "3 for 1..2", err_mess(->(b, c=42){}, 3)
+ assert_equal "1 for 0", err_mess(->(&block){}, 1)
+ # Double checking:
+ p = Proc.new{|b, c=42| :ok}
+ assert_equal :ok, p.call(1, 2, 3)
+ assert_equal :ok, p.call
+ end
+
+ def test_message_change_issue_6085
+ assert_equal "3 for 1..2", err_mess{ SignalException.new(1, "", nil) }
+ assert_equal "1 for 0", err_mess{ Hash.new(1){} }
+ assert_equal "3 for 1..2", err_mess{ Module.send :define_method, 1, 2, 3 }
+ assert_equal "1 for 2", err_mess{ "".sub!(//) }
+ assert_equal "0 for 1..2", err_mess{ "".sub!{} }
+ assert_equal "0 for 1+", err_mess{ exec }
+ assert_equal "0 for 1+", err_mess{ Struct.new }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_array.rb b/jni/ruby/test/ruby/test_array.rb
new file mode 100644
index 0000000..8c8b63c
--- /dev/null
+++ b/jni/ruby/test/ruby/test_array.rb
@@ -0,0 +1,2533 @@
+# coding: US-ASCII
+require 'test/unit'
+
+class TestArray < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @cls = Array
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_percent_i
+ assert_equal([:foo, :bar], %i[foo bar])
+ assert_equal([:"\"foo"], %i["foo])
+ end
+
+ def test_percent_I
+ x = 10
+ assert_equal([:foo, :b10], %I[foo b#{x}])
+ assert_equal([:"\"foo10"], %I["foo#{x}])
+ end
+
+ def test_0_literal
+ assert_equal([1, 2, 3, 4], [1, 2] + [3, 4])
+ assert_equal([1, 2, 1, 2], [1, 2] * 2)
+ assert_equal("1:2", [1, 2] * ":")
+
+ assert_equal([1, 2].hash, [1, 2].hash)
+
+ assert_equal([2,3], [1,2,3] & [2,3,4])
+ assert_equal([1,2,3,4], [1,2,3] | [2,3,4])
+ assert_equal([1,2,3] - [2,3], [1])
+
+ x = [0, 1, 2, 3, 4, 5]
+ assert_equal(2, x[2])
+ assert_equal([1, 2, 3], x[1..3])
+ assert_equal([1, 2, 3], x[1,3])
+
+ x[0, 2] = 10
+ assert_equal([10, 2, 3, 4, 5], x)
+
+ x[0, 0] = -1
+ assert_equal([-1, 10, 2, 3, 4, 5], x)
+
+ x[-1, 1] = 20
+ assert_equal(20, x[-1])
+ assert_equal(20, x.pop)
+ end
+
+ def test_array_andor_0
+ assert_equal([2], ([1,2,3]&[2,4,6]))
+ assert_equal([1,2,3,4,6], ([1,2,3]|[2,4,6]))
+ end
+
+ def test_compact_0
+ a = [nil, 1, nil, nil, 5, nil, nil]
+ assert_equal [1, 5], a.compact
+ assert_equal [nil, 1, nil, nil, 5, nil, nil], a
+ a.compact!
+ assert_equal [1, 5], a
+ end
+
+ def test_uniq_0
+ x = [1, 1, 4, 2, 5, 4, 5, 1, 2]
+ x.uniq!
+ assert_equal([1, 4, 2, 5], x)
+ end
+
+ def test_empty_0
+ assert_equal true, [].empty?
+ assert_equal false, [1].empty?
+ assert_equal false, [1, 1, 4, 2, 5, 4, 5, 1, 2].empty?
+ end
+
+ def test_sort_0
+ x = ["it", "came", "to", "pass", "that", "..."]
+ x = x.sort.join(" ")
+ assert_equal("... came it pass that to", x)
+ x = [2,5,3,1,7]
+ x.sort!{|a,b| a<=>b} # sort with condition
+ assert_equal([1,2,3,5,7], x)
+ x.sort!{|a,b| b-a} # reverse sort
+ assert_equal([7,5,3,2,1], x)
+ end
+
+ def test_split_0
+ x = "The Book of Mormon"
+ assert_equal(x.reverse, x.split(//).reverse!.join)
+ assert_equal(x.reverse, x.reverse!)
+ assert_equal("g:n:i:r:t:s: :e:t:y:b: :1", "1 byte string".split(//).reverse.join(":"))
+ x = "a b c d"
+ assert_equal(['a', 'b', 'c', 'd'], x.split)
+ assert_equal(['a', 'b', 'c', 'd'], x.split(' '))
+ end
+
+ def test_misc_0
+ assert(defined? "a".chomp, '"a".chomp is not defined')
+ assert_equal(["a", "b", "c"], "abc".scan(/./))
+ assert_equal([["1a"], ["2b"], ["3c"]], "1a2b3c".scan(/(\d.)/))
+ # non-greedy match
+ assert_equal([["a", "12"], ["b", "22"]], "a=12;b=22".scan(/(.*?)=(\d*);?/))
+
+ x = [1]
+ assert_equal('1:1:1:1:1', (x * 5).join(":"))
+ assert_equal('1', (x * 1).join(":"))
+ assert_equal('', (x * 0).join(":"))
+
+ *x = *(1..7).to_a
+ assert_equal(7, x.size)
+ assert_equal([1, 2, 3, 4, 5, 6, 7], x)
+
+ x = [1,2,3]
+ x[1,0] = x
+ assert_equal([1,1,2,3,2,3], x)
+
+ x = [1,2,3]
+ x[-1,0] = x
+ assert_equal([1,2,1,2,3,3], x)
+
+ x = [1,2,3]
+ x.concat(x)
+ assert_equal([1,2,3,1,2,3], x)
+
+ x = [1,2,3]
+ x.clear
+ assert_equal([], x)
+
+ x = [1,2,3]
+ y = x.dup
+ x << 4
+ y << 5
+ assert_equal([1,2,3,4], x)
+ assert_equal([1,2,3,5], y)
+ end
+
+ def test_beg_end_0
+ x = [1, 2, 3, 4, 5]
+
+ assert_equal(1, x.first)
+ assert_equal([1], x.first(1))
+ assert_equal([1, 2, 3], x.first(3))
+
+ assert_equal(5, x.last)
+ assert_equal([5], x.last(1))
+ assert_equal([3, 4, 5], x.last(3))
+
+ assert_equal(1, x.shift)
+ assert_equal([2, 3, 4], x.shift(3))
+ assert_equal([5], x)
+
+ assert_equal([2, 3, 4, 5], x.unshift(2, 3, 4))
+ assert_equal([1, 2, 3, 4, 5], x.unshift(1))
+ assert_equal([1, 2, 3, 4, 5], x)
+
+ assert_equal(5, x.pop)
+ assert_equal([3, 4], x.pop(2))
+ assert_equal([1, 2], x)
+
+ assert_equal([1, 2, 3, 4], x.push(3, 4))
+ assert_equal([1, 2, 3, 4, 5], x.push(5))
+ assert_equal([1, 2, 3, 4, 5], x)
+ end
+
+ def test_find_all_0
+ assert_respond_to([], :find_all)
+ assert_respond_to([], :select) # Alias
+ assert_equal([], [].find_all{ |obj| obj == "foo"})
+
+ x = ["foo", "bar", "baz", "baz", 1, 2, 3, 3, 4]
+ assert_equal(["baz","baz"], x.find_all{ |obj| obj == "baz" })
+ assert_equal([3,3], x.find_all{ |obj| obj == 3 })
+ end
+
+ def test_fill_0
+ assert_equal([-1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1))
+ assert_equal([0, 1, 2, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3))
+ assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3, 2))
+ assert_equal([0, 1, 2, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3, 5))
+ assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2, 2))
+ assert_equal([0, 1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 2, 5))
+ assert_equal([0, 1, 2, 3, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, -2, 1))
+ assert_equal([0, 1, 2, 3, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, -2, 3))
+ assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3..4))
+ assert_equal([0, 1, 2, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3...4))
+ assert_equal([0, 1, -1, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2..-2))
+ assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2...-2))
+ assert_equal([10, 11, 12, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill{|i| i+10})
+ assert_equal([0, 1, 2, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill(3){|i| i+10})
+ assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3, 2){|i| i+10})
+ assert_equal([0, 1, 2, 13, 14, 15, 16, 17], [0, 1, 2, 3, 4, 5].fill(3, 5){|i| i+10})
+ assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3..4){|i| i+10})
+ assert_equal([0, 1, 2, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(3...4){|i| i+10})
+ assert_equal([0, 1, 12, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(2..-2){|i| i+10})
+ assert_equal([0, 1, 12, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(2...-2){|i| i+10})
+ end
+
+ # From rubicon
+
+ def test_00_new
+ a = @cls.new()
+ assert_instance_of(@cls, a)
+ assert_equal(0, a.length)
+ assert_nil(a[0])
+ end
+
+ def test_01_square_brackets
+ a = @cls[ 5, 4, 3, 2, 1 ]
+ assert_instance_of(@cls, a)
+ assert_equal(5, a.length)
+ 5.times { |i| assert_equal(5-i, a[i]) }
+ assert_nil(a[6])
+ end
+
+ def test_AND # '&'
+ assert_equal(@cls[1, 3], @cls[ 1, 1, 3, 5 ] & @cls[ 1, 2, 3 ])
+ assert_equal(@cls[], @cls[ 1, 1, 3, 5 ] & @cls[ ])
+ assert_equal(@cls[], @cls[ ] & @cls[ 1, 2, 3 ])
+ assert_equal(@cls[], @cls[ 1, 2, 3 ] & @cls[ 4, 5, 6 ])
+ end
+
+ def test_MUL # '*'
+ assert_equal(@cls[], @cls[]*3)
+ assert_equal(@cls[1, 1, 1], @cls[1]*3)
+ assert_equal(@cls[1, 2, 1, 2, 1, 2], @cls[1, 2]*3)
+ assert_equal(@cls[], @cls[1, 2, 3] * 0)
+ assert_raise(ArgumentError) { @cls[1, 2]*(-3) }
+
+ assert_equal('1-2-3-4-5', @cls[1, 2, 3, 4, 5] * '-')
+ assert_equal('12345', @cls[1, 2, 3, 4, 5] * '')
+
+ end
+
+ def test_PLUS # '+'
+ assert_equal(@cls[], @cls[] + @cls[])
+ assert_equal(@cls[1], @cls[1] + @cls[])
+ assert_equal(@cls[1], @cls[] + @cls[1])
+ assert_equal(@cls[1, 1], @cls[1] + @cls[1])
+ assert_equal(@cls['cat', 'dog', 1, 2, 3], %w(cat dog) + (1..3).to_a)
+ end
+
+ def test_MINUS # '-'
+ assert_equal(@cls[], @cls[1] - @cls[1])
+ assert_equal(@cls[1], @cls[1, 2, 3, 4, 5] - @cls[2, 3, 4, 5])
+ # Ruby 1.8 feature change
+ #assert_equal(@cls[1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5])
+ assert_equal(@cls[1, 1, 1, 1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5])
+ a = @cls[]
+ 1000.times { a << 1 }
+ assert_equal(1000, a.length)
+ #assert_equal(@cls[1], a - @cls[2])
+ assert_equal(@cls[1] * 1000, a - @cls[2])
+ #assert_equal(@cls[1], @cls[1, 2, 1] - @cls[2])
+ assert_equal(@cls[1, 1], @cls[1, 2, 1] - @cls[2])
+ assert_equal(@cls[1, 2, 3], @cls[1, 2, 3] - @cls[4, 5, 6])
+ end
+
+ def test_LSHIFT # '<<'
+ a = @cls[]
+ a << 1
+ assert_equal(@cls[1], a)
+ a << 2 << 3
+ assert_equal(@cls[1, 2, 3], a)
+ a << nil << 'cat'
+ assert_equal(@cls[1, 2, 3, nil, 'cat'], a)
+ a << a
+ assert_equal(@cls[1, 2, 3, nil, 'cat', a], a)
+ end
+
+ def test_CMP # '<=>'
+ assert_equal(0, @cls[] <=> @cls[])
+ assert_equal(0, @cls[1] <=> @cls[1])
+ assert_equal(0, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'cat'])
+ assert_equal(-1, @cls[] <=> @cls[1])
+ assert_equal(1, @cls[1] <=> @cls[])
+ assert_equal(-1, @cls[1, 2, 3] <=> @cls[1, 2, 3, 'cat'])
+ assert_equal(1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3])
+ assert_equal(-1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'dog'])
+ assert_equal(1, @cls[1, 2, 3, 'dog'] <=> @cls[1, 2, 3, 'cat'])
+ end
+
+ def test_EQUAL # '=='
+ assert_operator(@cls[], :==, @cls[])
+ assert_operator(@cls[1], :==, @cls[1])
+ assert_operator(@cls[1, 1, 2, 2], :==, @cls[1, 1, 2, 2])
+ assert_operator(@cls[1.0, 1.0, 2.0, 2.0], :==, @cls[1, 1, 2, 2])
+ end
+
+ def test_VERY_EQUAL # '==='
+ assert_operator(@cls[], :===, @cls[])
+ assert_operator(@cls[1], :===, @cls[1])
+ assert_operator(@cls[1, 1, 2, 2], :===, @cls[1, 1, 2, 2])
+ assert_operator(@cls[1.0, 1.0, 2.0, 2.0], :===, @cls[1, 1, 2, 2])
+ end
+
+ def test_AREF # '[]'
+ a = @cls[*(1..100).to_a]
+
+ assert_equal(1, a[0])
+ assert_equal(100, a[99])
+ assert_nil(a[100])
+ assert_equal(100, a[-1])
+ assert_equal(99, a[-2])
+ assert_equal(1, a[-100])
+ assert_nil(a[-101])
+ assert_nil(a[-101,0])
+ assert_nil(a[-101,1])
+ assert_nil(a[-101,-1])
+ assert_nil(a[10,-1])
+
+ assert_equal(@cls[1], a[0,1])
+ assert_equal(@cls[100], a[99,1])
+ assert_equal(@cls[], a[100,1])
+ assert_equal(@cls[100], a[99,100])
+ assert_equal(@cls[100], a[-1,1])
+ assert_equal(@cls[99], a[-2,1])
+ assert_equal(@cls[], a[-100,0])
+ assert_equal(@cls[1], a[-100,1])
+
+ assert_equal(@cls[10, 11, 12], a[9, 3])
+ assert_equal(@cls[10, 11, 12], a[-91, 3])
+
+ assert_equal(@cls[1], a[0..0])
+ assert_equal(@cls[100], a[99..99])
+ assert_equal(@cls[], a[100..100])
+ assert_equal(@cls[100], a[99..200])
+ assert_equal(@cls[100], a[-1..-1])
+ assert_equal(@cls[99], a[-2..-2])
+
+ assert_equal(@cls[10, 11, 12], a[9..11])
+ assert_equal(@cls[10, 11, 12], a[-91..-89])
+
+ assert_nil(a[10, -3])
+ # Ruby 1.8 feature change:
+ # Array#[size..x] returns [] instead of nil.
+ #assert_nil(a[10..7])
+ assert_equal [], a[10..7]
+
+ assert_raise(TypeError) {a['cat']}
+ end
+
+ def test_ASET # '[]='
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[0] = 0)
+ assert_equal(@cls[0] + @cls[*(1..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[10,10] = 0)
+ assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[-1] = 0)
+ assert_equal(@cls[*(0..98).to_a] + @cls[0], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[-10, 10] = 0)
+ assert_equal(@cls[*(0..89).to_a] + @cls[0], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[0,1000] = 0)
+ assert_equal(@cls[0] , a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a[10..19] = 0)
+ assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a)
+
+ b = @cls[*%w( a b c )]
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[0,1] = b)
+ assert_equal(b + @cls[*(1..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[10,10] = b)
+ assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[-1, 1] = b)
+ assert_equal(@cls[*(0..98).to_a] + b, a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[-10, 10] = b)
+ assert_equal(@cls[*(0..89).to_a] + b, a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[0,1000] = b)
+ assert_equal(b , a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(b, a[10..19] = b)
+ assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a)
+
+ # Ruby 1.8 feature change:
+ # assigning nil does not remove elements.
+=begin
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[0,1] = nil)
+ assert_equal(@cls[*(1..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[10,10] = nil)
+ assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[-1, 1] = nil)
+ assert_equal(@cls[*(0..98).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[-10, 10] = nil)
+ assert_equal(@cls[*(0..89).to_a], a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[0,1000] = nil)
+ assert_equal(@cls[] , a)
+
+ a = @cls[*(0..99).to_a]
+ assert_equal(nil, a[10..19] = nil)
+ assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a)
+=end
+
+ a = @cls[1, 2, 3]
+ a[1, 0] = a
+ assert_equal([1, 1, 2, 3, 2, 3], a)
+
+ a = @cls[1, 2, 3]
+ a[-1, 0] = a
+ assert_equal([1, 2, 1, 2, 3, 3], a)
+
+ a = @cls[]
+ a[5,0] = [5]
+ assert_equal([nil, nil, nil, nil, nil, 5], a)
+
+ a = @cls[1]
+ a[1,0] = [2]
+ assert_equal([1, 2], a)
+
+ a = @cls[1]
+ a[1,1] = [2]
+ assert_equal([1, 2], a)
+ end
+
+ def test_assoc
+ a1 = @cls[*%w( cat feline )]
+ a2 = @cls[*%w( dog canine )]
+ a3 = @cls[*%w( mule asinine )]
+
+ a = @cls[ a1, a2, a3 ]
+
+ assert_equal(a1, a.assoc('cat'))
+ assert_equal(a3, a.assoc('mule'))
+ assert_equal(nil, a.assoc('asinine'))
+ assert_equal(nil, a.assoc('wombat'))
+ assert_equal(nil, a.assoc(1..2))
+ end
+
+ def test_at
+ a = @cls[*(0..99).to_a]
+ assert_equal(0, a.at(0))
+ assert_equal(10, a.at(10))
+ assert_equal(99, a.at(99))
+ assert_equal(nil, a.at(100))
+ assert_equal(99, a.at(-1))
+ assert_equal(0, a.at(-100))
+ assert_equal(nil, a.at(-101))
+ assert_raise(TypeError) { a.at('cat') }
+ end
+
+ def test_clear
+ a = @cls[1, 2, 3]
+ b = a.clear
+ assert_equal(@cls[], a)
+ assert_equal(@cls[], b)
+ assert_equal(a.__id__, b.__id__)
+ end
+
+ def test_clone
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = @cls[*(0..99).to_a]
+ a.taint if taint
+ a.freeze if frozen
+ b = a.clone
+
+ assert_equal(a, b)
+ assert_not_equal(a.__id__, b.__id__)
+ assert_equal(a.frozen?, b.frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+ end
+
+ def test_collect
+ a = @cls[ 1, 'cat', 1..1 ]
+ assert_equal([ Fixnum, String, Range], a.collect {|e| e.class} )
+ assert_equal([ 99, 99, 99], a.collect { 99 } )
+
+ assert_equal([], @cls[].collect { 99 })
+
+ # Ruby 1.9 feature change:
+ # Enumerable#collect without block returns an Enumerator.
+ #assert_equal([1, 2, 3], @cls[1, 2, 3].collect)
+ assert_kind_of Enumerator, @cls[1, 2, 3].collect
+ end
+
+ # also update map!
+ def test_collect!
+ a = @cls[ 1, 'cat', 1..1 ]
+ assert_equal([ Fixnum, String, Range], a.collect! {|e| e.class} )
+ assert_equal([ Fixnum, String, Range], a)
+
+ a = @cls[ 1, 'cat', 1..1 ]
+ assert_equal([ 99, 99, 99], a.collect! { 99 } )
+ assert_equal([ 99, 99, 99], a)
+
+ a = @cls[ ]
+ assert_equal([], a.collect! { 99 })
+ assert_equal([], a)
+ end
+
+ def test_compact
+ a = @cls[ 1, nil, nil, 2, 3, nil, 4 ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact)
+
+ a = @cls[ nil, 1, nil, 2, 3, nil, 4 ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact)
+
+ a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact)
+
+ a = @cls[ 1, 2, 3, 4 ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact)
+ end
+
+ def test_compact!
+ a = @cls[ 1, nil, nil, 2, 3, nil, 4 ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact!)
+ assert_equal(@cls[1, 2, 3, 4], a)
+
+ a = @cls[ nil, 1, nil, 2, 3, nil, 4 ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact!)
+ assert_equal(@cls[1, 2, 3, 4], a)
+
+ a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ]
+ assert_equal(@cls[1, 2, 3, 4], a.compact!)
+ assert_equal(@cls[1, 2, 3, 4], a)
+
+ a = @cls[ 1, 2, 3, 4 ]
+ assert_equal(nil, a.compact!)
+ assert_equal(@cls[1, 2, 3, 4], a)
+ end
+
+ def test_concat
+ assert_equal(@cls[1, 2, 3, 4], @cls[1, 2].concat(@cls[3, 4]))
+ assert_equal(@cls[1, 2, 3, 4], @cls[].concat(@cls[1, 2, 3, 4]))
+ assert_equal(@cls[1, 2, 3, 4], @cls[1, 2, 3, 4].concat(@cls[]))
+ assert_equal(@cls[], @cls[].concat(@cls[]))
+ assert_equal(@cls[@cls[1, 2], @cls[3, 4]], @cls[@cls[1, 2]].concat(@cls[@cls[3, 4]]))
+
+ a = @cls[1, 2, 3]
+ a.concat(a)
+ assert_equal([1, 2, 3, 1, 2, 3], a)
+
+ assert_raise(TypeError) { [0].concat(:foo) }
+ assert_raise(RuntimeError) { [0].freeze.concat(:foo) }
+ end
+
+ def test_count
+ a = @cls[1, 2, 3, 1, 2]
+ assert_equal(5, a.count)
+ assert_equal(2, a.count(1))
+ assert_equal(3, a.count {|x| x % 2 == 1 })
+ assert_equal(2, a.count(1) {|x| x % 2 == 1 })
+ assert_raise(ArgumentError) { a.count(0, 1) }
+
+ bug8654 = '[ruby-core:56072]'
+ assert_in_out_err [], <<-EOS, ["0"], [], bug8654
+ a1 = []
+ a2 = Array.new(100) { |i| i }
+ a2.count do |i|
+ p i
+ a2.replace(a1) if i == 0
+ end
+ EOS
+
+ assert_in_out_err [], <<-EOS, ["[]", "0"], [], bug8654
+ ARY = Array.new(100) { |i| i }
+ class Fixnum
+ alias old_equal ==
+ def == other
+ ARY.replace([]) if self.equal?(0)
+ p ARY
+ self.equal?(other)
+ end
+ end
+ p ARY.count(42)
+ EOS
+ end
+
+ def test_delete
+ a = @cls[*('cab'..'cat').to_a]
+ assert_equal('cap', a.delete('cap'))
+ assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a)
+
+ a = @cls[*('cab'..'cat').to_a]
+ assert_equal('cab', a.delete('cab'))
+ assert_equal(@cls[*('cac'..'cat').to_a], a)
+
+ a = @cls[*('cab'..'cat').to_a]
+ assert_equal('cat', a.delete('cat'))
+ assert_equal(@cls[*('cab'..'cas').to_a], a)
+
+ a = @cls[*('cab'..'cat').to_a]
+ assert_equal(nil, a.delete('cup'))
+ assert_equal(@cls[*('cab'..'cat').to_a], a)
+
+ a = @cls[*('cab'..'cat').to_a]
+ assert_equal(99, a.delete('cup') { 99 } )
+ assert_equal(@cls[*('cab'..'cat').to_a], a)
+
+ o = Object.new
+ def o.==(other); true; end
+ o2 = Object.new
+ def o2.==(other); true; end
+ a = @cls[1, o, o2, 2]
+ assert_equal(o2, a.delete(42))
+ assert_equal([1, 2], a)
+ end
+
+ def test_delete_at
+ a = @cls[*(1..5).to_a]
+ assert_equal(3, a.delete_at(2))
+ assert_equal(@cls[1, 2, 4, 5], a)
+
+ a = @cls[*(1..5).to_a]
+ assert_equal(4, a.delete_at(-2))
+ assert_equal(@cls[1, 2, 3, 5], a)
+
+ a = @cls[*(1..5).to_a]
+ assert_equal(nil, a.delete_at(5))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[*(1..5).to_a]
+ assert_equal(nil, a.delete_at(-6))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+ end
+
+ # also reject!
+ def test_delete_if
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.delete_if { false })
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.delete_if { true })
+ assert_equal(@cls[], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.delete_if { |i| i > 3 })
+ assert_equal(@cls[1, 2, 3], a)
+
+ bug2545 = '[ruby-core:27366]'
+ a = @cls[ 5, 6, 7, 8, 9, 10 ]
+ assert_equal(9, a.delete_if {|i| break i if i > 8; assert_equal(a[0], i) || true if i < 7})
+ assert_equal(@cls[7, 8, 9, 10], a, bug2545)
+ end
+
+ def test_dup
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = @cls[*(0..99).to_a]
+ a.taint if taint
+ a.freeze if frozen
+ b = a.dup
+
+ assert_equal(a, b)
+ assert_not_equal(a.__id__, b.__id__)
+ assert_equal(false, b.frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+ end
+
+ def test_each
+ a = @cls[*%w( ant bat cat dog )]
+ i = 0
+ a.each { |e|
+ assert_equal(a[i], e)
+ i += 1
+ }
+ assert_equal(4, i)
+
+ a = @cls[]
+ i = 0
+ a.each { |e|
+ assert_equal(a[i], e)
+ i += 1
+ }
+ assert_equal(0, i)
+
+ assert_equal(a, a.each {})
+ end
+
+ def test_each_index
+ a = @cls[*%w( ant bat cat dog )]
+ i = 0
+ a.each_index { |ind|
+ assert_equal(i, ind)
+ i += 1
+ }
+ assert_equal(4, i)
+
+ a = @cls[]
+ i = 0
+ a.each_index { |ind|
+ assert_equal(i, ind)
+ i += 1
+ }
+ assert_equal(0, i)
+
+ assert_equal(a, a.each_index {})
+ end
+
+ def test_empty?
+ assert_empty(@cls[])
+ assert_not_empty(@cls[1])
+ end
+
+ def test_eql?
+ assert_send([@cls[], :eql?, @cls[]])
+ assert_send([@cls[1], :eql?, @cls[1]])
+ assert_send([@cls[1, 1, 2, 2], :eql?, @cls[1, 1, 2, 2]])
+ assert_not_send([@cls[1.0, 1.0, 2.0, 2.0], :eql?, @cls[1, 1, 2, 2]])
+ end
+
+ def test_fill
+ assert_equal(@cls[], @cls[].fill(99))
+ assert_equal(@cls[], @cls[].fill(99, 0))
+ assert_equal(@cls[99], @cls[].fill(99, 0, 1))
+ assert_equal(@cls[99], @cls[].fill(99, 0..0))
+
+ assert_equal(@cls[99], @cls[1].fill(99))
+ assert_equal(@cls[99], @cls[1].fill(99, 0))
+ assert_equal(@cls[99], @cls[1].fill(99, 0, 1))
+ assert_equal(@cls[99], @cls[1].fill(99, 0..0))
+
+ assert_equal(@cls[99, 99], @cls[1, 2].fill(99))
+ assert_equal(@cls[99, 99], @cls[1, 2].fill(99, 0))
+ assert_equal(@cls[99, 99], @cls[1, 2].fill(99, nil))
+ assert_equal(@cls[1, 99], @cls[1, 2].fill(99, 1, nil))
+ assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0, 1))
+ assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0..0))
+ end
+
+ def test_first
+ assert_equal(3, @cls[3, 4, 5].first)
+ assert_equal(nil, @cls[].first)
+ end
+
+ def test_flatten
+ a1 = @cls[ 1, 2, 3]
+ a2 = @cls[ 5, 6 ]
+ a3 = @cls[ 4, a2 ]
+ a4 = @cls[ a1, a3 ]
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten)
+ assert_equal(@cls[ a1, a3], a4)
+
+ a5 = @cls[ a1, @cls[], a3 ]
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten)
+ assert_equal(@cls[], @cls[].flatten)
+ assert_equal(@cls[],
+ @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten)
+
+ assert_raise(TypeError, "[ruby-dev:31197]") { [[]].flatten("") }
+
+ a6 = @cls[[1, 2], 3]
+ a6.taint
+ a7 = a6.flatten
+ assert_equal(true, a7.tainted?)
+
+ a8 = @cls[[1, 2], 3]
+ a9 = a8.flatten(0)
+ assert_equal(a8, a9)
+ assert_not_same(a8, a9)
+ end
+
+ def test_flatten!
+ a1 = @cls[ 1, 2, 3]
+ a2 = @cls[ 5, 6 ]
+ a3 = @cls[ 4, a2 ]
+ a4 = @cls[ a1, a3 ]
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten!)
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a4)
+
+ a5 = @cls[ a1, @cls[], a3 ]
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten!)
+ assert_nil(a5.flatten!(0), '[ruby-core:23382]')
+ assert_equal(@cls[1, 2, 3, 4, 5, 6], a5)
+
+ assert_nil(@cls[].flatten!)
+ assert_equal(@cls[],
+ @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten!)
+
+ assert_nil(@cls[].flatten!(0), '[ruby-core:23382]')
+ end
+
+ def test_flatten_with_callcc
+ need_continuation
+ o = Object.new
+ def o.to_ary() callcc {|k| @cont = k; [1,2,3]} end
+ begin
+ assert_equal([10, 20, 1, 2, 3, 30, 1, 2, 3, 40], [10, 20, o, 30, o, 40].flatten)
+ rescue => e
+ else
+ o.instance_eval {@cont}.call
+ end
+ assert_instance_of(RuntimeError, e, '[ruby-dev:34798]')
+ assert_match(/reentered/, e.message, '[ruby-dev:34798]')
+ end
+
+ def test_permutation_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = [1,2,3]
+ begin
+ ary.permutation {
+ callcc {|k| cont = k} unless cont
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e)
+ assert_match(/reentered/, e.message)
+ end
+
+ def test_product_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = [1,2,3]
+ begin
+ ary.product {
+ callcc {|k| cont = k} unless cont
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e)
+ assert_match(/reentered/, e.message)
+ end
+
+ def test_combination_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = [1,2,3]
+ begin
+ ary.combination(2) {
+ callcc {|k| cont = k} unless cont
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e)
+ assert_match(/reentered/, e.message)
+ end
+
+ def test_repeated_permutation_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = [1,2,3]
+ begin
+ ary.repeated_permutation(2) {
+ callcc {|k| cont = k} unless cont
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e)
+ assert_match(/reentered/, e.message)
+ end
+
+ def test_repeated_combination_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = [1,2,3]
+ begin
+ ary.repeated_combination(2) {
+ callcc {|k| cont = k} unless cont
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e)
+ assert_match(/reentered/, e.message)
+ end
+
+ def test_hash
+ a1 = @cls[ 'cat', 'dog' ]
+ a2 = @cls[ 'cat', 'dog' ]
+ a3 = @cls[ 'dog', 'cat' ]
+ assert_equal(a1.hash, a2.hash)
+ assert_not_equal(a1.hash, a3.hash)
+ bug9231 = '[ruby-core:58993] [Bug #9231]'
+ assert_not_equal(false.hash, @cls[].hash, bug9231)
+ end
+
+ def test_include?
+ a = @cls[ 'cat', 99, /a/, @cls[ 1, 2, 3] ]
+ assert_include(a, 'cat')
+ assert_include(a, 99)
+ assert_include(a, /a/)
+ assert_include(a, [1,2,3])
+ assert_not_include(a, 'ca')
+ assert_not_include(a, [1,2])
+ end
+
+ def test_index
+ a = @cls[ 'cat', 99, /a/, 99, @cls[ 1, 2, 3] ]
+ assert_equal(0, a.index('cat'))
+ assert_equal(1, a.index(99))
+ assert_equal(4, a.index([1,2,3]))
+ assert_nil(a.index('ca'))
+ assert_nil(a.index([1,2]))
+
+ assert_equal(1, a.index(99) {|x| x == 'cat' })
+ end
+
+ def test_values_at
+ a = @cls[*('a'..'j').to_a]
+ assert_equal(@cls['a', 'c', 'e'], a.values_at(0, 2, 4))
+ assert_equal(@cls['j', 'h', 'f'], a.values_at(-1, -3, -5))
+ assert_equal(@cls['h', nil, 'a'], a.values_at(-3, 99, 0))
+ end
+
+ def test_join
+ $, = ""
+ a = @cls[]
+ assert_equal("", a.join)
+ assert_equal("", a.join(','))
+ assert_equal(Encoding::US_ASCII, a.join.encoding)
+
+ $, = ""
+ a = @cls[1, 2]
+ assert_equal("12", a.join)
+ assert_equal("12", a.join(nil))
+ assert_equal("1,2", a.join(','))
+
+ $, = ""
+ a = @cls[1, 2, 3]
+ assert_equal("123", a.join)
+ assert_equal("123", a.join(nil))
+ assert_equal("1,2,3", a.join(','))
+
+ $, = ":"
+ a = @cls[1, 2, 3]
+ assert_equal("1:2:3", a.join)
+ assert_equal("1:2:3", a.join(nil))
+ assert_equal("1,2,3", a.join(','))
+
+ $, = ""
+ a = @cls[1, 2, 3]
+ a.taint
+ s = a.join
+ assert_equal(true, s.tainted?)
+
+ bug5902 = '[ruby-core:42161]'
+ sep = ":".taint
+
+ s = @cls[].join(sep)
+ assert_equal(false, s.tainted?, bug5902)
+ s = @cls[1].join(sep)
+ assert_equal(false, s.tainted?, bug5902)
+ s = @cls[1, 2].join(sep)
+ assert_equal(true, s.tainted?, bug5902)
+
+ e = ''.force_encoding('EUC-JP')
+ u = ''.force_encoding('UTF-8')
+ assert_equal(Encoding::US_ASCII, [[]].join.encoding)
+ assert_equal(Encoding::US_ASCII, [1, [u]].join.encoding)
+ assert_equal(Encoding::UTF_8, [u, [e]].join.encoding)
+ assert_equal(Encoding::UTF_8, [u, [1]].join.encoding)
+ bug5379 = '[ruby-core:39776]'
+ assert_equal(Encoding::US_ASCII, [[], u, nil].join.encoding, bug5379)
+ assert_equal(Encoding::UTF_8, [[], "\u3042", nil].join.encoding, bug5379)
+ ensure
+ $, = nil
+ end
+
+ def test_last
+ assert_equal(nil, @cls[].last)
+ assert_equal(1, @cls[1].last)
+ assert_equal(99, @cls[*(3..99).to_a].last)
+ end
+
+ def test_length
+ assert_equal(0, @cls[].length)
+ assert_equal(1, @cls[1].length)
+ assert_equal(2, @cls[1, nil].length)
+ assert_equal(2, @cls[nil, 1].length)
+ assert_equal(234, @cls[*(0..233).to_a].length)
+ end
+
+ # also update collect!
+ def test_map!
+ a = @cls[ 1, 'cat', 1..1 ]
+ assert_equal(@cls[ Fixnum, String, Range], a.map! {|e| e.class} )
+ assert_equal(@cls[ Fixnum, String, Range], a)
+
+ a = @cls[ 1, 'cat', 1..1 ]
+ assert_equal(@cls[ 99, 99, 99], a.map! { 99 } )
+ assert_equal(@cls[ 99, 99, 99], a)
+
+ a = @cls[ ]
+ assert_equal(@cls[], a.map! { 99 })
+ assert_equal(@cls[], a)
+ end
+
+ def test_pack
+ a = @cls[*%w( cat wombat x yy)]
+ assert_equal("catwomx yy ", a.pack("A3A3A3A3"))
+ assert_equal("cat", a.pack("A*"))
+ assert_equal("cwx yy ", a.pack("A3@1A3@2A3A3"))
+ assert_equal("catwomx\000\000yy\000", a.pack("a3a3a3a3"))
+ assert_equal("cat", a.pack("a*"))
+ assert_equal("ca", a.pack("a2"))
+ assert_equal("cat\000\000", a.pack("a5"))
+
+ assert_equal("\x61", @cls["01100001"].pack("B8"))
+ assert_equal("\x61", @cls["01100001"].pack("B*"))
+ assert_equal("\x61", @cls["0110000100110111"].pack("B8"))
+ assert_equal("\x61\x37", @cls["0110000100110111"].pack("B16"))
+ assert_equal("\x61\x37", @cls["01100001", "00110111"].pack("B8B8"))
+ assert_equal("\x60", @cls["01100001"].pack("B4"))
+ assert_equal("\x40", @cls["01100001"].pack("B2"))
+
+ assert_equal("\x86", @cls["01100001"].pack("b8"))
+ assert_equal("\x86", @cls["01100001"].pack("b*"))
+ assert_equal("\x86", @cls["0110000100110111"].pack("b8"))
+ assert_equal("\x86\xec", @cls["0110000100110111"].pack("b16"))
+ assert_equal("\x86\xec", @cls["01100001", "00110111"].pack("b8b8"))
+ assert_equal("\x06", @cls["01100001"].pack("b4"))
+ assert_equal("\x02", @cls["01100001"].pack("b2"))
+
+ assert_equal("ABC", @cls[ 65, 66, 67 ].pack("C3"))
+ assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("C*"))
+ assert_equal("ABC", @cls[ 65, 66, 67 ].pack("c3"))
+ assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("c*"))
+
+
+ assert_equal("AB\n\x10", @cls["4142", "0a", "12"].pack("H4H2H1"))
+ assert_equal("AB\n\x02", @cls["1424", "a0", "21"].pack("h4h2h1"))
+
+ assert_equal("abc=02def=\ncat=\n=01=\n",
+ @cls["abc\002def", "cat", "\001"].pack("M9M3M4"))
+
+ assert_equal("aGVsbG8K\n", @cls["hello\n"].pack("m"))
+ assert_equal(",:&5L;&\\*:&5L;&\\*\n", @cls["hello\nhello\n"].pack("u"))
+
+ assert_equal("\u{a9 42 2260}", @cls[0xa9, 0x42, 0x2260].pack("U*"))
+
+
+ format = "c2x5CCxsdils_l_a6";
+ # Need the expression in here to force ary[5] to be numeric. This avoids
+ # test2 failing because ary2 goes str->numeric->str and ary does not.
+ ary = [1, -100, 127, 128, 32767, 987.654321098/100.0,
+ 12345, 123456, -32767, -123456, "abcdef"]
+ x = ary.pack(format)
+ ary2 = x.unpack(format)
+
+ assert_equal(ary.length, ary2.length)
+ assert_equal(ary.join(':'), ary2.join(':'))
+ assert_not_nil(x =~ /def/)
+
+=begin
+ skipping "Not tested:
+ D,d & double-precision float, native format\\
+ E & double-precision float, little-endian byte order\\
+ e & single-precision float, little-endian byte order\\
+ F,f & single-precision float, native format\\
+ G & double-precision float, network (big-endian) byte order\\
+ g & single-precision float, network (big-endian) byte order\\
+ I & unsigned integer\\
+ i & integer\\
+ L & unsigned long\\
+ l & long\\
+
+ N & long, network (big-endian) byte order\\
+ n & short, network (big-endian) byte-order\\
+ P & pointer to a structure (fixed-length string)\\
+ p & pointer to a null-terminated string\\
+ S & unsigned short\\
+ s & short\\
+ V & long, little-endian byte order\\
+ v & short, little-endian byte order\\
+ X & back up a byte\\
+ x & null byte\\
+ Z & ASCII string (null padded, count is width)\\
+"
+=end
+ end
+
+ def test_pop
+ a = @cls[ 'cat', 'dog' ]
+ assert_equal('dog', a.pop)
+ assert_equal(@cls['cat'], a)
+ assert_equal('cat', a.pop)
+ assert_equal(@cls[], a)
+ assert_nil(a.pop)
+ assert_equal(@cls[], a)
+ end
+
+ def test_push
+ a = @cls[1, 2, 3]
+ assert_equal(@cls[1, 2, 3, 4, 5], a.push(4, 5))
+ assert_equal(@cls[1, 2, 3, 4, 5, nil], a.push(nil))
+ # Ruby 1.8 feature:
+ # Array#push accepts any number of arguments.
+ #assert_raise(ArgumentError, "a.push()") { a.push() }
+ a.push
+ assert_equal @cls[1, 2, 3, 4, 5, nil], a
+ a.push 6, 7
+ assert_equal @cls[1, 2, 3, 4, 5, nil, 6, 7], a
+ end
+
+ def test_rassoc
+ a1 = @cls[*%w( cat feline )]
+ a2 = @cls[*%w( dog canine )]
+ a3 = @cls[*%w( mule asinine )]
+ a = @cls[ a1, a2, a3 ]
+
+ assert_equal(a1, a.rassoc('feline'))
+ assert_equal(a3, a.rassoc('asinine'))
+ assert_equal(nil, a.rassoc('dog'))
+ assert_equal(nil, a.rassoc('mule'))
+ assert_equal(nil, a.rassoc(1..2))
+ end
+
+ # also delete_if
+ def test_reject!
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(nil, a.reject! { false })
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.reject! { true })
+ assert_equal(@cls[], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.reject! { |i| i > 3 })
+ assert_equal(@cls[1, 2, 3], a)
+
+ bug2545 = '[ruby-core:27366]'
+ a = @cls[ 5, 6, 7, 8, 9, 10 ]
+ assert_equal(9, a.reject! {|i| break i if i > 8; assert_equal(a[0], i) || true if i < 7})
+ assert_equal(@cls[7, 8, 9, 10], a, bug2545)
+ end
+
+ def test_replace
+ a = @cls[ 1, 2, 3]
+ a_id = a.__id__
+ assert_equal(@cls[4, 5, 6], a.replace(@cls[4, 5, 6]))
+ assert_equal(@cls[4, 5, 6], a)
+ assert_equal(a_id, a.__id__)
+ assert_equal(@cls[], a.replace(@cls[]))
+
+ fa = a.dup.freeze
+ assert_nothing_raised(RuntimeError) { a.replace(a) }
+ assert_raise(RuntimeError) { fa.replace(fa) }
+ assert_raise(ArgumentError) { fa.replace() }
+ assert_raise(TypeError) { a.replace(42) }
+ assert_raise(RuntimeError) { fa.replace(42) }
+ end
+
+ def test_reverse
+ a = @cls[*%w( dog cat bee ant )]
+ assert_equal(@cls[*%w(ant bee cat dog)], a.reverse)
+ assert_equal(@cls[*%w(dog cat bee ant)], a)
+ assert_equal(@cls[], @cls[].reverse)
+ end
+
+ def test_reverse!
+ a = @cls[*%w( dog cat bee ant )]
+ assert_equal(@cls[*%w(ant bee cat dog)], a.reverse!)
+ assert_equal(@cls[*%w(ant bee cat dog)], a)
+ # Ruby 1.8 feature change:
+ # Array#reverse always returns self.
+ #assert_nil(@cls[].reverse!)
+ assert_equal @cls[], @cls[].reverse!
+ end
+
+ def test_reverse_each
+ a = @cls[*%w( dog cat bee ant )]
+ i = a.length
+ a.reverse_each { |e|
+ i -= 1
+ assert_equal(a[i], e)
+ }
+ assert_equal(0, i)
+
+ a = @cls[]
+ i = 0
+ a.reverse_each { |e|
+ i += 1
+ assert(false, "Never get here")
+ }
+ assert_equal(0, i)
+ end
+
+ def test_rindex
+ a = @cls[ 'cat', 99, /a/, 99, [ 1, 2, 3] ]
+ assert_equal(0, a.rindex('cat'))
+ assert_equal(3, a.rindex(99))
+ assert_equal(4, a.rindex([1,2,3]))
+ assert_nil(a.rindex('ca'))
+ assert_nil(a.rindex([1,2]))
+
+ assert_equal(3, a.rindex(99) {|x| x == [1,2,3] })
+ end
+
+ def test_shift
+ a = @cls[ 'cat', 'dog' ]
+ assert_equal('cat', a.shift)
+ assert_equal(@cls['dog'], a)
+ assert_equal('dog', a.shift)
+ assert_equal(@cls[], a)
+ assert_nil(a.shift)
+ assert_equal(@cls[], a)
+ end
+
+ def test_size
+ assert_equal(0, @cls[].size)
+ assert_equal(1, @cls[1].size)
+ assert_equal(100, @cls[*(0..99).to_a].size)
+ end
+
+ def test_slice
+ a = @cls[*(1..100).to_a]
+
+ assert_equal(1, a.slice(0))
+ assert_equal(100, a.slice(99))
+ assert_nil(a.slice(100))
+ assert_equal(100, a.slice(-1))
+ assert_equal(99, a.slice(-2))
+ assert_equal(1, a.slice(-100))
+ assert_nil(a.slice(-101))
+
+ assert_equal(@cls[1], a.slice(0,1))
+ assert_equal(@cls[100], a.slice(99,1))
+ assert_equal(@cls[], a.slice(100,1))
+ assert_equal(@cls[100], a.slice(99,100))
+ assert_equal(@cls[100], a.slice(-1,1))
+ assert_equal(@cls[99], a.slice(-2,1))
+
+ assert_equal(@cls[10, 11, 12], a.slice(9, 3))
+ assert_equal(@cls[10, 11, 12], a.slice(-91, 3))
+
+ assert_nil(a.slice(-101, 2))
+
+ assert_equal(@cls[1], a.slice(0..0))
+ assert_equal(@cls[100], a.slice(99..99))
+ assert_equal(@cls[], a.slice(100..100))
+ assert_equal(@cls[100], a.slice(99..200))
+ assert_equal(@cls[100], a.slice(-1..-1))
+ assert_equal(@cls[99], a.slice(-2..-2))
+
+ assert_equal(@cls[10, 11, 12], a.slice(9..11))
+ assert_equal(@cls[10, 11, 12], a.slice(-91..-89))
+
+ assert_nil(a.slice(-101..-1))
+
+ assert_nil(a.slice(10, -3))
+ # Ruby 1.8 feature change:
+ # Array#slice[size..x] always returns [].
+ #assert_nil(a.slice(10..7))
+ assert_equal @cls[], a.slice(10..7)
+ end
+
+ def test_slice!
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(3, a.slice!(2))
+ assert_equal(@cls[1, 2, 4, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(4, a.slice!(-2))
+ assert_equal(@cls[1, 2, 3, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(@cls[3,4], a.slice!(2,2))
+ assert_equal(@cls[1, 2, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(@cls[4,5], a.slice!(-2,2))
+ assert_equal(@cls[1, 2, 3], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(@cls[3,4], a.slice!(2..3))
+ assert_equal(@cls[1, 2, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(nil, a.slice!(20))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(nil, a.slice!(-6))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(nil, a.slice!(-6..4))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[1, 2, 3, 4, 5]
+ assert_equal(nil, a.slice!(-6,2))
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ assert_raise(ArgumentError) { @cls[1].slice! }
+ assert_raise(ArgumentError) { @cls[1].slice!(0, 0, 0) }
+ end
+
+ def test_sort
+ a = @cls[ 4, 1, 2, 3 ]
+ assert_equal(@cls[1, 2, 3, 4], a.sort)
+ assert_equal(@cls[4, 1, 2, 3], a)
+
+ assert_equal(@cls[4, 3, 2, 1], a.sort { |x, y| y <=> x} )
+ assert_equal(@cls[4, 1, 2, 3], a)
+
+ assert_equal(@cls[1, 2, 3, 4], a.sort { |x, y| (x - y) * (2**100) })
+
+ a.fill(1)
+ assert_equal(@cls[1, 1, 1, 1], a.sort)
+
+ assert_equal(@cls[], @cls[].sort)
+ end
+
+ def test_sort!
+ a = @cls[ 4, 1, 2, 3 ]
+ assert_equal(@cls[1, 2, 3, 4], a.sort!)
+ assert_equal(@cls[1, 2, 3, 4], a)
+
+ assert_equal(@cls[4, 3, 2, 1], a.sort! { |x, y| y <=> x} )
+ assert_equal(@cls[4, 3, 2, 1], a)
+
+ a.fill(1)
+ assert_equal(@cls[1, 1, 1, 1], a.sort!)
+
+ assert_equal(@cls[1], @cls[1].sort!)
+ assert_equal(@cls[], @cls[].sort!)
+
+ a = @cls[4, 3, 2, 1]
+ a.sort! {|m, n| a.replace([9, 8, 7, 6]); m <=> n }
+ assert_equal([1, 2, 3, 4], a)
+
+ a = @cls[4, 3, 2, 1]
+ a.sort! {|m, n| a.replace([9, 8, 7]); m <=> n }
+ assert_equal([1, 2, 3, 4], a)
+ end
+
+ def test_sort_with_callcc
+ need_continuation
+ n = 1000
+ cont = nil
+ ary = (1..100).to_a
+ begin
+ ary.sort! {|a,b|
+ callcc {|k| cont = k} unless cont
+ assert_equal(100, ary.size, '[ruby-core:16679]')
+ a <=> b
+ }
+ rescue => e
+ end
+ n -= 1
+ cont.call if 0 < n
+ assert_instance_of(RuntimeError, e, '[ruby-core:16679]')
+ assert_match(/reentered/, e.message, '[ruby-core:16679]')
+ end
+
+ def test_sort_with_replace
+ xary = (1..100).to_a
+ 100.times do
+ ary = (1..100).to_a
+ ary.sort! {|a,b| ary.replace(xary); a <=> b}
+ GC.start
+ assert_equal(xary, ary, '[ruby-dev:34732]')
+ end
+ end
+
+ def test_sort_bang_with_freeze
+ ary = []
+ o1 = Object.new
+ o1.singleton_class.class_eval {
+ define_method(:<=>) {|v|
+ ary.freeze
+ 1
+ }
+ }
+ o2 = o1.dup
+ ary << o1 << o2
+ orig = ary.dup
+ assert_raise(RuntimeError, "frozen during comparison") {ary.sort!}
+ assert_equal(orig, ary, "must not be modified once frozen")
+ end
+
+ def test_to_a
+ a = @cls[ 1, 2, 3 ]
+ a_id = a.__id__
+ assert_equal(a, a.to_a)
+ assert_equal(a_id, a.to_a.__id__)
+ end
+
+ def test_to_ary
+ a = [ 1, 2, 3 ]
+ b = @cls[*a]
+
+ a_id = a.__id__
+ assert_equal(a, b.to_ary)
+ if (@cls == Array)
+ assert_equal(a_id, a.to_ary.__id__)
+ end
+
+ o = Object.new
+ def o.to_ary
+ [4, 5]
+ end
+ assert_equal([1, 2, 3, 4, 5], a.concat(o))
+
+ o = Object.new
+ def o.to_ary
+ foo_bar()
+ end
+ assert_match(/foo_bar/, assert_raise(NoMethodError) {a.concat(o)}.message)
+ end
+
+ def test_to_s
+ $, = ""
+ a = @cls[]
+ assert_equal("[]", a.to_s)
+
+ $, = ""
+ a = @cls[1, 2]
+ assert_equal("[1, 2]", a.to_s)
+
+ $, = ""
+ a = @cls[1, 2, 3]
+ assert_equal("[1, 2, 3]", a.to_s)
+
+ $, = ":"
+ a = @cls[1, 2, 3]
+ assert_equal("[1, 2, 3]", a.to_s)
+ ensure
+ $, = nil
+ end
+
+ def test_to_h
+ kvp = Object.new
+ def kvp.to_ary
+ [:obtained, :via_to_ary]
+ end
+ array = [
+ [:key, :value],
+ kvp,
+ ]
+ assert_equal({key: :value, obtained: :via_to_ary}, array.to_h)
+
+ e = assert_raise(TypeError) {
+ [[:first_one, :ok], :not_ok].to_h
+ }
+ assert_equal "wrong element type Symbol at 1 (expected array)", e.message
+ e = assert_raise(ArgumentError) {
+ [[:first_one, :ok], [1, 2], [:not_ok]].to_h
+ }
+ assert_equal "wrong array length at 2 (expected 2, was 1)", e.message
+ end
+
+ def test_uniq
+ a = []
+ b = a.uniq
+ assert_equal([], a)
+ assert_equal([], b)
+ assert_not_same(a, b)
+
+ a = [1]
+ b = a.uniq
+ assert_equal([1], a)
+ assert_equal([1], b)
+ assert_not_same(a, b)
+
+ a = [1,1]
+ b = a.uniq
+ assert_equal([1,1], a)
+ assert_equal([1], b)
+ assert_not_same(a, b)
+
+ a = [1,2]
+ b = a.uniq
+ assert_equal([1,2], a)
+ assert_equal([1,2], b)
+ assert_not_same(a, b)
+
+ a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ]
+ b = a.dup
+ assert_equal(@cls[1, 2, 3, 4, nil], a.uniq)
+ assert_equal(b, a)
+
+ c = @cls["a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl"]
+ d = c.dup
+ assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c.uniq {|s| s[/^\w+/]})
+ assert_equal(d, c)
+
+ assert_equal(@cls[1, 2, 3], @cls[1, 2, 3].uniq)
+
+ a = %w(a a)
+ b = a.uniq
+ assert_equal(%w(a a), a)
+ assert(a.none?(&:frozen?))
+ assert_equal(%w(a), b)
+ assert(b.none?(&:frozen?))
+
+ bug9340 = "[ruby-core:59457]"
+ ary = [bug9340, bug9340.dup, bug9340.dup]
+ assert_equal 1, ary.uniq.size
+ assert_same bug9340, ary.uniq[0]
+ end
+
+ def test_uniq_with_block
+ a = []
+ b = a.uniq {|v| v.even? }
+ assert_equal([], a)
+ assert_equal([], b)
+ assert_not_same(a, b)
+
+ a = [1]
+ b = a.uniq {|v| v.even? }
+ assert_equal([1], a)
+ assert_equal([1], b)
+ assert_not_same(a, b)
+
+ a = [1,3]
+ b = a.uniq {|v| v.even? }
+ assert_equal([1,3], a)
+ assert_equal([1], b)
+ assert_not_same(a, b)
+
+ a = %w(a a)
+ b = a.uniq {|v| v }
+ assert_equal(%w(a a), a)
+ assert(a.none?(&:frozen?))
+ assert_equal(%w(a), b)
+ assert(b.none?(&:frozen?))
+ end
+
+ def test_uniq!
+ a = []
+ b = a.uniq!
+ assert_equal(nil, b)
+
+ a = [1]
+ b = a.uniq!
+ assert_equal(nil, b)
+
+ a = [1,1]
+ b = a.uniq!
+ assert_equal([1], a)
+ assert_equal([1], b)
+ assert_same(a, b)
+
+ a = [1,2]
+ b = a.uniq!
+ assert_equal([1,2], a)
+ assert_equal(nil, b)
+
+ a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ]
+ assert_equal(@cls[1, 2, 3, 4, nil], a.uniq!)
+ assert_equal(@cls[1, 2, 3, 4, nil], a)
+
+ c = @cls["a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl"]
+ assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c.uniq! {|s| s[/^\w+/]})
+ assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c)
+
+ c = @cls["a:def", "b:abc", "c:jkl"]
+ assert_equal(nil, c.uniq! {|s| s[/^\w+/]})
+ assert_equal(@cls[ "a:def", "b:abc", "c:jkl" ], c)
+
+ assert_nil(@cls[1, 2, 3].uniq!)
+
+ f = a.dup.freeze
+ assert_raise(ArgumentError) { a.uniq!(1) }
+ assert_raise(ArgumentError) { f.uniq!(1) }
+ assert_raise(RuntimeError) { f.uniq! }
+
+ assert_nothing_raised do
+ a = [ {c: "b"}, {c: "r"}, {c: "w"}, {c: "g"}, {c: "g"} ]
+ a.sort_by!{|e| e[:c]}
+ a.uniq! {|e| e[:c]}
+ end
+
+ a = %w(a a)
+ b = a.uniq
+ assert_equal(%w(a a), a)
+ assert(a.none?(&:frozen?))
+ assert_equal(%w(a), b)
+ assert(b.none?(&:frozen?))
+ end
+
+ def test_uniq_bang_with_block
+ a = []
+ b = a.uniq! {|v| v.even? }
+ assert_equal(nil, b)
+
+ a = [1]
+ b = a.uniq! {|v| v.even? }
+ assert_equal(nil, b)
+
+ a = [1,3]
+ b = a.uniq! {|v| v.even? }
+ assert_equal([1], a)
+ assert_equal([1], b)
+ assert_same(a, b)
+
+ a = [1,2]
+ b = a.uniq! {|v| v.even? }
+ assert_equal([1,2], a)
+ assert_equal(nil, b)
+
+ a = %w(a a)
+ b = a.uniq! {|v| v }
+ assert_equal(%w(a), b)
+ assert_same(a, b)
+ assert b.none?(&:frozen?)
+ end
+
+ def test_uniq_bang_with_freeze
+ ary = [1,2]
+ orig = ary.dup
+ assert_raise(RuntimeError, "frozen during comparison") {
+ ary.uniq! {|v| ary.freeze; 1}
+ }
+ assert_equal(orig, ary, "must not be modified once frozen")
+ end
+
+ def test_unshift
+ a = @cls[]
+ assert_equal(@cls['cat'], a.unshift('cat'))
+ assert_equal(@cls['dog', 'cat'], a.unshift('dog'))
+ assert_equal(@cls[nil, 'dog', 'cat'], a.unshift(nil))
+ assert_equal(@cls[@cls[1,2], nil, 'dog', 'cat'], a.unshift(@cls[1, 2]))
+ end
+
+ def test_OR # '|'
+ assert_equal(@cls[], @cls[] | @cls[])
+ assert_equal(@cls[1], @cls[1] | @cls[])
+ assert_equal(@cls[1], @cls[] | @cls[1])
+ assert_equal(@cls[1], @cls[1] | @cls[1])
+
+ assert_equal(@cls[1,2], @cls[1] | @cls[2])
+ assert_equal(@cls[1,2], @cls[1, 1] | @cls[2, 2])
+ assert_equal(@cls[1,2], @cls[1, 2] | @cls[1, 2])
+
+ a = %w(a b c)
+ b = %w(a b c d e)
+ c = a | b
+ assert_equal(c, b)
+ assert_not_same(c, b)
+ assert_equal(%w(a b c), a)
+ assert_equal(%w(a b c d e), b)
+ assert(a.none?(&:frozen?))
+ assert(b.none?(&:frozen?))
+ assert(c.none?(&:frozen?))
+ end
+
+ def test_OR_in_order
+ obj1, obj2 = Class.new do
+ attr_reader :name
+ def initialize(name) @name = name; end
+ def inspect; "test_OR_in_order(#{@name})"; end
+ def hash; 0; end
+ def eql?(a) true; end
+ break [new("1"), new("2")]
+ end
+ assert_equal([obj1], [obj1]|[obj2])
+ end
+
+ def test_combination
+ assert_equal(@cls[[]], @cls[1,2,3,4].combination(0).to_a)
+ assert_equal(@cls[[1],[2],[3],[4]], @cls[1,2,3,4].combination(1).to_a)
+ assert_equal(@cls[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], @cls[1,2,3,4].combination(2).to_a)
+ assert_equal(@cls[[1,2,3],[1,2,4],[1,3,4],[2,3,4]], @cls[1,2,3,4].combination(3).to_a)
+ assert_equal(@cls[[1,2,3,4]], @cls[1,2,3,4].combination(4).to_a)
+ assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a)
+ end
+
+ def test_product
+ assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]],
+ @cls[1,2,3].product([4,5]))
+ assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2]))
+
+ assert_equal(@cls[[1,3,5],[1,3,6],[1,4,5],[1,4,6],
+ [2,3,5],[2,3,6],[2,4,5],[2,4,6]],
+ @cls[1,2].product([3,4],[5,6]))
+ assert_equal(@cls[[1],[2]], @cls[1,2].product)
+ assert_equal(@cls[], @cls[1,2].product([]))
+
+ bug3394 = '[ruby-dev:41540]'
+ acc = []
+ EnvUtil.under_gc_stress {[1,2].product([3,4,5],[6,8]){|array| acc << array}}
+ assert_equal([[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
+ [2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]],
+ acc, bug3394)
+
+ def (o = Object.new).to_ary; GC.start; [3,4] end
+ acc = [1,2].product(*[o]*10)
+ assert_equal([1,2].product([3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4], [3,4]),
+ acc)
+
+ a = []
+ [1, 2].product([0, 1, 2, 3, 4][1, 4]) {|x| a << x }
+ a.all? {|x| assert_not_include(x, 0)}
+ end
+
+ def test_permutation
+ a = @cls[1,2,3]
+ assert_equal(@cls[[]], a.permutation(0).to_a)
+ assert_equal(@cls[[1],[2],[3]], a.permutation(1).to_a.sort)
+ assert_equal(@cls[[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]],
+ a.permutation(2).to_a.sort)
+ assert_equal(@cls[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]],
+ a.permutation(3).sort.to_a)
+ assert_equal(@cls[], a.permutation(4).to_a)
+ assert_equal(@cls[], a.permutation(-1).to_a)
+ assert_equal("abcde".each_char.to_a.permutation(5).sort,
+ "edcba".each_char.to_a.permutation(5).sort)
+ assert_equal(@cls[].permutation(0).to_a, @cls[[]])
+
+ a = @cls[1, 2, 3, 4]
+ b = @cls[]
+ a.permutation {|x| b << x; a.replace(@cls[9, 8, 7, 6]) }
+ assert_equal(@cls[9, 8, 7, 6], a)
+ assert_equal(@cls[1, 2, 3, 4].permutation.to_a, b)
+
+ bug3708 = '[ruby-dev:42067]'
+ assert_equal(b, @cls[0, 1, 2, 3, 4][1, 4].permutation.to_a, bug3708)
+
+ bug9932 = '[ruby-core:63103] [Bug #9932]'
+ assert_separately([], <<-"end;") # do
+ assert_nothing_raised(SystemStackError, "#{bug9932}") do
+ assert_equal(:ok, Array.new(100_000, nil).permutation {break :ok})
+ end
+ end;
+ end
+
+ def test_repeated_permutation
+ a = @cls[1,2]
+ assert_equal(@cls[[]], a.repeated_permutation(0).to_a)
+ assert_equal(@cls[[1],[2]], a.repeated_permutation(1).to_a.sort)
+ assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]],
+ a.repeated_permutation(2).to_a.sort)
+ assert_equal(@cls[[1,1,1],[1,1,2],[1,2,1],[1,2,2],
+ [2,1,1],[2,1,2],[2,2,1],[2,2,2]],
+ a.repeated_permutation(3).to_a.sort)
+ assert_equal(@cls[], a.repeated_permutation(-1).to_a)
+ assert_equal("abcde".each_char.to_a.repeated_permutation(5).sort,
+ "edcba".each_char.to_a.repeated_permutation(5).sort)
+ assert_equal(@cls[].repeated_permutation(0).to_a, @cls[[]])
+ assert_equal(@cls[].repeated_permutation(1).to_a, @cls[])
+
+ a = @cls[1, 2, 3, 4]
+ b = @cls[]
+ a.repeated_permutation(4) {|x| b << x; a.replace(@cls[9, 8, 7, 6]) }
+ assert_equal(@cls[9, 8, 7, 6], a)
+ assert_equal(@cls[1, 2, 3, 4].repeated_permutation(4).to_a, b)
+
+ a = @cls[0, 1, 2, 3, 4][1, 4].repeated_permutation(2)
+ assert_empty(a.reject {|x| !x.include?(0)})
+
+ assert_separately([], <<-"end;") # do
+ assert_nothing_raised(SystemStackError) do
+ assert_equal(:ok, Array.new(100_000, nil).repeated_permutation(500_000) {break :ok})
+ end
+ end;
+ end
+
+ def test_repeated_combination
+ a = @cls[1,2,3]
+ assert_equal(@cls[[]], a.repeated_combination(0).to_a)
+ assert_equal(@cls[[1],[2],[3]], a.repeated_combination(1).to_a.sort)
+ assert_equal(@cls[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]],
+ a.repeated_combination(2).to_a.sort)
+ assert_equal(@cls[[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
+ [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]],
+ a.repeated_combination(3).to_a.sort)
+ assert_equal(@cls[[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3],
+ [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
+ [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]],
+ a.repeated_combination(4).to_a.sort)
+ assert_equal(@cls[], a.repeated_combination(-1).to_a)
+ assert_equal("abcde".each_char.to_a.repeated_combination(5).map{|e|e.sort}.sort,
+ "edcba".each_char.to_a.repeated_combination(5).map{|e|e.sort}.sort)
+ assert_equal(@cls[].repeated_combination(0).to_a, @cls[[]])
+ assert_equal(@cls[].repeated_combination(1).to_a, @cls[])
+
+ a = @cls[1, 2, 3, 4]
+ b = @cls[]
+ a.repeated_combination(4) {|x| b << x; a.replace(@cls[9, 8, 7, 6]) }
+ assert_equal(@cls[9, 8, 7, 6], a)
+ assert_equal(@cls[1, 2, 3, 4].repeated_combination(4).to_a, b)
+
+ a = @cls[0, 1, 2, 3, 4][1, 4].repeated_combination(2)
+ assert_empty(a.reject {|x| !x.include?(0)})
+
+ assert_separately([], <<-"end;") # do
+ assert_nothing_raised(SystemStackError) do
+ assert_equal(:ok, Array.new(100_000, nil).repeated_combination(500_000) {break :ok})
+ end
+ end;
+ end
+
+ def test_take
+ assert_equal([1,2,3], [1,2,3,4,5,0].take(3))
+ assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) }
+ assert_equal([1,2], [1,2].take(1000000000), '[ruby-dev:34123]')
+ end
+
+ def test_take_while
+ assert_equal([1,2], [1,2,3,4,5,0].take_while {|i| i < 3 })
+ end
+
+ def test_drop
+ assert_equal([4,5,0], [1,2,3,4,5,0].drop(3))
+ assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].drop(-1) }
+ assert_equal([], [1,2].drop(1000000000), '[ruby-dev:34123]')
+ end
+
+ def test_drop_while
+ assert_equal([3,4,5,0], [1,2,3,4,5,0].drop_while {|i| i < 3 })
+ end
+
+ LONGP = [127, 63, 31, 15, 7].map {|x| 2**x-1 }.find do |x|
+ begin
+ [].first(x)
+ rescue ArgumentError
+ true
+ rescue RangeError
+ false
+ end
+ end
+
+ def test_ary_new
+ assert_raise(ArgumentError) { [].to_enum.first(-1) }
+ assert_raise(ArgumentError) { [].to_enum.first(LONGP) }
+ end
+
+ def test_try_convert
+ assert_equal([1], Array.try_convert([1]))
+ assert_equal(nil, Array.try_convert("1"))
+ end
+
+ def test_initialize
+ assert_nothing_raised { [].instance_eval { initialize } }
+ assert_nothing_raised { Array.new { } }
+ assert_equal([1, 2, 3], Array.new([1, 2, 3]))
+ assert_raise(ArgumentError) { Array.new(-1, 1) }
+ assert_raise(ArgumentError) { Array.new(LONGP, 1) }
+ assert_equal([1, 1, 1], Array.new(3, 1))
+ assert_equal([1, 1, 1], Array.new(3) { 1 })
+ assert_equal([1, 1, 1], Array.new(3, 1) { 1 })
+ end
+
+ def test_aset_error
+ assert_raise(IndexError) { [0][-2] = 1 }
+ assert_raise(IndexError) { [0][LONGP] = 2 }
+ assert_raise(IndexError) { [0][(LONGP + 1) / 2 - 1] = 2 }
+ assert_raise(IndexError) { [0][LONGP..-1] = 2 }
+ a = [0]
+ a[2] = 4
+ assert_equal([0, nil, 4], a)
+ assert_raise(ArgumentError) { [0][0, 0, 0] = 0 }
+ assert_raise(ArgumentError) { [0].freeze[0, 0, 0] = 0 }
+ assert_raise(TypeError) { [0][:foo] = 0 }
+ assert_raise(RuntimeError) { [0].freeze[:foo] = 0 }
+ end
+
+ def test_first2
+ assert_equal([0], [0].first(2))
+ assert_raise(ArgumentError) { [0].first(-1) }
+ end
+
+ def test_last2
+ assert_equal([0], [0].last(2))
+ assert_raise(ArgumentError) { [0].last(-1) }
+ end
+
+ def test_shift2
+ assert_equal(0, ([0] * 16).shift)
+ # check
+ a = [0, 1, 2]
+ a[3] = 3
+ a.shift(2)
+ assert_equal([2, 3], a)
+ end
+
+ def test_unshift_error
+ assert_raise(RuntimeError) { [].freeze.unshift('cat') }
+ assert_raise(RuntimeError) { [].freeze.unshift() }
+ end
+
+ def test_aref
+ assert_raise(ArgumentError) { [][0, 0, 0] }
+ end
+
+ def test_fetch
+ assert_equal(1, [].fetch(0, 0) { 1 })
+ assert_equal(1, [0, 1].fetch(-1))
+ assert_raise(IndexError) { [0, 1].fetch(2) }
+ assert_raise(IndexError) { [0, 1].fetch(-3) }
+ assert_equal(2, [0, 1].fetch(2, 2))
+ end
+
+ def test_index2
+ a = [0, 1, 2]
+ assert_equal(a, a.index.to_a)
+ assert_equal(1, a.index {|x| x == 1 })
+ end
+
+ def test_rindex2
+ a = [0, 1, 2]
+ assert_equal([2, 1, 0], a.rindex.to_a)
+ assert_equal(1, a.rindex {|x| x == 1 })
+
+ a = [0, 1]
+ e = a.rindex
+ assert_equal(1, e.next)
+ a.clear
+ assert_raise(StopIteration) { e.next }
+
+ o = Object.new
+ class << o; self; end.class_eval do
+ define_method(:==) {|x| a.clear; false }
+ end
+ a = [nil, o]
+ assert_equal(nil, a.rindex(0))
+ end
+
+ def test_ary_to_ary
+ o = Object.new
+ def o.to_ary; [1, 2, 3]; end
+ a, b, c = o
+ assert_equal([1, 2, 3], [a, b, c])
+ end
+
+ def test_splice
+ a = [0]
+ assert_raise(IndexError) { a[-2, 0] = nil }
+ end
+
+ def test_insert
+ a = [0]
+ assert_equal([0], a.insert(1))
+ assert_equal([0, 1], a.insert(1, 1))
+ assert_raise(ArgumentError) { a.insert }
+ assert_equal([0, 1, 2], a.insert(-1, 2))
+ assert_equal([0, 1, 3, 2], a.insert(-2, 3))
+ assert_raise(RuntimeError) { [0].freeze.insert(0)}
+ assert_raise(ArgumentError) { [0].freeze.insert }
+ end
+
+ def test_join2
+ a = []
+ a << a
+ assert_raise(ArgumentError){a.join}
+
+ def (a = Object.new).to_ary
+ [self]
+ end
+ assert_raise(ArgumentError, '[ruby-core:24150]'){[a].join}
+ assert_equal("12345", [1,[2,[3,4],5]].join)
+ end
+
+ def test_to_a2
+ klass = Class.new(Array)
+ a = klass.new.to_a
+ assert_equal([], a)
+ assert_equal(Array, a.class)
+ end
+
+ def test_values_at2
+ a = [0, 1, 2, 3, 4, 5]
+ assert_equal([1, 2, 3], a.values_at(1..3))
+ assert_equal([nil, nil], a.values_at(7..8))
+ bug6203 = '[ruby-core:43678]'
+ assert_equal([4, 5, nil, nil], a.values_at(4..7), bug6203)
+ assert_equal([nil], a.values_at(2**31-1))
+ end
+
+ def test_select
+ assert_equal([0, 2], [0, 1, 2, 3].select {|x| x % 2 == 0 })
+ end
+
+ # also keep_if
+ def test_select!
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(nil, a.select! { true })
+ assert_equal(a, a.keep_if { true })
+ assert_equal(@cls[1, 2, 3, 4, 5], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.select! { false })
+ assert_equal(@cls[], a)
+
+ a = @cls[ 1, 2, 3, 4, 5 ]
+ assert_equal(a, a.select! { |i| i > 3 })
+ assert_equal(@cls[4, 5], a)
+ end
+
+ def test_delete2
+ a = [0] * 1024 + [1] + [0] * 1024
+ a.delete(0)
+ assert_equal([1], a)
+ end
+
+ def test_reject
+ assert_equal([1, 3], [0, 1, 2, 3].reject {|x| x % 2 == 0 })
+ end
+
+ def test_reject_with_callcc
+ need_continuation
+ bug9727 = '[ruby-dev:48101] [Bug #9727]'
+ cont = nil
+ a = [*1..10].reject do |i|
+ callcc {|c| cont = c} if !cont and i == 10
+ false
+ end
+ if a.size < 1000
+ a.unshift(:x)
+ cont.call
+ end
+ assert_equal(1000, a.size, bug9727)
+ assert_equal([:x, *1..10], a.uniq, bug9727)
+ end
+
+ def test_zip
+ assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]],
+ [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"]))
+ a = []
+ [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"]) {|x| a << x }
+ assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]], a)
+
+ ary = Object.new
+ def ary.to_a; [1, 2]; end
+ assert_raise(TypeError) {%w(a b).zip(ary)}
+ def ary.each; [3, 4].each{|e|yield e}; end
+ assert_equal([['a', 3], ['b', 4]], %w(a b).zip(ary))
+ def ary.to_ary; [5, 6]; end
+ assert_equal([['a', 5], ['b', 6]], %w(a b).zip(ary))
+ end
+
+ def test_zip_bug
+ bug8153 = "ruby-core:53650"
+ r = 1..1
+ def r.respond_to?(*)
+ super
+ end
+ assert_equal [[42, 1]], [42].zip(r), bug8153
+ end
+
+ def test_transpose
+ assert_equal([[1, :a], [2, :b], [3, :c]],
+ [[1, 2, 3], [:a, :b, :c]].transpose)
+ assert_raise(IndexError) { [[1, 2, 3], [:a, :b]].transpose }
+ end
+
+ def test_clear2
+ assert_equal([], ([0] * 1024).clear)
+ end
+
+ def test_fill2
+ assert_raise(ArgumentError) { [].fill(0, 1, LONGP) }
+ end
+
+ def test_times
+ assert_raise(ArgumentError) { [0, 0, 0, 0] * ((LONGP + 1) / 4) }
+ end
+
+ def test_equal
+ o = Object.new
+ def o.to_ary; end
+ def o.==(x); :foo; end
+ assert_equal([0, 1, 2], o)
+ assert_not_equal([0, 1, 2], [0, 1, 3])
+ end
+
+ A = Array.new(3, &:to_s)
+ B = A.dup
+
+ def test_equal_resize
+ o = Object.new
+ def o.==(o)
+ A.clear
+ B.clear
+ true
+ end
+ A[1] = o
+ assert_equal(A, B)
+ end
+
+ def test_flatten_error
+ a = []
+ a << a
+ assert_raise(ArgumentError) { a.flatten }
+
+ f = [].freeze
+ assert_raise(ArgumentError) { a.flatten!(1, 2) }
+ assert_raise(TypeError) { a.flatten!(:foo) }
+ assert_raise(ArgumentError) { f.flatten!(1, 2) }
+ assert_raise(RuntimeError) { f.flatten! }
+ assert_raise(RuntimeError) { f.flatten!(:foo) }
+ end
+
+ def test_shuffle
+ 100.times do
+ assert_equal([0, 1, 2], [2, 1, 0].shuffle.sort)
+ end
+
+ gen = Random.new(0)
+ assert_raise(ArgumentError) {[1, 2, 3].shuffle(1, random: gen)}
+ srand(0)
+ 100.times do
+ assert_equal([0, 1, 2].shuffle, [0, 1, 2].shuffle(random: gen))
+ end
+
+ assert_raise_with_message(ArgumentError, /unknown keyword/) do
+ [0, 1, 2].shuffle(xawqij: "a")
+ end
+ assert_raise_with_message(ArgumentError, /unknown keyword/) do
+ [0, 1, 2].shuffle!(xawqij: "a")
+ end
+ end
+
+ def test_shuffle_random
+ gen = proc do
+ 10000000
+ end
+ class << gen
+ alias rand call
+ end
+ assert_raise(RangeError) {
+ [*0..2].shuffle(random: gen)
+ }
+
+ ary = (0...10000).to_a
+ gen = proc do
+ ary.replace([])
+ 0.5
+ end
+ class << gen
+ alias rand call
+ end
+ assert_raise(RuntimeError) {ary.shuffle!(random: gen)}
+
+ zero = Object.new
+ def zero.to_int
+ 0
+ end
+ gen_to_int = proc do |max|
+ zero
+ end
+ class << gen_to_int
+ alias rand call
+ end
+ ary = (0...10000).to_a
+ assert_equal(ary.rotate, ary.shuffle(random: gen_to_int))
+ end
+
+ def test_sample
+ 100.times do
+ assert_include([0, 1, 2], [2, 1, 0].sample)
+ samples = [2, 1, 0].sample(2)
+ samples.each{|sample|
+ assert_include([0, 1, 2], sample)
+ }
+ end
+
+ srand(0)
+ a = (1..18).to_a
+ (0..20).each do |n|
+ 100.times do
+ b = a.sample(n)
+ assert_equal([n, 18].min, b.size)
+ assert_equal(a, (a | b).sort)
+ assert_equal(b.sort, (a & b).sort)
+ end
+
+ h = Hash.new(0)
+ 1000.times do
+ a.sample(n).each {|x| h[x] += 1 }
+ end
+ assert_operator(h.values.min * 2, :>=, h.values.max) if n != 0
+ end
+
+ assert_raise(ArgumentError, '[ruby-core:23374]') {[1, 2].sample(-1)}
+
+ gen = Random.new(0)
+ srand(0)
+ a = (1..18).to_a
+ (0..20).each do |n|
+ 100.times do |i|
+ assert_equal(a.sample(n), a.sample(n, random: gen), "#{i}/#{n}")
+ end
+ end
+
+ assert_raise_with_message(ArgumentError, /unknown keyword/) do
+ [0, 1, 2].sample(xawqij: "a")
+ end
+ end
+
+ def test_sample_random
+ ary = (0...10000).to_a
+ assert_raise(ArgumentError) {ary.sample(1, 2, random: nil)}
+ gen0 = proc do |max|
+ max/2
+ end
+ class << gen0
+ alias rand call
+ end
+ gen1 = proc do |max|
+ ary.replace([])
+ max/2
+ end
+ class << gen1
+ alias rand call
+ end
+ assert_equal(5000, ary.sample(random: gen0))
+ assert_nil(ary.sample(random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000], ary.sample(1, random: gen0))
+ assert_equal([], ary.sample(1, random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000, 4999], ary.sample(2, random: gen0))
+ assert_equal([], ary.sample(2, random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000, 4999, 5001], ary.sample(3, random: gen0))
+ assert_equal([], ary.sample(3, random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000, 4999, 5001, 4998], ary.sample(4, random: gen0))
+ assert_equal([], ary.sample(4, random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000, 4999, 5001, 4998, 5002, 4997, 5003, 4996, 5004, 4995], ary.sample(10, random: gen0))
+ assert_equal([], ary.sample(10, random: gen1))
+ assert_equal([], ary)
+ ary = (0...10000).to_a
+ assert_equal([5000, 0, 5001, 2, 5002, 4, 5003, 6, 5004, 8, 5005], ary.sample(11, random: gen0))
+ ary.sample(11, random: gen1) # implementation detail, may change in the future
+ assert_equal([], ary)
+
+ half = Object.new
+ def half.to_int
+ 5000
+ end
+ gen_to_int = proc do |max|
+ half
+ end
+ class << gen_to_int
+ alias rand call
+ end
+ ary = (0...10000).to_a
+ assert_equal(5000, ary.sample(random: gen_to_int))
+ end
+
+ def test_cycle
+ a = []
+ [0, 1, 2].cycle do |i|
+ a << i
+ break if a.size == 10
+ end
+ assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], a)
+
+ a = [0, 1, 2]
+ assert_nil(a.cycle { a.clear })
+
+ a = []
+ [0, 1, 2].cycle(3) {|i| a << i }
+ assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2], a)
+ end
+
+ def test_reverse_each2
+ a = [0, 1, 2, 3, 4, 5]
+ r = []
+ a.reverse_each do |x|
+ r << x
+ a.pop
+ a.pop
+ end
+ assert_equal([5, 3, 1], r)
+ end
+
+ def test_combination2
+ assert_equal(:called, (0..100).to_a.combination(50) { break :called }, "[ruby-core:29240] ... must be yielded even if 100C50 > signed integer")
+ end
+
+ def test_combination_clear
+ bug9939 = '[ruby-core:63149] [Bug #9939]'
+ assert_separately([], <<-'end;')
+ 100_000.times {Array.new(1000)}
+ a = [*0..100]
+ a.combination(3) {|*,x| a.clear}
+ end;
+ end
+
+ def test_product2
+ a = (0..100).to_a
+ assert_raise(RangeError) do
+ a.product(a, a, a, a, a, a, a, a, a, a)
+ end
+ assert_nothing_raised(RangeError) do
+ a.product(a, a, a, a, a, a, a, a, a, a) { break }
+ end
+ end
+
+ class Array2 < Array
+ end
+
+ def test_array_subclass
+ assert_equal(Array2, Array2[1,2,3].uniq.class, "[ruby-dev:34581]")
+ assert_equal(Array2, Array2[1,2][0,1].class) # embeded
+ assert_equal(Array2, Array2[*(1..100)][1..99].class) #not embeded
+ end
+
+ def test_inspect
+ a = @cls[1, 2, 3]
+ a.taint
+ s = a.inspect
+ assert_equal(true, s.tainted?)
+ end
+
+ def test_initialize2
+ a = [1] * 1000
+ a.instance_eval { initialize }
+ assert_equal([], a)
+ end
+
+ def test_shift_shared_ary
+ a = (1..100).to_a
+ b = []
+ b.replace(a)
+ assert_equal((1..10).to_a, a.shift(10))
+ assert_equal((11..100).to_a, a)
+ end
+
+ def test_replace_shared_ary
+ a = [1] * 100
+ b = []
+ b.replace(a)
+ a.replace([1, 2, 3])
+ assert_equal([1, 2, 3], a)
+ assert_equal([1] * 100, b)
+ end
+
+ def test_fill_negative_length
+ a = (1..10).to_a
+ a.fill(:foo, 5, -3)
+ assert_equal((1..10).to_a, a)
+ end
+
+ def test_slice_frozen_array
+ a = [1,2,3,4,5].freeze
+ assert_equal([1,2,3,4], a[0,4])
+ assert_equal([2,3,4,5], a[1,4])
+ end
+
+ def test_sort_by!
+ a = [1,3,5,2,4]
+ a.sort_by! {|x| -x }
+ assert_equal([5,4,3,2,1], a)
+ end
+
+ def test_rotate
+ a = [1,2,3,4,5].freeze
+ assert_equal([2,3,4,5,1], a.rotate)
+ assert_equal([5,1,2,3,4], a.rotate(-1))
+ assert_equal([3,4,5,1,2], a.rotate(2))
+ assert_equal([4,5,1,2,3], a.rotate(-2))
+ assert_equal([4,5,1,2,3], a.rotate(13))
+ assert_equal([3,4,5,1,2], a.rotate(-13))
+ a = [1].freeze
+ assert_equal([1], a.rotate)
+ assert_equal([1], a.rotate(2))
+ assert_equal([1], a.rotate(-4))
+ assert_equal([1], a.rotate(13))
+ assert_equal([1], a.rotate(-13))
+ a = [].freeze
+ assert_equal([], a.rotate)
+ assert_equal([], a.rotate(2))
+ assert_equal([], a.rotate(-4))
+ assert_equal([], a.rotate(13))
+ assert_equal([], a.rotate(-13))
+ a = [1,2,3]
+ assert_raise(ArgumentError) { a.rotate(1, 1) }
+ assert_equal([1,2,3,4,5].rotate(2**31-1), [1,2,3,4,5].rotate(2**31-0.1))
+ assert_equal([1,2,3,4,5].rotate(-2**31), [1,2,3,4,5].rotate(-2**31-0.9))
+ end
+
+ def test_rotate!
+ a = [1,2,3,4,5]
+ assert_equal([2,3,4,5,1], a.rotate!)
+ assert_equal([2,3,4,5,1], a)
+ assert_equal([4,5,1,2,3], a.rotate!(2))
+ assert_equal([5,1,2,3,4], a.rotate!(-4))
+ assert_equal([3,4,5,1,2], a.rotate!(13))
+ assert_equal([5,1,2,3,4], a.rotate!(-13))
+ a = [1]
+ assert_equal([1], a.rotate!)
+ assert_equal([1], a.rotate!(2))
+ assert_equal([1], a.rotate!(-4))
+ assert_equal([1], a.rotate!(13))
+ assert_equal([1], a.rotate!(-13))
+ a = []
+ assert_equal([], a.rotate!)
+ assert_equal([], a.rotate!(2))
+ assert_equal([], a.rotate!(-4))
+ assert_equal([], a.rotate!(13))
+ assert_equal([], a.rotate!(-13))
+ a = [].freeze
+ assert_raise_with_message(RuntimeError, /can\'t modify frozen/) {a.rotate!}
+ a = [1,2,3]
+ assert_raise(ArgumentError) { a.rotate!(1, 1) }
+ end
+
+ def test_bsearch_typechecks_return_values
+ assert_raise(TypeError) do
+ [1, 2, 42, 100, 666].bsearch{ "not ok" }
+ end
+ assert_equal [1, 2, 42, 100, 666].bsearch{}, [1, 2, 42, 100, 666].bsearch{false}
+ end
+
+ def test_bsearch_with_no_block
+ enum = [1, 2, 42, 100, 666].bsearch
+ assert_nil enum.size
+ assert_equal 42, enum.each{|x| x >= 33 }
+ end
+
+ def test_bsearch_in_find_minimum_mode
+ a = [0, 4, 7, 10, 12]
+ assert_equal(4, a.bsearch {|x| x >= 4 })
+ assert_equal(7, a.bsearch {|x| x >= 6 })
+ assert_equal(0, a.bsearch {|x| x >= -1 })
+ assert_equal(nil, a.bsearch {|x| x >= 100 })
+ end
+
+ def test_bsearch_in_find_any_mode
+ a = [0, 4, 7, 10, 12]
+ assert_include([4, 7], a.bsearch {|x| 1 - x / 4 })
+ assert_equal(nil, a.bsearch {|x| 4 - x / 2 })
+ assert_equal(nil, a.bsearch {|x| 1 })
+ assert_equal(nil, a.bsearch {|x| -1 })
+
+ assert_include([4, 7], a.bsearch {|x| (1 - x / 4) * (2**100) })
+ assert_equal(nil, a.bsearch {|x| 1 * (2**100) })
+ assert_equal(nil, a.bsearch {|x| (-1) * (2**100) })
+
+ assert_include([4, 7], a.bsearch {|x| (2**100).coerce((1 - x / 4) * (2**100)).first })
+ end
+
+ def test_shared_marking
+ reduce = proc do |s|
+ s.gsub(/(verify_internal_consistency_reachable_i:\sWB\smiss\s\S+\s\(T_ARRAY\)\s->\s)\S+\s\((proc|T_NONE)\)\n
+ \K(?:\1\S+\s\(\2\)\n)*/x) do
+ "...(snip #{$&.count("\n")} lines)...\n"
+ end
+ end
+ begin
+ assert_normal_exit(<<-EOS, '[Bug #9718]', timeout: 5, stdout_filter: reduce)
+ queue = []
+ 50.times do
+ 10_000.times do
+ queue << lambda{}
+ end
+ GC.start(full_mark: false, immediate_sweep: true)
+ GC.verify_internal_consistency
+ queue.shift.call
+ end
+ EOS
+ rescue Timeout::Error => e
+ skip e.message
+ end
+ end
+
+ sizeof_long = [0].pack("l!").size
+ sizeof_voidp = [""].pack("p").size
+ if sizeof_long < sizeof_voidp
+ ARY_MAX = (1<<(8*sizeof_long-1)) / sizeof_voidp - 1
+ Bug11235 = '[ruby-dev:49043] [Bug #11235]'
+
+ def test_push_over_ary_max
+ assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;")
+ a = Array.new(ARGV[0].to_i)
+ assert_raise(IndexError, ARGV[1]) {0x1000.times {a.push(1)}}
+ end;
+ end
+
+ def test_unshift_over_ary_max
+ assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;")
+ a = Array.new(ARGV[0].to_i)
+ assert_raise(IndexError, ARGV[1]) {0x1000.times {a.unshift(1)}}
+ end;
+ end
+
+ def test_splice_over_ary_max
+ assert_separately(['-', ARY_MAX.to_s, Bug11235], <<-"end;")
+ a = Array.new(ARGV[0].to_i)
+ assert_raise(IndexError, ARGV[1]) {a[0, 0] = Array.new(0x1000)}
+ end;
+ end
+ end
+
+ private
+ def need_continuation
+ unless respond_to?(:callcc, true)
+ EnvUtil.suppress_warning {require 'continuation'}
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_assignment.rb b/jni/ruby/test/ruby/test_assignment.rb
new file mode 100644
index 0000000..9c0fd48
--- /dev/null
+++ b/jni/ruby/test/ruby/test_assignment.rb
@@ -0,0 +1,760 @@
+require 'test/unit'
+
+class TestAssignment < Test::Unit::TestCase
+ def test_assign
+ a=[]; a[0] ||= "bar";
+ assert_equal("bar", a[0])
+ h={}; h["foo"] ||= "bar";
+ assert_equal("bar", h["foo"])
+
+ aa = 5
+ aa ||= 25
+ assert_equal(5, aa)
+ bb ||= 25
+ assert_equal(25, bb)
+ cc &&=33
+ assert_nil(cc)
+ cc = 5
+ cc &&=44
+ assert_equal(44, cc)
+ end
+
+ def test_assign_simple
+ a = nil; assert_nil(a)
+ a = 1; assert_equal(1, a)
+ a = []; assert_equal([], a)
+ a = [1]; assert_equal([1], a)
+ a = [nil]; assert_equal([nil], a)
+ a = [[]]; assert_equal([[]], a)
+ a = [1,2]; assert_equal([1,2], a)
+ a = [*[]]; assert_equal([], a)
+ a = [*[1]]; assert_equal([1], a)
+ a = [*[1,2]]; assert_equal([1,2], a)
+ end
+
+ def test_assign_splat
+ a = *[]; assert_equal([], a)
+ a = *[1]; assert_equal([1], a)
+ a = *[nil]; assert_equal([nil], a)
+ a = *[[]]; assert_equal([[]], a)
+ a = *[1,2]; assert_equal([1,2], a)
+ a = *[*[]]; assert_equal([], a)
+ a = *[*[1]]; assert_equal([1], a)
+ a = *[*[1,2]]; assert_equal([1,2], a)
+ end
+
+ def test_assign_ary
+ *a = nil; assert_equal([nil], a)
+ *a = 1; assert_equal([1], a)
+ *a = []; assert_equal([], a)
+ *a = [1]; assert_equal([1], a)
+ *a = [nil]; assert_equal([nil], a)
+ *a = [[]]; assert_equal([[]], a)
+ *a = [1,2]; assert_equal([1,2], a)
+ *a = [*[]]; assert_equal([], a)
+ *a = [*[1]]; assert_equal([1], a)
+ *a = [*[1,2]]; assert_equal([1,2], a)
+ end
+
+ def test_assign_ary_splat
+ *a = *[]; assert_equal([], a)
+ *a = *[1]; assert_equal([1], a)
+ *a = *[nil]; assert_equal([nil], a)
+ *a = *[[]]; assert_equal([[]], a)
+ *a = *[1,2]; assert_equal([1,2], a)
+ *a = *[*[]]; assert_equal([], a)
+ *a = *[*[1]]; assert_equal([1], a)
+ *a = *[*[1,2]]; assert_equal([1,2], a)
+ end
+
+ def test_massign_simple
+ a,b,*c = nil; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = 1; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = []; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = [1]; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = [nil]; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = [[]]; assert_equal([[],nil,[]], [a,b,c])
+ a,b,*c = [1,2]; assert_equal([1,2,[]], [a,b,c])
+ a,b,*c = [*[]]; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = [*[1]]; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = [*[1,2]]; assert_equal([1,2,[]], [a,b,c])
+ end
+
+ def test_massign_splat
+ a,b,*c = *[]; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = *[1]; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = *[nil]; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = *[[]]; assert_equal([[],nil,[]], [a,b,c])
+ a,b,*c = *[1,2]; assert_equal([1,2,[]], [a,b,c])
+ a,b,*c = *[*[]]; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = *[*[1]]; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c])
+ end
+
+ def test_assign_abbreviated
+ bug2050 = '[ruby-core:25629]'
+ a = Hash.new {[]}
+ b = [1, 2]
+ assert_equal([1, 2, 3], a[:x] += [*b, 3], bug2050)
+ assert_equal([1, 2, 3], a[:x], bug2050)
+ assert_equal([1, 2, 3, [1, 2, 3]], a[:x] <<= [*b, 3], bug2050)
+ assert_equal([1, 2, 3, [1, 2, 3]], a[:x], bug2050)
+ end
+
+ def test_assign_private_self
+ bug9907 = '[ruby-core:62949] [Bug #9907]'
+
+ o = Object.new
+ class << o
+ private
+ def foo; 42; end
+ def [](i); 42; end
+ def foo=(a); 42; end
+ def []=(i, a); 42; end
+ end
+
+ assert_raise(NoMethodError) {
+ o.instance_eval {o.foo = 1}
+ }
+ assert_nothing_raised(NoMethodError) {
+ assert_equal(1, o.instance_eval {self.foo = 1})
+ }
+
+ assert_raise(NoMethodError) {
+ o.instance_eval {o[0] = 1}
+ }
+ assert_nothing_raised(NoMethodError) {
+ assert_equal(1, o.instance_eval {self[0] = 1})
+ }
+
+ assert_nothing_raised(NoMethodError, bug9907) {
+ assert_equal(43, o.instance_eval {self.foo += 1})
+ }
+ assert_nothing_raised(NoMethodError, bug9907) {
+ assert_equal(1, o.instance_eval {self.foo &&= 1})
+ }
+
+ assert_nothing_raised(NoMethodError, bug9907) {
+ assert_equal(43, o.instance_eval {self[0] += 1})
+ }
+ assert_nothing_raised(NoMethodError, bug9907) {
+ assert_equal(1, o.instance_eval {self[0] &&= 1})
+ }
+ end
+
+ def test_yield
+ def f; yield(nil); end; f {|a| assert_nil(a)}; undef f
+ def f; yield(1); end; f {|a| assert_equal(1, a)}; undef f
+ def f; yield([]); end; f {|a| assert_equal([], a)}; undef f
+ def f; yield([1]); end; f {|a| assert_equal([1], a)}; undef f
+ def f; yield([nil]); end; f {|a| assert_equal([nil], a)}; undef f
+ def f; yield([[]]); end; f {|a| assert_equal([[]], a)}; undef f
+ def f; yield([*[]]); end; f {|a| assert_equal([], a)}; undef f
+ def f; yield([*[1]]); end; f {|a| assert_equal([1], a)}; undef f
+ def f; yield([*[1,2]]); end; f {|a| assert_equal([1,2], a)}; undef f
+
+ def f; yield(*[1]); end; f {|a| assert_equal(1, a)}; undef f
+ def f; yield(*[nil]); end; f {|a| assert_equal(nil, a)}; undef f
+ def f; yield(*[[]]); end; f {|a| assert_equal([], a)}; undef f
+ def f; yield(*[*[1]]); end; f {|a| assert_equal(1, a)}; undef f
+
+ def f; yield; end; f {|*a| assert_equal([], a)}; undef f
+ def f; yield(nil); end; f {|*a| assert_equal([nil], a)}; undef f
+ def f; yield(1); end; f {|*a| assert_equal([1], a)}; undef f
+ def f; yield([]); end; f {|*a| assert_equal([[]], a)}; undef f
+ def f; yield([1]); end; f {|*a| assert_equal([[1]], a)}; undef f
+ def f; yield([nil]); end; f {|*a| assert_equal([[nil]], a)}; undef f
+ def f; yield([[]]); end; f {|*a| assert_equal([[[]]], a)}; undef f
+ def f; yield([1,2]); end; f {|*a| assert_equal([[1,2]], a)}; undef f
+ def f; yield([*[]]); end; f {|*a| assert_equal([[]], a)}; undef f
+ def f; yield([*[1]]); end; f {|*a| assert_equal([[1]], a)}; undef f
+ def f; yield([*[1,2]]); end; f {|*a| assert_equal([[1,2]], a)}; undef f
+
+ def f; yield(*[]); end; f {|*a| assert_equal([], a)}; undef f
+ def f; yield(*[1]); end; f {|*a| assert_equal([1], a)}; undef f
+ def f; yield(*[nil]); end; f {|*a| assert_equal([nil], a)}; undef f
+ def f; yield(*[[]]); end; f {|*a| assert_equal([[]], a)}; undef f
+ def f; yield(*[*[]]); end; f {|*a| assert_equal([], a)}; undef f
+ def f; yield(*[*[1]]); end; f {|*a| assert_equal([1], a)}; undef f
+ def f; yield(*[*[1,2]]); end; f {|*a| assert_equal([1,2], a)}; undef f
+
+ def f; yield; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(nil); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(1); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
+ def f; yield([]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield([1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
+ def f; yield([nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield([[]]); end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])}; undef f
+ def f; yield([*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield([*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
+ def f; yield([*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f
+
+ def f; yield(*[]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
+ def f; yield(*[*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f
+ end
+
+ def test_return
+ def r; return; end; a = r(); assert_nil(a); undef r
+ def r; return nil; end; a = r(); assert_nil(a); undef r
+ def r; return 1; end; a = r(); assert_equal(1, a); undef r
+ def r; return []; end; a = r(); assert_equal([], a); undef r
+ def r; return [1]; end; a = r(); assert_equal([1], a); undef r
+ def r; return [nil]; end; a = r(); assert_equal([nil], a); undef r
+ def r; return [[]]; end; a = r(); assert_equal([[]], a); undef r
+ def r; return [*[]]; end; a = r(); assert_equal([], a); undef r
+ def r; return [*[1]]; end; a = r(); assert_equal([1], a); undef r
+ def r; return [*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r
+
+ def r; return *[]; end; a = r(); assert_equal([], a); undef r
+ def r; return *[1]; end; a = r(); assert_equal([1], a); undef r
+ def r; return *[nil]; end; a = r(); assert_equal([nil], a); undef r
+ def r; return *[[]]; end; a = r(); assert_equal([[]], a); undef r
+ def r; return *[*[]]; end; a = r(); assert_equal([], a); undef r
+ def r; return *[*[1]]; end; a = r(); assert_equal([1], a); undef r
+ def r; return *[*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r
+
+ def r; return *[[]]; end; a = *r(); assert_equal([[]], a); undef r
+ def r; return *[*[1,2]]; end; a = *r(); assert_equal([1,2], a); undef r
+
+ def r; return; end; *a = r(); assert_equal([nil], a); undef r
+ def r; return nil; end; *a = r(); assert_equal([nil], a); undef r
+ def r; return 1; end; *a = r(); assert_equal([1], a); undef r
+ def r; return []; end; *a = r(); assert_equal([], a); undef r
+ def r; return [1]; end; *a = r(); assert_equal([1], a); undef r
+ def r; return [nil]; end; *a = r(); assert_equal([nil], a); undef r
+ def r; return [[]]; end; *a = r(); assert_equal([[]], a); undef r
+ def r; return [1,2]; end; *a = r(); assert_equal([1,2], a); undef r
+ def r; return [*[]]; end; *a = r(); assert_equal([], a); undef r
+ def r; return [*[1]]; end; *a = r(); assert_equal([1], a); undef r
+ def r; return [*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r
+
+ def r; return *[]; end; *a = r(); assert_equal([], a); undef r
+ def r; return *[1]; end; *a = r(); assert_equal([1], a); undef r
+ def r; return *[nil]; end; *a = r(); assert_equal([nil], a); undef r
+ def r; return *[[]]; end; *a = r(); assert_equal([[]], a); undef r
+ def r; return *[1,2]; end; *a = r(); assert_equal([1,2], a); undef r
+ def r; return *[*[]]; end; *a = r(); assert_equal([], a); undef r
+ def r; return *[*[1]]; end; *a = r(); assert_equal([1], a); undef r
+ def r; return *[*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r
+
+ def r; return *[[]]; end; *a = *r(); assert_equal([[]], a); undef r
+ def r; return *[1,2]; end; *a = *r(); assert_equal([1,2], a); undef r
+ def r; return *[*[1,2]]; end; *a = *r(); assert_equal([1,2], a); undef r
+
+ def r; return; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return 1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
+ def r; return []; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return [1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
+ def r; return [nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return [[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r
+ def r; return [1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
+ def r; return [*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return [*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
+ def r; return [*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
+
+ def r; return *[]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return *[1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
+ def r; return *[nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return *[[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r
+ def r; return *[1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
+ def r; return *[*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
+ def r; return *[*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
+ def r; return *[*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
+
+ def r; return 1, *[]; end; a,b = r(); assert_equal([1,nil], [a,b]); undef r
+ def r; return 1,2,*[1]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r
+ def r; return 1,2,3,*[1,2]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r
+ end
+
+ def test_lambda
+ f = lambda {|r,| assert_equal([], r)}
+ f.call([], *[])
+
+ f = lambda {|r,*l| assert_equal([], r); assert_equal([1], l)}
+ f.call([], *[1])
+
+ f = lambda{|x| x}
+ assert_equal(42, f.call(42))
+ assert_equal([42], f.call([42]))
+ assert_equal([[42]], f.call([[42]]))
+ assert_equal([42,55], f.call([42,55]))
+
+ f = lambda{|x,| x}
+ assert_equal(42, f.call(42))
+ assert_equal([42], f.call([42]))
+ assert_equal([[42]], f.call([[42]]))
+ assert_equal([42,55], f.call([42,55]))
+
+ f = lambda{|*x| x}
+ assert_equal([42], f.call(42))
+ assert_equal([[42]], f.call([42]))
+ assert_equal([[[42]]], f.call([[42]]))
+ assert_equal([[42,55]], f.call([42,55]))
+ assert_equal([42,55], f.call(42,55))
+ end
+
+ def test_multi
+ a,=*[1]
+ assert_equal(1, a)
+ a,=*[[1]]
+ assert_equal([1], a)
+ a,=*[[[1]]]
+ assert_equal([[1]], a)
+
+ x, (y, z) = 1, 2, 3
+ assert_equal([1,2,nil], [x,y,z])
+ x, (y, z) = 1, [2,3]
+ assert_equal([1,2,3], [x,y,z])
+ x, (y, z) = 1, [2]
+ assert_equal([1,2,nil], [x,y,z])
+ end
+
+ def test_break
+ a = loop do break; end; assert_nil(a)
+ a = loop do break nil; end; assert_nil(a)
+ a = loop do break 1; end; assert_equal(1, a)
+ a = loop do break []; end; assert_equal([], a)
+ a = loop do break [1]; end; assert_equal([1], a)
+ a = loop do break [nil]; end; assert_equal([nil], a)
+ a = loop do break [[]]; end; assert_equal([[]], a)
+ a = loop do break [*[]]; end; assert_equal([], a)
+ a = loop do break [*[1]]; end; assert_equal([1], a)
+ a = loop do break [*[1,2]]; end; assert_equal([1,2], a)
+
+ a = loop do break *[]; end; assert_equal([], a)
+ a = loop do break *[1]; end; assert_equal([1], a)
+ a = loop do break *[nil]; end; assert_equal([nil], a)
+ a = loop do break *[[]]; end; assert_equal([[]], a)
+ a = loop do break *[*[]]; end; assert_equal([], a)
+ a = loop do break *[*[1]]; end; assert_equal([1], a)
+ a = loop do break *[*[1,2]]; end; assert_equal([1,2], a)
+
+ *a = loop do break; end; assert_equal([nil], a)
+ *a = loop do break nil; end; assert_equal([nil], a)
+ *a = loop do break 1; end; assert_equal([1], a)
+ *a = loop do break []; end; assert_equal([], a)
+ *a = loop do break [1]; end; assert_equal([1], a)
+ *a = loop do break [nil]; end; assert_equal([nil], a)
+ *a = loop do break [[]]; end; assert_equal([[]], a)
+ *a = loop do break [1,2]; end; assert_equal([1,2], a)
+ *a = loop do break [*[]]; end; assert_equal([], a)
+ *a = loop do break [*[1]]; end; assert_equal([1], a)
+ *a = loop do break [*[1,2]]; end; assert_equal([1,2], a)
+
+ *a = loop do break *[]; end; assert_equal([], a)
+ *a = loop do break *[1]; end; assert_equal([1], a)
+ *a = loop do break *[nil]; end; assert_equal([nil], a)
+ *a = loop do break *[[]]; end; assert_equal([[]], a)
+ *a = loop do break *[1,2]; end; assert_equal([1,2], a)
+ *a = loop do break *[*[]]; end; assert_equal([], a)
+ *a = loop do break *[*[1]]; end; assert_equal([1], a)
+ *a = loop do break *[*[1,2]]; end; assert_equal([1,2], a)
+
+ *a = *loop do break *[[]]; end; assert_equal([[]], a)
+ *a = *loop do break *[1,2]; end; assert_equal([1,2], a)
+ *a = *loop do break *[*[1,2]]; end; assert_equal([1,2], a)
+
+ a,b,*c = loop do break; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break nil; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break 1; end; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = loop do break []; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break [1]; end; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = loop do break [nil]; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break [[]]; end; assert_equal([[],nil,[]], [a,b,c])
+ a,b,*c = loop do break [1,2]; end; assert_equal([1,2,[]], [a,b,c])
+ a,b,*c = loop do break [*[]]; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break [*[1]]; end; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = loop do break [*[1,2]]; end; assert_equal([1,2,[]], [a,b,c])
+
+ a,b,*c = loop do break *[]; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break *[1]; end; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = loop do break *[nil]; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break *[[]]; end; assert_equal([[],nil,[]], [a,b,c])
+ a,b,*c = loop do break *[1,2]; end; assert_equal([1,2,[]], [a,b,c])
+ a,b,*c = loop do break *[*[]]; end; assert_equal([nil,nil,[]], [a,b,c])
+ a,b,*c = loop do break *[*[1]]; end; assert_equal([1,nil,[]], [a,b,c])
+ a,b,*c = loop do break *[*[1,2]]; end; assert_equal([1,2,[]], [a,b,c])
+ end
+
+ def test_next
+ def r(val); a = yield(); assert_equal(val, a); end
+ r(nil){next}
+ r(nil){next nil}
+ r(1){next 1}
+ r([]){next []}
+ r([1]){next [1]}
+ r([nil]){next [nil]}
+ r([[]]){next [[]]}
+ r([]){next [*[]]}
+ r([1]){next [*[1]]}
+ r([1,2]){next [*[1,2]]}
+
+ r([]){next *[]}
+ r([1]){next *[1]}
+ r([nil]){next *[nil]}
+ r([[]]){next *[[]]}
+ r([]){next *[*[]]}
+ r([1]){next *[*[1]]}
+ r([1,2]){next *[*[1,2]]}
+ undef r
+
+ def r(val); *a = yield(); assert_equal(val, a); end
+ r([nil]){next}
+ r([nil]){next nil}
+ r([1]){next 1}
+ r([]){next []}
+ r([1]){next [1]}
+ r([nil]){next [nil]}
+ r([[]]){next [[]]}
+ r([1,2]){next [1,2]}
+ r([]){next [*[]]}
+ r([1]){next [*[1]]}
+ r([1,2]){next [*[1,2]]}
+ undef r
+
+ def r(val); *a = *yield(); assert_equal(val, a); end
+ r([[]]){next *[[]]}
+ r([1,2]){next *[1,2]}
+ r([1,2]){next *[*[1,2]]}
+ undef r
+
+ def r(val); a,b,*c = yield(); assert_equal(val, [a,b,c]); end
+ r([nil,nil,[]]){next}
+ r([nil,nil,[]]){next nil}
+ r([1,nil,[]]){next 1}
+ r([nil,nil,[]]){next []}
+ r([1,nil,[]]){next [1]}
+ r([nil,nil,[]]){next [nil]}
+ r([[],nil,[]]){next [[]]}
+ r([1,2,[]]){next [1,2]}
+ r([nil,nil,[]]){next [*[]]}
+ r([1,nil,[]]){next [*[1]]}
+ r([1,2,[]]){next [*[1,2]]}
+ undef r
+
+ def r(val); a,b,*c = *yield(); assert_equal(val, [a,b,c]); end
+ r([[],nil,[]]){next *[[]]}
+ r([1,2,[]]){next *[1,2]}
+ r([1,2,[]]){next *[*[1,2]]}
+ undef r
+ end
+
+ def test_massign
+ a = nil
+ assert(defined?(a))
+ assert_nil(a)
+
+ # multiple asignment
+ a, b = 1, 2
+ assert_equal 1, a
+ assert_equal 2, b
+
+ a, b, c = 1, 2, 3
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+
+ a = 1
+ b = 2
+ a, b = b, a
+ assert_equal 2, a
+ assert_equal 1, b
+
+ a, = 1, 2
+ assert_equal 1, a
+
+ a, = 1, 2, 3
+ assert_equal 1, a
+
+ a, * = 1, 2, 3
+ assert_equal 1, a
+
+ a, *b = 1, 2, 3
+ assert_equal 1, a
+ assert_equal [2, 3], b
+
+ # not supported yet
+ #a, *b, c = 1, 2, 3, 4
+ #assert_equal 1, a
+ #assert_equal [2,3], b
+ #assert_equal 4, c
+
+ a = 1, 2
+ assert_equal [1, 2], a
+
+ a = [1, 2], [3, 4]
+ assert_equal [[1,2], [3,4]], a
+
+ a, (b, c), d = 1, [2, 3], 4
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+ assert_equal 4, d
+
+ *a = 1, 2, 3
+ assert_equal([1, 2, 3], a)
+
+ *a = 4
+ assert_equal([4], a)
+
+ *a = nil
+ assert_equal([nil], a)
+
+ a, b = 1
+ assert_equal 1, a
+ assert_nil b
+
+ a, b = [1, 2]
+ assert_equal 1, a
+ assert_equal 2, b
+ end
+
+ def test_nested_massign
+ (a, b), c = [[1, 2], 3]; assert_equal [1,2,3], [a,b,c]
+ a, (b, c) = [[1, 2], 3]; assert_equal [[1,2], 3, nil], [a,b,c]
+ a, (b, c) = [1, [2, 3]]; assert_equal [1,2,3], [a,b,c]
+ (a, b), *c = [[1, 2], 3]; assert_equal [1,2,[3]], [a,b,c]
+ (a,b),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,3,4,5],[a,b,c,d,e]
+ (a,*b),c,(d,e,*) = [[1,2],3,[4,5]]; assert_equal [1,[2],3,4,5],[a,b,c,d,e]
+ (a,b),c,(d,*e) = [[1,2,3],4,[5,6,7,8]]; assert_equal [1,2,4,5,[6,7,8]],[a,b,c,d,e]
+ (a,(b1,b2)),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,nil,3,4,5],[a,b1,b2,c,d,e]
+ (a,(b1,b2)),c,(d,e) = [[1,[21,22]],3,[4,5]]; assert_equal [1,21,22,3,4,5],[a,b1,b2,c,d,e]
+ end
+
+ class MyObj
+ def to_ary
+ [[1,2],[3,4]]
+ end
+ end
+
+ def test_to_ary_splat
+ a, b = MyObj.new
+ assert_equal [[1,2],[3,4]], [a,b]
+ end
+
+ A = 1
+ B = 2
+ X, Y = A, B
+ class Base
+ A = 3
+ B = 4
+ end
+
+ def test_const_massign
+ assert_equal [1,2], [X,Y]
+ a, b = Base::A, Base::B
+ assert_equal [3,4], [a,b]
+ end
+end
+
+require_relative 'sentence'
+class TestAssignmentGen < Test::Unit::TestCase
+ Syntax = {
+ :exp => [["0"],
+ ["nil"],
+ ["false"],
+ ["[]"],
+ ["[",:exps,"]"]],
+ :exps => [[:exp],
+ [:exp,",",:exps]],
+ :arg => [[:exp]],
+ :mrhs => [[:args,",",:arg],
+ [:args,",","*",:arg],
+ ["*",:arg]],
+ :args => [[:arg],
+ ["*",:arg],
+ [:args,",",:arg],
+ [:args,",","*",:arg]],
+ :mlhs => [[:mlhs_basic],
+ ["(",:mlhs_inner,")"]],
+ :mlhs_inner => [[:mlhs_basic],
+ ["(",:mlhs_inner,")"]],
+ :mlhs_basic => [[:mlhs_head],
+ [:mlhs_head,:mlhs_item],
+ [:mlhs_head,"*",:mlhs_node],
+ [:mlhs_head,"*",:mlhs_node,",",:mlhs_post],
+ [:mlhs_head,"*"],
+ [:mlhs_head,"*",",", :mlhs_post],
+ [ "*",:mlhs_node],
+ [ "*",:mlhs_node,",",:mlhs_post],
+ [ "*"],
+ [ "*",",", :mlhs_post]],
+ :mlhs_head => [[:mlhs_item,","],
+ [:mlhs_head,:mlhs_item,","]],
+ :mlhs_post => [[:mlhs_item],
+ [:mlhs_post,",",:mlhs_item]],
+ :mlhs_item => [[:mlhs_node],
+ ["(",:mlhs_inner,")"]],
+ :mlhs_node => [["var"]],
+ :xassign => [["var"," = ",:exp],
+ ["var"," = ",:mrhs],
+ [:mlhs," = ",:exp],
+ [:mlhs," = ",:mrhs]],
+ }
+
+ def rename_var(obj)
+ vars = []
+ r = obj.subst('var') {
+ var = "v#{vars.length}"
+ vars << var
+ var
+ }
+ return r, vars
+ end
+
+ def expand_except_paren(obj)
+ return obj if obj.respond_to? :to_str
+ obj.expand {|s|
+ !(s[0] == '(' && s[-1] == ')') &&
+ !(s[0] == '[' && s[-1] == ']')
+ }
+ end
+
+ def extract_single_element(ary)
+ raise "not a single element array: #{ary.inspect}" if ary.length != 1
+ ary[0]
+ end
+
+ def emu_assign_ary(lhs, rv, h)
+ rv = rv.respond_to?(:to_ary) ? rv : [rv]
+ rv = rv.dup
+ a = [[]]
+ lhs.each {|e|
+ if e == ','
+ a << []
+ else
+ a.last << e
+ end
+ }
+ a.pop if a.last == []
+ pre = []
+ star = post = nil
+ a.each {|e|
+ if post
+ post << e
+ elsif e[0] == '*'
+ star = e
+ post = []
+ else
+ pre << e
+ end
+ }
+ pre.map! {|e| extract_single_element(e) }
+ if star
+ if star == ['*']
+ star = nil
+ else
+ star = extract_single_element(star[1..-1])
+ end
+ end
+ post.map! {|e| extract_single_element(e) } if post
+
+ until pre.empty?
+ emu_assign_single(pre.shift, rv.shift, h)
+ end
+
+ if post
+ if rv.length < post.length
+ until post.empty?
+ emu_assign_single(post.shift, rv.shift, h)
+ end
+ else
+ until post.empty?
+ emu_assign_single(post.pop, rv.pop, h)
+ end
+ end
+ end
+
+ if star
+ emu_assign_single(star, rv, h)
+ end
+ end
+
+ def emu_assign_single(lhs, rv, h={})
+ if lhs.respond_to? :to_str
+ if /\A[a-z0-9]+\z/ =~ lhs
+ h[lhs] = rv
+ else
+ raise "unexpected lhs string: #{lhs.inspect}"
+ end
+ elsif Sentence === lhs
+ if lhs[0] == '(' && lhs[-1] == ')'
+ emu_assign_ary(lhs[1...-1], rv, h)
+ elsif lhs.length == 1 && String === lhs[0] && /\A[a-z0-9]+\z/ =~ lhs[0]
+ h[lhs[0]] = rv
+ else
+ raise "unexpected lhs sentence: #{lhs.inspect}"
+ end
+ else
+ raise "unexpected lhs: #{lhs.inspect}"
+ end
+ h
+ end
+
+ def emu_assign(assign)
+ lhs = expand_except_paren(assign[0])
+ rhs = expand_except_paren(assign[2])
+ lopen = Sentence === lhs && lhs[-1] != ')' && lhs.any? {|e| e == '*' || e == ',' }
+ ropen = Sentence === rhs && rhs[-1] != ']' && rhs.any? {|e| e == '*' || e == ',' }
+ lhs = Sentence.new(['(']+lhs.to_a+[')']) if lopen
+ begin
+ rv = eval((ropen ? ["[",assign[2],"]"] : assign[2]).join(''))
+ rescue Exception
+ rv = $!.message
+ end
+ emu_assign_single(lhs, rv)
+ end
+
+ def do_assign(assign, vars)
+ assign = assign.to_s
+ code1 = "#{assign}; [#{vars.join(",")}]"
+ assign.gsub!(/\bv\d+\b/, "o.a")
+ code2 = "o=[];class << o; self end.send(:define_method,:a=){|v|self << v};#{assign};o"
+ begin
+ vals1 = eval(code1)
+ rescue Exception
+ return {:ex=>$!.message}
+ end
+ begin
+ vals2 = eval(code2)
+ rescue Exception
+ return {:ex=>$!.message}
+ end
+ assert_equal(vals1, vals2, code1)
+ vals = vals1
+ h = {}
+ [vars, vals].transpose.each {|k,v| h[k] = v }
+ h
+ end
+
+ def check(assign)
+ assign, vars = rename_var(assign)
+ sent = assign.to_s
+ bruby = do_assign(assign, vars).to_a.sort
+ bemu = emu_assign(assign).to_a.sort
+ assert_equal(bemu, bruby, sent)
+ end
+
+ def test_assignment
+ syntax = Sentence.expand_syntax(Syntax)
+ Sentence.each(syntax, :xassign, 4) {|assign|
+ check(assign)
+ }
+ end
+
+ def test_optimized_aset
+ bug9448 = Class.new do
+ def []=(key, new_value)
+ '[ruby-core:60071] [Bug #9448]'
+ end
+ end
+ o = bug9448.new
+ assert_equal("ok", o['current'] = "ok")
+ end
+end
diff --git a/jni/ruby/test/ruby/test_autoload.rb b/jni/ruby/test/ruby/test_autoload.rb
new file mode 100644
index 0000000..da8855b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_autoload.rb
@@ -0,0 +1,207 @@
+require 'test/unit'
+require 'tempfile'
+require 'thread'
+
+class TestAutoload < Test::Unit::TestCase
+ def test_autoload_so
+ # Date is always available, unless excluded intentionally.
+ assert_in_out_err([], <<-INPUT, [], [])
+ autoload :Date, "date"
+ begin Date; rescue LoadError; end
+ INPUT
+ end
+
+ def test_non_realpath_in_loadpath
+ require 'tmpdir'
+ tmpdir = Dir.mktmpdir('autoload')
+ tmpdirs = [tmpdir]
+ tmpdirs.unshift(tmpdir + '/foo')
+ Dir.mkdir(tmpdirs[0])
+ tmpfiles = [tmpdir + '/foo.rb', tmpdir + '/foo/bar.rb']
+ open(tmpfiles[0] , 'w') do |f|
+ f.puts <<-INPUT
+$:.unshift(File.expand_path('..', __FILE__)+'/./foo')
+module Foo
+ autoload :Bar, 'bar'
+end
+p Foo::Bar
+ INPUT
+ end
+ open(tmpfiles[1], 'w') do |f|
+ f.puts 'class Foo::Bar; end'
+ end
+ assert_in_out_err([tmpfiles[0]], "", ["Foo::Bar"], [])
+ ensure
+ File.unlink(*tmpfiles) rescue nil if tmpfiles
+ tmpdirs.each {|dir| Dir.rmdir(dir)}
+ end
+
+ def test_autoload_p
+ bug4565 = '[ruby-core:35679]'
+
+ require 'tmpdir'
+ Dir.mktmpdir('autoload') {|tmpdir|
+ tmpfile = tmpdir + '/foo.rb'
+ a = Module.new do
+ autoload :X, tmpfile
+ end
+ b = Module.new do
+ include a
+ end
+ assert_equal(true, a.const_defined?(:X))
+ assert_equal(true, b.const_defined?(:X))
+ assert_equal(tmpfile, a.autoload?(:X), bug4565)
+ assert_equal(tmpfile, b.autoload?(:X), bug4565)
+ }
+ end
+
+ def test_autoload_with_unqualified_file_name # [ruby-core:69206]
+ lp = $LOAD_PATH.dup
+ lf = $LOADED_FEATURES.dup
+
+ Dir.mktmpdir('autoload') { |tmpdir|
+ $LOAD_PATH << tmpdir
+
+ Dir.chdir(tmpdir) do
+ eval <<-END
+ class ::Object
+ module A
+ autoload :C, 'b'
+ end
+ end
+ END
+
+ File.open('b.rb', 'w') {|file| file.puts 'module A; class C; end; end'}
+ assert_kind_of Class, ::A::C
+ end
+ }
+ ensure
+ $LOAD_PATH.replace lp
+ $LOADED_FEATURES.replace lf
+ Object.send(:remove_const, :A) if Object.const_defined?(:A)
+ end
+
+ def test_require_explicit
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts 'class Object; AutoloadTest = 1; end'
+ file.close
+ add_autoload(file.path)
+ begin
+ assert_nothing_raised do
+ assert(require file.path)
+ assert_equal(1, ::AutoloadTest)
+ end
+ ensure
+ remove_autoload_constant
+ end
+ }
+ end
+
+ def test_threaded_accessing_constant
+ # Suppress "warning: loading in progress, circular require considered harmful"
+ EnvUtil.default_warning {
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts 'sleep 0.5; class AutoloadTest; X = 1; end'
+ file.close
+ add_autoload(file.path)
+ begin
+ assert_nothing_raised do
+ t1 = Thread.new { ::AutoloadTest::X }
+ t2 = Thread.new { ::AutoloadTest::X }
+ [t1, t2].each(&:join)
+ end
+ ensure
+ remove_autoload_constant
+ end
+ }
+ }
+ end
+
+ def test_threaded_accessing_inner_constant
+ # Suppress "warning: loading in progress, circular require considered harmful"
+ EnvUtil.default_warning {
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts 'class AutoloadTest; sleep 0.5; X = 1; end'
+ file.close
+ add_autoload(file.path)
+ begin
+ assert_nothing_raised do
+ t1 = Thread.new { ::AutoloadTest::X }
+ t2 = Thread.new { ::AutoloadTest::X }
+ [t1, t2].each(&:join)
+ end
+ ensure
+ remove_autoload_constant
+ end
+ }
+ }
+ end
+
+ def test_nameerror_when_autoload_did_not_define_the_constant
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts ''
+ file.close
+ add_autoload(file.path)
+ begin
+ assert_raise(NameError) do
+ AutoloadTest
+ end
+ ensure
+ remove_autoload_constant
+ end
+ }
+ end
+
+ def test_override_autoload
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts ''
+ file.close
+ add_autoload(file.path)
+ begin
+ eval %q(class AutoloadTest; end)
+ assert_equal(Class, AutoloadTest.class)
+ ensure
+ remove_autoload_constant
+ end
+ }
+ end
+
+ def test_override_while_autoloading
+ Tempfile.create(['autoload', '.rb']) {|file|
+ file.puts 'class AutoloadTest; sleep 0.5; end'
+ file.close
+ add_autoload(file.path)
+ begin
+ # while autoloading...
+ t = Thread.new { AutoloadTest }
+ sleep 0.1
+ # override it
+ EnvUtil.suppress_warning {
+ eval %q(AutoloadTest = 1)
+ }
+ t.join
+ assert_equal(1, AutoloadTest)
+ ensure
+ remove_autoload_constant
+ end
+ }
+ end
+
+ def add_autoload(path)
+ (@autoload_paths ||= []) << path
+ eval <<-END
+ class ::Object
+ autoload :AutoloadTest, #{path.dump}
+ end
+ END
+ end
+
+ def remove_autoload_constant
+ $".replace($" - @autoload_paths)
+ eval <<-END
+ class ::Object
+ remove_const(:AutoloadTest)
+ end
+ END
+ end
+end
diff --git a/jni/ruby/test/ruby/test_backtrace.rb b/jni/ruby/test/ruby/test_backtrace.rb
new file mode 100644
index 0000000..ad1ea80
--- /dev/null
+++ b/jni/ruby/test/ruby/test_backtrace.rb
@@ -0,0 +1,246 @@
+require 'test/unit'
+require 'thread'
+
+class TestBacktrace < Test::Unit::TestCase
+ def test_exception
+ bt = Fiber.new{
+ begin
+ raise
+ rescue => e
+ e.backtrace
+ end
+ }.resume
+ assert_equal(1, bt.size)
+ assert_match(/.+:\d+:.+/, bt[0])
+ end
+
+ def helper_test_exception_backtrace_locations
+ raise
+ end
+
+ def test_exception_backtrace_locations
+ backtrace, backtrace_locations = Fiber.new{
+ begin
+ raise
+ rescue => e
+ [e.backtrace, e.backtrace_locations]
+ end
+ }.resume
+ assert_equal(backtrace, backtrace_locations.map{|e| e.to_s})
+
+ backtrace, backtrace_locations = Fiber.new{
+ begin
+ begin
+ helper_test_exception_backtrace_locations
+ rescue
+ raise
+ end
+ rescue => e
+ [e.backtrace, e.backtrace_locations]
+ end
+ }.resume
+ assert_equal(backtrace, backtrace_locations.map{|e| e.to_s})
+ end
+
+ def call_helper_test_exception_backtrace_locations
+ helper_test_exception_backtrace_locations(:bad_argument)
+ end
+
+ def test_argument_error_backtrace_locations
+ backtrace, backtrace_locations = Fiber.new{
+ begin
+ helper_test_exception_backtrace_locations(1)
+ rescue ArgumentError => e
+ [e.backtrace, e.backtrace_locations]
+ end
+ }.resume
+ assert_equal(backtrace, backtrace_locations.map{|e| e.to_s})
+
+ backtrace, backtrace_locations = Fiber.new{
+ begin
+ call_helper_test_exception_backtrace_locations
+ rescue ArgumentError => e
+ [e.backtrace, e.backtrace_locations]
+ end
+ }.resume
+ assert_equal(backtrace, backtrace_locations.map{|e| e.to_s})
+ end
+
+ def test_caller_lev
+ cs = []
+ Fiber.new{
+ Proc.new{
+ cs << caller(0)
+ cs << caller(1)
+ cs << caller(2)
+ cs << caller(3)
+ cs << caller(4)
+ cs << caller(5)
+ }.call
+ }.resume
+ assert_equal(3, cs[0].size)
+ assert_equal(2, cs[1].size)
+ assert_equal(1, cs[2].size)
+ assert_equal(0, cs[3].size)
+ assert_equal(nil, cs[4])
+
+ #
+ max = 7
+ rec = lambda{|n|
+ if n > 0
+ 1.times{
+ rec[n-1]
+ }
+ else
+ (max*3).times{|i|
+ total_size = caller(0).size
+ c = caller(i)
+ if c
+ assert_equal(total_size - i, caller(i).size, "[ruby-dev:45673]")
+ end
+ }
+ end
+ }
+ Fiber.new{
+ rec[max]
+ }.resume
+ end
+
+ def test_caller_lev_and_n
+ m = 10
+ rec = lambda{|n|
+ if n < 0
+ (m*6).times{|lev|
+ (m*6).times{|i|
+ t = caller(0).size
+ r = caller(lev, i)
+ r = r.size if r.respond_to? :size
+
+ # STDERR.puts [t, lev, i, r].inspect
+ if i == 0
+ assert_equal(0, r, [t, lev, i, r].inspect)
+ elsif t < lev
+ assert_equal(nil, r, [t, lev, i, r].inspect)
+ else
+ if t - lev > i
+ assert_equal(i, r, [t, lev, i, r].inspect)
+ else
+ assert_equal(t - lev, r, [t, lev, i, r].inspect)
+ end
+ end
+ }
+ }
+ else
+ rec[n-1]
+ end
+ }
+ rec[m]
+ end
+
+ def test_caller_with_nil_length
+ assert_equal caller(0), caller(0, nil)
+ end
+
+ def test_caller_locations
+ cs = caller(0); locs = caller_locations(0).map{|loc|
+ loc.to_s
+ }
+ assert_equal(cs, locs)
+ end
+
+ def test_caller_locations_with_range
+ cs = caller(0,2); locs = caller_locations(0..1).map { |loc|
+ loc.to_s
+ }
+ assert_equal(cs, locs)
+ end
+
+ def test_caller_locations_to_s_inspect
+ cs = caller(0); locs = caller_locations(0)
+ cs.zip(locs){|str, loc|
+ assert_equal(str, loc.to_s)
+ assert_equal(str.inspect, loc.inspect)
+ }
+ end
+
+ def th_rec q, n=10
+ if n > 1
+ th_rec q, n-1
+ else
+ q.pop
+ end
+ end
+
+ def test_thread_backtrace
+ begin
+ q = Queue.new
+ th = Thread.new{
+ th_rec q
+ }
+ sleep 0.5
+ th_backtrace = th.backtrace
+ th_locations = th.backtrace_locations
+
+ assert_equal(10, th_backtrace.count{|e| e =~ /th_rec/})
+ assert_equal(th_backtrace, th_locations.map{|e| e.to_s})
+ assert_equal(th_backtrace, th.backtrace(0))
+ assert_equal(th_locations.map{|e| e.to_s},
+ th.backtrace_locations(0).map{|e| e.to_s})
+ th_backtrace.size.times{|n|
+ assert_equal(n, th.backtrace(0, n).size)
+ assert_equal(n, th.backtrace_locations(0, n).size)
+ }
+ n = th_backtrace.size
+ assert_equal(n, th.backtrace(0, n + 1).size)
+ assert_equal(n, th.backtrace_locations(0, n + 1).size)
+ ensure
+ q << true
+ th.join
+ end
+ end
+
+ def test_thread_backtrace_locations_with_range
+ begin
+ q = Queue.new
+ th = Thread.new{
+ th_rec q
+ }
+ sleep 0.5
+ bt = th.backtrace(0,2)
+ locs = th.backtrace_locations(0..1).map { |loc|
+ loc.to_s
+ }
+ assert_equal(bt, locs)
+ ensure
+ q << true
+ th.join
+ end
+ end
+
+ def test_core_backtrace_alias
+ obj = BasicObject.new
+ e = assert_raise(NameError) do
+ class << obj
+ alias foo bar
+ end
+ end
+ assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label)
+ end
+
+ def test_core_backtrace_undef
+ obj = BasicObject.new
+ e = assert_raise(NameError) do
+ class << obj
+ undef foo
+ end
+ end
+ assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label)
+ end
+
+ def test_core_backtrace_hash_merge
+ e = assert_raise(TypeError) do
+ {**nil}
+ end
+ assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_basicinstructions.rb b/jni/ruby/test/ruby/test_basicinstructions.rb
new file mode 100644
index 0000000..4a1dc9c
--- /dev/null
+++ b/jni/ruby/test/ruby/test_basicinstructions.rb
@@ -0,0 +1,700 @@
+require 'test/unit'
+
+ConstTest = 3
+class Class
+ alias _remove_const remove_const
+ public :_remove_const
+end
+
+class TestBasicInstructions < Test::Unit::TestCase
+
+ def test_immediates
+ assert_equal((1==1), true)
+ assert_equal((1==2), false)
+ assert_equal [][0], nil
+ assert_equal "sym".intern, :sym
+ assert_equal "sym".intern, :"sym"
+ assert_equal 1234 + 0, 1234
+ assert_equal 1234, 1_2_3_4
+ assert_equal 41, 0b0101001
+ assert_equal 420, 0644
+ assert_equal 18, 0x12
+ assert_equal 123456789012345678901234567890 + 0,
+ 123456789012345678901234567890
+ assert_equal 1.234 + 0.0, 1.234
+ end
+
+ def test_self
+ assert_equal self, self
+ assert_equal false, (self == false) # Qfalse==0 in C
+ assert_equal false, (self == nil)
+ assert_equal false, (self == 0)
+ end
+
+ def test_string
+ expected = "str" + "ing"
+ assert_equal expected, 'string'
+ assert_equal expected, "string"
+ assert_equal expected, %q(string)
+ assert_equal expected, %Q(string)
+ assert_equal expected, %(string)
+ end
+
+ def test_dstring
+ assert_equal "2", "#{1+1}"
+ s = "OK"
+ assert_equal "OK", "#{s}"
+ assert_equal "OKx", "#{s}x"
+ assert_equal "xOK", "x#{s}"
+ assert_equal "xOKx", "x#{s}x"
+ end
+
+ def test_dsym
+ assert_equal :a3c, :"a#{1+2}c"
+ s = "sym"
+ assert_equal :sym, :"#{s}"
+ assert_equal :sym, :"#{"#{"#{s}"}"}"
+ end
+
+ def test_xstr
+ assert_equal 'hoge', `echo hoge`.chomp
+ assert_equal '3', `echo #{1 + 2}`.chomp
+ hoge = 'huga'
+ assert_equal 'huga', `echo #{hoge}`.chomp
+ end
+
+ def test_regexp
+ assert_equal(/test/, /test/)
+ assert_equal 'test', /test/.source
+ assert_equal 'TEST', /TEST/.source
+ assert_equal true, !!(/test/ =~ 'test')
+ assert_equal false, !!(/test/ =~ 'does not match')
+
+ re = /test/
+ assert_equal re, re
+ assert_equal 'test', re.source
+ assert_equal true, !!(re =~ 'test')
+ assert_equal false, !!(re =~ 'does not match')
+
+ assert_equal(/x#{1+1}x/, /x#{1+1}x/)
+ s = "OK"
+ assert_equal(/x#{s}x/, /x#{s}x/)
+ assert_equal true, !!(/x#{s}x/ =~ "xOKx")
+ assert_equal false, !!(/x#{s}x/ =~ "does not match")
+
+ s = "OK"
+ prev = nil
+ 3.times do
+ re = /#{s}/o
+ assert_same prev, re if prev
+ prev = re
+ end
+ end
+
+ def test_array
+ assert_equal [], []
+ assert_equal 0, [].size
+ assert_equal [1, 2, 3], [1, 2, 3]
+ assert_equal [3, 7, 11], [1+2, 3+4, 5+6]
+ assert_equal [[1], [2], [3]], [[1], [2], [3]]
+
+ a = [1, 2, 3]
+ assert_equal 1, a[0]
+ assert_equal 2, a[1]
+ assert_equal 3, a[2]
+ assert_nil a[3]
+
+ a = %w( a b c )
+ assert_equal 'a', a[0]
+ assert_equal 'b', a[1]
+ assert_equal 'c', a[2]
+ assert_nil a[3]
+ end
+
+ def test_hash
+ assert_equal({}, {})
+ assert_equal({1=>2}, {1=>2})
+ assert_equal({1=>2, 3=>4}, {1=>2, 3=>4})
+ assert_equal({1=>2, 3=>4}, {3=>4, 1=>2})
+ # assert_equal({1=>2, 3=>4}, {1,2, 3,4}) # 1.9 doesn't support
+ assert_equal({"key"=>"val"}, {"key"=>"val"})
+ end
+
+ def test_range
+ assert_equal((1..3), (1..3))
+ assert_equal((1...3), (1...3))
+ assert_not_equal((1...3), (1..3))
+ assert_not_equal((1..3), (1...3))
+ assert_equal((1..3), (1..2+1))
+ assert_equal((1...3), (1...2+1))
+ assert_equal(('a'..'z'), ('a'..'z'))
+ end
+
+ def test_not
+ assert_equal true, !nil
+ assert_equal true, !false
+ assert_equal false, !true
+ assert_equal false, !3
+ assert_equal false, !(1+1)
+
+ assert_equal false, !!nil
+ assert_equal false, !!false
+ assert_equal true, !!true
+ assert_equal true, !!3
+ assert_equal true, !!(1+1)
+
+ assert_equal true, (not nil)
+ assert_equal true, (not false)
+ assert_equal false, (not true)
+ assert_equal false, (not 3)
+ assert_equal false, (not (1 + 1))
+
+ assert_equal false, (not not nil)
+ assert_equal false, (not not false)
+ assert_equal true, (not not true)
+ assert_equal true, (not not 3)
+ assert_equal true, (not not (1+1))
+ end
+
+ def test_local_variable
+ a = 7
+ assert_equal 7, a
+ assert_equal a, a
+ b = 17
+ assert_equal 7, a
+ assert_equal 17, b
+ assert_equal a, a
+ assert_equal b, b
+ assert_not_equal a, b
+ assert_not_equal b, a
+ a = b
+ assert_equal 17, a
+ assert_equal 17, b
+ assert_equal a, a
+ assert_equal b, b
+ assert_equal a, b
+ assert_equal b, a
+ c = 28
+ assert_equal 17, a
+ assert_equal 17, b
+ assert_equal 28, c
+ assert_equal a, a
+ assert_equal b, b
+ assert_equal a, b
+ assert_equal c, c
+ assert_not_equal a, c
+ assert_not_equal b, c
+ a = b = c
+ assert_equal 28, a
+ assert_equal 28, b
+ assert_equal 28, c
+ assert_equal a, a
+ assert_equal b, b
+ assert_equal a, b
+ assert_equal b, a
+ assert_equal a, c
+ assert_equal c, a
+ assert_equal b, c
+ assert_equal c, b
+
+ a = 1
+ b = 2
+ c = 3
+ set_lvar_in_another_method
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+ end
+
+ def set_lvar_in_another_method
+ assert_raise(NameError) { a }
+ assert_raise(NameError) { b }
+ assert_raise(NameError) { c }
+ a = "NOT OK"
+ b = "NOT OK"
+ c = "NOT OK"
+ end
+
+ class Const
+ $Const = self
+ C = 'Const::C'
+ def self.c() C end
+ def c() C end
+
+ class A
+ C = 'Const::A::C'
+ def self.c() C end
+ def c() C end
+ CC = 'Const::A::CC'
+ def self.cc() CC end
+ def cc() CC end
+
+ class B
+ C = 'Const::A::B::C'
+ def self.c() C end
+ def c() C end
+ def self.cc() CC end
+ def cc() CC end
+ end
+ end
+
+ class AA < A
+ def self.cc() CC end
+ def cc() CC end
+ end
+
+ class AAA < AA
+ def self.cc() CC end
+ def cc() CC end
+ end
+ end
+ C = 0
+
+ def test_const_path
+ do_test_const_path
+ do_test_const_path
+ do_test_const_path
+ end
+
+ def do_test_const_path
+ assert_equal 0, C
+ assert_equal 0, C
+ assert_equal 3, ::ConstTest
+ assert_equal 3, ::ConstTest
+ assert_equal $Const, Const
+
+ assert_equal 'Const::C', Const::C
+ assert_equal 'Const::C', Const::C
+ assert_equal 'Const::A::C', Const::A::C
+ assert_equal 'Const::A::C', Const::A::C
+ assert_equal 'Const::A::B::C', Const::A::B::C
+ assert_equal 'Const::A::B::C', Const::A::B::C
+
+ Const::A::B._remove_const :C
+ assert_equal 'Const::C', Const::C
+ assert_equal 'Const::A::C', Const::A::C
+ assert_raise(NameError) { Const::A::B::C }
+
+ Const::A._remove_const :C
+ assert_equal 'Const::C', Const::C
+ assert_raise(NameError) { Const::A::C }
+ assert_raise(NameError) { Const::A::B::C }
+
+ Const._remove_const :C
+ assert_raise(NameError) { Const::C }
+ assert_raise(NameError) { Const::A::C }
+ assert_raise(NameError) { Const::A::B::C }
+
+ Const::A.const_set :C, 'Const::A::C'
+ assert_raise(NameError) { Const::C }
+ assert_equal 'Const::A::C', Const::A::C
+ assert_raise(NameError) { Const::A::B::C }
+
+ Const::A::B.const_set :C, 'Const::A::B::C'
+ assert_raise(NameError) { Const::C }
+ assert_equal 'Const::A::C', Const::A::C
+ assert_equal 'Const::A::B::C', Const::A::B::C
+
+ Const.const_set :C, 'Const::C'
+ assert_equal 'Const::C', Const::C
+ assert_equal 'Const::A::C', Const::A::C
+ assert_equal 'Const::A::B::C', Const::A::B::C
+ end
+
+ def test_const_cref
+ do_test_const_cref
+ do_test_const_cref
+ do_test_const_cref
+ end
+
+ def do_test_const_cref
+ assert_equal 'Const::C', Const.new.c
+ assert_equal 'Const::A::C', Const::A.new.c
+ assert_equal 'Const::A::B::C', Const::A::B.new.c
+
+ assert_equal 'Const::C', Const.c
+ assert_equal 'Const::A::C', Const::A.c
+ assert_equal 'Const::A::B::C', Const::A::B.c
+
+ Const::A::B._remove_const :C
+ assert_equal 'Const::C', Const.c
+ assert_equal 'Const::A::C', Const::A.c
+ assert_equal 'Const::A::C', Const::A::B.c
+ assert_equal 'Const::C', Const.new.c
+ assert_equal 'Const::A::C', Const::A.new.c
+ assert_equal 'Const::A::C', Const::A::B.new.c
+
+ Const::A._remove_const :C
+ assert_equal 'Const::C', Const.c
+ assert_equal 'Const::C', Const::A.c
+ assert_equal 'Const::C', Const::A::B.c
+ assert_equal 'Const::C', Const.new.c
+ assert_equal 'Const::C', Const::A.new.c
+ assert_equal 'Const::C', Const::A::B.new.c
+
+ Const::A::B.const_set :C, 'Const::A::B::C'
+ assert_equal 'Const::C', Const.c
+ assert_equal 'Const::C', Const::A.c
+ assert_equal 'Const::A::B::C', Const::A::B.c
+ assert_equal 'Const::C', Const.new.c
+ assert_equal 'Const::C', Const::A.new.c
+ assert_equal 'Const::A::B::C', Const::A::B.new.c
+
+ Const::A.const_set :C, 'Const::A::C'
+ assert_equal 'Const::C', Const.c
+ assert_equal 'Const::A::C', Const::A.c
+ assert_equal 'Const::A::B::C', Const::A::B.c
+ assert_equal 'Const::C', Const.new.c
+ assert_equal 'Const::A::C', Const::A.new.c
+ assert_equal 'Const::A::B::C', Const::A::B.new.c
+ ensure
+ # reset
+ Const.const_set :C, 'Const::C' unless Const.const_defined?(:C)
+ Const::A.const_set :C, 'Const::A::C' unless Const::A.const_defined?(:C)
+ Const::A::B.const_set :C, 'Const::A::B::C' unless Const::A::B.const_defined?(:C)
+ end
+
+ def test_const_inherit
+ do_test_const_inherit
+ do_test_const_inherit
+ do_test_const_inherit
+ end
+
+ def do_test_const_inherit
+ assert_equal 'Const::A::CC', Const::A.cc
+ assert_equal 'Const::A::CC', Const::AA.cc
+ assert_equal 'Const::A::CC', Const::AAA.cc
+ assert_equal 'Const::A::CC', Const::A.new.cc
+ assert_equal 'Const::A::CC', Const::AA.new.cc
+ assert_equal 'Const::A::CC', Const::AAA.new.cc
+
+ Const::AA.const_set :CC, 'Const::AA::CC'
+ assert_equal 'Const::A::CC', Const::A.cc
+ assert_equal 'Const::AA::CC', Const::AA.cc
+ assert_equal 'Const::AA::CC', Const::AAA.cc
+ assert_equal 'Const::A::CC', Const::A.new.cc
+ assert_equal 'Const::AA::CC', Const::AA.new.cc
+ assert_equal 'Const::AA::CC', Const::AAA.new.cc
+
+ Const::AAA.const_set :CC, 'Const::AAA::CC'
+ assert_equal 'Const::A::CC', Const::A.cc
+ assert_equal 'Const::AA::CC', Const::AA.cc
+ assert_equal 'Const::AAA::CC', Const::AAA.cc
+ assert_equal 'Const::A::CC', Const::A.new.cc
+ assert_equal 'Const::AA::CC', Const::AA.new.cc
+ assert_equal 'Const::AAA::CC', Const::AAA.new.cc
+
+ Const::AA._remove_const :CC
+ assert_equal 'Const::A::CC', Const::A.cc
+ assert_equal 'Const::A::CC', Const::AA.cc
+ assert_equal 'Const::AAA::CC', Const::AAA.cc
+ assert_equal 'Const::A::CC', Const::A.new.cc
+ assert_equal 'Const::A::CC', Const::AA.new.cc
+ assert_equal 'Const::AAA::CC', Const::AAA.new.cc
+
+ Const::AAA._remove_const :CC
+ assert_equal 'Const::A::CC', Const::A.cc
+ assert_equal 'Const::A::CC', Const::AA.cc
+ assert_equal 'Const::A::CC', Const::AAA.cc
+ assert_equal 'Const::A::CC', Const::A.new.cc
+ assert_equal 'Const::A::CC', Const::AA.new.cc
+ assert_equal 'Const::A::CC', Const::AAA.new.cc
+ end
+
+ def test_global_variable
+ $gvar1 = 1
+ assert_equal 1, $gvar1
+ $gvar1 = 2
+ assert_equal 2, $gvar1
+ $gvar2 = 77
+ assert_equal 2, $gvar1
+ assert_equal 77, $gvar2
+ $gvar2 = $gvar1
+ assert_equal 2, $gvar1
+ assert_equal 2, $gvar2
+ $gvar1 = 1
+ assert_equal 1, $gvar1
+ assert_equal 2, $gvar2
+ set_gvar_in_another_method
+ assert_equal "OK1", $gvar1
+ assert_equal "OK2", $gvar2
+ end
+
+ def set_gvar_in_another_method
+ assert_equal 1, $gvar1
+ assert_equal 2, $gvar2
+ $gvar1 = "OK1"
+ $gvar2 = "OK2"
+ end
+
+ class CVarA
+ @@cv = 'CVarA@@cv'
+ def self.cv() @@cv end
+ def self.cv=(v) @@cv = v end
+ class << self
+ def cv2() @@cv end
+ end
+ def cv() @@cv end
+ def cv=(v) @@cv = v end
+ end
+
+ class CVarB < CVarA
+ def self.cvB() @@cv end
+ def self.cvB=(v) @@cv = v end
+ class << self
+ def cvB2() @@cv end
+ end
+ def cvB() @@cv end
+ def cvB=(v) @@cv = v end
+ end
+
+ def test_class_variable
+ assert_equal 'CVarA@@cv', CVarA.cv
+ assert_equal 'CVarA@@cv', CVarA.cv2
+ assert_equal 'CVarA@@cv', CVarA.new.cv
+ CVarA.cv = 'singleton'
+ assert_equal 'singleton', CVarA.cv
+ assert_equal 'singleton', CVarA.cv2
+ assert_equal 'singleton', CVarA.new.cv
+ CVarA.new.cv = 'instance'
+ assert_equal 'instance', CVarA.cv
+ assert_equal 'instance', CVarA.cv2
+ assert_equal 'instance', CVarA.new.cv
+
+ CVarA.cv = 'CVarA@@cv'
+ CVarB.cv = 'B/singleton'
+ assert_equal 'B/singleton', CVarB.cv
+ assert_equal 'B/singleton', CVarB.cv2
+ assert_equal 'B/singleton', CVarB.new.cv
+ assert_equal 'B/singleton', CVarA.cv
+ assert_equal 'B/singleton', CVarA.cv2
+ assert_equal 'B/singleton', CVarA.new.cv
+ CVarB.new.cv = 'B/instance'
+ assert_equal 'B/instance', CVarB.cv
+ assert_equal 'B/instance', CVarB.cv2
+ assert_equal 'B/instance', CVarB.new.cv
+ assert_equal 'B/instance', CVarA.cv
+ assert_equal 'B/instance', CVarA.cv2
+ assert_equal 'B/instance', CVarA.new.cv
+
+ CVarA.cv = 'CVarA@@cv'
+ assert_equal('CVarA@@cv', CVarB.cvB)
+ assert_equal('CVarA@@cv', CVarB.cvB2)
+ assert_equal('CVarA@@cv', CVarB.new.cvB)
+ CVarB.cvB = 'B/singleton'
+ assert_equal 'B/singleton', CVarB.cvB
+ assert_equal 'B/singleton', CVarB.cvB2
+ assert_equal 'B/singleton', CVarB.new.cvB
+ assert_equal 'B/singleton', CVarA.cv
+ assert_equal 'B/singleton', CVarA.cv2
+ assert_equal 'B/singleton', CVarA.new.cv
+ CVarB.new.cvB = 'B/instance'
+ assert_equal 'B/instance', CVarB.cvB
+ assert_equal 'B/instance', CVarB.cvB2
+ assert_equal 'B/instance', CVarB.new.cvB
+ assert_equal 'B/instance', CVarA.cv
+ assert_equal 'B/instance', CVarA.cv2
+ assert_equal 'B/instance', CVarA.new.cv
+
+ CVarA.cv = 'CVarA@@cv'
+ CVarB.cvB = 'CVarB@@cv'
+ end
+
+ class OP
+ attr_reader :x
+ attr_accessor :foo
+ def x=(x)
+ @x = x
+ :Bug1996
+ end
+ Bug1996 = '[ruby-dev:39163], [ruby-core:25143]'
+ def [](i)
+ @x
+ end
+ def []=(i, x)
+ @x = x
+ :Bug2050
+ end
+ Bug2050 = '[ruby-core:25387]'
+ end
+
+ def test_opassign2_1
+ x = nil
+ assert_equal 1, x ||= 1
+ assert_equal 1, x
+ assert_equal 2, x &&= 2
+ assert_equal 2, x
+ assert_equal 2, x ||= 3
+ assert_equal 2, x
+ assert_equal 4, x &&= 4
+ assert_equal 4, x
+ assert_equal 5, x += 1
+ assert_equal 5, x
+ assert_equal 4, x -= 1
+ assert_equal 4, x
+ end
+
+ def test_opassign2_2
+ y = OP.new
+ y.x = nil
+ assert_equal 1, y.x ||= 1, OP::Bug1996
+ assert_equal 1, y.x
+ assert_equal 2, y.x &&= 2, OP::Bug1996
+ assert_equal 2, y.x
+ assert_equal 2, y.x ||= 3
+ assert_equal 2, y.x
+ assert_equal 4, y.x &&= 4, OP::Bug1996
+ assert_equal 4, y.x
+ assert_equal 5, y.x += 1, OP::Bug1996
+ assert_equal 5, y.x
+ assert_equal 4, y.x -= 1, OP::Bug1996
+ assert_equal 4, y.x
+ end
+
+ def test_opassign2_3
+ z = OP.new
+ z.x = OP.new
+ z.x.x = nil
+ assert_equal 1, z.x.x ||= 1, OP::Bug1996
+ assert_equal 1, z.x.x
+ assert_equal 2, z.x.x &&= 2, OP::Bug1996
+ assert_equal 2, z.x.x
+ assert_equal 2, z.x.x ||= 3
+ assert_equal 2, z.x.x
+ assert_equal 4, z.x.x &&= 4, OP::Bug1996
+ assert_equal 4, z.x.x
+ assert_equal 5, z.x.x += 1, OP::Bug1996
+ assert_equal 5, z.x.x
+ assert_equal 4, z.x.x -= 1, OP::Bug1996
+ assert_equal 4, z.x.x
+ end
+
+ def test_opassign1_1
+ a = []
+ a[0] = nil
+ assert_equal 1, a[0] ||= 1
+ assert_equal 1, a[0]
+ assert_equal 2, a[0] &&= 2
+ assert_equal 2, a[0]
+ assert_equal 2, a[0] ||= 3
+ assert_equal 2, a[0]
+ assert_equal 4, a[0] &&= 4
+ assert_equal 4, a[0]
+ assert_equal 5, a[0] += 1
+ assert_equal 5, a[0]
+ assert_equal 4, a[0] -= 1
+ assert_equal 4, a[0]
+ end
+
+ def test_opassign1_2
+ x = OP.new
+ x[0] = nil
+ assert_equal 1, x[0] ||= 1, OP::Bug2050
+ assert_equal 1, x[0]
+ assert_equal 2, x[0] &&= 2, OP::Bug2050
+ assert_equal 2, x[0]
+ assert_equal 2, x[0] ||= 3, OP::Bug2050
+ assert_equal 2, x[0]
+ assert_equal 4, x[0] &&= 4, OP::Bug2050
+ assert_equal 4, x[0]
+ assert_equal 5, x[0] += 1, OP::Bug2050
+ assert_equal 5, x[0]
+ assert_equal 4, x[0] -= 1, OP::Bug2050
+ assert_equal 4, x[0]
+ end
+
+ def test_send_opassign
+ return if defined?(RUBY_ENGINE) and RUBY_ENGINE != "ruby"
+
+ bug7773 = '[ruby-core:51821]'
+ x = OP.new
+ assert_equal 42, x.foo = 42, bug7773
+ assert_equal 42, x.foo, bug7773
+ assert_equal -6, x.send(:foo=, -6), bug7773
+ assert_equal -6, x.foo, bug7773
+ assert_equal :Bug1996, x.send(:x=, :case_when_setter_returns_other_value), bug7773
+ assert_equal :case_when_setter_returns_other_value, x.x, bug7773
+ end
+
+ def test_backref
+ /re/ =~ 'not match'
+ assert_nil $~
+ assert_nil $`
+ assert_nil $&
+ assert_nil $'
+ assert_nil $+
+ assert_nil $1
+ assert_nil $2
+ assert_nil $3
+ assert_nil $4
+ assert_nil $5
+ assert_nil $6
+ assert_nil $7
+ assert_nil $8
+ assert_nil $9
+
+ /(a)(b)(c)(d)(e)(f)(g)(h)(i)/ =~ 'xabcdefghiy'
+ assert_not_nil $~
+ assert_instance_of MatchData, $~
+ assert_equal 'abcdefghi', $~[0]
+ assert_equal 'a', $~[1]
+ assert_equal 'b', $~[2]
+ assert_equal 'c', $~[3]
+ assert_equal 'd', $~[4]
+ assert_equal 'e', $~[5]
+ assert_equal 'f', $~[6]
+ assert_equal 'g', $~[7]
+ assert_equal 'h', $~[8]
+ assert_equal 'i', $~[9]
+ assert_equal 'x', $`
+ assert_equal 'abcdefghi', $&
+ assert_equal "y", $'
+ assert_equal 'i', $+
+ assert_equal 'a', $1
+ assert_equal 'b', $2
+ assert_equal 'c', $3
+ assert_equal 'd', $4
+ assert_equal 'e', $5
+ assert_equal 'f', $6
+ assert_equal 'g', $7
+ assert_equal 'h', $8
+ assert_equal 'i', $9
+
+ /re/ =~ 'not match'
+ assert_nil $~
+ assert_nil $`
+ assert_nil $&
+ assert_nil $'
+ assert_nil $+
+ assert_nil $1
+ assert_nil $2
+ assert_nil $3
+ assert_nil $4
+ assert_nil $5
+ assert_nil $6
+ assert_nil $7
+ assert_nil $8
+ assert_nil $9
+ end
+
+ def test_array_splat
+ feature1125 = '[ruby-core:21901]'
+
+ a = []
+ assert_equal [], [*a]
+ assert_equal [1], [1, *a]
+ assert_not_same(a, [*a], feature1125)
+ a = [2]
+ assert_equal [2], [*a]
+ assert_equal [1, 2], [1, *a]
+ assert_not_same(a, [*a], feature1125)
+ a = [2, 3]
+ assert_equal [2, 3], [*a]
+ assert_equal [1, 2, 3], [1, *a]
+ assert_not_same(a, [*a], feature1125)
+
+ a = nil
+ assert_equal [], [*a]
+ assert_equal [1], [1, *a]
+ end
+end
diff --git a/jni/ruby/test/ruby/test_beginendblock.rb b/jni/ruby/test/ruby/test_beginendblock.rb
new file mode 100644
index 0000000..9c9d6b5
--- /dev/null
+++ b/jni/ruby/test/ruby/test_beginendblock.rb
@@ -0,0 +1,190 @@
+require 'test/unit'
+require 'tempfile'
+require 'timeout'
+
+class TestBeginEndBlock < Test::Unit::TestCase
+ DIR = File.dirname(File.expand_path(__FILE__))
+
+ def q(content)
+ "\"#{content}\""
+ end
+
+ def test_beginendblock
+ ruby = EnvUtil.rubybin
+ target = File.join(DIR, 'beginmainend.rb')
+ result = IO.popen([ruby, target]){|io|io.read}
+ assert_equal(%w(b1 b2-1 b2 main b3-1 b3 b4 e1 e1-1 e4 e4-2 e4-1 e4-1-1 e3 e2), result.split)
+
+ Tempfile.create(self.class.name) {|input|
+ inputpath = input.path
+ result = IO.popen([ruby, "-n", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read}
+ assert_equal(%w(:begin), result.split)
+ result = IO.popen([ruby, "-p", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read}
+ assert_equal(%w(:begin), result.split)
+ input.puts "foo\nbar"
+ input.close
+ result = IO.popen([ruby, "-n", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read}
+ assert_equal(%w(:begin :end), result.split)
+ result = IO.popen([ruby, "-p", "-eBEGIN{p :begin}", "-eEND{p :end}", inputpath]){|io|io.read}
+ assert_equal(%w(:begin foo bar :end), result.split)
+ }
+ end
+
+ def test_begininmethod
+ assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do
+ eval("def foo; BEGIN {}; end")
+ end
+
+ assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do
+ eval('eval("def foo; BEGIN {}; end")')
+ end
+ end
+
+ def test_begininclass
+ assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do
+ eval("class TestBeginEndBlock; BEGIN {}; end")
+ end
+ end
+
+ def test_endblockwarn
+ ruby = EnvUtil.rubybin
+ # Use Tempfile to create temporary file path.
+ Tempfile.create(self.class.name) {|launcher|
+ Tempfile.create(self.class.name) {|errout|
+
+ launcher << <<EOF
+# -*- coding: #{ruby.encoding.name} -*-
+errout = ARGV.shift
+STDERR.reopen(File.open(errout, "w"))
+STDERR.sync = true
+Dir.chdir(#{q(DIR)})
+system("#{ruby}", "endblockwarn_rb")
+EOF
+ launcher.close
+ launcherpath = launcher.path
+ errout.close
+ erroutpath = errout.path
+ system(ruby, launcherpath, erroutpath)
+ expected = <<EOW
+endblockwarn_rb:2: warning: END in method; use at_exit
+(eval):2: warning: END in method; use at_exit
+EOW
+ assert_equal(expected, File.read(erroutpath))
+ }
+ }
+ end
+
+ def test_raise_in_at_exit
+ ruby = EnvUtil.rubybin
+ out = IO.popen([ruby, '-e', 'STDERR.reopen(STDOUT)',
+ '-e', 'at_exit{raise %[SomethingBad]}',
+ '-e', 'raise %[SomethingElse]']) {|f|
+ f.read
+ }
+ status = $?
+ assert_match(/SomethingBad/, out, "[ruby-core:9675]")
+ assert_match(/SomethingElse/, out, "[ruby-core:9675]")
+ assert_not_predicate(status, :success?)
+ end
+
+ def test_exitcode_in_at_exit
+ bug8501 = '[ruby-core:55365] [Bug #8501]'
+ ruby = EnvUtil.rubybin
+ out = IO.popen([ruby, '-e', 'STDERR.reopen(STDOUT)',
+ '-e', 'o = Object.new; def o.inspect; raise "[Bug #8501]"; end',
+ '-e', 'at_exit{o.nope}']) {|f|
+ f.read
+ }
+ status = $?
+ assert_match(/undefined method `nope'/, out, bug8501)
+ assert_not_predicate(status, :success?, bug8501)
+ end
+
+ def test_propagate_exit_code
+ ruby = EnvUtil.rubybin
+ assert_equal false, system(ruby, '-e', 'at_exit{exit 2}')
+ assert_equal 2, $?.exitstatus
+ assert_nil $?.termsig
+ end
+
+ def test_propagate_signaled
+ ruby = EnvUtil.rubybin
+ out = IO.popen(
+ [ruby,
+ '-e', 'trap(:INT, "DEFAULT")',
+ '-e', 'STDERR.reopen(STDOUT)',
+ '-e', 'at_exit{Process.kill(:INT, $$); sleep 5 }']) {|f|
+ timeout(10) {
+ f.read
+ }
+ }
+ assert_match(/Interrupt$/, out)
+ Process.kill(0, 0) rescue return # check if signal works
+ assert_nil $?.exitstatus
+ assert_equal Signal.list["INT"], $?.termsig
+ end
+
+ def test_endblock_raise
+ ruby = EnvUtil.rubybin
+ th = nil
+ out = IO.popen(
+ [ruby,
+ '-e', 'class C; def write(x); puts x; STDOUT.flush; sleep 0.01; end; end',
+ '-e', '$stderr = C.new',
+ '-e', 'END {raise "e1"}; END {puts "e2"}',
+ '-e', 'END {raise "e3"}; END {puts "e4"}',
+ '-e', 'END {raise "e5"}; END {puts "e6"}']) {|f|
+ th = Thread.new {sleep 5; Process.kill :KILL, f.pid}
+ f.read
+ }
+ assert_match(/e1/, out)
+ assert_match(/e6/, out)
+ ensure
+ th.kill.join if th.alive?
+ end
+
+ def test_nested_at_exit
+ Tempfile.create(["test_nested_at_exit_", ".rb"]) {|t|
+ t.puts "at_exit { puts :outer0 }"
+ t.puts "at_exit { puts :outer1_begin; at_exit { puts :inner1 }; puts :outer1_end }"
+ t.puts "at_exit { puts :outer2_begin; at_exit { puts :inner2 }; puts :outer2_end }"
+ t.puts "at_exit { puts :outer3 }"
+ t.flush
+
+ expected = [ "outer3",
+ "outer2_begin",
+ "outer2_end",
+ "inner2",
+ "outer1_begin",
+ "outer1_end",
+ "inner1",
+ "outer0" ]
+
+ assert_in_out_err(t.path, "", expected, [], "[ruby-core:35237]")
+ }
+ end
+
+ def test_rescue_at_exit
+ bug5218 = '[ruby-core:43173][Bug #5218]'
+ cmd = [
+ "raise 'X' rescue nil",
+ "nil",
+ "exit(42)",
+ ]
+ %w[at_exit END].each do |ex|
+ out, err, status = EnvUtil.invoke_ruby(cmd.map {|s|["-e", "#{ex} {#{s}}"]}.flatten, "", true, true)
+ assert_equal(["", "", 42], [out, err, status.exitstatus], "#{bug5218}: #{ex}")
+ end
+ end
+
+ def test_callcc_at_exit
+ bug9110 = '[ruby-core:58329][Bug #9110]'
+ script = <<EOS
+require "continuation"
+c = nil
+at_exit { c.call }
+at_exit { callcc {|_c| c = _c } }
+EOS
+ assert_normal_exit(script, bug9110)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_bignum.rb b/jni/ruby/test/ruby/test_bignum.rb
new file mode 100644
index 0000000..2c6eda0
--- /dev/null
+++ b/jni/ruby/test/ruby/test_bignum.rb
@@ -0,0 +1,711 @@
+require 'test/unit'
+
+class TestBignum < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @fmax = Float::MAX.to_i
+ @fmax2 = @fmax * 2
+ @big = (1 << 63) - 1
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def fact(n)
+ return 1 if n == 0
+ f = 1
+ while n>0
+ f *= n
+ n -= 1
+ end
+ return f
+ end
+
+ def test_bignum
+ $x = fact(40)
+ assert_equal($x, $x)
+ assert_equal($x, fact(40))
+ assert_operator($x, :<, $x+2)
+ assert_operator($x, :>, $x-2)
+ assert_equal(815915283247897734345611269596115894272000000000, $x)
+ assert_not_equal(815915283247897734345611269596115894272000000001, $x)
+ assert_equal(815915283247897734345611269596115894272000000001, $x+1)
+ assert_equal(335367096786357081410764800000, $x/fact(20))
+ $x = -$x
+ assert_equal(-815915283247897734345611269596115894272000000000, $x)
+ assert_equal(2-(2**32), -(2**32-2))
+ assert_equal(2**32 - 5, (2**32-3)-2)
+
+ for i in 1000..1014
+ assert_equal(2 ** i, 1 << i)
+ end
+
+ n1 = 1 << 1000
+ for i in 1000..1014
+ assert_equal(n1, 1 << i)
+ n1 *= 2
+ end
+
+ n2=n1
+ for i in 1..10
+ n1 = n1 / 2
+ n2 = n2 >> 1
+ assert_equal(n1, n2)
+ end
+
+ for i in 4000..4096
+ n1 = 1 << i;
+ assert_equal(n1-1, (n1**2-1) / (n1+1))
+ end
+ end
+
+ def test_calc
+ b = 10**80
+ a = b * 9 + 7
+ assert_equal(7, a.modulo(b))
+ assert_equal(-b + 7, a.modulo(-b))
+ assert_equal(b + -7, (-a).modulo(b))
+ assert_equal(-7, (-a).modulo(-b))
+ assert_equal(7, a.remainder(b))
+ assert_equal(7, a.remainder(-b))
+ assert_equal(-7, (-a).remainder(b))
+ assert_equal(-7, (-a).remainder(-b))
+
+ assert_equal(10000000000000000000100000000000000000000, 10**40+10**20)
+ assert_equal(100000000000000000000, 10**40/10**20)
+
+ a = 677330545177305025495135714080
+ b = 14269972710765292560
+ assert_equal(0, a % b)
+ assert_equal(0, -a % b)
+ end
+
+ def shift_test(a)
+ b = a / (2 ** 32)
+ c = a >> 32
+ assert_equal(b, c)
+
+ b = a * (2 ** 32)
+ c = a << 32
+ assert_equal(b, c)
+ end
+
+ def test_shift
+ shift_test(-4518325415524767873)
+ shift_test(-0xfffffffffffffffff)
+ end
+
+ def test_to_s
+ assert_equal("fvvvvvvvvvvvv" ,18446744073709551615.to_s(32), "[ruby-core:10686]")
+ assert_equal("g000000000000" ,18446744073709551616.to_s(32), "[ruby-core:10686]")
+ assert_equal("3w5e11264sgsf" ,18446744073709551615.to_s(36), "[ruby-core:10686]")
+ assert_equal("3w5e11264sgsg" ,18446744073709551616.to_s(36), "[ruby-core:10686]")
+ assert_equal("nd075ib45k86f" ,18446744073709551615.to_s(31), "[ruby-core:10686]")
+ assert_equal("nd075ib45k86g" ,18446744073709551616.to_s(31), "[ruby-core:10686]")
+ assert_equal("1777777777777777777777" ,18446744073709551615.to_s(8))
+ assert_equal("-1777777777777777777777" ,-18446744073709551615.to_s(8))
+ assert_match(/\A10{99}1\z/, (10**100+1).to_s)
+ assert_match(/\A10{900}9{100}\z/, (10**1000+(10**100-1)).to_s)
+ end
+
+ b = 2**64
+ b *= b until Bignum === b
+
+ T_ZERO = b.coerce(0).first
+ T_ONE = b.coerce(1).first
+ T_MONE = b.coerce(-1).first
+ T31 = b.coerce(2**31).first # 2147483648
+ T31P = b.coerce(T31 - 1).first # 2147483647
+ T32 = b.coerce(2**32).first # 4294967296
+ T32P = b.coerce(T32 - 1).first # 4294967295
+ T64 = b.coerce(2**64).first # 18446744073709551616
+ T64P = b.coerce(T64 - 1).first # 18446744073709551615
+ T1024 = b.coerce(2**1024).first
+ T1024P = b.coerce(T1024 - 1).first
+
+ f = b
+ while Bignum === f-1
+ f = f >> 1
+ end
+ FIXNUM_MAX = f-1
+
+ def test_prepare
+ assert_instance_of(Bignum, T_ZERO)
+ assert_instance_of(Bignum, T_ONE)
+ assert_instance_of(Bignum, T_MONE)
+ assert_instance_of(Bignum, T31)
+ assert_instance_of(Bignum, T31P)
+ assert_instance_of(Bignum, T32)
+ assert_instance_of(Bignum, T32P)
+ assert_instance_of(Bignum, T64)
+ assert_instance_of(Bignum, T64P)
+ assert_instance_of(Bignum, T1024)
+ assert_instance_of(Bignum, T1024P)
+ end
+
+ def test_big_2comp
+ assert_equal("-4294967296", (~T32P).to_s)
+ assert_equal("..f00000000", "%x" % -T32)
+ end
+
+ def test_int2inum
+ assert_equal([T31P], [T31P].pack("I").unpack("I"))
+ assert_equal([T31P], [T31P].pack("i").unpack("i"))
+ end
+
+ def test_quad_pack
+ assert_equal([ 1], [ 1].pack("q").unpack("q"))
+ assert_equal([- 1], [- 1].pack("q").unpack("q"))
+ assert_equal([ T31P], [ T31P].pack("q").unpack("q"))
+ assert_equal([-T31P], [-T31P].pack("q").unpack("q"))
+ assert_equal([ T64P], [ T64P].pack("Q").unpack("Q"))
+ assert_equal([ 0], [ T64 ].pack("Q").unpack("Q"))
+ end
+
+ def test_str_to_inum
+ assert_equal(1, " +1".to_i)
+ assert_equal(-1, " -1".to_i)
+ assert_equal(0, "++1".to_i)
+ assert_equal(73, "111".oct)
+ assert_equal(273, "0x111".oct)
+ assert_equal(7, "0b111".oct)
+ assert_equal(73, "0o111".oct)
+ assert_equal(111, "0d111".oct)
+ assert_equal(73, "0111".oct)
+ assert_equal(111, Integer("111"))
+ assert_equal(13, "111".to_i(3))
+ assert_raise(ArgumentError) { "111".to_i(37) }
+ assert_equal(1333, "111".to_i(36))
+ assert_equal(1057, "111".to_i(32))
+ assert_equal(0, "00a".to_i)
+ assert_equal(1, Integer("1 "))
+ assert_raise(ArgumentError) { Integer("1_") }
+ assert_raise(ArgumentError) { Integer("1__") }
+ assert_raise(ArgumentError) { Integer("1_0 x") }
+ assert_equal(T31P, "1111111111111111111111111111111".to_i(2))
+ assert_equal(0_2, '0_2'.to_i)
+ assert_equal(00_2, '00_2'.to_i)
+ assert_equal(00_02, '00_02'.to_i)
+ end
+
+ def test_to_s2
+ assert_raise(ArgumentError) { T31P.to_s(37) }
+ assert_equal("9" * 32768, (10**32768-1).to_s)
+ assert_raise(RangeError) { Process.wait(1, T64P) }
+ assert_equal("0", T_ZERO.to_s)
+ assert_equal("1", T_ONE.to_s)
+ end
+
+ def test_to_f
+ assert_nothing_raised { T31P.to_f.to_i }
+ assert_raise(FloatDomainError) { (1024**1024).to_f.to_i }
+ assert_equal(1, (2**50000).to_f.infinite?)
+ assert_equal(-1, (-(2**50000)).to_f.infinite?)
+ end
+
+ def test_cmp
+ assert_operator(T31P, :>, 1)
+ assert_operator(T31P, :<, 2147483648.0)
+ assert_operator(T31P, :<, T64P)
+ assert_operator(T64P, :>, T31P)
+ assert_raise(ArgumentError) { T31P < "foo" }
+ assert_operator(T64, :<, (1.0/0.0))
+ assert_not_operator(T64, :>, (1.0/0.0))
+ end
+
+ def test_eq
+ assert_not_equal(T31P, 1)
+ assert_equal(T31P, 2147483647.0)
+ assert_not_equal(T31P, "foo")
+ assert_not_equal(2**77889, (1.0/0.0), '[ruby-core:31603]')
+ end
+
+ def test_eql
+ assert_send([T31P, :eql?, T31P])
+ end
+
+ def test_convert
+ assert_equal([255], [T_MONE].pack("C").unpack("C"))
+ assert_equal([0], [T32].pack("C").unpack("C"))
+ assert_raise(RangeError) { 0.to_s(T32) }
+ end
+
+ def test_sub
+ assert_equal(-T31, T32 - (T32 + T31))
+ x = 2**100
+ assert_equal(1, (x+2) - (x+1))
+ assert_equal(-1, (x+1) - (x+2))
+ assert_equal(0, (2**100) - (2.0**100))
+ o = Object.new
+ def o.coerce(x); [x, 2**100+2]; end
+ assert_equal(-1, (2**100+1) - o)
+ assert_equal(-1, T_ONE - 2)
+ end
+
+ def test_plus
+ assert_equal(T32.to_f, T32P + 1.0)
+ assert_raise(TypeError) { T32 + "foo" }
+ assert_equal(1267651809154049016125877911552, (2**100) + (2**80))
+ assert_equal(1267651809154049016125877911552, (2**80) + (2**100))
+ assert_equal(2**101, (2**100) + (2.0**100))
+ o = Object.new
+ def o.coerce(x); [x, 2**80]; end
+ assert_equal(1267651809154049016125877911552, (2**100) + o)
+ end
+
+ def test_minus
+ assert_equal(T32P.to_f, T32 - 1.0)
+ assert_raise(TypeError) { T32 - "foo" }
+ end
+
+ def test_mul
+ assert_equal(T32.to_f, T32 * 1.0)
+ assert_raise(TypeError) { T32 * "foo" }
+ o = Object.new
+ def o.coerce(x); [x, 2**100]; end
+ assert_equal(2**180, (2**80) * o)
+ end
+
+ def test_mul_balance
+ assert_equal(3**7000, (3**5000) * (3**2000))
+ end
+
+ def test_mul_large_numbers
+ a = %w[
+ 32580286268570032115047167942578356789222410206194227403993117616454027392
+ 62501901985861926098797067562795526004375784403965882943322008991129440928
+ 33855888840298794008677656280486901895499985197580043127115026675632969396
+ 55040226415022070581995493731570435346323030715226718346725312551631168110
+ 83966158581772380474470605428802018934282425947323171408377505151988776271
+ 85865548747366001752375899635539662017095652855537225416899242508164949615
+ 96848508410008685252121247181772953744297349638273854170932226446528911938
+ 03430429031094465344063914822790537339912760237589085026016396616506014081
+ 53557719631183538265614091691713138728177917059624255801026099255450058876
+ 97412698978242128457751836011774504753020608663272925708049430557191193188
+ 23212591809241860763625985763438355314593186083254640117460724730431447842
+ 15432124830037389073162094304199742919767272162759192882136828372588787906
+ 96027938532441670018954643423581446981760344524184231299785949158765352788
+ 38452309862972527623669323263424418781899966895996672291193305401609553502
+ 63893514163147729201340204483973131948541009975283778189609285614445485714
+ 63843850089417416331356938086609682943037801440660232801570877143192251897
+ 63026816485314923378023904237699794122181407920355722922555234540701118607
+ 37971417665315821995516986204709574657462370947443531049033704997194647442
+ 13711787319587466437795542850136751816475182349380345341647976135081955799
+ 56787050815348701001765730577514591032367920292271016649813170789854524395
+ 72571698998841196411826453893352760318867994518757872432266374568779920489
+ 55597104558927387008506485038236352630863481679853742412042588244086070827
+ 43705456833283086410967648483312972903432798923897357373793064381177468258
+ 69131640408147806442422254638590386673344704147156793990832671592488742473
+ 31524606724894164324227362735271650556732855509929890983919463699819116427
+ ].join.to_i
+ b = %w[
+ 31519454770031243652776765515030872050264386564379909299874378289835540661
+ 99756262835346828114038365624177182230027040172583473561802565238817167503
+ 85144159132462819032164726177606533272071955542237648482852154879445654746
+ 25061253606344846225905712926863168413666058602449408307586532461776530803
+ 56810626880722653177544008166119272373179841889454920521993413902672848145
+ 77974951972342194855267960390195830413354782136431833731467699250684103370
+ 98571305167189174270854698169136844578685346745340041520068176478277580590
+ 43810457765638903028049263788987034217272442328962400931269515791911786205
+ 15357047519615932249418012945178659435259428163356223753159488306813844040
+ 93609959555018799309373542926110109744437994067754004273450659607204900586
+ 28878103661124568217617766580438460505513654179249613168352070584906185237
+ 34829991855182473813233425492094534396541544295119674419522772382981982574
+ 64708442087451070125274285088681225122475041996116377707892328889948526913
+ 82239084041628877737628853240361038273348062246951097300286513836140601495
+ 63604611754185656404194406869925540477185577643853560887894081047256701731
+ 66884554460428760857958761948461476977864005799494946578017758268987123749
+ 85937011490156431231903167442071541493304390639100774497107347884381581049
+ 85451663323551635322518839895028929788021096587229364219084708576998525298
+ 39594168681411529110089531428721005176467479027585291807482375043729783455
+ 35827667428080449919778142400266842990117940984804919512360370451936835708
+ 76338722049621773169385978521438867493162717866679193103745711403152099047
+ 27294943901673885707639094215339506973982546487889199083181789561917985023
+ 82368442718514694400160954955539704757794969665555505203532944598698824542
+ 00599461848630034847211204029842422678421808487300084850702007663003230882
+ 16645745324467830796203354080471008809087072562876681588151822072260738003
+ ].join.to_i
+ c = %w[
+ 10269128594368631269792194698469828812223242061960065022209211719149714886
+ 03494742299892841188636314745174778237781513956755034582435818316155459882
+ 71422025990633195596790290038198841087091600598192959108790192789550336119
+ 13849937951116346796903163312950010689963716629093190601532313463306463573
+ 64436438673379454947908896258675634478867189655764364639888427350090856831
+ 84369949421175534994092429682748078316130135651006102162888937624830856951
+ 64818150356583421988135211585954838926347035741143424980258821170351244310
+ 33072045488402539147707418016613224788469923473310249137422855065567940804
+ 75231970365923936034328561426062696074717204901606475826224235014948198414
+ 19979210494282212322919438926816203585575357874850252052656098969732107129
+ 30639419804565653489687198910271702181183420960744232756057631336661646896
+ 48734093497394719644969417287962767186599484579769717220518657324467736902
+ 16947995288312851432262922140679347615046098863974141226499783975470926697
+ 95970415188661518504275964397022973192968233221707696639386238428211541334
+ 69925631385166494600401675904803418143232703594169525858261988389529181035
+ 06048776134746377586210180203524132714354779486439559392942733781343640971
+ 02430607931736785273011780813863748280091795277451796799961887248262211653
+ 38966967509803488282644299584920109534552889962877144862747797551711984992
+ 00726518175235286668236031649728858774545087668286506201943248842967749907
+ 05345423019480534625965140632428736051632750698608916592720742728646191514
+ 86268964807395494825321744802493138032936406889713953832376411900451422777
+ 06372983421062172556566901346288286168790235741528630664513209619789835729
+ 36999522461733403414326366959273556098219489572448083984779946889707480205
+ 42459898495081687425132939473146331452400120169525968892769310016015870148
+ 66821361032541586130017904207971120217385522074967066199941112154460026348
+ 07223950375610474071278649031647998546085807777970592429037128484222394216
+ 33776560239741740193444702279919018283324070210090106960567819910943036248
+ 16660475627526085805165023447934326510232828674828006752369603151390527384
+ 16810180735871644266726954590262010744712519045524839388305761859432443670
+ 05188791334908140831469790180096209292338569623252372975043915954675335333
+ 66614002146554533771788633057869340167604765688639181655208751680821446276
+ 75871494160208888666798836473728725968253820774671626436794492530356258709
+ 62318715778035246655925307167306434486713879511272648637608703497794724929
+ 54912261106702913491290913962825303534484477936036071463820553314826894581
+ 36951927032835690160443252405644718368516656317176848748544135126122940034
+ 68454782581240953957381976073459570718038035358630417744490242611126043987
+ 89191812971310096496208294948623403471433467614886863238916702384858514703
+ 24327715474804343531844042107910755966152655912676456945146277848606406879
+ 49724219295823540160221752189725460676360350860849986313532861445465771187
+ 86822806696323658053947125253562001971534265078959827450518368635828010637
+ 91977444206363529864361796188661941906329947840521598310396004328950804758
+ 79728679236044038853668859284513594307352133390781441610395116807369310560
+ 35193762565748328526426224069629084264376146174383444988110993194030351064
+ 29660536743256949099972314033972121470913480844652490838985461134989129492
+ 75577567064571716731774820127381261057956083604361635892088585967074514802
+ 51958582645785905276289980534832170529946494815794770854644518463332458915
+ 77572397432680871220602513555535017751714443325264019171753694163676670792
+ 04353584782364068773777058727187323211012094819929720407636607815292764459
+ 21851731257845562153822058534043916834839514338448582518847879059020959697
+ 90538105704766415685100946308842788321400392381169436435078204622400475281
+ ].join.to_i
+ assert_equal(c, a*b, '[ruby-core:48552]')
+ end
+
+ def test_divrem
+ assert_equal(0, T32 / T64)
+ end
+
+ def test_divide
+ bug5490 = '[ruby-core:40429]'
+ assert_raise(ZeroDivisionError, bug5490) {T1024./(0)}
+ assert_equal(Float::INFINITY, T1024./(0.0), bug5490)
+ end
+
+ def test_div
+ assert_equal(T32.to_f, T32 / 1.0)
+ assert_raise(TypeError) { T32 / "foo" }
+ assert_equal(0x20000000, 0x40000001.div(2.0), "[ruby-dev:34553]")
+ bug5490 = '[ruby-core:40429]'
+ assert_raise(ZeroDivisionError, bug5490) {T1024.div(0)}
+ assert_raise(ZeroDivisionError, bug5490) {T1024.div(0.0)}
+ end
+
+ def test_idiv
+ assert_equal(715827882, 1073741824.div(Rational(3,2)), ' [ruby-dev:34066]')
+ end
+
+ def test_modulo
+ assert_raise(TypeError) { T32 % "foo" }
+ end
+
+ def test_remainder
+ assert_equal(0, T32.remainder(1))
+ assert_raise(TypeError) { T32.remainder("foo") }
+ end
+
+ def test_divmod
+ assert_equal([T32, 0], T32.divmod(1))
+ assert_equal([2, 0], T32.divmod(T31))
+ assert_raise(TypeError) { T32.divmod("foo") }
+ end
+
+ def test_quo
+ assert_kind_of(Float, T32.quo(1.0))
+
+ assert_equal(T32.to_f, T32.quo(1))
+ assert_equal(T32.to_f, T32.quo(1.0))
+ assert_equal(T32.to_f, T32.quo(T_ONE))
+
+ assert_raise(TypeError) { T32.quo("foo") }
+
+ assert_equal(1024**1024, (1024**1024).quo(1))
+ assert_equal(Float::INFINITY, (1024**1024).quo(1.0))
+ assert_equal(1024**1024*2, (1024**1024*2).quo(1))
+ inf = 1 / 0.0; nan = inf / inf
+
+ assert_send([(1024**1024*2).quo(nan), :nan?])
+ end
+
+ def test_pow
+ assert_equal(1.0, T32 ** 0.0)
+ assert_equal(1.0 / T32, T32 ** -1)
+ assert_equal(1, (T32 ** T32).infinite?)
+ assert_equal(1, (T32 ** (2**30-1)).infinite?)
+
+ ### rational changes the behavior of Bignum#**
+ #assert_raise(TypeError) { T32**"foo" }
+ assert_raise(TypeError, ArgumentError) { T32**"foo" }
+
+ feature3429 = '[ruby-core:30735]'
+ assert_instance_of(Bignum, (2 ** 7830457), feature3429)
+ end
+
+ def test_and
+ assert_equal(0, T32 & 1)
+ assert_equal(-T32, (-T32) & (-T31))
+ assert_equal(0, T32 & T64)
+ end
+
+ def test_or
+ assert_equal(T32 + 1, T32 | 1)
+ assert_equal(T32 + T31, T32 | T31)
+ assert_equal(-T31, (-T32) | (-T31))
+ assert_equal(T64 + T32, T32 | T64)
+ assert_equal(FIXNUM_MAX, T_ZERO | FIXNUM_MAX)
+ end
+
+ def test_xor
+ assert_equal(T32 + 1, T32 ^ 1)
+ assert_equal(T32 + T31, T32 ^ T31)
+ assert_equal(T31, (-T32) ^ (-T31))
+ assert_equal(T64 + T32, T32 ^ T64)
+ end
+
+ class DummyNumeric < Numeric
+ def to_int
+ 1
+ end
+ end
+
+ def test_and_with_float
+ assert_raise(TypeError) { T1024 & 1.5 }
+ end
+
+ def test_and_with_rational
+ assert_raise(TypeError, "#1792") { T1024 & Rational(3, 2) }
+ end
+
+ def test_and_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { T1024 & DummyNumeric.new }
+ end
+
+ def test_or_with_float
+ assert_raise(TypeError) { T1024 | 1.5 }
+ end
+
+ def test_or_with_rational
+ assert_raise(TypeError, "#1792") { T1024 | Rational(3, 2) }
+ end
+
+ def test_or_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { T1024 | DummyNumeric.new }
+ end
+
+ def test_xor_with_float
+ assert_raise(TypeError) { T1024 ^ 1.5 }
+ end
+
+ def test_xor_with_rational
+ assert_raise(TypeError, "#1792") { T1024 ^ Rational(3, 2) }
+ end
+
+ def test_xor_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { T1024 ^ DummyNumeric.new }
+ end
+
+ def test_shift2
+ assert_equal(2**33, (2**32) << 1)
+ assert_equal(2**31, (2**32) << -1)
+ assert_equal(2**33, (2**32) << 1.0)
+ assert_equal(2**31, (2**32) << -1.0)
+ assert_equal(2**33, (2**32) << T_ONE)
+ assert_equal(2**31, (2**32) << T_MONE)
+ assert_equal(2**31, (2**32) >> 1)
+ assert_equal(2**33, (2**32) >> -1)
+ assert_equal(2**31, (2**32) >> 1.0)
+ assert_equal(2**33, (2**32) >> -1.0)
+ assert_equal(2**31, (2**32) >> T_ONE)
+ assert_equal(2**33, (2**32) >> T_MONE)
+ assert_equal( 0, (2**32) >> (2**32))
+ assert_equal(-1, -(2**32) >> (2**32))
+ assert_equal( 0, (2**32) >> 128)
+ assert_equal(-1, -(2**32) >> 128)
+ assert_equal( 0, (2**31) >> 32)
+ assert_equal(-1, -(2**31) >> 32)
+ end
+
+ def test_shift_bigshift
+ big = 2**300
+ assert_equal(2**65538 / (2**65537), 2**65538 >> big.coerce(65537).first)
+ end
+
+ def test_aref
+ assert_equal(0, (2**32)[0])
+ assert_equal(0, (2**32)[2**32])
+ assert_equal(0, (2**32)[-(2**32)])
+ assert_equal(0, (2**32)[T_ZERO])
+ assert_equal(0, (-(2**64))[0])
+ assert_equal(1, (-2**256)[256])
+ end
+
+ def test_hash
+ assert_nothing_raised { T31P.hash }
+ end
+
+ def test_coerce
+ assert_equal([T64P, T31P], T31P.coerce(T64P))
+ assert_raise(TypeError) { T31P.coerce(nil) }
+ end
+
+ def test_abs
+ assert_equal(T31P, (-T31P).abs)
+ end
+
+ def test_size
+ assert_kind_of(Integer, T31P.size)
+ end
+
+ def test_odd
+ assert_equal(true, (2**32+1).odd?)
+ assert_equal(false, (2**32).odd?)
+ end
+
+ def test_even
+ assert_equal(false, (2**32+1).even?)
+ assert_equal(true, (2**32).even?)
+ end
+
+ def test_interrupt_during_to_s
+ if defined?(Bignum::GMP_VERSION)
+ return # GMP doesn't support interrupt during an operation.
+ end
+ time = Time.now
+ start_flag = false
+ end_flag = false
+ num = (65536 ** 65536)
+ thread = Thread.new do
+ start_flag = true
+ num.to_s
+ end_flag = true
+ end
+ sleep 0.001 until start_flag
+ thread.raise
+ thread.join rescue nil
+ time = Time.now - time
+ skip "too fast cpu" if end_flag
+ assert_operator(time, :<, 10)
+ end
+
+ def test_interrupt_during_bigdivrem
+ if defined?(Bignum::GMP_VERSION)
+ return # GMP doesn't support interrupt during an operation.
+ end
+ return unless Process.respond_to?(:kill)
+ begin
+ trace = []
+ oldtrap = Signal.trap(:INT) {|sig| trace << :int }
+ a = 456 ** 100
+ b = 123 ** 100
+ c = nil
+ 100.times do |n|
+ a **= 3
+ b **= 3
+ trace.clear
+ th = Thread.new do
+ sleep 0.1; Process.kill :INT, $$
+ sleep 0.1; Process.kill :INT, $$
+ end
+ c = a / b
+ trace << :end
+ th.join
+ if trace == [:int, :int, :end]
+ assert_equal(a / b, c)
+ return
+ end
+ end
+ skip "cannot create suitable test case"
+ ensure
+ Signal.trap(:INT, oldtrap) if oldtrap
+ end
+ end
+
+ def test_too_big_to_s
+ if (big = 2**31-1).is_a?(Fixnum)
+ return
+ end
+ assert_raise_with_message(RangeError, /too big to convert/) {(1 << big).to_s}
+ end
+
+ def test_fix_fdiv
+ assert_not_equal(0, 1.fdiv(@fmax2))
+ assert_in_delta(0.5, 1.fdiv(@fmax2) * @fmax, 0.01)
+ end
+
+ def test_big_fdiv
+ assert_equal(1, @big.fdiv(@big))
+ assert_not_equal(0, @big.fdiv(@fmax2))
+ assert_not_equal(0, @fmax2.fdiv(@big))
+ assert_not_equal(0, @fmax2.fdiv(@fmax2))
+ assert_in_delta(0.5, @fmax.fdiv(@fmax2), 0.01)
+ assert_in_delta(1.0, @fmax2.fdiv(@fmax2), 0.01)
+ end
+
+ def test_float_fdiv
+ b = 1E+300.to_i
+ assert_equal(b, (b ** 2).fdiv(b))
+ assert_send([@big.fdiv(0.0 / 0.0), :nan?])
+ assert_in_delta(1E+300, (10**500).fdiv(1E+200), 1E+285)
+ end
+
+ def test_obj_fdiv
+ o = Object.new
+ def o.coerce(x); [x, 2**100]; end
+ assert_equal((2**200).to_f, (2**300).fdiv(o))
+ end
+
+ def test_singleton_method
+ # this test assumes 32bit/64bit platform
+ assert_raise(TypeError) { a = 1 << 64; def a.foo; end }
+ end
+
+ def test_frozen
+ assert_equal(true, (2**100).frozen?)
+ end
+
+ def test_bitwise_and_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { T1024 & obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(T1024 & 10, T1024 & obj)
+ end
+
+ def test_bitwise_or_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { T1024 | obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(T1024 | 10, T1024 | obj)
+ end
+
+ def test_bitwise_xor_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { T1024 ^ obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(T1024 ^ 10, T1024 ^ obj)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_call.rb b/jni/ruby/test/ruby/test_call.rb
new file mode 100644
index 0000000..5b81eb1
--- /dev/null
+++ b/jni/ruby/test/ruby/test_call.rb
@@ -0,0 +1,34 @@
+require 'test/unit'
+
+class TestCall < Test::Unit::TestCase
+ def aaa(a, b=100, *rest)
+ res = [a, b]
+ res += rest if rest
+ return res
+ end
+
+ def test_call
+ assert_raise(ArgumentError) {aaa()}
+ assert_raise(ArgumentError) {aaa}
+
+ assert_equal([1, 100], aaa(1))
+ assert_equal([1, 2], aaa(1, 2))
+ assert_equal([1, 2, 3, 4], aaa(1, 2, 3, 4))
+ assert_equal([1, 2, 3, 4], aaa(1, *[2, 3, 4]))
+ end
+
+ def test_callinfo
+ bug9622 = '[ruby-core:61422] [Bug #9622]'
+ o = Class.new do
+ def foo(*args)
+ bar(:foo, *args)
+ end
+ def bar(name)
+ name
+ end
+ end.new
+ e = assert_raise(ArgumentError) {o.foo(100)}
+ assert_nothing_raised(ArgumentError) {o.foo}
+ assert_raise_with_message(ArgumentError, e.message, bug9622) {o.foo(100)}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_case.rb b/jni/ruby/test/ruby/test_case.rb
new file mode 100644
index 0000000..f20d1df
--- /dev/null
+++ b/jni/ruby/test/ruby/test_case.rb
@@ -0,0 +1,124 @@
+require 'test/unit'
+
+class TestCase < Test::Unit::TestCase
+ def test_case
+ case 5
+ when 1, 2, 3, 4, 6, 7, 8
+ assert(false)
+ when 5
+ assert(true)
+ end
+
+ case 5
+ when 5
+ assert(true)
+ when 1..10
+ assert(false)
+ end
+
+ case 5
+ when 1..10
+ assert(true)
+ else
+ assert(false)
+ end
+
+ case 5
+ when 5
+ assert(true)
+ else
+ assert(false)
+ end
+
+ case "foobar"
+ when /^f.*r$/
+ assert(true)
+ else
+ assert(false)
+ end
+
+ case
+ when true
+ assert(true)
+ when false, nil
+ assert(false)
+ else
+ assert(false)
+ end
+
+ case "+"
+ when *%w/. +/
+ assert(true)
+ else
+ assert(false)
+ end
+
+ case
+ when *[], false
+ assert(false)
+ else
+ assert(true)
+ end
+
+ case
+ when *false, []
+ assert(true)
+ else
+ assert(false)
+ end
+
+ assert_raise(NameError) do
+ case
+ when false, *x, false
+ end
+ end
+ end
+
+ def test_deoptimization
+ assert_in_out_err(['-e', <<-EOS], '', %w[42], [])
+ class Symbol; undef ===; def ===(o); p 42; true; end; end; case :foo; when :foo; end
+ EOS
+
+ assert_in_out_err(['-e', <<-EOS], '', %w[42], [])
+ class Fixnum; undef ===; def ===(o); p 42; true; end; end; case 1; when 1; end
+ EOS
+ end
+
+ def test_optimization
+ case 1
+ when 0.9, 1.1
+ assert(false)
+ when 1.0
+ assert(true)
+ else
+ assert(false)
+ end
+ case 536870912
+ when 536870911.9, 536870912.1
+ assert(false)
+ when 536870912.0
+ assert(true)
+ else
+ assert(false)
+ end
+ end
+
+ def test_method_missing
+ flag = false
+
+ case 1
+ when Class.new(BasicObject) { def method_missing(*) true end }.new
+ flag = true
+ end
+
+ assert(flag)
+ end
+
+ def test_nomethoderror
+ assert_raise(NoMethodError) {
+ case 1
+ when Class.new(BasicObject) { }.new
+ end
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_class.rb b/jni/ruby/test/ruby/test_class.rb
new file mode 100644
index 0000000..e17f56f
--- /dev/null
+++ b/jni/ruby/test/ruby/test_class.rb
@@ -0,0 +1,402 @@
+require 'test/unit'
+
+class TestClass < Test::Unit::TestCase
+ # ------------------
+ # Various test classes
+ # ------------------
+
+ class ClassOne
+ attr :num_args
+ @@subs = []
+ def initialize(*args)
+ @num_args = args.size
+ @args = args
+ end
+ def [](n)
+ @args[n]
+ end
+ def ClassOne.inherited(klass)
+ @@subs.push klass
+ end
+ def subs
+ @@subs
+ end
+ end
+
+ class ClassTwo < ClassOne
+ end
+
+ class ClassThree < ClassOne
+ end
+
+ class ClassFour < ClassThree
+ end
+
+ # ------------------
+ # Start of tests
+ # ------------------
+
+ def test_s_inherited
+ assert_equal([ClassTwo, ClassThree, ClassFour], ClassOne.new.subs)
+ end
+
+ def test_s_new
+ c = Class.new
+ assert_same(Class, c.class)
+ assert_same(Object, c.superclass)
+
+ c = Class.new(Fixnum)
+ assert_same(Class, c.class)
+ assert_same(Fixnum, c.superclass)
+ end
+
+ def test_00_new_basic
+ a = ClassOne.new
+ assert_equal(ClassOne, a.class)
+ assert_equal(0, a.num_args)
+
+ a = ClassOne.new(1, 2, 3)
+ assert_equal(3, a.num_args)
+ assert_equal(1, a[0])
+ end
+
+ def test_01_new_inherited
+ a = ClassTwo.new
+ assert_equal(ClassTwo, a.class)
+ assert_equal(0, a.num_args)
+
+ a = ClassTwo.new(1, 2, 3)
+ assert_equal(3, a.num_args)
+ assert_equal(1, a[0])
+ end
+
+ def test_superclass
+ assert_equal(ClassOne, ClassTwo.superclass)
+ assert_equal(Object, ClassTwo.superclass.superclass)
+ assert_equal(BasicObject, ClassTwo.superclass.superclass.superclass)
+ end
+
+ def test_class_cmp
+ assert_raise(TypeError) { Class.new <= 1 }
+ assert_raise(TypeError) { Class.new >= 1 }
+ assert_nil(Class.new <=> 1)
+ end
+
+ def test_class_initialize
+ assert_raise(TypeError) do
+ Class.new.instance_eval { initialize }
+ end
+ end
+
+ def test_instanciate_singleton_class
+ c = class << Object.new; self; end
+ assert_raise(TypeError) { c.new }
+ end
+
+ def test_superclass_of_basicobject
+ assert_equal(nil, BasicObject.superclass)
+ end
+
+ def test_module_function
+ c = Class.new
+ assert_raise(TypeError) do
+ Module.instance_method(:module_function).bind(c).call(:foo)
+ end
+ end
+
+ def test_extend_object
+ c = Class.new
+ assert_raise(TypeError) do
+ Module.instance_method(:extend_object).bind(c).call(Object.new)
+ end
+ end
+
+ def test_append_features
+ c = Class.new
+ assert_raise(TypeError) do
+ Module.instance_method(:append_features).bind(c).call(Module.new)
+ end
+ end
+
+ def test_prepend_features
+ c = Class.new
+ assert_raise(TypeError) do
+ Module.instance_method(:prepend_features).bind(c).call(Module.new)
+ end
+ end
+
+ def test_module_specific_methods
+ assert_empty(Class.private_instance_methods(true) &
+ [:module_function, :extend_object, :append_features, :prepend_features])
+ end
+
+ def test_method_redefinition
+ feature2155 = '[ruby-dev:39400]'
+
+ line = __LINE__+4
+ stderr = EnvUtil.verbose_warning do
+ Class.new do
+ def foo; end
+ def foo; end
+ end
+ end
+ assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
+ assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
+
+ assert_warning '' do
+ Class.new do
+ def foo; end
+ alias bar foo
+ def foo; end
+ end
+ end
+
+ assert_warning '' do
+ Class.new do
+ def foo; end
+ alias bar foo
+ alias bar foo
+ end
+ end
+
+ line = __LINE__+4
+ stderr = EnvUtil.verbose_warning do
+ Class.new do
+ define_method(:foo) do end
+ def foo; end
+ end
+ end
+ assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
+ assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
+
+ assert_warning '' do
+ Class.new do
+ define_method(:foo) do end
+ alias bar foo
+ alias bar foo
+ end
+ end
+
+ assert_warning '' do
+ Class.new do
+ def foo; end
+ undef foo
+ end
+ end
+ end
+
+ def test_check_inheritable
+ assert_raise(TypeError) { Class.new(Object.new) }
+
+ o = Object.new
+ c = class << o; self; end
+ assert_raise(TypeError) { Class.new(c) }
+ assert_raise(TypeError) { Class.new(Class) }
+ assert_raise(TypeError) { eval("class Foo < Class; end") }
+ end
+
+ def test_initialize_copy
+ c = Class.new
+ assert_raise(TypeError) { c.instance_eval { initialize_copy(1) } }
+
+ o = Object.new
+ c = class << o; self; end
+ assert_raise(TypeError) { c.dup }
+
+ assert_raise(TypeError) { BasicObject.dup }
+ end
+
+ def test_singleton_class
+ assert_raise(TypeError) { 1.extend(Module.new) }
+ assert_raise(TypeError) { 1.0.extend(Module.new) }
+ assert_raise(TypeError) { (2.0**1000).extend(Module.new) }
+ assert_raise(TypeError) { :foo.extend(Module.new) }
+
+ assert_in_out_err([], <<-INPUT, %w(:foo :foo true true), [])
+ module Foo; def foo; :foo; end; end
+ false.extend(Foo)
+ true.extend(Foo)
+ p false.foo
+ p true.foo
+ p FalseClass.include?(Foo)
+ p TrueClass.include?(Foo)
+ INPUT
+ end
+
+ def test_uninitialized
+ assert_raise(TypeError) { Class.allocate.new }
+ assert_raise(TypeError) { Class.allocate.superclass }
+ bug6863 = '[ruby-core:47148]'
+ assert_raise(TypeError, bug6863) { Class.new(Class.allocate) }
+ end
+
+ def test_nonascii_name
+ c = eval("class ::C\u{df}; self; end")
+ assert_equal("C\u{df}", c.name, '[ruby-core:24600]')
+ c = eval("class C\u{df}; self; end")
+ assert_equal("TestClass::C\u{df}", c.name, '[ruby-core:24600]')
+ end
+
+ def test_invalid_jump_from_class_definition
+ assert_raise(SyntaxError) { eval("class C; next; end") }
+ assert_raise(SyntaxError) { eval("class C; break; end") }
+ assert_raise(SyntaxError) { eval("class C; redo; end") }
+ assert_raise(SyntaxError) { eval("class C; retry; end") }
+ assert_raise(SyntaxError) { eval("class C; return; end") }
+ assert_raise(SyntaxError) { eval("class C; yield; end") }
+ end
+
+ def test_clone
+ original = Class.new {
+ def foo
+ return super()
+ end
+ }
+ mod = Module.new {
+ def foo
+ return "mod#foo"
+ end
+ }
+ copy = original.clone
+ copy.send(:include, mod)
+ assert_equal("mod#foo", copy.new.foo)
+ end
+
+ def test_nested_class_removal
+ assert_normal_exit('File.__send__(:remove_const, :Stat); at_exit{File.stat(".")}; GC.start')
+ end
+
+ class PrivateClass
+ end
+ private_constant :PrivateClass
+
+ def test_redefine_private_class
+ assert_raise(NameError) do
+ eval("class ::TestClass::PrivateClass; end")
+ end
+ eval <<-END
+ class ::TestClass
+ class PrivateClass
+ def foo; 42; end
+ end
+ end
+ END
+ assert_equal(42, PrivateClass.new.foo)
+ end
+
+ StrClone = String.clone
+ Class.new(StrClone)
+
+ def test_cloned_class
+ bug5274 = StrClone.new("[ruby-dev:44460]")
+ assert_equal(bug5274, Marshal.load(Marshal.dump(bug5274)))
+ end
+
+ def test_cannot_reinitialize_class_with_initialize_copy # [ruby-core:50869]
+ assert_in_out_err([], <<-'end;', ["Object"], [])
+ class Class
+ def initialize_copy(*); super; end
+ end
+
+ class A; end
+ class B; end
+
+ A.send(:initialize_copy, Class.new(B)) rescue nil
+
+ p A.superclass
+ end;
+ end
+
+ module M
+ C = 1
+
+ def self.m
+ C
+ end
+ end
+
+ def test_constant_access_from_method_in_cloned_module # [ruby-core:47834]
+ m = M.dup
+ assert_equal 1, m::C
+ assert_equal 1, m.m
+ end
+
+ def test_invalid_superclass
+ assert_raise(TypeError) do
+ eval <<-'end;'
+ class C < nil
+ end
+ end;
+ end
+
+ assert_raise(TypeError) do
+ eval <<-'end;'
+ class C < false
+ end
+ end;
+ end
+
+ assert_raise(TypeError) do
+ eval <<-'end;'
+ class C < true
+ end
+ end;
+ end
+
+ assert_raise(TypeError) do
+ eval <<-'end;'
+ class C < 0
+ end
+ end;
+ end
+
+ assert_raise(TypeError) do
+ eval <<-'end;'
+ class C < ""
+ end
+ end;
+ end
+ end
+
+ def test_cloned_singleton_method_added
+ bug5283 = '[ruby-dev:44477]'
+ added = []
+ c = Class.new
+ c.singleton_class.class_eval do
+ define_method(:singleton_method_added) {|mid| added << [self, mid]}
+ def foo; :foo; end
+ end
+ added.clear
+ d = c.clone
+ assert_empty(added.grep(->(k) {c == k[0]}), bug5283)
+ assert_equal(:foo, d.foo)
+ end
+
+ def test_singleton_class_p
+ feature7609 = '[ruby-core:51087] [Feature #7609]'
+ assert_predicate(self.singleton_class, :singleton_class?, feature7609)
+ assert_not_predicate(self.class, :singleton_class?, feature7609)
+ end
+
+ def test_freeze_to_s
+ assert_nothing_raised("[ruby-core:41858] [Bug #5828]") {
+ Class.new.freeze.clone.to_s
+ }
+ end
+
+ def test_singleton_class_of_frozen_object
+ obj = Object.new
+ c = obj.singleton_class
+ obj.freeze
+ assert_raise_with_message(RuntimeError, /frozen object/) {
+ c.class_eval {def f; end}
+ }
+ end
+
+ def test_singleton_class_message
+ c = Class.new.freeze
+ assert_raise_with_message(RuntimeError, /frozen Class/) {
+ def c.f; end
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_clone.rb b/jni/ruby/test/ruby/test_clone.rb
new file mode 100644
index 0000000..c5e2469
--- /dev/null
+++ b/jni/ruby/test/ruby/test_clone.rb
@@ -0,0 +1,28 @@
+require 'test/unit'
+
+class TestClone < Test::Unit::TestCase
+ module M001; end
+ module M002; end
+ module M003; include M002; end
+ module M002; include M001; end
+ module M003; include M002; end
+
+ def test_clone
+ foo = Object.new
+ def foo.test
+ "test"
+ end
+ bar = foo.clone
+ def bar.test2
+ "test2"
+ end
+
+ assert_equal("test2", bar.test2)
+ assert_equal("test", bar.test)
+ assert_equal("test", foo.test)
+
+ assert_raise(NoMethodError) {foo.test2}
+
+ assert_equal([M003, M002, M001], M003.ancestors)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_comparable.rb b/jni/ruby/test/ruby/test_comparable.rb
new file mode 100644
index 0000000..efa630f
--- /dev/null
+++ b/jni/ruby/test/ruby/test_comparable.rb
@@ -0,0 +1,94 @@
+require 'test/unit'
+
+class TestComparable < Test::Unit::TestCase
+ def setup
+ @o = Object.new
+ @o.extend(Comparable)
+ end
+ def cmp(b)
+ class << @o; self; end.class_eval {
+ undef :<=>
+ define_method(:<=>, b)
+ }
+ end
+
+ def test_equal
+ cmp->(x) do 0; end
+ assert_equal(true, @o == nil)
+ cmp->(x) do 1; end
+ assert_equal(false, @o == nil)
+ cmp->(x) do raise NotImplementedError, "Not a RuntimeError" end
+ assert_raise(NotImplementedError) { @o == nil }
+ bug7688 = '[ruby-core:51389] [Bug #7688]'
+ cmp->(x) do raise StandardError, "A standard error should be rescued"; end
+ warn = /Comparable#== will no more rescue exceptions .+ in the next release/
+ assert_warn(warn, bug7688) { @o == nil }
+ end
+
+ def test_gt
+ cmp->(x) do 1; end
+ assert_equal(true, @o > nil)
+ cmp->(x) do 0; end
+ assert_equal(false, @o > nil)
+ cmp->(x) do -1; end
+ assert_equal(false, @o > nil)
+ end
+
+ def test_ge
+ cmp->(x) do 1; end
+ assert_equal(true, @o >= nil)
+ cmp->(x) do 0; end
+ assert_equal(true, @o >= nil)
+ cmp->(x) do -1; end
+ assert_equal(false, @o >= nil)
+ end
+
+ def test_lt
+ cmp->(x) do 1; end
+ assert_equal(false, @o < nil)
+ cmp->(x) do 0; end
+ assert_equal(false, @o < nil)
+ cmp->(x) do -1; end
+ assert_equal(true, @o < nil)
+ end
+
+ def test_le
+ cmp->(x) do 1; end
+ assert_equal(false, @o <= nil)
+ cmp->(x) do 0; end
+ assert_equal(true, @o <= nil)
+ cmp->(x) do -1; end
+ assert_equal(true, @o <= nil)
+ end
+
+ def test_between
+ cmp->(x) do 0 <=> x end
+ assert_equal(false, @o.between?(1, 2))
+ assert_equal(false, @o.between?(-2, -1))
+ assert_equal(true, @o.between?(-1, 1))
+ assert_equal(true, @o.between?(0, 0))
+ end
+
+ def test_err
+ assert_raise(ArgumentError) { 1.0 < nil }
+ assert_raise(ArgumentError) { 1.0 < Object.new }
+ e = EnvUtil.labeled_class("E\u{30a8 30e9 30fc}")
+ assert_raise_with_message(ArgumentError, /E\u{30a8 30e9 30fc}/) {
+ 1.0 < e.new
+ }
+ end
+
+ def test_inversed_compare
+ bug7870 = '[ruby-core:52305] [Bug #7870]'
+ assert_nothing_raised(SystemStackError, bug7870) {
+ assert_nil(Time.new <=> "")
+ }
+ end
+
+ def test_no_cmp
+ bug9003 = '[ruby-core:57736] [Bug #9003]'
+ assert_nothing_raised(SystemStackError, bug9003) {
+ @o <=> @o.dup
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_complex.rb b/jni/ruby/test/ruby/test_complex.rb
new file mode 100644
index 0000000..1cbab2d
--- /dev/null
+++ b/jni/ruby/test/ruby/test_complex.rb
@@ -0,0 +1,1014 @@
+require 'test/unit'
+require 'cmath'
+
+class ComplexSub < Complex; end
+
+class Complex_Test < Test::Unit::TestCase
+
+ def test_rationalize
+ assert_equal(1.quo(3), Complex(1/3.0, 0).rationalize, '[ruby-core:38885]')
+ assert_equal(1.quo(5), Complex(0.2, 0).rationalize, '[ruby-core:38885]')
+ assert_equal(5.quo(2), Complex(2.5, 0).rationalize(0), '[ruby-core:40667]')
+ end
+
+ def test_compsub
+ c = ComplexSub.__send__(:convert, 1)
+
+ assert_kind_of(Numeric, c)
+
+ assert_instance_of(ComplexSub, c)
+
+ c2 = c + 1
+ assert_instance_of(ComplexSub, c2)
+ c2 = c - 1
+ assert_instance_of(ComplexSub, c2)
+
+ c3 = c - c2
+ assert_instance_of(ComplexSub, c3)
+
+ s = Marshal.dump(c)
+ c5 = Marshal.load(s)
+ assert_equal(c, c5)
+ assert_instance_of(ComplexSub, c5)
+
+ c1 = Complex(1)
+ assert_equal(c1.hash, c.hash, '[ruby-dev:38850]')
+ assert_equal([true, true], [c.eql?(c1), c1.eql?(c)])
+ end
+
+ def test_eql_p
+ c = Complex(0)
+ c2 = Complex(0)
+ c3 = Complex(1)
+
+ assert_equal(true, c.eql?(c2))
+ assert_equal(false, c.eql?(c3))
+
+ assert_equal(false, c.eql?(0))
+ end
+
+ def test_hash
+ assert_instance_of(Fixnum, Complex(1,2).hash)
+ assert_instance_of(Fixnum, Complex(1.0,2.0).hash)
+
+ h = {}
+ h[Complex(0)] = 0
+ h[Complex(0,1)] = 1
+ h[Complex(1,0)] = 2
+ h[Complex(1,1)] = 3
+
+ assert_equal(4, h.size)
+ assert_equal(2, h[Complex(1,0)])
+
+ h[Complex(0,0)] = 9
+ assert_equal(4, h.size)
+
+ h[Complex(0.0,0.0)] = 9.0
+ assert_equal(5, h.size)
+
+ if (0.0/0).nan? && !((0.0/0).eql?(0.0/0))
+ h = {}
+ 3.times{h[Complex(0.0/0)] = 1}
+ assert_equal(3, h.size)
+ end
+ end
+
+ def test_freeze
+ c = Complex(1)
+ c.freeze
+ assert_equal(true, c.frozen?)
+ assert_instance_of(String, c.to_s)
+ end
+
+ def test_conv
+ c = Complex(0,0)
+ assert_equal(Complex(0,0), c)
+
+ c = Complex(2**32, 2**32)
+ assert_equal(Complex(2**32,2**32), c)
+ assert_equal([2**32,2**32], [c.real,c.imag])
+
+ c = Complex(-2**32, 2**32)
+ assert_equal(Complex(-2**32,2**32), c)
+ assert_equal([-2**32,2**32], [c.real,c.imag])
+
+ c = Complex(2**32, -2**32)
+ assert_equal(Complex(2**32,-2**32), c)
+ assert_equal([2**32,-2**32], [c.real,c.imag])
+
+ c = Complex(-2**32, -2**32)
+ assert_equal(Complex(-2**32,-2**32), c)
+ assert_equal([-2**32,-2**32], [c.real,c.imag])
+
+ c = Complex(Complex(1,2),2)
+ assert_equal(Complex(1,4), c)
+
+ c = Complex(2,Complex(1,2))
+ assert_equal(Complex(0,1), c)
+
+ c = Complex(Complex(1,2),Complex(1,2))
+ assert_equal(Complex(-1,3), c)
+
+ c = Complex::I
+ assert_equal(Complex(0,1), c)
+
+ assert_equal(Complex(1),Complex(1))
+ assert_equal(Complex(1),Complex('1'))
+ assert_equal(Complex(3.0,3.0),Complex('3.0','3.0'))
+ assert_equal(Complex(1,1),Complex('3/3','3/3'))
+ assert_raise(TypeError){Complex(nil)}
+ assert_raise(TypeError){Complex(Object.new)}
+ assert_raise(ArgumentError){Complex()}
+ assert_raise(ArgumentError){Complex(1,2,3)}
+
+ if (0.0/0).nan?
+ assert_nothing_raised{Complex(0.0/0)}
+ end
+ if (1.0/0).infinite?
+ assert_nothing_raised{Complex(1.0/0)}
+ end
+ end
+
+ def test_attr
+ c = Complex(4)
+
+ assert_equal(4, c.real)
+ assert_equal(0, c.imag)
+
+ c = Complex(4,5)
+
+ assert_equal(4, c.real)
+ assert_equal(5, c.imag)
+
+ if -0.0.to_s == '-0.0'
+ c = Complex(-0.0,-0.0)
+
+ assert_equal('-0.0', c.real.to_s)
+ assert_equal('-0.0', c.imag.to_s)
+ end
+
+ c = Complex(4)
+
+ assert_equal(4, c.real)
+ assert_equal(0, c.imag)
+ assert_equal(c.imag, c.imaginary)
+
+ c = Complex(4,5)
+
+ assert_equal(4, c.real)
+ assert_equal(5, c.imag)
+ assert_equal(c.imag, c.imaginary)
+
+ if -0.0.to_s == '-0.0'
+ c = Complex(-0.0,-0.0)
+
+ assert_equal('-0.0', c.real.to_s)
+ assert_equal('-0.0', c.imag.to_s)
+ assert_equal(c.imag.to_s, c.imaginary.to_s)
+ end
+
+ c = Complex(4)
+
+ assert_equal(4, c.real)
+ assert_equal(c.imag, c.imaginary)
+ assert_equal(0, c.imag)
+
+ c = Complex(4,5)
+
+ assert_equal(4, c.real)
+ assert_equal(5, c.imag)
+ assert_equal(c.imag, c.imaginary)
+
+ c = Complex(-0.0,-0.0)
+
+ assert_equal('-0.0', c.real.to_s)
+ assert_equal('-0.0', c.imag.to_s)
+ assert_equal(c.imag.to_s, c.imaginary.to_s)
+ end
+
+ def test_attr2
+ c = Complex(1)
+
+ assert_equal(false, c.integer?)
+ assert_equal(false, c.real?)
+
+ assert_equal(true, Complex(0).zero?)
+ assert_equal(true, Complex(0,0).zero?)
+ assert_equal(false, Complex(1,0).zero?)
+ assert_equal(false, Complex(0,1).zero?)
+ assert_equal(false, Complex(1,1).zero?)
+
+ assert_equal(nil, Complex(0).nonzero?)
+ assert_equal(nil, Complex(0,0).nonzero?)
+ assert_equal(Complex(1,0), Complex(1,0).nonzero?)
+ assert_equal(Complex(0,1), Complex(0,1).nonzero?)
+ assert_equal(Complex(1,1), Complex(1,1).nonzero?)
+ end
+
+ def test_rect
+ assert_equal([1,2], Complex.rectangular(1,2).rectangular)
+ assert_equal([1,2], Complex.rect(1,2).rect)
+ end
+
+ def test_polar
+ assert_equal([1,2], Complex.polar(1,2).polar)
+ end
+
+ def test_uplus
+ assert_equal(Complex(1), +Complex(1))
+ assert_equal(Complex(-1), +Complex(-1))
+ assert_equal(Complex(1,1), +Complex(1,1))
+ assert_equal(Complex(-1,1), +Complex(-1,1))
+ assert_equal(Complex(1,-1), +Complex(1,-1))
+ assert_equal(Complex(-1,-1), +Complex(-1,-1))
+
+ if -0.0.to_s == '-0.0'
+ c = +Complex(0.0,0.0)
+ assert_equal('0.0', c.real.to_s)
+ assert_equal('0.0', c.imag.to_s)
+
+ c = +Complex(-0.0,-0.0)
+ assert_equal('-0.0', c.real.to_s)
+ assert_equal('-0.0', c.imag.to_s)
+ end
+ end
+
+ def test_negate
+ assert_equal(Complex(-1), -Complex(1))
+ assert_equal(Complex(1), -Complex(-1))
+ assert_equal(Complex(-1,-1), -Complex(1,1))
+ assert_equal(Complex(1,-1), -Complex(-1,1))
+ assert_equal(Complex(-1,1), -Complex(1,-1))
+ assert_equal(Complex(1,1), -Complex(-1,-1))
+
+ if -0.0.to_s == '-0.0'
+ c = -Complex(0.0,0.0)
+ assert_equal('-0.0', c.real.to_s)
+ assert_equal('-0.0', c.imag.to_s)
+
+ c = -Complex(-0.0,-0.0)
+ assert_equal('0.0', c.real.to_s)
+ assert_equal('0.0', c.imag.to_s)
+ end
+ end
+
+ def test_add
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(3,5), c + c2)
+
+ assert_equal(Complex(3,2), c + 2)
+ assert_equal(Complex(3.0,2), c + 2.0)
+
+ assert_equal(Complex(Rational(3,1),Rational(2)), c + Rational(2))
+ assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3))
+ end
+
+ def test_sub
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(-1,-1), c - c2)
+
+ assert_equal(Complex(-1,2), c - 2)
+ assert_equal(Complex(-1.0,2), c - 2.0)
+
+ assert_equal(Complex(Rational(-1,1),Rational(2)), c - Rational(2))
+ assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3))
+ end
+
+ def test_mul
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(-4,7), c * c2)
+
+ assert_equal(Complex(2,4), c * 2)
+ assert_equal(Complex(2.0,4.0), c * 2.0)
+
+ assert_equal(Complex(Rational(2,1),Rational(4)), c * Rational(2))
+ assert_equal(Complex(Rational(2,3),Rational(4,3)), c * Rational(2,3))
+ end
+
+ def test_div
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2)
+
+ c = Complex(1.0,2.0)
+ c2 = Complex(2.0,3.0)
+
+ r = c / c2
+ assert_in_delta(0.615, r.real, 0.001)
+ assert_in_delta(0.076, r.imag, 0.001)
+
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(Rational(1,2),1), c / 2)
+ assert_equal(Complex(0.5,1.0), c / 2.0)
+
+ assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+ assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+ end
+
+ def test_quo
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(Rational(8,13),Rational(1,13)), c.quo(c2))
+
+ c = Complex(1.0,2.0)
+ c2 = Complex(2.0,3.0)
+
+ r = c.quo(c2)
+ assert_in_delta(0.615, r.real, 0.001)
+ assert_in_delta(0.076, r.imag, 0.001)
+
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(Rational(1,2),1), c.quo(2))
+ assert_equal(Complex(0.5,1.0), c.quo(2.0))
+
+ assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+ assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+ end
+
+ def test_fdiv
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ r = c.fdiv(c2)
+ assert_in_delta(0.615, r.real, 0.001)
+ assert_in_delta(0.076, r.imag, 0.001)
+
+ c = Complex(1.0,2.0)
+ c2 = Complex(2.0,3.0)
+
+ r = c.fdiv(c2)
+ assert_in_delta(0.615, r.real, 0.001)
+ assert_in_delta(0.076, r.imag, 0.001)
+
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ assert_equal(Complex(0.5,1.0), c.fdiv(2))
+ assert_equal(Complex(0.5,1.0), c.fdiv(2.0))
+ end
+
+ def test_expt
+ c = Complex(1,2)
+ c2 = Complex(2,3)
+
+ r = c ** c2
+ assert_in_delta(-0.015, r.real, 0.001)
+ assert_in_delta(-0.179, r.imag, 0.001)
+
+ assert_equal(Complex(-3,4), c ** 2)
+ assert_equal(Complex(Rational(-3,25),Rational(-4,25)), c ** -2)
+
+ r = c ** 2.0
+ assert_in_delta(-3.0, r.real, 0.001)
+ assert_in_delta(4.0, r.imag, 0.001)
+
+ r = c ** -2.0
+ assert_in_delta(-0.12, r.real, 0.001)
+ assert_in_delta(-0.16, r.imag, 0.001)
+
+ assert_equal(Complex(-3,4), c ** Rational(2))
+ assert_equal(Complex(Rational(-3,25),Rational(-4,25)),
+ c ** Rational(-2)) # why failed?
+
+ r = c ** Rational(2,3)
+ assert_in_delta(1.264, r.real, 0.001)
+ assert_in_delta(1.150, r.imag, 0.001)
+
+ r = c ** Rational(-2,3)
+ assert_in_delta(0.432, r.real, 0.001)
+ assert_in_delta(-0.393, r.imag, 0.001)
+ end
+
+ def test_cmp
+ assert_raise(NoMethodError){1 <=> Complex(1,1)}
+ assert_raise(NoMethodError){Complex(1,1) <=> 1}
+ assert_raise(NoMethodError){Complex(1,1) <=> Complex(1,1)}
+ end
+
+ def test_eqeq
+ assert_equal(Complex(1), Complex(1,0))
+ assert_equal(Complex(-1), Complex(-1,0))
+
+ assert_not_equal(Complex(1), Complex(2,1))
+ assert_operator(Complex(2,1), :!=, Complex(1))
+ assert_not_equal(nil, Complex(1))
+ assert_not_equal('', Complex(1))
+
+ nan = 0.0 / 0
+ if nan.nan? && nan != nan
+ assert_not_equal(Complex(nan, 0), Complex(nan, 0))
+ assert_not_equal(Complex(0, nan), Complex(0, nan))
+ assert_not_equal(Complex(nan, nan), Complex(nan, nan))
+ end
+ end
+
+ def test_coerce
+ assert_equal([Complex(2),Complex(1)], Complex(1).coerce(2))
+ assert_equal([Complex(2.2),Complex(1)], Complex(1).coerce(2.2))
+ assert_equal([Complex(Rational(2)),Complex(1)],
+ Complex(1).coerce(Rational(2)))
+ assert_equal([Complex(2),Complex(1)], Complex(1).coerce(Complex(2)))
+ end
+
+ class ObjectX
+ def + (x) Rational(1) end
+ alias - +
+ alias * +
+ alias / +
+ alias quo +
+ alias ** +
+ def coerce(x) [x, Complex(1)] end
+ end
+
+ def test_coerce2
+ x = ObjectX.new
+ %w(+ - * / quo **).each do |op|
+ assert_kind_of(Numeric, Complex(1).__send__(op, x))
+ end
+ end
+
+ def test_math
+ c = Complex(1,2)
+
+ assert_in_delta(2.236, c.abs, 0.001)
+ assert_in_delta(2.236, c.magnitude, 0.001)
+ assert_equal(5, c.abs2)
+
+ assert_equal(c.abs, Math.sqrt(c * c.conj))
+ assert_equal(c.abs, Math.sqrt(c.real**2 + c.imag**2))
+ assert_equal(c.abs2, c * c.conj)
+ assert_equal(c.abs2, c.real**2 + c.imag**2)
+
+ assert_in_delta(1.107, c.arg, 0.001)
+ assert_in_delta(1.107, c.angle, 0.001)
+ assert_in_delta(1.107, c.phase, 0.001)
+
+ r = c.polar
+ assert_in_delta(2.236, r[0], 0.001)
+ assert_in_delta(1.107, r[1], 0.001)
+ assert_equal(Complex(1,-2), c.conjugate)
+ assert_equal(Complex(1,-2), c.conj)
+
+ assert_equal(Complex(1,2), c.numerator)
+ assert_equal(1, c.denominator)
+ end
+
+ def test_to_s
+ c = Complex(1,2)
+
+ assert_instance_of(String, c.to_s)
+ assert_equal('1+2i', c.to_s)
+
+ assert_equal('0+2i', Complex(0,2).to_s)
+ assert_equal('0-2i', Complex(0,-2).to_s)
+ assert_equal('1+2i', Complex(1,2).to_s)
+ assert_equal('-1+2i', Complex(-1,2).to_s)
+ assert_equal('-1-2i', Complex(-1,-2).to_s)
+ assert_equal('1-2i', Complex(1,-2).to_s)
+ assert_equal('-1-2i', Complex(-1,-2).to_s)
+
+ assert_equal('0+2.0i', Complex(0,2.0).to_s)
+ assert_equal('0-2.0i', Complex(0,-2.0).to_s)
+ assert_equal('1.0+2.0i', Complex(1.0,2.0).to_s)
+ assert_equal('-1.0+2.0i', Complex(-1.0,2.0).to_s)
+ assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+ assert_equal('1.0-2.0i', Complex(1.0,-2.0).to_s)
+ assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+
+ assert_equal('0+2/1i', Complex(0,Rational(2)).to_s)
+ assert_equal('0-2/1i', Complex(0,Rational(-2)).to_s)
+ assert_equal('1+2/1i', Complex(1,Rational(2)).to_s)
+ assert_equal('-1+2/1i', Complex(-1,Rational(2)).to_s)
+ assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s)
+ assert_equal('1-2/1i', Complex(1,Rational(-2)).to_s)
+ assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s)
+
+ assert_equal('0+2/3i', Complex(0,Rational(2,3)).to_s)
+ assert_equal('0-2/3i', Complex(0,Rational(-2,3)).to_s)
+ assert_equal('1+2/3i', Complex(1,Rational(2,3)).to_s)
+ assert_equal('-1+2/3i', Complex(-1,Rational(2,3)).to_s)
+ assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s)
+ assert_equal('1-2/3i', Complex(1,Rational(-2,3)).to_s)
+ assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s)
+
+ nan = 0.0 / 0
+ inf = 1.0 / 0
+ if nan.nan?
+ assert_equal('NaN+NaN*i', Complex(nan,nan).to_s)
+ end
+ if inf.infinite?
+ assert_equal('Infinity+Infinity*i', Complex(inf,inf).to_s)
+ assert_equal('Infinity-Infinity*i', Complex(inf,-inf).to_s)
+ end
+ end
+
+ def test_inspect
+ c = Complex(1,2)
+
+ assert_instance_of(String, c.inspect)
+ assert_equal('(1+2i)', c.inspect)
+ end
+
+ def test_marshal
+ c = Complex(1,2)
+ c.instance_eval{@ivar = 9}
+
+ s = Marshal.dump(c)
+ c2 = Marshal.load(s)
+ assert_equal(c, c2)
+ assert_equal(9, c2.instance_variable_get(:@ivar))
+ assert_instance_of(Complex, c2)
+
+ c = Complex(Rational(1,2),Rational(2,3))
+
+ s = Marshal.dump(c)
+ c2 = Marshal.load(s)
+ assert_equal(c, c2)
+ assert_instance_of(Complex, c2)
+
+ bug3656 = '[ruby-core:31622]'
+ c = Complex(1,2)
+ c.freeze
+ assert_predicate(c, :frozen?)
+ result = c.marshal_load([2,3]) rescue :fail
+ assert_equal(:fail, result, bug3656)
+ assert_equal(Complex(1,2), c)
+ end
+
+ def test_marshal_compatibility
+ bug6625 = '[ruby-core:45775]'
+ dump = "\x04\x08o:\x0cComplex\x07:\x0a@reali\x06:\x0b@imagei\x07"
+ assert_nothing_raised(bug6625) do
+ assert_equal(Complex(1, 2), Marshal.load(dump), bug6625)
+ end
+ end
+
+ def test_parse
+ assert_equal(Complex(5), '5'.to_c)
+ assert_equal(Complex(-5), '-5'.to_c)
+ assert_equal(Complex(5,3), '5+3i'.to_c)
+ assert_equal(Complex(-5,3), '-5+3i'.to_c)
+ assert_equal(Complex(5,-3), '5-3i'.to_c)
+ assert_equal(Complex(-5,-3), '-5-3i'.to_c)
+ assert_equal(Complex(0,3), '3i'.to_c)
+ assert_equal(Complex(0,-3), '-3i'.to_c)
+ assert_equal(Complex(5,1), '5+i'.to_c)
+ assert_equal(Complex(0,1), 'i'.to_c)
+ assert_equal(Complex(0,1), '+i'.to_c)
+ assert_equal(Complex(0,-1), '-i'.to_c)
+
+ assert_equal(Complex(5,3), '5+3I'.to_c)
+ assert_equal(Complex(5,3), '5+3j'.to_c)
+ assert_equal(Complex(5,3), '5+3J'.to_c)
+ assert_equal(Complex(0,3), '3I'.to_c)
+ assert_equal(Complex(0,3), '3j'.to_c)
+ assert_equal(Complex(0,3), '3J'.to_c)
+ assert_equal(Complex(0,1), 'I'.to_c)
+ assert_equal(Complex(0,1), 'J'.to_c)
+
+ assert_equal(Complex(5.0), '5.0'.to_c)
+ assert_equal(Complex(-5.0), '-5.0'.to_c)
+ assert_equal(Complex(5.0,3.0), '5.0+3.0i'.to_c)
+ assert_equal(Complex(-5.0,3.0), '-5.0+3.0i'.to_c)
+ assert_equal(Complex(5.0,-3.0), '5.0-3.0i'.to_c)
+ assert_equal(Complex(-5.0,-3.0), '-5.0-3.0i'.to_c)
+ assert_equal(Complex(0.0,3.0), '3.0i'.to_c)
+ assert_equal(Complex(0.0,-3.0), '-3.0i'.to_c)
+
+ assert_equal(Complex(5.1), '5.1'.to_c)
+ assert_equal(Complex(-5.2), '-5.2'.to_c)
+ assert_equal(Complex(5.3,3.4), '5.3+3.4i'.to_c)
+ assert_equal(Complex(-5.5,3.6), '-5.5+3.6i'.to_c)
+ assert_equal(Complex(5.3,-3.4), '5.3-3.4i'.to_c)
+ assert_equal(Complex(-5.5,-3.6), '-5.5-3.6i'.to_c)
+ assert_equal(Complex(0.0,3.1), '3.1i'.to_c)
+ assert_equal(Complex(0.0,-3.2), '-3.2i'.to_c)
+
+ assert_equal(Complex(5.0), '5e0'.to_c)
+ assert_equal(Complex(-5.0), '-5e0'.to_c)
+ assert_equal(Complex(5.0,3.0), '5e0+3e0i'.to_c)
+ assert_equal(Complex(-5.0,3.0), '-5e0+3e0i'.to_c)
+ assert_equal(Complex(5.0,-3.0), '5e0-3e0i'.to_c)
+ assert_equal(Complex(-5.0,-3.0), '-5e0-3e0i'.to_c)
+ assert_equal(Complex(0.0,3.0), '3e0i'.to_c)
+ assert_equal(Complex(0.0,-3.0), '-3e0i'.to_c)
+
+ assert_equal(Complex(5e1), '5e1'.to_c)
+ assert_equal(Complex(-5e2), '-5e2'.to_c)
+ assert_equal(Complex(5e3,3e4), '5e003+3e4i'.to_c)
+ assert_equal(Complex(-5e5,3e6), '-5e5+3e006i'.to_c)
+ assert_equal(Complex(5e3,-3e4), '5e003-3e4i'.to_c)
+ assert_equal(Complex(-5e5,-3e6), '-5e5-3e006i'.to_c)
+ assert_equal(Complex(0.0,3e1), '3e1i'.to_c)
+ assert_equal(Complex(0.0,-3e2), '-3e2i'.to_c)
+
+ assert_equal(Complex(0.33), '.33'.to_c)
+ assert_equal(Complex(0.33), '0.33'.to_c)
+ assert_equal(Complex(-0.33), '-.33'.to_c)
+ assert_equal(Complex(-0.33), '-0.33'.to_c)
+ assert_equal(Complex(-0.33), '-0.3_3'.to_c)
+
+ assert_equal(Complex.polar(10,10), '10@10'.to_c)
+ assert_equal(Complex.polar(-10,-10), '-10@-10'.to_c)
+ assert_equal(Complex.polar(10.5,10.5), '10.5@10.5'.to_c)
+ assert_equal(Complex.polar(-10.5,-10.5), '-10.5@-10.5'.to_c)
+
+ assert_equal(Complex(5), Complex('5'))
+ assert_equal(Complex(-5), Complex('-5'))
+ assert_equal(Complex(5,3), Complex('5+3i'))
+ assert_equal(Complex(-5,3), Complex('-5+3i'))
+ assert_equal(Complex(5,-3), Complex('5-3i'))
+ assert_equal(Complex(-5,-3), Complex('-5-3i'))
+ assert_equal(Complex(0,3), Complex('3i'))
+ assert_equal(Complex(0,-3), Complex('-3i'))
+ assert_equal(Complex(5,1), Complex('5+i'))
+ assert_equal(Complex(0,1), Complex('i'))
+ assert_equal(Complex(0,1), Complex('+i'))
+ assert_equal(Complex(0,-1), Complex('-i'))
+
+ assert_equal(Complex(5,3), Complex('5+3I'))
+ assert_equal(Complex(5,3), Complex('5+3j'))
+ assert_equal(Complex(5,3), Complex('5+3J'))
+ assert_equal(Complex(0,3), Complex('3I'))
+ assert_equal(Complex(0,3), Complex('3j'))
+ assert_equal(Complex(0,3), Complex('3J'))
+ assert_equal(Complex(0,1), Complex('I'))
+ assert_equal(Complex(0,1), Complex('J'))
+
+ assert_equal(Complex(5.0), Complex('5.0'))
+ assert_equal(Complex(-5.0), Complex('-5.0'))
+ assert_equal(Complex(5.0,3.0), Complex('5.0+3.0i'))
+ assert_equal(Complex(-5.0,3.0), Complex('-5.0+3.0i'))
+ assert_equal(Complex(5.0,-3.0), Complex('5.0-3.0i'))
+ assert_equal(Complex(-5.0,-3.0), Complex('-5.0-3.0i'))
+ assert_equal(Complex(0.0,3.0), Complex('3.0i'))
+ assert_equal(Complex(0.0,-3.0), Complex('-3.0i'))
+
+ assert_equal(Complex(5.1), Complex('5.1'))
+ assert_equal(Complex(-5.2), Complex('-5.2'))
+ assert_equal(Complex(5.3,3.4), Complex('5.3+3.4i'))
+ assert_equal(Complex(-5.5,3.6), Complex('-5.5+3.6i'))
+ assert_equal(Complex(5.3,-3.4), Complex('5.3-3.4i'))
+ assert_equal(Complex(-5.5,-3.6), Complex('-5.5-3.6i'))
+ assert_equal(Complex(0.0,3.1), Complex('3.1i'))
+ assert_equal(Complex(0.0,-3.2), Complex('-3.2i'))
+
+ assert_equal(Complex(5.0), Complex('5e0'))
+ assert_equal(Complex(-5.0), Complex('-5e0'))
+ assert_equal(Complex(5.0,3.0), Complex('5e0+3e0i'))
+ assert_equal(Complex(-5.0,3.0), Complex('-5e0+3e0i'))
+ assert_equal(Complex(5.0,-3.0), Complex('5e0-3e0i'))
+ assert_equal(Complex(-5.0,-3.0), Complex('-5e0-3e0i'))
+ assert_equal(Complex(0.0,3.0), Complex('3e0i'))
+ assert_equal(Complex(0.0,-3.0), Complex('-3e0i'))
+
+ assert_equal(Complex(5e1), Complex('5e1'))
+ assert_equal(Complex(-5e2), Complex('-5e2'))
+ assert_equal(Complex(5e3,3e4), Complex('5e003+3e4i'))
+ assert_equal(Complex(-5e5,3e6), Complex('-5e5+3e006i'))
+ assert_equal(Complex(5e3,-3e4), Complex('5e003-3e4i'))
+ assert_equal(Complex(-5e5,-3e6), Complex('-5e5-3e006i'))
+ assert_equal(Complex(0.0,3e1), Complex('3e1i'))
+ assert_equal(Complex(0.0,-3e2), Complex('-3e2i'))
+
+ assert_equal(Complex(0.33), Complex('.33'))
+ assert_equal(Complex(0.33), Complex('0.33'))
+ assert_equal(Complex(-0.33), Complex('-.33'))
+ assert_equal(Complex(-0.33), Complex('-0.33'))
+ assert_equal(Complex(-0.33), Complex('-0.3_3'))
+
+ assert_equal(Complex.polar(10,10), Complex('10@10'))
+ assert_equal(Complex.polar(-10,-10), Complex('-10@-10'))
+ assert_equal(Complex.polar(10.5,10.5), Complex('10.5@10.5'))
+ assert_equal(Complex.polar(-10.5,-10.5), Complex('-10.5@-10.5'))
+
+ assert_equal(Complex(0), ''.to_c)
+ assert_equal(Complex(0), ' '.to_c)
+ assert_equal(Complex(5), "\f\n\r\t\v5\0".to_c)
+ assert_equal(Complex(0), '_'.to_c)
+ assert_equal(Complex(0), '_5'.to_c)
+ assert_equal(Complex(5), '5_'.to_c)
+ assert_equal(Complex(5), '5x'.to_c)
+ assert_equal(Complex(5), '5+_3i'.to_c)
+ assert_equal(Complex(5), '5+3_i'.to_c)
+ assert_equal(Complex(5,3), '5+3i_'.to_c)
+ assert_equal(Complex(5,3), '5+3ix'.to_c)
+ assert_raise(ArgumentError){ Complex('')}
+ assert_raise(ArgumentError){ Complex('_')}
+ assert_raise(ArgumentError){ Complex("\f\n\r\t\v5\0")}
+ assert_raise(ArgumentError){ Complex('_5')}
+ assert_raise(ArgumentError){ Complex('5_')}
+ assert_raise(ArgumentError){ Complex('5x')}
+ assert_raise(ArgumentError){ Complex('5+_3i')}
+ assert_raise(ArgumentError){ Complex('5+3_i')}
+ assert_raise(ArgumentError){ Complex('5+3i_')}
+ assert_raise(ArgumentError){ Complex('5+3ix')}
+
+ assert_equal(Complex(Rational(1,5)), '1/5'.to_c)
+ assert_equal(Complex(Rational(-1,5)), '-1/5'.to_c)
+ assert_equal(Complex(Rational(1,5),3), '1/5+3i'.to_c)
+ assert_equal(Complex(Rational(1,5),-3), '1/5-3i'.to_c)
+ assert_equal(Complex(Rational(-1,5),3), '-1/5+3i'.to_c)
+ assert_equal(Complex(Rational(-1,5),-3), '-1/5-3i'.to_c)
+ assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c)
+ assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c)
+ assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c)
+ assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c)
+ assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c)
+ assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c)
+ assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c)
+ assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c)
+ assert_equal(Complex.polar(Rational(1,5),Rational(3,2)), Complex('1/5@3/2'))
+ assert_equal(Complex.polar(Rational(-1,5),Rational(-3,2)), Complex('-1/5@-3/2'))
+
+ end
+
+ def test_respond
+ c = Complex(1,1)
+ assert_equal(false, c.respond_to?(:%))
+ assert_equal(false, c.respond_to?(:<))
+ assert_equal(false, c.respond_to?(:<=))
+ assert_equal(false, c.respond_to?(:<=>))
+ assert_equal(false, c.respond_to?(:>))
+ assert_equal(false, c.respond_to?(:>=))
+ assert_equal(false, c.respond_to?(:between?))
+ assert_equal(false, c.respond_to?(:div))
+ assert_equal(false, c.respond_to?(:divmod))
+ assert_equal(false, c.respond_to?(:floor))
+ assert_equal(false, c.respond_to?(:ceil))
+ assert_equal(false, c.respond_to?(:modulo))
+ assert_equal(false, c.respond_to?(:remainder))
+ assert_equal(false, c.respond_to?(:round))
+ assert_equal(false, c.respond_to?(:step))
+ assert_equal(false, c.respond_to?(:tunrcate))
+
+ assert_equal(false, c.respond_to?(:positive?))
+ assert_equal(false, c.respond_to?(:negative?))
+ assert_equal(false, c.respond_to?(:sign))
+
+ assert_equal(false, c.respond_to?(:quotient))
+ assert_equal(false, c.respond_to?(:quot))
+ assert_equal(false, c.respond_to?(:quotrem))
+
+ assert_equal(false, c.respond_to?(:gcd))
+ assert_equal(false, c.respond_to?(:lcm))
+ assert_equal(false, c.respond_to?(:gcdlcm))
+ end
+
+ def test_to_i
+ assert_equal(3, Complex(3).to_i)
+ assert_equal(3, Integer(Complex(3)))
+ assert_raise(RangeError){Complex(3,2).to_i}
+ assert_raise(RangeError){Integer(Complex(3,2))}
+ end
+
+ def test_to_f
+ assert_equal(3.0, Complex(3).to_f)
+ assert_equal(3.0, Float(Complex(3)))
+ assert_raise(RangeError){Complex(3,2).to_f}
+ assert_raise(RangeError){Float(Complex(3,2))}
+ end
+
+ def test_to_r
+ assert_equal(Rational(3), Complex(3).to_r)
+ assert_equal(Rational(3), Rational(Complex(3)))
+ assert_raise(RangeError){Complex(3,2).to_r}
+ assert_raise(RangeError){Rational(Complex(3,2))}
+ end
+
+ def test_to_c
+ c = nil.to_c
+ assert_equal([0,0], [c.real, c.imag])
+
+ c = 0.to_c
+ assert_equal([0,0], [c.real, c.imag])
+
+ c = 1.to_c
+ assert_equal([1,0], [c.real, c.imag])
+
+ c = 1.1.to_c
+ assert_equal([1.1, 0], [c.real, c.imag])
+
+ c = Rational(1,2).to_c
+ assert_equal([Rational(1,2), 0], [c.real, c.imag])
+
+ c = Complex(1,2).to_c
+ assert_equal([1, 2], [c.real, c.imag])
+
+ if (0.0/0).nan?
+ assert_nothing_raised{(0.0/0).to_c}
+ end
+ if (1.0/0).infinite?
+ assert_nothing_raised{(1.0/0).to_c}
+ end
+ end
+
+ def test_supp
+ assert_equal(true, 1.real?)
+ assert_equal(true, 1.1.real?)
+
+ assert_equal(1, 1.real)
+ assert_equal(0, 1.imag)
+ assert_equal(0, 1.imaginary)
+
+ assert_equal(1.1, 1.1.real)
+ assert_equal(0, 1.1.imag)
+ assert_equal(0, 1.1.imaginary)
+
+ assert_equal(1, 1.magnitude)
+ assert_equal(1, -1.magnitude)
+ assert_equal(1, 1.0.magnitude)
+ assert_equal(1, -1.0.magnitude)
+
+ assert_equal(4, 2.abs2)
+ assert_equal(4, -2.abs2)
+ assert_equal(4.0, 2.0.abs2)
+ assert_equal(4.0, -2.0.abs2)
+
+ assert_equal(0, 1.arg)
+ assert_equal(0, 1.angle)
+ assert_equal(0, 1.phase)
+
+ assert_equal(0, 1.0.arg)
+ assert_equal(0, 1.0.angle)
+ assert_equal(0, 1.0.phase)
+
+ if (0.0/0).nan?
+ nan = 0.0/0
+ assert_same(nan, nan.arg)
+ assert_same(nan, nan.angle)
+ assert_same(nan, nan.phase)
+ end
+
+ assert_equal(Math::PI, -1.arg)
+ assert_equal(Math::PI, -1.angle)
+ assert_equal(Math::PI, -1.phase)
+
+ assert_equal(Math::PI, -1.0.arg)
+ assert_equal(Math::PI, -1.0.angle)
+ assert_equal(Math::PI, -1.0.phase)
+
+ assert_equal([1,0], 1.rect)
+ assert_equal([-1,0], -1.rect)
+ assert_equal([1,0], 1.rectangular)
+ assert_equal([-1,0], -1.rectangular)
+
+ assert_equal([1.0,0], 1.0.rect)
+ assert_equal([-1.0,0], -1.0.rect)
+ assert_equal([1.0,0], 1.0.rectangular)
+ assert_equal([-1.0,0], -1.0.rectangular)
+
+ assert_equal([1,0], 1.polar)
+ assert_equal([1, Math::PI], -1.polar)
+
+ assert_equal([1.0,0], 1.0.polar)
+ assert_equal([1.0, Math::PI], -1.0.polar)
+
+ assert_equal(1, 1.conjugate)
+ assert_equal(-1, -1.conjugate)
+ assert_equal(1, 1.conj)
+ assert_equal(-1, -1.conj)
+
+ assert_equal(1.1, 1.1.conjugate)
+ assert_equal(-1.1, -1.1.conjugate)
+ assert_equal(1.1, 1.1.conj)
+ assert_equal(-1.1, -1.1.conj)
+
+ assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2))
+
+ assert_equal(0.5, 1.fdiv(2))
+ assert_equal(5000000000.0, 10000000000.fdiv(2))
+ assert_equal(0.5, 1.0.fdiv(2))
+ assert_equal(0.25, Rational(1,2).fdiv(2))
+ assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2))
+
+ unless $".grep(/(?:\A|(?<!add)\/)complex/).empty?
+ assert_equal(Complex(0,2), CMath.sqrt(-4.0))
+ assert_equal(Complex(0,2), CMath.sqrt(-4))
+ assert_equal(Complex(0,2), CMath.sqrt(Rational(-4)))
+
+ assert_equal(Complex(0,3), CMath.sqrt(-9.0))
+ assert_equal(Complex(0,3), CMath.sqrt(-9))
+ assert_equal(Complex(0,3), CMath.sqrt(Rational(-9)))
+
+ c = CMath.sqrt(Complex(1, 2))
+ assert_in_delta(1.272, c.real, 0.001)
+ assert_in_delta(0.786, c.imag, 0.001)
+
+ c = CMath.sqrt(-9)
+ assert_in_delta(0.0, c.real, 0.001)
+ assert_in_delta(3.0, c.imag, 0.001)
+
+ c = CMath.exp(Complex(1, 2))
+ assert_in_delta(-1.131, c.real, 0.001)
+ assert_in_delta(2.471, c.imag, 0.001)
+
+ c = CMath.sin(Complex(1, 2))
+ assert_in_delta(3.165, c.real, 0.001)
+ assert_in_delta(1.959, c.imag, 0.001)
+
+ c = CMath.cos(Complex(1, 2))
+ assert_in_delta(2.032, c.real, 0.001)
+ assert_in_delta(-3.051, c.imag, 0.001)
+
+ c = CMath.tan(Complex(1, 2))
+ assert_in_delta(0.033, c.real, 0.001)
+ assert_in_delta(1.014, c.imag, 0.001)
+
+ c = CMath.sinh(Complex(1, 2))
+ assert_in_delta(-0.489, c.real, 0.001)
+ assert_in_delta(1.403, c.imag, 0.001)
+
+ c = CMath.cosh(Complex(1, 2))
+ assert_in_delta(-0.642, c.real, 0.001)
+ assert_in_delta(1.068, c.imag, 0.001)
+
+ c = CMath.tanh(Complex(1, 2))
+ assert_in_delta(1.166, c.real, 0.001)
+ assert_in_delta(-0.243, c.imag, 0.001)
+
+ c = CMath.log(Complex(1, 2))
+ assert_in_delta(0.804, c.real, 0.001)
+ assert_in_delta(1.107, c.imag, 0.001)
+
+ c = CMath.log(Complex(1, 2), Math::E)
+ assert_in_delta(0.804, c.real, 0.001)
+ assert_in_delta(1.107, c.imag, 0.001)
+
+ c = CMath.log(-1)
+ assert_in_delta(0.0, c.real, 0.001)
+ assert_in_delta(Math::PI, c.imag, 0.001)
+
+ c = CMath.log(8, 2)
+ assert_in_delta(3.0, c.real, 0.001)
+ assert_in_delta(0.0, c.imag, 0.001)
+
+ c = CMath.log(-8, -2)
+ assert_in_delta(1.092, c.real, 0.001)
+ assert_in_delta(-0.420, c.imag, 0.001)
+
+ c = CMath.log10(Complex(1, 2))
+ assert_in_delta(0.349, c.real, 0.001)
+ assert_in_delta(0.480, c.imag, 0.001)
+
+ c = CMath.asin(Complex(1, 2))
+ assert_in_delta(0.427, c.real, 0.001)
+ assert_in_delta(1.528, c.imag, 0.001)
+
+ c = CMath.acos(Complex(1, 2))
+ assert_in_delta(1.143, c.real, 0.001)
+ assert_in_delta(-1.528, c.imag, 0.001)
+
+ c = CMath.atan(Complex(1, 2))
+ assert_in_delta(1.338, c.real, 0.001)
+ assert_in_delta(0.402, c.imag, 0.001)
+
+ c = CMath.atan2(Complex(1, 2), 1)
+ assert_in_delta(1.338, c.real, 0.001)
+ assert_in_delta(0.402, c.imag, 0.001)
+
+ c = CMath.asinh(Complex(1, 2))
+ assert_in_delta(1.469, c.real, 0.001)
+ assert_in_delta(1.063, c.imag, 0.001)
+
+ c = CMath.acosh(Complex(1, 2))
+ assert_in_delta(1.528, c.real, 0.001)
+ assert_in_delta(1.143, c.imag, 0.001)
+
+ c = CMath.atanh(Complex(1, 2))
+ assert_in_delta(0.173, c.real, 0.001)
+ assert_in_delta(1.178, c.imag, 0.001)
+ end
+
+ end
+
+ def test_ruby19
+ assert_raise(NoMethodError){ Complex.new(1) }
+ assert_raise(NoMethodError){ Complex.new!(1) }
+ assert_raise(NoMethodError){ Complex.reduce(1) }
+ end
+
+ def test_fixed_bug
+ assert_equal(Complex(1), 1 ** Complex(1))
+ assert_equal('-1.0-0.0i', Complex(-1.0, -0.0).to_s)
+ assert_in_delta(Math::PI, Complex(-0.0).arg, 0.001)
+ assert_equal(Complex(2e3, 2e4), '2e3+2e4i'.to_c)
+ assert_raise(ArgumentError){ Complex('--8i')}
+ end
+
+ def test_known_bug
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_complex2.rb b/jni/ruby/test/ruby/test_complex2.rb
new file mode 100644
index 0000000..3ee7810
--- /dev/null
+++ b/jni/ruby/test/ruby/test_complex2.rb
@@ -0,0 +1,735 @@
+require 'test/unit'
+
+class Complex_Test2 < Test::Unit::TestCase
+
+ def test_kumi
+ skip unless defined?(Rational)
+
+ assert_equal(Complex(1, 0), +Complex(1, 0))
+ assert_equal(Complex(-1, 0), -Complex(1, 0))
+ assert_equal(Complex(2, 0),
+ Complex(1, 0) + Complex(1, 0))
+ assert_equal(Complex(0, 0),
+ Complex(1, 0) - Complex(1, 0))
+ assert_equal(Complex(1, 0),
+ Complex(1, 0) * Complex(1, 0))
+ assert_equal(Complex(1, 0),
+ Complex(1, 0) / Complex(1, 0))
+ assert_equal(Complex(1073741790, 0),
+ Complex(1, 0) + Complex(1073741789, 0))
+ assert_equal(Complex(-1073741788, 0),
+ Complex(1, 0) - Complex(1073741789, 0))
+ assert_equal(Complex(1073741789, 0),
+ Complex(1, 0) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1, 1073741789), 0),
+ Complex(1, 0) / Complex(1073741789, 0))
+ assert_equal(Complex(1073741828, 0),
+ Complex(1, 0) + Complex(1073741827, 0))
+ assert_equal(Complex(-1073741826, 0),
+ Complex(1, 0) - Complex(1073741827, 0))
+ assert_equal(Complex(1073741827, 0),
+ Complex(1, 0) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1, 1073741827), 0),
+ Complex(1, 0) / Complex(1073741827, 0))
+ assert_equal(Complex(1073741790, 1073741789),
+ Complex(1, 0) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(-1073741788, -1073741789),
+ Complex(1, 0) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(1073741789, 1073741789),
+ Complex(1, 0) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1, 2147483578), Rational(-1, 2147483578)),
+ Complex(1, 0) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(1073741790, 1073741827),
+ Complex(1, 0) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(-1073741788, -1073741827),
+ Complex(1, 0) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(1073741789, 1073741827),
+ Complex(1, 0) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1073741789, 2305842940494218450), Rational(-1073741827, 2305842940494218450)),
+ Complex(1, 0) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(1073741828, 1073741827),
+ Complex(1, 0) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(-1073741826, -1073741827),
+ Complex(1, 0) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(1073741827, 1073741827),
+ Complex(1, 0) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1, 2147483654), Rational(-1, 2147483654)),
+ Complex(1, 0) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(1, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(38, 1073741827), Rational(-1073741789, 1073741827)),
+ Complex(1, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(1, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1073741827, 2147483578), Rational(-1073741827, 2147483578)),
+ Complex(1, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(2147483616, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(1, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-38, 1073741789), Rational(-1073741827, 1073741789)),
+ Complex(1, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(1, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741789, 2147483654), Rational(-1073741789, 2147483654)),
+ Complex(1, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(1, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(38, 1073741827), Rational(-1073741827, 1073741789)),
+ Complex(1, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(1, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1329227869515035739611240300898290063, 2658455833113515253509575011810600482), Rational(-1329227963598474519442525600436190287, 2658455833113515253509575011810600482)),
+ Complex(1, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741789, 0), +Complex(1073741789, 0))
+ assert_equal(Complex(-1073741789, 0), -Complex(1073741789, 0))
+ assert_equal(Complex(1073741790, 0),
+ Complex(1073741789, 0) + Complex(1, 0))
+ assert_equal(Complex(1073741788, 0),
+ Complex(1073741789, 0) - Complex(1, 0))
+ assert_equal(Complex(1073741789, 0),
+ Complex(1073741789, 0) * Complex(1, 0))
+ assert_equal(Complex(1073741789, 0),
+ Complex(1073741789, 0) / Complex(1, 0))
+ assert_equal(Complex(2147483578, 0),
+ Complex(1073741789, 0) + Complex(1073741789, 0))
+ assert_equal(Complex(0, 0),
+ Complex(1073741789, 0) - Complex(1073741789, 0))
+ assert_equal(Complex(1152921429444920521, 0),
+ Complex(1073741789, 0) * Complex(1073741789, 0))
+ assert_equal(Complex(1, 0),
+ Complex(1073741789, 0) / Complex(1073741789, 0))
+ assert_equal(Complex(2147483616, 0),
+ Complex(1073741789, 0) + Complex(1073741827, 0))
+ assert_equal(Complex(-38, 0),
+ Complex(1073741789, 0) - Complex(1073741827, 0))
+ assert_equal(Complex(1152921470247108503, 0),
+ Complex(1073741789, 0) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), 0),
+ Complex(1073741789, 0) / Complex(1073741827, 0))
+ assert_equal(Complex(2147483578, 1073741789),
+ Complex(1073741789, 0) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, -1073741789),
+ Complex(1073741789, 0) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(1152921429444920521, 1152921429444920521),
+ Complex(1073741789, 0) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1, 2), Rational(-1, 2)),
+ Complex(1073741789, 0) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(2147483578, 1073741827),
+ Complex(1073741789, 0) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(0, -1073741827),
+ Complex(1073741789, 0) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(1152921429444920521, 1152921470247108503),
+ Complex(1073741789, 0) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921429444920521, 2305842940494218450), Rational(-1152921470247108503, 2305842940494218450)),
+ Complex(1073741789, 0) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(2147483616, 1073741827),
+ Complex(1073741789, 0) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(-38, -1073741827),
+ Complex(1073741789, 0) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(1152921470247108503, 1152921470247108503),
+ Complex(1073741789, 0) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1073741789, 2147483654), Rational(-1073741789, 2147483654)),
+ Complex(1073741789, 0) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(1073741789, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(-1073741789, 1073741827)),
+ Complex(1073741789, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921429444920521, 1073741827), Rational(1152921429444920521, 1073741827)),
+ Complex(1073741789, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1073741827, 2), Rational(-1073741827, 2)),
+ Complex(1073741789, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(1073741789, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(-1073741827, 1073741789)),
+ Complex(1073741789, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741827, 1073741827),
+ Complex(1073741789, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921429444920521, 2147483654), Rational(-1152921429444920521, 2147483654)),
+ Complex(1073741789, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(1073741789, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(-1073741827, 1073741789)),
+ Complex(1073741789, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921429444920521, 1073741827), 1073741827),
+ Complex(1073741789, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1427247510601733037449111325195428279286542707, 2658455833113515253509575011810600482), Rational(-1427247611623052908177132720890654139107803443, 2658455833113515253509575011810600482)),
+ Complex(1073741789, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741827, 0), +Complex(1073741827, 0))
+ assert_equal(Complex(-1073741827, 0), -Complex(1073741827, 0))
+ assert_equal(Complex(1073741828, 0),
+ Complex(1073741827, 0) + Complex(1, 0))
+ assert_equal(Complex(1073741826, 0),
+ Complex(1073741827, 0) - Complex(1, 0))
+ assert_equal(Complex(1073741827, 0),
+ Complex(1073741827, 0) * Complex(1, 0))
+ assert_equal(Complex(1073741827, 0),
+ Complex(1073741827, 0) / Complex(1, 0))
+ assert_equal(Complex(2147483616, 0),
+ Complex(1073741827, 0) + Complex(1073741789, 0))
+ assert_equal(Complex(38, 0),
+ Complex(1073741827, 0) - Complex(1073741789, 0))
+ assert_equal(Complex(1152921470247108503, 0),
+ Complex(1073741827, 0) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1073741827, 1073741789), 0),
+ Complex(1073741827, 0) / Complex(1073741789, 0))
+ assert_equal(Complex(2147483654, 0),
+ Complex(1073741827, 0) + Complex(1073741827, 0))
+ assert_equal(Complex(0, 0),
+ Complex(1073741827, 0) - Complex(1073741827, 0))
+ assert_equal(Complex(1152921511049297929, 0),
+ Complex(1073741827, 0) * Complex(1073741827, 0))
+ assert_equal(Complex(1, 0),
+ Complex(1073741827, 0) / Complex(1073741827, 0))
+ assert_equal(Complex(2147483616, 1073741789),
+ Complex(1073741827, 0) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(38, -1073741789),
+ Complex(1073741827, 0) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(1152921470247108503, 1152921470247108503),
+ Complex(1073741827, 0) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1073741827, 2147483578), Rational(-1073741827, 2147483578)),
+ Complex(1073741827, 0) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(2147483616, 1073741827),
+ Complex(1073741827, 0) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(38, -1073741827),
+ Complex(1073741827, 0) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(1152921470247108503, 1152921511049297929),
+ Complex(1073741827, 0) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921470247108503, 2305842940494218450), Rational(-1152921511049297929, 2305842940494218450)),
+ Complex(1073741827, 0) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(2147483654, 1073741827),
+ Complex(1073741827, 0) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, -1073741827),
+ Complex(1073741827, 0) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(1152921511049297929, 1152921511049297929),
+ Complex(1073741827, 0) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1, 2), Rational(-1, 2)),
+ Complex(1073741827, 0) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(1073741827, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(-1073741789, 1073741827)),
+ Complex(1073741827, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(1073741789, 1073741789),
+ Complex(1073741827, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921511049297929, 2147483578), Rational(-1152921511049297929, 2147483578)),
+ Complex(1073741827, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(1073741827, 0) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921469173366676, 1073741789), Rational(-1073741827, 1073741789)),
+ Complex(1073741827, 0) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921511049297929, 1073741789), Rational(1152921511049297929, 1073741789)),
+ Complex(1073741827, 0) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741789, 2), Rational(-1073741789, 2)),
+ Complex(1073741827, 0) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(1073741827, 0) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(-1073741827, 1073741789)),
+ Complex(1073741827, 0) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741789, Rational(1152921511049297929, 1073741789)),
+ Complex(1073741827, 0) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1427247561112392079020469430422559713421565101, 2658455833113515253509575011810600482), Rational(-1427247662133715524919164459706626955683034349, 2658455833113515253509575011810600482)),
+ Complex(1073741827, 0) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741789, 1073741789), +Complex(1073741789, 1073741789))
+ assert_equal(Complex(-1073741789, -1073741789), -Complex(1073741789, 1073741789))
+ assert_equal(Complex(1073741790, 1073741789),
+ Complex(1073741789, 1073741789) + Complex(1, 0))
+ assert_equal(Complex(1073741788, 1073741789),
+ Complex(1073741789, 1073741789) - Complex(1, 0))
+ assert_equal(Complex(1073741789, 1073741789),
+ Complex(1073741789, 1073741789) * Complex(1, 0))
+ assert_equal(Complex(1073741789, 1073741789),
+ Complex(1073741789, 1073741789) / Complex(1, 0))
+ assert_equal(Complex(2147483578, 1073741789),
+ Complex(1073741789, 1073741789) + Complex(1073741789, 0))
+ assert_equal(Complex(0, 1073741789),
+ Complex(1073741789, 1073741789) - Complex(1073741789, 0))
+ assert_equal(Complex(1152921429444920521, 1152921429444920521),
+ Complex(1073741789, 1073741789) * Complex(1073741789, 0))
+ assert_equal(Complex(1, 1),
+ Complex(1073741789, 1073741789) / Complex(1073741789, 0))
+ assert_equal(Complex(2147483616, 1073741789),
+ Complex(1073741789, 1073741789) + Complex(1073741827, 0))
+ assert_equal(Complex(-38, 1073741789),
+ Complex(1073741789, 1073741789) - Complex(1073741827, 0))
+ assert_equal(Complex(1152921470247108503, 1152921470247108503),
+ Complex(1073741789, 1073741789) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(1073741789, 1073741789) / Complex(1073741827, 0))
+ assert_equal(Complex(2147483578, 2147483578),
+ Complex(1073741789, 1073741789) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, 0),
+ Complex(1073741789, 1073741789) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, 2305842858889841042),
+ Complex(1073741789, 1073741789) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(1, 0),
+ Complex(1073741789, 1073741789) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(2147483578, 2147483616),
+ Complex(1073741789, 1073741789) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(0, -38),
+ Complex(1073741789, 1073741789) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(-40802187982, 2305842899692029024),
+ Complex(1073741789, 1073741789) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921449846014512, 1152921470247109225), Rational(-20401093991, 1152921470247109225)),
+ Complex(1073741789, 1073741789) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(2147483616, 2147483616),
+ Complex(1073741789, 1073741789) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(-38, -38),
+ Complex(1073741789, 1073741789) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, 2305842940494217006),
+ Complex(1073741789, 1073741789) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1073741789, 1073741827), 0),
+ Complex(1073741789, 1073741789) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850292, 1073741827)),
+ Complex(1073741789, 1073741789) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921469173366714, 1073741827)),
+ Complex(1073741789, 1073741789) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, Rational(2305842858889841042, 1073741827)),
+ Complex(1073741789, 1073741789) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(1073741827, 0),
+ Complex(1073741789, 1073741789) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921430518662348, 1073741789)),
+ Complex(1073741789, 1073741789) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(1152921428371178694, 1073741789)),
+ Complex(1073741789, 1073741789) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, 2147483654),
+ Complex(1073741789, 1073741789) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921429444920521, 1073741827), 0),
+ Complex(1073741789, 1073741789) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921430518662348, 1073741789)),
+ Complex(1073741789, 1073741789) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921428371178694, 1073741789)),
+ Complex(1073741789, 1073741789) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1073741827), Rational(2305842940494218450, 1073741827)),
+ Complex(1073741789, 1073741789) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1427247561112392972813122023043041209197173075, 1329227916556757626754787505905300241), Rational(-50510659935364010697847612929910630368, 1329227916556757626754787505905300241)),
+ Complex(1073741789, 1073741789) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741789, 1073741827), +Complex(1073741789, 1073741827))
+ assert_equal(Complex(-1073741789, -1073741827), -Complex(1073741789, 1073741827))
+ assert_equal(Complex(1073741790, 1073741827),
+ Complex(1073741789, 1073741827) + Complex(1, 0))
+ assert_equal(Complex(1073741788, 1073741827),
+ Complex(1073741789, 1073741827) - Complex(1, 0))
+ assert_equal(Complex(1073741789, 1073741827),
+ Complex(1073741789, 1073741827) * Complex(1, 0))
+ assert_equal(Complex(1073741789, 1073741827),
+ Complex(1073741789, 1073741827) / Complex(1, 0))
+ assert_equal(Complex(2147483578, 1073741827),
+ Complex(1073741789, 1073741827) + Complex(1073741789, 0))
+ assert_equal(Complex(0, 1073741827),
+ Complex(1073741789, 1073741827) - Complex(1073741789, 0))
+ assert_equal(Complex(1152921429444920521, 1152921470247108503),
+ Complex(1073741789, 1073741827) * Complex(1073741789, 0))
+ assert_equal(Complex(1, Rational(1073741827, 1073741789)),
+ Complex(1073741789, 1073741827) / Complex(1073741789, 0))
+ assert_equal(Complex(2147483616, 1073741827),
+ Complex(1073741789, 1073741827) + Complex(1073741827, 0))
+ assert_equal(Complex(-38, 1073741827),
+ Complex(1073741789, 1073741827) - Complex(1073741827, 0))
+ assert_equal(Complex(1152921470247108503, 1152921511049297929),
+ Complex(1073741789, 1073741827) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), 1),
+ Complex(1073741789, 1073741827) / Complex(1073741827, 0))
+ assert_equal(Complex(2147483578, 2147483616),
+ Complex(1073741789, 1073741827) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, 38),
+ Complex(1073741789, 1073741827) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(-40802187982, 2305842899692029024),
+ Complex(1073741789, 1073741827) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1073741808, 1073741789), Rational(19, 1073741789)),
+ Complex(1073741789, 1073741827) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(2147483578, 2147483654),
+ Complex(1073741789, 1073741827) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(0, 0),
+ Complex(1073741789, 1073741827) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(-81604377408, 2305842940494217006),
+ Complex(1073741789, 1073741827) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(1, 0),
+ Complex(1073741789, 1073741827) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(2147483616, 2147483654),
+ Complex(1073741789, 1073741827) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(-38, 0),
+ Complex(1073741789, 1073741827) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(-40802189426, 2305842981296406432),
+ Complex(1073741789, 1073741827) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1073741808, 1073741827), Rational(19, 1073741827)),
+ Complex(1073741789, 1073741827) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921512123039718, 1073741827)),
+ Complex(1073741789, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921509975556140, 1073741827)),
+ Complex(1073741789, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(-40802187982, 1073741827), Rational(2305842899692029024, 1073741827)),
+ Complex(1073741789, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921490648203216, 1073741789), Rational(20401094713, 1073741789)),
+ Complex(1073741789, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921471320850330, 1073741789)),
+ Complex(1073741789, 1073741827) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921428371178694, 1073741789), Rational(1152921469173366676, 1073741789)),
+ Complex(1073741789, 1073741827) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-40802189426, 1073741789), Rational(2305842981296406432, 1073741789)),
+ Complex(1073741789, 1073741827) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921449846014512, 1073741827), Rational(20401093991, 1073741827)),
+ Complex(1073741789, 1073741827) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850330, 1073741789)),
+ Complex(1073741789, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921469173366714, 1073741827), Rational(1152921469173366676, 1073741789)),
+ Complex(1073741789, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-131433047608170424214, 1152921470247108503), 2147483616),
+ Complex(1073741789, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1427247586367724281184137892451027617484788528, 1329227916556757626754787505905300241), Rational(-25255330414578331645234047212843119171, 1329227916556757626754787505905300241)),
+ Complex(1073741789, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741827, 1073741827), +Complex(1073741827, 1073741827))
+ assert_equal(Complex(-1073741827, -1073741827), -Complex(1073741827, 1073741827))
+ assert_equal(Complex(1073741828, 1073741827),
+ Complex(1073741827, 1073741827) + Complex(1, 0))
+ assert_equal(Complex(1073741826, 1073741827),
+ Complex(1073741827, 1073741827) - Complex(1, 0))
+ assert_equal(Complex(1073741827, 1073741827),
+ Complex(1073741827, 1073741827) * Complex(1, 0))
+ assert_equal(Complex(1073741827, 1073741827),
+ Complex(1073741827, 1073741827) / Complex(1, 0))
+ assert_equal(Complex(2147483616, 1073741827),
+ Complex(1073741827, 1073741827) + Complex(1073741789, 0))
+ assert_equal(Complex(38, 1073741827),
+ Complex(1073741827, 1073741827) - Complex(1073741789, 0))
+ assert_equal(Complex(1152921470247108503, 1152921470247108503),
+ Complex(1073741827, 1073741827) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(1073741827, 1073741827) / Complex(1073741789, 0))
+ assert_equal(Complex(2147483654, 1073741827),
+ Complex(1073741827, 1073741827) + Complex(1073741827, 0))
+ assert_equal(Complex(0, 1073741827),
+ Complex(1073741827, 1073741827) - Complex(1073741827, 0))
+ assert_equal(Complex(1152921511049297929, 1152921511049297929),
+ Complex(1073741827, 1073741827) * Complex(1073741827, 0))
+ assert_equal(Complex(1, 1),
+ Complex(1073741827, 1073741827) / Complex(1073741827, 0))
+ assert_equal(Complex(2147483616, 2147483616),
+ Complex(1073741827, 1073741827) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(38, 38),
+ Complex(1073741827, 1073741827) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, 2305842940494217006),
+ Complex(1073741827, 1073741827) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1073741827, 1073741789), 0),
+ Complex(1073741827, 1073741827) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(2147483616, 2147483654),
+ Complex(1073741827, 1073741827) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(38, 0),
+ Complex(1073741827, 1073741827) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(-40802189426, 2305842981296406432),
+ Complex(1073741827, 1073741827) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921490648203216, 1152921470247109225), Rational(-20401094713, 1152921470247109225)),
+ Complex(1073741827, 1073741827) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(2147483654, 2147483654),
+ Complex(1073741827, 1073741827) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, 0),
+ Complex(1073741827, 1073741827) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, 2305843022098595858),
+ Complex(1073741827, 1073741827) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(1, 0),
+ Complex(1073741827, 1073741827) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921512123039718, 1073741827)),
+ Complex(1073741827, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(1152921509975556140, 1073741827)),
+ Complex(1073741827, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, 2147483578),
+ Complex(1073741827, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921511049297929, 1073741789), 0),
+ Complex(1073741827, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1152921471320850330, 1073741789)),
+ Complex(1073741827, 1073741827) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921469173366676, 1073741789), Rational(1152921469173366676, 1073741789)),
+ Complex(1073741827, 1073741827) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, Rational(2305843022098595858, 1073741789)),
+ Complex(1073741827, 1073741827) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1073741789, 0),
+ Complex(1073741827, 1073741827) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921471320850330, 1073741789)),
+ Complex(1073741827, 1073741827) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921509975556140, 1073741827), Rational(1152921469173366676, 1073741789)),
+ Complex(1073741827, 1073741827) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1073741789), Rational(2305842940494218450, 1073741789)),
+ Complex(1073741827, 1073741827) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1427247611623053801969816945064593334552299725, 1329227916556757626754787505905300241), Rational(-50510661722949347514642033621130734624, 1329227916556757626754787505905300241)),
+ Complex(1073741827, 1073741827) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)), +Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(-1073741789, 1073741827), Rational(-1073741789, 1073741827)), -Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1, 0))
+ assert_equal(Complex(Rational(-38, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1, 0))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 0))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1152921429444920521, 1073741827), Rational(1152921429444920521, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1, 1073741827), Rational(1, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741827, 0))
+ assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(1073741789, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741827, 0))
+ assert_equal(Complex(1073741789, 1073741789),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1073741789, 1152921511049297929), Rational(1073741789, 1152921511049297929)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850292, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921469173366714, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, Rational(2305842858889841042, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1, 1073741827), 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921512123039718, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921509975556140, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-40802187982, 1073741827), Rational(2305842899692029024, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921449846014512, 1237940005850657200720054075), Rational(-20401093991, 1237940005850657200720054075)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921512123039718, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(-1152921509975556140, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, 2147483578),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1073741789, 1152921511049297929), 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2147483578, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, Rational(2305842858889841042, 1152921511049297929)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(1, 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2305842940494218450, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1152921470247108503), Rational(-81604377408, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, 2),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921429444920521, 1152921511049297929), 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2305842940494218450, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, Rational(-81604377408, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1152921511049297929), Rational(2305842940494218450, 1152921511049297929)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1329227869515036572020512360130906225, 1329227916556757626754787505905300241), Rational(-47041717725097069072123994784, 1329227916556757626754787505905300241)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)), +Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-1073741827, 1073741789), Rational(-1073741827, 1073741789)), -Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2147483616, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1, 0))
+ assert_equal(Complex(Rational(38, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1, 0))
+ assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1, 0))
+ assert_equal(Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1, 0))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 0))
+ assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 0))
+ assert_equal(Complex(1073741827, 1073741827),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1073741827, 1152921429444920521), Rational(1073741827, 1152921429444920521)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741827, 0))
+ assert_equal(Complex(Rational(-1152921469173366676, 1073741789), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1152921511049297929, 1073741789), Rational(1152921511049297929, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1, 1073741789), Rational(1, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921430518662348, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(-1152921428371178694, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(0, 2147483654),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1073741827, 1152921429444920521), 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1152921430518662348, 1073741789), Rational(1152921471320850330, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-1152921428371178694, 1073741789), Rational(-1152921469173366676, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-40802189426, 1073741789), Rational(2305842981296406432, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921490648203216, 1237939962039641331329903525), Rational(-20401094713, 1237939962039641331329903525)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921471320850330, 1073741789), Rational(1152921471320850330, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(-1152921469173366676, 1073741789), Rational(-1152921469173366676, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(0, Rational(2305843022098595858, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1, 1073741789), 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2305842940494218450, 1152921470247108503)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(81604377408, 1152921470247108503), Rational(81604377408, 1152921470247108503)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, 2),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921511049297929, 1152921429444920521), 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(2147483654, 1073741789), Rational(2147483654, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, Rational(2305843022098595858, 1152921429444920521)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1, 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2147483654, 1073741789)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(81604377408, 1152921470247108503), 0),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1152921429444920521), Rational(2305842940494218450, 1152921429444920521)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1329227963598475351851856578029295025, 1329227916556757626754787505905300241), Rational(-47041721054734275145774394016, 1329227916556757626754787505905300241)),
+ Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)), +Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-1073741789, 1073741827), Rational(-1073741827, 1073741789)), -Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2147483616, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1, 0))
+ assert_equal(Complex(Rational(-38, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1, 0))
+ assert_equal(Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1, 0))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 0))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1152921429444920521, 1073741827), 1073741827),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1, 1073741827), Rational(1073741827, 1152921429444920521)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 0))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741827, 0))
+ assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(1073741827, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741827, 0))
+ assert_equal(Complex(1073741789, Rational(1152921511049297929, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1073741789, 1152921511049297929), Rational(1, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741827, 0))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921430518662348, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921428371178694, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(-81604377408, 1073741827), Rational(2305842940494218450, 1073741827)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1152921470247109225, 1237939962039640556088331867), Rational(40802188704, 1237939962039640556088331867)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741789))
+ assert_equal(Complex(Rational(1152921471320850292, 1073741827), Rational(1152921471320850330, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-1152921469173366714, 1073741827), Rational(-1152921469173366676, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(-131433047608170424214, 1152921470247108503), 2147483616),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1237939983945150041266564176, 1329227916556755129526882950667240175), Rational(19, 1152921470247109225)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741789, 1073741827))
+ assert_equal(Complex(Rational(1152921512123039718, 1073741827), Rational(1152921471320850330, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(-1152921509975556140, 1073741827), Rational(-1152921469173366676, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(-81604377408, 1073741789), Rational(2305842940494218450, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(1152921470247109225, 1237940005850656425478454981), Rational(40802188704, 1237940005850656425478454981)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(1073741827, 1073741827))
+ assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2305842940494218450, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(0, Rational(81604377408, 1152921470247108503)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(-81604377408, 1152921511049297929), Rational(2305842940494218450, 1152921511049297929)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(1152921470247109225, 1152921429444920521), Rational(40802188704, 1152921429444920521)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827)))
+ assert_equal(Complex(Rational(2305842940494218450, 1152921470247108503), Rational(2147483654, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1152921470247108503), 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-81604377408, 1152921429444920521), Rational(2305842940494218450, 1152921429444920521)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(1152921470247109225, 1152921511049297929), Rational(40802188704, 1152921511049297929)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(2147483578, 1073741827), Rational(2147483654, 1073741789)),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) + Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(0, 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) - Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(Rational(-188166877559662688435796777600, 1329227916556754297117581432254901009), 2),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) * Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ assert_equal(Complex(1, 0),
+ Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)) / Complex(Rational(1073741789, 1073741827), Rational(1073741827, 1073741789)))
+ end
+
+ def test_kumi2
+ assert_equal('0.0+0.0i', (+Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0-0.0i', (-Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) * Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(-0.0, +0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(+0.0, +0.0) * Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) * Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) + Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, +0.0) - Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, +0.0) * Complex(-0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (+Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (-Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) + Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) - Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) * Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) + Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) - Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(-0.0, +0.0) * Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) + Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) - Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) * Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, +0.0) + Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) - Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, +0.0) * Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0-0.0i', (+Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (-Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) + Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) - Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) * Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) + Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) - Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) * Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) + Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) - Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) * Complex(+0.0, -0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(+0.0, -0.0) + Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(+0.0, -0.0) - Complex(-0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(+0.0, -0.0) * Complex(-0.0, -0.0)).to_s)
+ assert_equal('-0.0-0.0i', (+Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (-Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) + Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0-0.0i', (Complex(-0.0, -0.0) - Complex(+0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) * Complex(+0.0, +0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) + Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) - Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) * Complex(-0.0, +0.0)).to_s)
+ assert_equal('0.0-0.0i', (Complex(-0.0, -0.0) + Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) - Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0+0.0i', (Complex(-0.0, -0.0) * Complex(+0.0, -0.0)).to_s)
+ assert_equal('-0.0-0.0i', (Complex(-0.0, -0.0) + Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) - Complex(-0.0, -0.0)).to_s)
+ assert_equal('0.0+0.0i', (Complex(-0.0, -0.0) * Complex(-0.0, -0.0)).to_s)
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_complexrational.rb b/jni/ruby/test/ruby/test_complexrational.rb
new file mode 100644
index 0000000..cef4074
--- /dev/null
+++ b/jni/ruby/test/ruby/test_complexrational.rb
@@ -0,0 +1,407 @@
+require 'test/unit'
+
+class ComplexRational_Test < Test::Unit::TestCase
+
+ def test_rat_srat
+ skip unless defined?(Rational)
+
+ c = SimpleRat(1,3)
+ cc = Rational(3,2)
+
+ assert_kind_of(Numeric, c)
+ assert_kind_of(Numeric, cc)
+
+ assert_instance_of(SimpleRat, c)
+ assert_instance_of(Rational, cc)
+
+ assert_equal(SimpleRat(1,3), +c)
+ assert_equal(SimpleRat(-1,3), -c)
+
+ assert_equal(SimpleRat(7,3), c + 2)
+ assert_equal(SimpleRat(-5,3), c - 2)
+ assert_equal(SimpleRat(2,3), c * 2)
+ assert_equal(SimpleRat(1,6), c / 2)
+ assert_equal(SimpleRat(1,9), c ** 2)
+ assert_equal(-1, c <=> 2)
+
+ assert_equal(SimpleRat(7,3), 2 + c)
+ assert_equal(SimpleRat(5,3), 2 - c)
+ assert_equal(SimpleRat(2,3), 2 * c)
+ assert_equal(SimpleRat(6,1), 2 / c)
+ assert_in_delta(1.2599, 2 ** c, 0.001)
+ assert_equal(1, 2 <=> c)
+
+ assert_equal(SimpleRat(11,6), c + cc)
+ assert_equal(SimpleRat(-7,6), c - cc)
+ assert_equal(SimpleRat(1,2), c * cc)
+ assert_equal(SimpleRat(2,9), c / cc)
+ assert_in_delta(0.1924, c ** cc, 0.001)
+ assert_equal(-1, c <=> cc)
+
+ assert_equal(SimpleRat(11,6), cc + c)
+ assert_equal(SimpleRat(7,6), cc - c)
+ assert_equal(SimpleRat(1,2), cc * c)
+ assert_equal(SimpleRat(9,2), cc / c)
+ assert_in_delta(1.1447, cc ** c, 0.001)
+ assert_equal(1, cc <=> c)
+
+ assert_equal(SimpleRat, (+c).class)
+ assert_equal(SimpleRat, (-c).class)
+
+ assert_equal(SimpleRat, (c + 2).class)
+ assert_equal(SimpleRat, (c - 2).class)
+ assert_equal(SimpleRat, (c * 2).class)
+ assert_equal(SimpleRat, (c / 2).class)
+ assert_equal(SimpleRat, (c ** 2).class)
+
+ assert_equal(SimpleRat, (2 + c).class)
+ assert_equal(SimpleRat, (2 - c).class)
+ assert_equal(SimpleRat, (2 * c).class)
+ assert_equal(SimpleRat, (2 / c).class)
+ assert_equal(Float, (2 ** c).class)
+
+ assert_equal(SimpleRat, (c + cc).class)
+ assert_equal(SimpleRat, (c - cc).class)
+ assert_equal(SimpleRat, (c * cc).class)
+ assert_equal(SimpleRat, (c / cc).class)
+ assert_equal(Float, (c ** cc).class)
+
+ assert_equal(SimpleRat, (cc + c).class)
+ assert_equal(SimpleRat, (cc - c).class)
+ assert_equal(SimpleRat, (cc * c).class)
+ assert_equal(SimpleRat, (cc / c).class)
+ assert_equal(Float, (cc ** c).class)
+
+ assert_equal(0, Rational(2,3) <=> SimpleRat(2,3))
+ assert_equal(0, SimpleRat(2,3) <=> Rational(2,3))
+ assert_equal(Rational(2,3), SimpleRat(2,3))
+ assert_equal(SimpleRat(2,3), Rational(2,3))
+
+ assert_equal(SimpleRat, (c + 0).class)
+ assert_equal(SimpleRat, (c - 0).class)
+ assert_equal(SimpleRat, (c * 0).class)
+ assert_equal(SimpleRat, (c * 1).class)
+ assert_equal(SimpleRat, (0 + c).class)
+ assert_equal(SimpleRat, (0 - c).class)
+ assert_equal(SimpleRat, (0 * c).class)
+ assert_equal(SimpleRat, (1 * c).class)
+ end
+
+ def test_comp_srat
+ skip unless defined?(Rational)
+
+ c = Complex(SimpleRat(2,3),SimpleRat(1,2))
+ cc = Complex(Rational(3,2),Rational(2,1))
+
+ assert_equal(Complex(SimpleRat(2,3),SimpleRat(1,2)), +c)
+ assert_equal(Complex(SimpleRat(-2,3),SimpleRat(-1,2)), -c)
+
+ assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), c + 2)
+ assert_equal(Complex(SimpleRat(-4,3),SimpleRat(1,2)), c - 2)
+ assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), c * 2)
+ assert_equal(Complex(SimpleRat(1,3),SimpleRat(1,4)), c / 2)
+ assert_equal(Complex(SimpleRat(7,36),SimpleRat(2,3)), c ** 2)
+ assert_raise(NoMethodError){c <=> 2}
+
+ assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), 2 + c)
+ assert_equal(Complex(SimpleRat(4,3),SimpleRat(-1,2)), 2 - c)
+ assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), 2 * c)
+ assert_equal(Complex(SimpleRat(48,25),SimpleRat(-36,25)), 2 / c)
+ r = 2 ** c
+ assert_in_delta(1.4940, r.real, 0.001)
+ assert_in_delta(0.5392, r.imag, 0.001)
+ assert_raise(NoMethodError){2 <=> c}
+
+ assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), c + cc)
+ assert_equal(Complex(SimpleRat(-5,6),SimpleRat(-3,2)), c - cc)
+ assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), c * cc)
+ assert_equal(Complex(SimpleRat(8,25),SimpleRat(-7,75)), c / cc)
+ r = c ** cc
+ assert_in_delta(0.1732, r.real, 0.001)
+ assert_in_delta(0.1186, r.imag, 0.001)
+ assert_raise(NoMethodError){c <=> cc}
+
+ assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), cc + c)
+ assert_equal(Complex(SimpleRat(5,6),SimpleRat(3,2)), cc - c)
+ assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), cc * c)
+ assert_equal(Complex(SimpleRat(72,25),SimpleRat(21,25)), cc / c)
+ r = cc ** c
+ assert_in_delta(0.5498, r.real, 0.001)
+ assert_in_delta(1.0198, r.imag, 0.001)
+ assert_raise(NoMethodError){cc <=> c}
+
+ assert_equal([SimpleRat,SimpleRat],
+ (+c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (-c).instance_eval{[real.class, imag.class]})
+
+ assert_equal([SimpleRat,SimpleRat],
+ (c + 2).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c - 2).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c * 2).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c / 2).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c ** 2).instance_eval{[real.class, imag.class]})
+
+ assert_equal([SimpleRat,SimpleRat],
+ (c + cc).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c - cc).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c * cc).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c / cc).instance_eval{[real.class, imag.class]})
+ assert_equal([Float,Float],
+ (c ** cc).instance_eval{[real.class, imag.class]})
+
+ assert_equal([SimpleRat,SimpleRat],
+ (cc + c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (cc - c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (cc * c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (cc / c).instance_eval{[real.class, imag.class]})
+ assert_equal([Float,Float],
+ (cc ** c).instance_eval{[real.class, imag.class]})
+
+ assert_equal(Complex(SimpleRat(2,3),SimpleRat(3,2)),
+ Complex(Rational(2,3),Rational(3,2)))
+ assert_equal(Complex(Rational(2,3),Rational(3,2)),
+ Complex(SimpleRat(2,3),SimpleRat(3,2)))
+
+ assert_equal([SimpleRat,SimpleRat],
+ (c + 0).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c - 0).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c * 0).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (c * 1).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (0 + c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (0 - c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (0 * c).instance_eval{[real.class, imag.class]})
+ assert_equal([SimpleRat,SimpleRat],
+ (1 * c).instance_eval{[real.class, imag.class]})
+ end
+
+end
+
+def SimpleRat(*a) SimpleRat.new(*a) end
+
+class SimpleRat < Numeric
+
+ def initialize(num, den = 1)
+ if den == 0
+ raise ZeroDivisionError, "divided by zero"
+ end
+ if den < 0
+ num = -num
+ den = -den
+ end
+ gcd = num.gcd(den)
+ @num = num.div(gcd)
+ @den = den.div(gcd)
+ end
+
+ def numerator() @num end
+ def denominator() @den end
+
+ def +@ () self end
+ def -@ () self.class.new(-@num, @den) end
+
+ def + (o)
+ case o
+ when SimpleRat, Rational
+ a = @num * o.denominator
+ b = o.numerator * @den
+ self.class.new(a + b, @den * o.denominator)
+ when Integer
+ self + self.class.new(o)
+ when Float
+ to_f + o
+ else
+ x, y = o.coerce(self)
+ x + y
+ end
+ end
+
+ def - (o)
+ case o
+ when SimpleRat, Rational
+ a = @num * o.denominator
+ b = o.numerator * @den
+ self.class.new(a - b, @den * o.denominator)
+ when Integer
+ self - self.class.new(o)
+ when Float
+ to_f - o
+ else
+ x, y = o.coerce(self)
+ x - y
+ end
+ end
+
+ def * (o)
+ case o
+ when SimpleRat, Rational
+ a = @num * o.numerator
+ b = @den * o.denominator
+ self.class.new(a, b)
+ when Integer
+ self * self.class.new(o)
+ when Float
+ to_f * o
+ else
+ x, y = o.coerce(self)
+ x * y
+ end
+ end
+
+ def quo(o)
+ case o
+ when SimpleRat, Rational
+ a = @num * o.denominator
+ b = @den * o.numerator
+ self.class.new(a, b)
+ when Integer
+ if o == 0
+ raise raise ZeroDivisionError, "divided by zero"
+ end
+ self.quo(self.class.new(o))
+ when Float
+ to_f.quo(o)
+ else
+ x, y = o.coerce(self)
+ x.quo(y)
+ end
+ end
+
+ alias / quo
+
+ def floor
+ @num.div(@den)
+ end
+
+ def ceil
+ -((-@num).div(@den))
+ end
+
+ def truncate
+ if @num < 0
+ return -((-@num).div(@den))
+ end
+ @num.div(@den)
+ end
+
+ alias to_i truncate
+
+ def round
+ if @num < 0
+ num = -@num
+ num = num * 2 + @den
+ den = @den * 2
+ -(num.div(den))
+ else
+ num = @num * 2 + @den
+ den = @den * 2
+ num.div(den)
+ end
+ end
+
+ def div(o) (self / o).floor end
+ def quot(o) (self / o).truncate end
+
+ def modulo(o)
+ q = div(o)
+ self - o * q
+ end
+
+ def remainder(o)
+ q = quot(o)
+ self - o * q
+ end
+
+ alias % modulo
+
+ def divmod(o) [div(o), modulo(o)] end
+ def quotrem(o) [quot(o), remainder(o)] end
+
+ def ** (o)
+ case o
+ when SimpleRat, Rational
+ Float(self) ** o
+ when Integer
+ if o > 0
+ a = @num ** o
+ b = @den ** o
+ elsif o < 0
+ a = @den ** -o
+ b = @num ** -o
+ else
+ a = b = 1
+ end
+ self.class.new(a, b)
+ when Float
+ to_f ** o
+ else
+ x, y = o.coerce(self)
+ x ** y
+ end
+ end
+
+ def <=> (o)
+ case o
+ when SimpleRat, Rational
+ a = @num * o.denominator
+ b = o.numerator * @den
+ return a <=> b
+ when Integer
+ self <=> self.class.new(o)
+ when Float
+ to_f <=> o
+ else
+ x, y = o.coerce(self)
+ x <=> y
+ end
+ end
+
+ def == (o)
+ begin
+ (self <=> o) == 0
+ rescue
+ false
+ end
+ end
+
+ def coerce(o)
+ case o
+ when Rational
+ [self.class.new(o.numerator, o.denominator), self]
+ when Integer
+ [self.class.new(o), self]
+ when Float
+ [o, self.to_f]
+ else
+ super
+ end
+ end
+
+ def hash() @num.hash ^ @den.hash end
+
+ def to_f() @num.to_f / @den.to_f end
+ def to_r() self end
+ def to_s() format('%s/%s', @num, @den) end
+
+ def inspect() format('#SR(%s)', to_s) end
+
+ def marshal_dump() [@num, @den] end
+ def marshal_load(a) @num, @den = a end
+
+end
diff --git a/jni/ruby/test/ruby/test_condition.rb b/jni/ruby/test/ruby/test_condition.rb
new file mode 100644
index 0000000..ba2e068
--- /dev/null
+++ b/jni/ruby/test/ruby/test_condition.rb
@@ -0,0 +1,16 @@
+require 'test/unit'
+
+class TestCondition < Test::Unit::TestCase
+
+ # [should] first test to see if we can run the tests.
+
+ def test_condition
+ $x = '0';
+
+ $x == $x && assert(true)
+ $x != $x && assert(false)
+ $x == $x || assert(false)
+ $x != $x || assert(true)
+
+ end
+end
diff --git a/jni/ruby/test/ruby/test_const.rb b/jni/ruby/test/ruby/test_const.rb
new file mode 100644
index 0000000..892d775
--- /dev/null
+++ b/jni/ruby/test/ruby/test_const.rb
@@ -0,0 +1,72 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+
+class TestConst < Test::Unit::TestCase
+ TEST1 = 1
+ TEST2 = 2
+
+ module Const
+ TEST3 = 3
+ TEST4 = 4
+ end
+
+ module Const2
+ TEST3 = 6
+ TEST4 = 8
+ end
+
+ def test_const
+ assert defined?(TEST1)
+ assert_equal 1, TEST1
+ assert defined?(TEST2)
+ assert_equal 2, TEST2
+
+ self.class.class_eval {
+ include Const
+ }
+ assert defined?(TEST1)
+ assert_equal 1, TEST1
+ assert defined?(TEST2)
+ assert_equal 2, TEST2
+ assert defined?(TEST3)
+ assert_equal 3, TEST3
+ assert defined?(TEST4)
+ assert_equal 4, TEST4
+
+ self.class.class_eval {
+ include Const2
+ }
+ STDERR.print "intentionally redefines TEST3, TEST4\n" if $VERBOSE
+ assert defined?(TEST1)
+ assert_equal 1, TEST1
+ assert defined?(TEST2)
+ assert_equal 2, TEST2
+ assert defined?(TEST3)
+ assert_equal 6, TEST3
+ assert defined?(TEST4)
+ assert_equal 8, TEST4
+ end
+
+ def test_redefinition
+ c = Class.new
+ name = "X\u{5b9a 6570}"
+ c.const_set(name, 1)
+ prev_line = __LINE__ - 1
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_warning(<<-WARNING) {c.const_set(name, 2)}
+#{__FILE__}:#{__LINE__-1}: warning: already initialized constant #{c}::#{name}
+#{__FILE__}:#{prev_line}: warning: previous definition of #{name} was here
+WARNING
+ end
+ end
+
+ def test_redefinition_memory_leak
+ code = <<-PRE
+olderr = $stderr.dup
+$stderr.reopen(File::NULL, "wb")
+350000.times { FOO = :BAR }
+$stderr.reopen(olderr)
+PRE
+ assert_no_memory_leak([], '', code, 'redefined constant', timeout: 30)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_continuation.rb b/jni/ruby/test/ruby/test_continuation.rb
new file mode 100644
index 0000000..8d57b8b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_continuation.rb
@@ -0,0 +1,134 @@
+require 'test/unit'
+EnvUtil.suppress_warning {require 'continuation'}
+require 'fiber'
+
+class TestContinuation < Test::Unit::TestCase
+ def test_create
+ assert_equal(:ok, callcc{:ok})
+ assert_equal(:ok, callcc{|c| c.call :ok})
+ end
+
+ def test_call
+ assert_equal(:ok, callcc{|c| c.call :ok})
+
+ ary = []
+ ary << callcc{|c|
+ @cont = c
+ :a
+ }
+ @cont.call :b if ary.length < 3
+ assert_equal([:a, :b, :b], ary)
+ end
+
+ def test_check_localvars
+ vv = 0
+ @v = 0
+ @ary = []
+ [1, 2, 3].each{|i|
+ callcc {|k| @k = k}
+ @v += 1
+ vv += 1
+ }
+ @ary << [vv, @v]
+ @k.call if @v < 10
+ assert_equal((3..10).map{|e| [e, e]}, @ary)
+ end
+
+ def test_error
+ cont = callcc{|c| c}
+ assert_raise(RuntimeError){
+ Thread.new{cont.call}.join
+ }
+ assert_raise(LocalJumpError){
+ callcc
+ }
+ assert_raise(RuntimeError){
+ c = nil
+ Fiber.new do
+ callcc {|c2| c = c2 }
+ end.resume
+ c.call
+ }
+ end
+
+ def test_ary_flatten
+ assert_normal_exit %q{
+ require 'continuation'
+ n = 0
+ o = Object.new
+ def o.to_ary() callcc {|k| $k = k; [1,2,3]} end
+ [10,20,o,30,o,40].flatten.inspect
+ n += 1
+ $k.call if n < 100
+ }, '[ruby-dev:34798]'
+ end
+
+ def test_marshal_dump
+ assert_normal_exit %q{
+ require 'continuation'
+ n = 0
+ o = Object.new
+ def o.marshal_dump() callcc {|k| $k = k }; "fofof" end
+ a = [1,2,3,o,4,5,6]
+ Marshal.dump(a).inspect
+ n += 1
+ $k.call if n < 100
+ }, '[ruby-dev:34802]'
+ end
+
+ def tracing_with_set_trace_func
+ orig_thread = Thread.current
+ cont = nil
+ func = lambda do |*args|
+ if orig_thread == Thread.current
+ if cont
+ @memo += 1
+ c = cont
+ cont = nil
+ c.call(nil)
+ end
+ end
+ end
+ cont = callcc { |cc| cc }
+ if cont
+ set_trace_func(func)
+ else
+ set_trace_func(nil)
+ end
+ end
+
+ def test_tracing_with_set_trace_func
+ @memo = 0
+ tracing_with_set_trace_func
+ tracing_with_set_trace_func
+ tracing_with_set_trace_func
+ assert_equal 3, @memo
+ end
+
+ def tracing_with_thread_set_trace_func
+ cont = nil
+ func = lambda do |*args|
+ if cont
+ @memo += 1
+ c = cont
+ cont = nil
+ c.call(nil)
+ end
+ end
+ cont = callcc { |cc| cc }
+ if cont
+ Thread.current.set_trace_func(func)
+ else
+ Thread.current.set_trace_func(nil)
+ end
+ end
+
+ def test_tracing_with_thread_set_trace_func
+ @memo = 0
+ tracing_with_thread_set_trace_func
+ tracing_with_thread_set_trace_func
+ tracing_with_thread_set_trace_func
+ assert_equal 3, @memo
+ end
+end
+
diff --git a/jni/ruby/test/ruby/test_defined.rb b/jni/ruby/test/ruby/test_defined.rb
new file mode 100644
index 0000000..d5e8418
--- /dev/null
+++ b/jni/ruby/test/ruby/test_defined.rb
@@ -0,0 +1,211 @@
+require 'test/unit'
+
+class TestDefined < Test::Unit::TestCase
+ class Foo
+ def foo
+ p :foo
+ end
+ protected :foo
+ def bar(f)
+ yield(defined?(self.foo))
+ yield(defined?(f.foo))
+ end
+ def baz(f)
+ end
+ attr_accessor :attr
+ def attrasgn_test
+ yield(defined?(self.attr = 1))
+ end
+ end
+
+ def defined_test
+ return !defined?(yield)
+ end
+
+ def test_defined
+ $x = nil
+
+ assert(defined?($x)) # global variable
+ assert_equal('global-variable', defined?($x))# returns description
+
+ assert_nil(defined?(foo)) # undefined
+ foo=5
+ assert(defined?(foo)) # local variable
+
+ assert(defined?(Array)) # constant
+ assert(defined?(::Array)) # toplevel constant
+ assert(defined?(File::Constants)) # nested constant
+ assert(defined?(Object.new)) # method
+ assert(defined?(Object::new)) # method
+ assert(!defined?(Object.print)) # private method
+ assert(defined?(1 == 2)) # operator expression
+
+ f = Foo.new
+ assert_nil(defined?(f.foo)) # protected method
+ f.bar(f) { |v| assert(v) }
+ assert_nil(defined?(f.quux)) # undefined method
+ assert_nil(defined?(f.baz(x))) # undefined argument
+ x = 0
+ assert(defined?(f.baz(x)))
+ assert_nil(defined?(f.quux(x)))
+ assert(defined?(print(x)))
+ assert_nil(defined?(quux(x)))
+ assert(defined?(f.attr = 1))
+ f.attrasgn_test { |v| assert(v) }
+
+ assert(defined_test) # not iterator
+ assert(!defined_test{}) # called as iterator
+
+ /a/ =~ ''
+ assert_equal nil, defined?($&)
+ assert_equal nil, defined?($`)
+ assert_equal nil, defined?($')
+ assert_equal nil, defined?($+)
+ assert_equal nil, defined?($1)
+ assert_equal nil, defined?($2)
+ /a/ =~ 'a'
+ assert_equal 'global-variable', defined?($&)
+ assert_equal 'global-variable', defined?($`)
+ assert_equal 'global-variable', defined?($') # '
+ assert_equal nil, defined?($+)
+ assert_equal nil, defined?($1)
+ assert_equal nil, defined?($2)
+ /(a)/ =~ 'a'
+ assert_equal 'global-variable', defined?($&)
+ assert_equal 'global-variable', defined?($`)
+ assert_equal 'global-variable', defined?($') # '
+ assert_equal 'global-variable', defined?($+)
+ assert_equal 'global-variable', defined?($1)
+ assert_equal nil, defined?($2)
+ /(a)b/ =~ 'ab'
+ assert_equal 'global-variable', defined?($&)
+ assert_equal 'global-variable', defined?($`)
+ assert_equal 'global-variable', defined?($') # '
+ assert_equal 'global-variable', defined?($+)
+ assert_equal 'global-variable', defined?($1)
+ assert_equal nil, defined?($2)
+
+ assert_equal("nil", defined?(nil))
+ assert_equal("true", defined?(true))
+ assert_equal("false", defined?(false))
+ assert_equal("expression", defined?(1))
+
+ bug8224 = '[ruby-core:54024] [Bug #8224]'
+ (1..3).each do |level|
+ expr = "("*level+")"*level
+ assert_equal("nil", eval("defined? #{expr}"), "#{bug8224} defined? #{expr}")
+ assert_equal("nil", eval("defined?(#{expr})"), "#{bug8224} defined?(#{expr})")
+ end
+ end
+
+ def test_defined_impl_specific
+ feature7035 = '[ruby-core:47558]' # not spec
+ assert_predicate(defined?(Foo), :frozen?, feature7035)
+ assert_same(defined?(Foo), defined?(Array), feature7035)
+ end
+
+ class TestAutoloadedSuperclass
+ autoload :A, "a"
+ end
+
+ class TestAutoloadedSubclass < TestAutoloadedSuperclass
+ def a?
+ defined?(A)
+ end
+ end
+
+ def test_autoloaded_subclass
+ bug = "[ruby-core:35509]"
+
+ x = TestAutoloadedSuperclass.new
+ class << x
+ def a?; defined?(A); end
+ end
+ assert_equal("constant", x.a?, bug)
+
+ assert_equal("constant", TestAutoloadedSubclass.new.a?, bug)
+ end
+
+ class TestAutoloadedNoload
+ autoload :A, "a"
+ def a?
+ defined?(A)
+ end
+ def b?
+ defined?(A::B)
+ end
+ end
+
+ def test_autoloaded_noload
+ loaded = $".dup
+ $".clear
+ loadpath = $:.dup
+ $:.clear
+ x = TestAutoloadedNoload.new
+ assert_equal("constant", x.a?)
+ assert_nil(x.b?)
+ assert_equal([], $")
+ ensure
+ $".replace(loaded)
+ $:.replace(loadpath)
+ end
+
+ def test_exception
+ bug5786 = '[ruby-dev:45021]'
+ assert_nil(defined?(raise("[Bug#5786]")::A), bug5786)
+ end
+
+ def test_define_method
+ bug6644 = '[ruby-core:45831]'
+ a = Class.new do
+ def self.def_f!;
+ singleton_class.send(:define_method, :f) { defined? super }
+ end
+ end
+ aa = Class.new(a)
+ a.def_f!
+ assert_nil(a.f)
+ assert_nil(aa.f)
+ aa.def_f!
+ assert_equal("super", aa.f, bug6644)
+ assert_nil(a.f, bug6644)
+ end
+
+ def test_super_in_included_method
+ c0 = Class.new do
+ def m
+ end
+ end
+ m1 = Module.new do
+ def m
+ defined?(super)
+ end
+ end
+ c = Class.new(c0) do include m1
+ def m
+ super
+ end
+ end
+ assert_equal("super", c.new.m)
+ end
+
+ def test_super_in_block
+ bug8367 = '[ruby-core:54769] [Bug #8367]'
+ c = Class.new do
+ def x; end
+ end
+
+ m = Module.new do
+ def b; yield; end
+ def x; b {return defined?(super)}; end
+ end
+
+ o = c.new
+ o.extend(m)
+ assert_equal("super", o.x, bug8367)
+ end
+
+ def test_super_toplevel
+ assert_separately([], "assert_nil(defined?(super))")
+ end
+end
diff --git a/jni/ruby/test/ruby/test_dir.rb b/jni/ruby/test/ruby/test_dir.rb
new file mode 100644
index 0000000..85fdd16
--- /dev/null
+++ b/jni/ruby/test/ruby/test_dir.rb
@@ -0,0 +1,328 @@
+require 'test/unit'
+
+require 'tmpdir'
+require 'fileutils'
+
+class TestDir < Test::Unit::TestCase
+
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @root = File.realpath(Dir.mktmpdir('__test_dir__'))
+ @nodir = File.join(@root, "dummy")
+ for i in ?a..?z
+ if i.ord % 2 == 0
+ FileUtils.touch(File.join(@root, i))
+ else
+ FileUtils.mkdir(File.join(@root, i))
+ end
+ end
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ FileUtils.remove_entry_secure @root if File.directory?(@root)
+ end
+
+ def test_seek
+ dir = Dir.open(@root)
+ begin
+ cache = []
+ loop do
+ pos = dir.tell
+ break unless name = dir.read
+ cache << [pos, name]
+ end
+ for x,y in cache.sort_by {|z| z[0] % 3 } # shuffle
+ dir.seek(x)
+ assert_equal(y, dir.read)
+ end
+ ensure
+ dir.close
+ end
+ end
+
+ def test_nodir
+ assert_raise(Errno::ENOENT) { Dir.open(@nodir) }
+ end
+
+ def test_inspect
+ d = Dir.open(@root)
+ assert_match(/^#<Dir:#{ Regexp.quote(@root) }>$/, d.inspect)
+ assert_match(/^#<Dir:.*>$/, Dir.allocate.inspect)
+ ensure
+ d.close
+ end
+
+ def test_path
+ d = Dir.open(@root)
+ assert_equal(@root, d.path)
+ assert_nil(Dir.allocate.path)
+ ensure
+ d.close
+ end
+
+ def test_set_pos
+ d = Dir.open(@root)
+ loop do
+ i = d.pos
+ break unless x = d.read
+ d.pos = i
+ assert_equal(x, d.read)
+ end
+ ensure
+ d.close
+ end
+
+ def test_rewind
+ d = Dir.open(@root)
+ a = (0..5).map { d.read }
+ d.rewind
+ b = (0..5).map { d.read }
+ assert_equal(a, b)
+ ensure
+ d.close
+ end
+
+ def test_chdir
+ @pwd = Dir.pwd
+ @env_home = ENV["HOME"]
+ @env_logdir = ENV["LOGDIR"]
+ ENV.delete("HOME")
+ ENV.delete("LOGDIR")
+
+ assert_raise(Errno::ENOENT) { Dir.chdir(@nodir) }
+ assert_raise(ArgumentError) { Dir.chdir }
+ ENV["HOME"] = @pwd
+ Dir.chdir do
+ assert_equal(@pwd, Dir.pwd)
+ Dir.chdir(@root)
+ assert_equal(@root, Dir.pwd)
+ end
+
+ ensure
+ begin
+ Dir.chdir(@pwd)
+ rescue
+ abort("cannot return the original directory: #{ @pwd }")
+ end
+ if @env_home
+ ENV["HOME"] = @env_home
+ else
+ ENV.delete("HOME")
+ end
+ if @env_logdir
+ ENV["LOGDIR"] = @env_logdir
+ else
+ ENV.delete("LOGDIR")
+ end
+ end
+
+ def test_chroot_nodir
+ assert_raise(NotImplementedError, Errno::ENOENT, Errno::EPERM
+ ) { Dir.chroot(File.join(@nodir, "")) }
+ end
+
+ def test_close
+ d = Dir.open(@root)
+ d.close
+ assert_raise(IOError) { d.read }
+ end
+
+ def test_glob
+ assert_equal((%w(. ..) + (?a..?z).to_a).map{|f| File.join(@root, f) },
+ Dir.glob(File.join(@root, "*"), File::FNM_DOTMATCH).sort)
+ assert_equal([@root] + (?a..?z).map {|f| File.join(@root, f) }.sort,
+ Dir.glob([@root, File.join(@root, "*")]).sort)
+ assert_equal([@root] + (?a..?z).map {|f| File.join(@root, f) }.sort,
+ Dir.glob(@root + "\0\0\0" + File.join(@root, "*")).sort)
+
+ assert_equal((?a..?z).step(2).map {|f| File.join(File.join(@root, f), "") }.sort,
+ Dir.glob(File.join(@root, "*/")).sort)
+ assert_equal([File.join(@root, '//a')], Dir.glob(@root + '//a'))
+
+ FileUtils.touch(File.join(@root, "{}"))
+ assert_equal(%w({} a).map{|f| File.join(@root, f) },
+ Dir.glob(File.join(@root, '{\{\},a}')))
+ assert_equal([], Dir.glob(File.join(@root, '[')))
+ assert_equal([], Dir.glob(File.join(@root, '[a-\\')))
+
+ assert_equal([File.join(@root, "a")], Dir.glob(File.join(@root, 'a\\')))
+ assert_equal((?a..?f).map {|f| File.join(@root, f) }.sort, Dir.glob(File.join(@root, '[abc/def]')).sort)
+ end
+
+ def test_glob_recursive
+ bug6977 = '[ruby-core:47418]'
+ bug8006 = '[ruby-core:53108] [Bug #8006]'
+ Dir.chdir(@root) do
+ assert_include(Dir.glob("a/**/*", File::FNM_DOTMATCH), "a/.", bug8006)
+
+ FileUtils.mkdir_p("a/b/c/d/e/f")
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/d/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/d/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/b/c/d/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/?/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/**/d/e/f"), bug6977)
+ assert_equal(["a/b/c/d/e/f"], Dir.glob("a/**/c/**/d/e/f"), bug6977)
+
+ bug8283 = '[ruby-core:54387] [Bug #8283]'
+ dirs = ["a/.x", "a/b/.y"]
+ FileUtils.mkdir_p(dirs)
+ dirs.map {|dir| open("#{dir}/z", "w") {}}
+ assert_equal([], Dir.glob("a/**/z").sort, bug8283)
+ assert_equal(["a/.x/z"], Dir.glob("a/**/.x/z"), bug8283)
+ assert_equal(["a/.x/z"], Dir.glob("a/.x/**/z"), bug8283)
+ assert_equal(["a/b/.y/z"], Dir.glob("a/**/.y/z"), bug8283)
+ end
+ end
+
+ def test_foreach
+ assert_equal(Dir.foreach(@root).to_a.sort, %w(. ..) + (?a..?z).to_a)
+ end
+
+ def test_dir_enc
+ dir = Dir.open(@root, encoding: "UTF-8")
+ begin
+ while name = dir.read
+ assert_equal(Encoding.find("UTF-8"), name.encoding)
+ end
+ ensure
+ dir.close
+ end
+
+ dir = Dir.open(@root, encoding: "ASCII-8BIT")
+ begin
+ while name = dir.read
+ assert_equal(Encoding.find("ASCII-8BIT"), name.encoding)
+ end
+ ensure
+ dir.close
+ end
+ end
+
+ def test_unknown_keywords
+ bug8060 = '[ruby-dev:47152] [Bug #8060]'
+ assert_raise_with_message(ArgumentError, /unknown keyword/, bug8060) do
+ Dir.open(@root, xawqij: "a") {}
+ end
+ end
+
+ def test_symlink
+ begin
+ ["dummy", *?a..?z].each do |f|
+ File.symlink(File.join(@root, f),
+ File.join(@root, "symlink-#{ f }"))
+ end
+ rescue NotImplementedError
+ return
+ end
+
+ assert_equal([*?a..?z, *"symlink-a".."symlink-z"].each_slice(2).map {|f, _| File.join(@root, f + "/") }.sort,
+ Dir.glob(File.join(@root, "*/")).sort)
+
+ Dir.glob(File.join(@root, "**/"))
+ end
+
+ def test_glob_metachar
+ bug8597 = '[ruby-core:55764] [Bug #8597]'
+ assert_empty(Dir.glob(File.join(@root, "<")), bug8597)
+ end
+
+ def test_glob_cases
+ feature5994 = "[ruby-core:42469] [Feature #5994]"
+ feature5994 << "\nDir.glob should return the filename with actual cases on the filesystem"
+ Dir.chdir(File.join(@root, "a")) do
+ open("FileWithCases", "w") {}
+ return unless File.exist?("filewithcases")
+ assert_equal(%w"FileWithCases", Dir.glob("filewithcases"), feature5994)
+ end
+ Dir.chdir(@root) do
+ assert_equal(%w"a/FileWithCases", Dir.glob("A/filewithcases"), feature5994)
+ end
+ end
+
+ def test_glob_super_root
+ bug9648 = '[ruby-core:61552] [Bug #9648]'
+ roots = Dir.glob("/*")
+ assert_equal(roots.map {|n| "/..#{n}"}, Dir.glob("/../*"), bug9648)
+ end
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ def test_glob_legacy_short_name
+ bug10819 = '[ruby-core:67954] [Bug #10819]'
+ skip unless /\A\w:/ =~ ENV["ProgramFiles"]
+ short = "#$&/PROGRA~1"
+ skip unless File.directory?(short)
+ entries = Dir.glob("#{short}/Common*")
+ assert_not_empty(entries, bug10819)
+ assert_equal(Dir.glob("#{File.expand_path(short)}/Common*"), entries, bug10819)
+ end
+ end
+
+ def test_home
+ env_home = ENV["HOME"]
+ env_logdir = ENV["LOGDIR"]
+ ENV.delete("HOME")
+ ENV.delete("LOGDIR")
+
+ assert_raise(ArgumentError) { Dir.home }
+ assert_raise(ArgumentError) { Dir.home("") }
+ ENV["HOME"] = @nodir
+ assert_nothing_raised(ArgumentError) {
+ assert_equal(@nodir, Dir.home)
+ assert_equal(@nodir, Dir.home(""))
+ }
+ %W[no:such:user \u{7559 5b88}:\u{756a}].each do |user|
+ assert_raise_with_message(ArgumentError, /#{user}/) {Dir.home(user)}
+ end
+ ensure
+ ENV["HOME"] = env_home
+ ENV["LOGDIR"] = env_logdir
+ end
+
+ def test_symlinks_not_resolved
+ Dir.mktmpdir do |dirname|
+ Dir.chdir(dirname) do
+ begin
+ File.symlink('some-dir', 'dir-symlink')
+ rescue NotImplementedError
+ return
+ end
+
+ Dir.mkdir('some-dir')
+ File.write('some-dir/foo', 'some content')
+
+ assert_equal [ 'dir-symlink', 'some-dir' ], Dir['*'].sort
+ assert_equal [ 'dir-symlink', 'some-dir', 'some-dir/foo' ], Dir['**/*'].sort
+ end
+ end
+ end
+
+ def test_fileno
+ Dir.open(".") {|d|
+ if d.respond_to? :fileno
+ assert_kind_of(Integer, d.fileno)
+ else
+ assert_raise(NotImplementedError) { d.fileno }
+ end
+ }
+ end
+
+ def test_insecure_chdir
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE=3
+ Dir.chdir("/")
+ end.call
+ end
+ m = "\u{79fb 52d5}"
+ d = Class.new(Dir) {singleton_class.class_eval {alias_method m, :chdir}}
+ assert_raise_with_message(SecurityError, /#{m}/) do
+ proc do
+ $SAFE=3
+ d.__send__(m, "/")
+ end.call
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_dir_m17n.rb b/jni/ruby/test/ruby/test_dir_m17n.rb
new file mode 100644
index 0000000..04186e5
--- /dev/null
+++ b/jni/ruby/test/ruby/test_dir_m17n.rb
@@ -0,0 +1,389 @@
+require 'test/unit'
+require 'tmpdir'
+
+class TestDir_M17N < Test::Unit::TestCase
+ def with_tmpdir
+ Dir.mktmpdir {|dir|
+ Dir.chdir(dir) {
+ yield dir
+ }
+ }
+ end
+
+ def assert_raw_file_name(code, encoding)
+ with_tmpdir { |dir|
+ assert_separately(["-E#{encoding}"], <<-EOS, :chdir=>dir)
+ filename = #{code}.chr('UTF-8').force_encoding("#{encoding}")
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename)
+ EOS
+
+ assert_separately(%w[-EASCII-8BIT], <<-EOS, :chdir=>dir)
+ filename = #{code}.chr('UTF-8').force_encoding("ASCII-8BIT")
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ expected_filename = #{code}.chr('UTF-8').encode(Encoding.find("filesystem")) rescue expected_filename = "?"
+ expected_filename = expected_filename.force_encoding("ASCII-8BIT")
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ case
+ when ents.include?(filename)
+ when ents.include?(expected_filename)
+ filename = expected_filename
+ else
+ ents = Dir.entries(".", {:encoding => Encoding.find("filesystem")})
+ filename = expected_filename
+ end
+ end
+ assert_include(ents, filename)
+ EOS
+ }
+ end
+
+ ## UTF-8 default_external, no default_internal
+
+ def test_filename_extutf8
+ with_tmpdir {|d|
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename = "\u3042"
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename)
+ EOS
+ }
+ end
+
+ def test_filename_extutf8_invalid
+ with_tmpdir {|d|
+ assert_separately(%w[-EASCII-8BIT], <<-'EOS', :chdir=>d)
+ filename = "\xff".force_encoding("ASCII-8BIT") # invalid byte sequence as UTF-8
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ filename = "%FF" if /darwin/ =~ RUBY_PLATFORM && ents.include?("%FF")
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename = "\xff".force_encoding("UTF-8") # invalid byte sequence as UTF-8
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ filename = "%FF" if /darwin/ =~ RUBY_PLATFORM && ents.include?("%FF")
+ assert_include(ents, filename)
+ EOS
+ }
+ end unless /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_filename_as_bytes_extutf8
+ with_tmpdir {|d|
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename = "\xc2\xa1".force_encoding("utf-8")
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ if /mswin|mingw|darwin/ =~ RUBY_PLATFORM
+ filename = "\x8f\xa2\xc2".force_encoding("euc-jp")
+ else
+ filename = "\xc2\xa1".force_encoding("euc-jp")
+ end
+ assert_nothing_raised(Errno::ENOENT) do
+ open(filename) {}
+ end
+ EOS
+ # no meaning test on windows
+ unless /mswin|mingw|darwin/ =~ RUBY_PLATFORM
+ assert_separately(%W[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename1 = "\xc2\xa1".force_encoding("utf-8")
+ filename2 = "\xc2\xa1".force_encoding("euc-jp")
+ filename3 = filename1.encode("euc-jp")
+ filename4 = filename2.encode("utf-8")
+ assert_file.stat(filename1)
+ assert_file.stat(filename2)
+ assert_file.not_exist?(filename3)
+ assert_file.not_exist?(filename4)
+ EOS
+ end
+ }
+ end
+
+ ## UTF-8 default_external, EUC-JP default_internal
+
+ def test_filename_extutf8_inteucjp_representable
+ with_tmpdir {|d|
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename = "\u3042"
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding("euc-jp")
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding("euc-jp")
+ assert_nothing_raised(Errno::ENOENT) do
+ open(filename) {}
+ end
+ EOS
+ }
+ end
+
+ def test_filename_extutf8_inteucjp_unrepresentable
+ with_tmpdir {|d|
+ assert_separately(%w[-EUTF-8], <<-'EOS', :chdir=>d)
+ filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
+ filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP
+ File.open(filename1, "w") {}
+ File.open(filename2, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename1)
+ assert_include(ents, filename2)
+ EOS
+ assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d)
+ filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
+ filename2 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ assert_include(ents, filename1)
+ assert_include(ents, filename2)
+ EOS
+ assert_separately(%w[-EUTF-8:EUC-JP], <<-'EOS', :chdir=>d)
+ filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
+ filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP
+ filename3 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP
+ assert_file.stat(filename1)
+ assert_file.stat(filename2)
+ assert_file.stat(filename3)
+ EOS
+ }
+ end
+
+ ## others
+
+ def test_filename_bytes_euc_jp
+ with_tmpdir {|d|
+ assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding("euc-jp")
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ ents.each {|e| e.force_encoding("ASCII-8BIT") }
+ if /darwin/ =~ RUBY_PLATFORM
+ filename = filename.encode("utf-8")
+ end
+ assert_include(ents, filename.force_encoding("ASCII-8BIT"))
+ EOS
+ }
+ end
+
+ def test_filename_euc_jp
+ with_tmpdir {|d|
+ assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding("euc-jp")
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ if /darwin/ =~ RUBY_PLATFORM
+ filename = filename.encode("utf-8").force_encoding("euc-jp")
+ end
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EASCII-8BIT], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding('ASCII-8BIT')
+ win_expected_filename = filename.encode(Encoding.find("filesystem"), "euc-jp") rescue "?"
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ unless ents.include?(filename)
+ case RUBY_PLATFORM
+ when /darwin/
+ filename = filename.encode("utf-8", "euc-jp").b
+ when /mswin|mingw/
+ if ents.include?(win_expected_filename.dup.force_encoding("ASCII-8BIT"))
+ ents = Dir.entries(".", {:encoding => Encoding.find("filesystem")})
+ filename = win_expected_filename
+ end
+ end
+ end
+ assert_include(ents, filename)
+ EOS
+ }
+ end
+
+ def test_filename_utf8_raw_jp_name
+ assert_raw_file_name(0x3042, "UTF-8")
+ end
+
+ def test_filename_utf8_raw_windows_1251_name
+ assert_raw_file_name(0x0424, "UTF-8")
+ end
+
+ def test_filename_utf8_raw_windows_1252_name
+ assert_raw_file_name(0x00c6, "UTF-8")
+ end
+
+ def test_filename_ext_euc_jp_and_int_utf_8
+ with_tmpdir {|d|
+ assert_separately(%w[-EEUC-JP], <<-'EOS', :chdir=>d)
+ filename = "\xA4\xA2".force_encoding("euc-jp")
+ File.open(filename, "w") {}
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ if /darwin/ =~ RUBY_PLATFORM
+ filename = filename.encode("utf-8", "euc-jp").force_encoding("euc-jp")
+ end
+ assert_include(ents, filename)
+ EOS
+ assert_separately(%w[-EEUC-JP:UTF-8], <<-'EOS', :chdir=>d)
+ filename = "\u3042"
+ opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
+ ents = Dir.entries(".", opts)
+ if /darwin/ =~ RUBY_PLATFORM
+ filename = filename.force_encoding("euc-jp")
+ end
+ assert_include(ents, filename)
+ EOS
+ }
+ end
+
+ def test_error_nonascii
+ bug6071 = '[ruby-dev:45279]'
+ paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
+ encs = with_tmpdir {
+ paths.map {|path|
+ Dir.open(path) rescue $!.message.encoding
+ }
+ }
+ assert_equal(paths.map(&:encoding), encs, bug6071)
+ end
+
+ def test_inspect_nonascii
+ bug6072 = '[ruby-dev:45280]'
+ paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
+ encs = with_tmpdir {
+ paths.map {|path|
+ Dir.mkdir(path)
+ Dir.open(path) {|d| d.inspect.encoding}
+ }
+ }
+ assert_equal(paths.map(&:encoding), encs, bug6072)
+ end
+
+ def test_glob_incompatible
+ d = "\u{3042}\u{3044}".encode("utf-16le")
+ assert_raise(Encoding::CompatibilityError) {Dir.glob(d)}
+ m = Class.new {define_method(:to_path) {d}}
+ assert_raise(Encoding::CompatibilityError) {Dir.glob(m.new)}
+ end
+
+ def test_glob_compose
+ bug7267 = '[ruby-core:48745] [Bug #7267]'
+
+ pp = Object.new.extend(Test::Unit::Assertions)
+ def pp.mu_pp(str) #:nodoc:
+ str.dump
+ end
+
+ with_tmpdir {|d|
+ orig = %W"d\u{e9}tente x\u{304c 304e 3050 3052 3054}"
+ orig.each {|n| open(n, "w") {}}
+ orig.each do |o|
+ n = Dir.glob("#{o[0..0]}*")[0]
+ pp.assert_equal(o, n, bug7267)
+ end
+ }
+ end
+
+ def with_enc_path
+ with_tmpdir do |d|
+ names = %W"\u{391 392 393 394 395} \u{3042 3044 3046 3048 304a}"
+ names.each do |dir|
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ Dir.mkdir(dir) rescue next
+ begin
+ yield(dir)
+ ensure
+ File.chmod(0700, dir)
+ end
+ end
+ end
+ end
+ end
+
+ def test_glob_warning_opendir
+ with_enc_path do |dir|
+ open("#{dir}/x", "w") {}
+ File.chmod(0300, dir)
+ next if File.readable?(dir)
+ assert_warning(/#{dir}/) do
+ Dir.glob("#{dir}/*")
+ end
+ end
+ end
+
+ def test_glob_warning_match_all
+ with_enc_path do |dir|
+ open("#{dir}/x", "w") {}
+ File.chmod(0000, dir)
+ next if File.readable?(dir)
+ assert_warning(/#{dir}/) do
+ Dir.glob("#{dir}/x")
+ end
+ end
+ end
+
+ def test_glob_warning_match_dir
+ with_enc_path do |dir|
+ Dir.mkdir("#{dir}/x")
+ File.chmod(0000, dir)
+ next if File.readable?(dir)
+ assert_warning(/#{dir}/) do
+ Dir.glob("#{dir}/x/")
+ end
+ end
+ end
+
+ def test_glob_escape_multibyte
+ name = "\x81\\".force_encoding(Encoding::Shift_JIS)
+ with_tmpdir do
+ open(name, "w") {} rescue next
+ match, = Dir.glob("#{name}*")
+ next unless match and match.encoding == Encoding::Shift_JIS
+ assert_equal([name], Dir.glob("\\#{name}*"))
+ end
+ end
+
+ def test_entries_compose
+ bug7267 = '[ruby-core:48745] [Bug #7267]'
+
+ pp = Object.new.extend(Test::Unit::Assertions)
+ def pp.mu_pp(ary) #:nodoc:
+ '[' << ary.map {|str| "#{str.dump}(#{str.encoding})"}.join(', ') << ']'
+ end
+
+ with_tmpdir {|d|
+ orig = %W"d\u{e9}tente x\u{304c 304e 3050 3052 3054}"
+ orig.each {|n| open(n, "w") {}}
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ opts = {:encoding => Encoding.default_external}
+ orig.map! {|o| o.encode(Encoding.find("filesystem")) rescue o.tr("^a-z", "?")}
+ else
+ enc = Encoding.find("filesystem")
+ enc = Encoding::ASCII_8BIT if enc == Encoding::US_ASCII
+ orig.each {|o| o.force_encoding(enc) }
+ end
+ ents = Dir.entries(".", opts).reject {|n| /\A\./ =~ n}
+ ents.sort!
+ pp.assert_equal(orig, ents, bug7267)
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_econv.rb b/jni/ruby/test/ruby/test_econv.rb
new file mode 100644
index 0000000..f423ebf
--- /dev/null
+++ b/jni/ruby/test/ruby/test_econv.rb
@@ -0,0 +1,926 @@
+require 'test/unit'
+
+class TestEncodingConverter < Test::Unit::TestCase
+ def check_ec(edst, esrc, eres, dst, src, ec, off, len, opts=nil)
+ res = ec.primitive_convert(src, dst, off, len, opts)
+ assert_equal([edst.dup.force_encoding("ASCII-8BIT"),
+ esrc.dup.force_encoding("ASCII-8BIT"),
+ eres],
+ [dst.dup.force_encoding("ASCII-8BIT"),
+ src.dup.force_encoding("ASCII-8BIT"),
+ res])
+ end
+
+ def assert_econv(converted, eres, obuf_bytesize, ec, consumed, rest, opts=nil)
+ ec = Encoding::Converter.new(*ec) if Array === ec
+ i = consumed + rest
+ o = ""
+ ret = ec.primitive_convert(i, o, 0, obuf_bytesize, opts)
+ assert_equal([converted, eres, rest],
+ [o, ret, i])
+ end
+
+ def assert_errinfo(e_res, e_enc1, e_enc2, e_error_bytes, e_readagain_bytes, ec)
+ assert_equal([e_res, e_enc1, e_enc2,
+ e_error_bytes && e_error_bytes.dup.force_encoding("ASCII-8BIT"),
+ e_readagain_bytes && e_readagain_bytes.dup.force_encoding("ASCII-8BIT")],
+ ec.primitive_errinfo)
+ end
+
+ def test_s_asciicompat_encoding
+ assert_equal(Encoding::STATELESS_ISO_2022_JP, Encoding::Converter.asciicompat_encoding("ISO-2022-JP"))
+ assert_equal(Encoding::STATELESS_ISO_2022_JP, Encoding::Converter.asciicompat_encoding(Encoding::ISO_2022_JP))
+ assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-16BE"))
+ assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-16LE"))
+ assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-32BE"))
+ assert_equal(Encoding::UTF_8, Encoding::Converter.asciicompat_encoding("UTF-32LE"))
+ assert_nil(Encoding::Converter.asciicompat_encoding("EUC-JP"))
+ assert_nil(Encoding::Converter.asciicompat_encoding("UTF-8"))
+ assert_nil(Encoding::Converter.asciicompat_encoding(Encoding::UTF_8))
+ assert_nil(Encoding::Converter.asciicompat_encoding("xml_attr_escape"))
+ assert_nil(Encoding::Converter.asciicompat_encoding("encoding-not-exist"))
+ end
+
+ def test_asciicompat_encoding_iso2022jp
+ acenc = Encoding::Converter.asciicompat_encoding("ISO-2022-JP")
+ str = "\e$B~~\e(B".force_encoding("iso-2022-jp")
+ str2 = str.encode(acenc)
+ str3 = str2.encode("ISO-2022-JP")
+ assert_equal(str, str3)
+ end
+
+ def test_s_new
+ assert_kind_of(Encoding::Converter, Encoding::Converter.new("UTF-8", "EUC-JP"))
+ assert_kind_of(Encoding::Converter, Encoding::Converter.new(Encoding::UTF_8, Encoding::EUC_JP))
+ end
+
+ def test_s_new_convpath
+ assert_equal([], Encoding::Converter.new([]).convpath)
+ assert_equal([[Encoding::UTF_8, Encoding::EUC_JP]],
+ Encoding::Converter.new([["UTF-8", "EUC-JP"]]).convpath)
+ assert_equal([[Encoding::UTF_8, Encoding::WINDOWS_31J]],
+ Encoding::Converter.new([["utf-8", "cp932"]]).convpath)
+ assert_equal([[Encoding::UTF_8, Encoding::EUC_JP]],
+ Encoding::Converter.new([[Encoding::UTF_8, Encoding::EUC_JP]]).convpath)
+ assert_equal([[Encoding::ISO_8859_1, Encoding::UTF_8],
+ [Encoding::UTF_8, Encoding::EUC_JP]],
+ Encoding::Converter.new([["iso-8859-1", "euc-jp"]]).convpath)
+ assert_equal([[Encoding::ISO_8859_1, Encoding::UTF_8],
+ [Encoding::UTF_8, Encoding::EUC_JP],
+ "universal_newline"],
+ Encoding::Converter.new([["iso-8859-1", "euc-jp"], "universal_newline"]).convpath)
+ assert_equal(["universal_newline",
+ [Encoding::ISO_8859_1, Encoding::UTF_8],
+ [Encoding::UTF_8, Encoding::EUC_JP],
+ "universal_newline"],
+ Encoding::Converter.new(["universal_newline", ["iso-8859-1", "euc-jp"], "universal_newline"]).convpath)
+ end
+
+ def test_s_new_fail
+ name1 = "encoding-which-is-not-exist-1"
+ name2 = "encoding-which-is-not-exist-2"
+
+ assert_raise(Encoding::ConverterNotFoundError) {
+ Encoding::Converter.new(name1, name2)
+ }
+
+ encoding_list = Encoding.list.map {|e| e.name }
+ assert_not_include(encoding_list, name1)
+ assert_not_include(encoding_list, name2)
+ end
+
+ def test_newline_converter_with_ascii_incompatible
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR)
+ }
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::CRLF_NEWLINE_DECORATOR)
+ }
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::CR_NEWLINE_DECORATOR)
+ }
+
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-16BE", "UTF-8", Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR)
+ }
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::CRLF_NEWLINE_DECORATOR)
+ }
+ assert_nothing_raised {
+ Encoding::Converter.new("UTF-8", "UTF-16BE", Encoding::Converter::CR_NEWLINE_DECORATOR)
+ }
+ end
+
+ def test_get_encoding
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ assert_equal(Encoding::UTF_8, ec.source_encoding)
+ assert_equal(Encoding::EUC_JP, ec.destination_encoding)
+ end
+
+ def test_result_encoding
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ dst = "".force_encoding("ASCII-8BIT")
+ assert_equal(Encoding::ASCII_8BIT, dst.encoding)
+ ec.primitive_convert("\u{3042}", dst, nil, 10)
+ assert_equal(Encoding::EUC_JP, dst.encoding)
+ end
+
+ def test_output_region
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ ec.primitive_convert(src="a", dst="b", nil, 1, :partial_input=>true)
+ assert_equal("ba", dst)
+ ec.primitive_convert(src="a", dst="b", 0, 1, :partial_input=>true)
+ assert_equal("a", dst)
+ ec.primitive_convert(src="a", dst="b", 1, 1, :partial_input=>true)
+ assert_equal("ba", dst)
+ assert_raise(ArgumentError) {
+ ec.primitive_convert(src="a", dst="b", 2, 1, :partial_input=>true)
+ }
+ assert_raise(ArgumentError) {
+ ec.primitive_convert(src="a", dst="b", -1, 1, :partial_input=>true)
+ }
+ assert_raise(ArgumentError) {
+ ec.primitive_convert(src="a", dst="b", 1, -1, :partial_input=>true)
+ }
+ end
+
+ def test_nil_source_buffer
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ ret = ec.primitive_convert(nil, "", nil, 10)
+ assert_equal(:finished, ret)
+ end
+
+ def test_nil_destination_bytesize
+ ec = Encoding::Converter.new("Shift_JIS", "UTF-8")
+ n = 10000
+ src = "\xa1".force_encoding("Shift_JIS") * n
+ ret = ec.primitive_convert(src, dst="", nil, nil)
+ assert_equal(:finished, ret)
+ assert_equal("\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst)
+ end
+
+ def test_nil_destination_bytesize2
+ ec = Encoding::Converter.new("Shift_JIS", "UTF-8")
+ n = 10000
+ src = "\xa1".force_encoding("Shift_JIS") * n
+ ret = ec.primitive_convert(src, dst="")
+ assert_equal(:finished, ret)
+ assert_equal("\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst)
+ end
+
+ def test_nil_destination_bytesize_with_nonnil_byteoffset
+ ec = Encoding::Converter.new("Shift_JIS", "UTF-8")
+ n = 2000
+ src = "\xa1".force_encoding("Shift_JIS") * n
+ dst = "abcd" * 2000
+ ret = ec.primitive_convert(src, dst, 3, nil)
+ assert_equal(:finished, ret)
+ assert_equal("abc" + "\xEF\xBD\xA1".force_encoding("UTF-8") * n, dst)
+ end
+
+ def test_partial_input
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ ret = ec.primitive_convert(src="", dst="", nil, 10, :partial_input=>true)
+ assert_equal(:source_buffer_empty, ret)
+ ret = ec.primitive_convert(src="", dst="", nil, 10)
+ assert_equal(:finished, ret)
+ end
+
+ def test_accumulate_dst1
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ a = ["", "abc\u{3042}def", ec, nil, 1]
+ check_ec("a", "c\u{3042}def", :destination_buffer_full, *a)
+ check_ec("ab", "\u{3042}def", :destination_buffer_full, *a)
+ check_ec("abc", "def", :destination_buffer_full, *a)
+ check_ec("abc\xA4", "def", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2", "ef", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2d", "f", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2de", "", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2def", "", :finished, *a)
+ end
+
+ def test_accumulate_dst2
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ a = ["", "abc\u{3042}def", ec, nil, 2]
+ check_ec("ab", "\u{3042}def", :destination_buffer_full, *a)
+ check_ec("abc\xA4", "def", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2d", "f", :destination_buffer_full, *a)
+ check_ec("abc\xA4\xA2def", "", :finished, *a)
+ end
+
+ def test_eucjp_to_utf8
+ assert_econv("", :finished, 100, ["UTF-8", "EUC-JP"], "", "")
+ assert_econv("a", :finished, 100, ["UTF-8", "EUC-JP"], "a", "")
+ end
+
+ def test_iso2022jp
+ assert_econv("", :finished, 100, ["Shift_JIS", "ISO-2022-JP"], "", "")
+ end
+
+ def test_iso2022jp_encode
+ ec = Encoding::Converter.new("EUC-JP", "ISO-2022-JP")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "a"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "\xA2"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "\xA4"; check_ec("a\e$B\"$", "", :source_buffer_empty, *a)
+ src << "\xA1"; check_ec("a\e$B\"$", "", :source_buffer_empty, *a)
+ src << "\xA2"; check_ec("a\e$B\"$!\"", "", :source_buffer_empty, *a)
+ src << "b"; check_ec("a\e$B\"$!\"\e(Bb", "", :source_buffer_empty, *a)
+ src << "\xA2\xA6"; check_ec("a\e$B\"$!\"\e(Bb\e$B\"&", "", :source_buffer_empty, *a)
+ a[-1] = 0; check_ec("a\e$B\"$!\"\e(Bb\e$B\"&\e(B", "", :finished, *a)
+ end
+
+ def test_iso2022jp_decode
+ ec = Encoding::Converter.new("ISO-2022-JP", "EUC-JP")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "a"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "\e"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "$"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "B"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "\x21"; check_ec("a", "", :source_buffer_empty, *a)
+ src << "\x22"; check_ec("a\xA1\xA2", "", :source_buffer_empty, *a)
+ src << "\n"; check_ec("a\xA1\xA2", "", :invalid_byte_sequence, *a)
+ src << "\x23"; check_ec("a\xA1\xA2", "", :source_buffer_empty, *a)
+ src << "\x24"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a)
+ src << "\e"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a)
+ src << "("; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a)
+ src << "B"; check_ec("a\xA1\xA2\xA3\xA4", "", :source_buffer_empty, *a)
+ src << "c"; check_ec("a\xA1\xA2\xA3\xA4c", "", :source_buffer_empty, *a)
+ src << "\n"; check_ec("a\xA1\xA2\xA3\xA4c\n","", :source_buffer_empty, *a)
+ end
+
+ def test_invalid
+ assert_econv("", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "\x80", "")
+ assert_econv("a", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "a\x80", "")
+ assert_econv("a", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "a\x80", "\x80")
+ assert_econv("abc", :invalid_byte_sequence, 100, ["UTF-8", "EUC-JP"], "abc\xFF", "def")
+ assert_econv("abc", :invalid_byte_sequence, 100, ["Shift_JIS", "EUC-JP"], "abc\xFF", "def")
+ assert_econv("abc", :invalid_byte_sequence, 100, ["ISO-2022-JP", "EUC-JP"], "abc\xFF", "def")
+ end
+
+ def test_invalid2
+ ec = Encoding::Converter.new("Shift_JIS", "EUC-JP")
+ a = ["", "abc\xFFdef", ec, nil, 1]
+ check_ec("a", "c\xFFdef", :destination_buffer_full, *a)
+ check_ec("ab", "\xFFdef", :destination_buffer_full, *a)
+ check_ec("abc", "def", :invalid_byte_sequence, *a)
+ check_ec("abcd", "f", :destination_buffer_full, *a)
+ check_ec("abcde", "", :destination_buffer_full, *a)
+ check_ec("abcdef", "", :finished, *a)
+ end
+
+ def test_invalid3
+ ec = Encoding::Converter.new("Shift_JIS", "EUC-JP")
+ a = ["", "abc\xFFdef", ec, nil, 10]
+ check_ec("abc", "def", :invalid_byte_sequence, *a)
+ check_ec("abcdef", "", :finished, *a)
+ end
+
+ def test_invalid4
+ ec = Encoding::Converter.new("Shift_JIS", "EUC-JP")
+ a = ["", "abc\xFFdef", ec, nil, 10, :after_output=>true]
+ check_ec("a", "bc\xFFdef", :after_output, *a)
+ check_ec("ab", "c\xFFdef", :after_output, *a)
+ check_ec("abc", "\xFFdef", :after_output, *a)
+ check_ec("abc", "def", :invalid_byte_sequence, *a)
+ check_ec("abcd", "ef", :after_output, *a)
+ check_ec("abcde", "f", :after_output, *a)
+ check_ec("abcdef", "", :after_output, *a)
+ check_ec("abcdef", "", :finished, *a)
+ end
+
+ def test_invalid_utf16le
+ ec = Encoding::Converter.new("UTF-16LE", "UTF-8")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "A"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x01"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x02"; check_ec("A", "", :invalid_byte_sequence, *a)
+ src << "\x03"; check_ec("A\u{0201}", "", :source_buffer_empty, *a)
+ src << "\x04"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :invalid_byte_sequence, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xdc"; check_ec("A\u{0201}\u{0403}\u{10000}", "", :source_buffer_empty, *a)
+ end
+
+ def test_invalid_utf16be
+ ec = Encoding::Converter.new("UTF-16BE", "UTF-8")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "A"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x02"; check_ec("A", "", :invalid_byte_sequence, *a)
+ src << "\x01"; check_ec("A\u{0201}", "", :source_buffer_empty, *a)
+ src << "\x04"; check_ec("A\u{0201}", "", :source_buffer_empty, *a)
+ src << "\x03"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xd8"; check_ec("A\u{0201}\u{0403}", "", :invalid_byte_sequence, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\xdc"; check_ec("A\u{0201}\u{0403}", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A\u{0201}\u{0403}\u{10000}", "", :source_buffer_empty, *a)
+ end
+
+ def test_invalid_utf32be
+ ec = Encoding::Converter.new("UTF-32BE", "UTF-8")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "A"; check_ec("A", "", :source_buffer_empty, *a)
+
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\xdc"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :invalid_byte_sequence, *a)
+
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "B"; check_ec("AB", "", :source_buffer_empty, *a)
+
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "C"; check_ec("ABC", "", :source_buffer_empty, *a)
+ end
+
+ def test_invalid_utf32le
+ ec = Encoding::Converter.new("UTF-32LE", "UTF-8")
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "A"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\xdc"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :invalid_byte_sequence, *a)
+
+ src << "B"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("A", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+
+ src << "C"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("AB", "", :source_buffer_empty, *a)
+ src << "\x00"; check_ec("ABC", "", :source_buffer_empty, *a)
+ end
+
+ def test_errors
+ ec = Encoding::Converter.new("UTF-16BE", "EUC-JP")
+ a = ["", "\xFF\xFE\x00A\xDC\x00\x00B", ec, nil, 10]
+ check_ec("", "\x00A\xDC\x00\x00B", :undefined_conversion, *a)
+ check_ec("A", "\x00B", :invalid_byte_sequence, *a) # \xDC\x00 is invalid as UTF-16BE
+ check_ec("AB", "", :finished, *a)
+ end
+
+ def test_errors2
+ ec = Encoding::Converter.new("UTF-16BE", "EUC-JP")
+ a = ["", "\xFF\xFE\x00A\xDC\x00\x00B", ec, nil, 10, :after_output=>true]
+ check_ec("", "\x00A\xDC\x00\x00B", :undefined_conversion, *a)
+ check_ec("A", "\xDC\x00\x00B", :after_output, *a)
+ check_ec("A", "\x00B", :invalid_byte_sequence, *a)
+ check_ec("AB", "", :after_output, *a)
+ check_ec("AB", "", :finished, *a)
+ end
+
+ def test_universal_newline
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", universal_newline: true)
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a)
+ src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a)
+ src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a)
+ src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a)
+ src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a)
+ src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a)
+ end
+
+ def test_universal_newline2
+ ec = Encoding::Converter.new("", "", universal_newline: true)
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a)
+ src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a)
+ src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a)
+ src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a)
+ src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a)
+ src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a)
+ end
+
+ def test_universal_newline3
+ ec = Encoding::Converter.new("", "", universal_newline: true)
+ a = ["", src="", ec, nil, 50, :partial_input=>true]
+ src << "abc\r\ndef"; check_ec("abc\ndef", "", :source_buffer_empty, *a)
+ src << "ghi\njkl"; check_ec("abc\ndefghi\njkl", "", :source_buffer_empty, *a)
+ src << "mno\rpqr"; check_ec("abc\ndefghi\njklmno\npqr", "", :source_buffer_empty, *a)
+ src << "stu\r"; check_ec("abc\ndefghi\njklmno\npqrstu", "", :source_buffer_empty, *a)
+ src << "\nvwx"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx", "", :source_buffer_empty, *a)
+ src << "\nyz"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a)
+ src << "\r"; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz", "", :source_buffer_empty, *a)
+ a[-1] = nil
+ src << ""; check_ec("abc\ndefghi\njklmno\npqrstu\nvwx\nyz\n", "", :finished, *a)
+ end
+
+ def test_crlf_newline
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", crlf_newline: true)
+ assert_econv("abc\r\ndef", :finished, 50, ec, "abc\ndef", "")
+ end
+
+ def test_crlf_newline2
+ ec = Encoding::Converter.new("", "", crlf_newline: true)
+ assert_econv("abc\r\ndef", :finished, 50, ec, "abc\ndef", "")
+ end
+
+ def test_cr_newline
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", cr_newline: true)
+ assert_econv("abc\rdef", :finished, 50, ec, "abc\ndef", "")
+ end
+
+ def test_cr_newline2
+ ec = Encoding::Converter.new("", "", cr_newline: true)
+ assert_econv("abc\rdef", :finished, 50, ec, "abc\ndef", "")
+ end
+
+ def test_no_universal_newline1
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", universal_newline: false)
+ assert_econv("abc\r\ndef", :finished, 50, ec, "abc\r\ndef", "")
+ end
+
+ def test_no_universal_newline2
+ ec = Encoding::Converter.new("", "", universal_newline: false)
+ assert_econv("abc\r\ndef", :finished, 50, ec, "abc\r\ndef", "")
+ end
+
+ def test_after_output
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP")
+ a = ["", "abc\u{3042}def", ec, nil, 100, :after_output=>true]
+ check_ec("a", "bc\u{3042}def", :after_output, *a)
+ check_ec("ab", "c\u{3042}def", :after_output, *a)
+ check_ec("abc", "\u{3042}def", :after_output, *a)
+ check_ec("abc\xA4\xA2", "def", :after_output, *a)
+ check_ec("abc\xA4\xA2d", "ef", :after_output, *a)
+ check_ec("abc\xA4\xA2de", "f", :after_output, *a)
+ check_ec("abc\xA4\xA2def", "", :after_output, *a)
+ check_ec("abc\xA4\xA2def", "", :finished, *a)
+ end
+
+ def test_errinfo_invalid_euc_jp
+ ec = Encoding::Converter.new("EUC-JP", "Shift_JIS")
+ ec.primitive_convert("\xff", "", nil, 10)
+ assert_errinfo(:invalid_byte_sequence, "EUC-JP", "Shift_JIS", "\xFF", "", ec)
+ end
+
+ def test_errinfo_invalid_euc_jp2
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ ec.primitive_convert("\xff", "", nil, 10)
+ assert_errinfo(:invalid_byte_sequence, "EUC-JP", "UTF-8", "\xFF", "", ec)
+ end
+
+ def test_errinfo_undefined_hiragana
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ ec.primitive_convert("\xa4\xa2", "", nil, 10)
+ assert_errinfo(:undefined_conversion, "UTF-8", "ISO-8859-1", "\xE3\x81\x82", "", ec)
+ end
+
+ def test_errinfo_invalid_partial_character
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ ec.primitive_convert("\xa4", "", nil, 10)
+ assert_errinfo(:incomplete_input, "EUC-JP", "UTF-8", "\xA4", "", ec)
+ end
+
+ def test_errinfo_valid_partial_character
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ ec.primitive_convert("\xa4", "", nil, 10, :partial_input=>true)
+ assert_errinfo(:source_buffer_empty, nil, nil, nil, nil, ec)
+ end
+
+ def test_errinfo_invalid_utf16be
+ ec = Encoding::Converter.new("UTF-16BE", "UTF-8")
+ ec.primitive_convert(src="\xd8\x00\x00@", "", nil, 10)
+ assert_errinfo(:invalid_byte_sequence, "UTF-16BE", "UTF-8", "\xD8\x00", "\x00", ec)
+ assert_equal("@", src)
+ end
+
+ def test_errinfo_invalid_utf16le
+ ec = Encoding::Converter.new("UTF-16LE", "UTF-8")
+ ec.primitive_convert(src="\x00\xd8@\x00", "", nil, 10)
+ assert_errinfo(:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "@\x00", ec)
+ assert_equal("", src)
+ end
+
+ def test_output_iso2022jp
+ ec = Encoding::Converter.new("EUC-JP", "ISO-2022-JP")
+ ec.primitive_convert(src="\xa1\xa1", dst="", nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!".force_encoding("ISO-2022-JP"), dst)
+ assert_equal(nil, ec.insert_output("???"))
+ ec.primitive_convert("", dst, nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!\e(B???".force_encoding("ISO-2022-JP"), dst)
+ ec.primitive_convert(src="\xa1\xa2", dst, nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!\e(B???\e$B!\"".force_encoding("ISO-2022-JP"), dst)
+
+ assert_equal(nil, ec.insert_output("\xA1\xA1".force_encoding("EUC-JP")))
+ ec.primitive_convert("", dst, nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!\e(B???\e$B!\"!!".force_encoding("ISO-2022-JP"), dst)
+
+ ec.primitive_convert(src="\xa1\xa3", dst, nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!\e(B???\e$B!\"!!!\#".force_encoding("ISO-2022-JP"), dst)
+
+ assert_equal(nil, ec.insert_output("\u3042"))
+ ec.primitive_convert("", dst, nil, 10, :partial_input=>true)
+ assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"".force_encoding("ISO-2022-JP"), dst)
+
+ assert_raise(Encoding::UndefinedConversionError) {
+ ec.insert_output("\uFFFD")
+ }
+
+ assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"".force_encoding("ISO-2022-JP"), dst)
+
+ ec.primitive_convert("", dst, nil, 10)
+ assert_equal("\e$B!!\e(B???\e$B!\"!!!\#$\"\e(B".force_encoding("ISO-2022-JP"), dst)
+ end
+
+ def test_exc_invalid
+ err = assert_raise(Encoding::InvalidByteSequenceError) {
+ "abc\xa4def".encode("ISO-8859-1", "EUC-JP")
+ }
+ assert_equal("EUC-JP", err.source_encoding_name)
+ assert_equal("UTF-8", err.destination_encoding_name)
+ assert_equal(Encoding::EUC_JP, err.source_encoding)
+ assert_equal(Encoding::UTF_8, err.destination_encoding)
+ assert_equal("\xA4".force_encoding("ASCII-8BIT"), err.error_bytes)
+ assert_equal("d", err.readagain_bytes)
+ assert_equal(false, err.incomplete_input?)
+ end
+
+ def test_exc_incomplete
+ err = assert_raise(Encoding::InvalidByteSequenceError) {
+ "abc\xa4".encode("ISO-8859-1", "EUC-JP")
+ }
+ assert_equal("EUC-JP", err.source_encoding_name)
+ assert_equal("UTF-8", err.destination_encoding_name)
+ assert_equal(Encoding::EUC_JP, err.source_encoding)
+ assert_equal(Encoding::UTF_8, err.destination_encoding)
+ assert_equal("\xA4".force_encoding("ASCII-8BIT"), err.error_bytes)
+ assert_equal(nil, err.readagain_bytes)
+ assert_equal(true, err.incomplete_input?)
+ end
+
+ def test_exc_undef
+ err = assert_raise(Encoding::UndefinedConversionError) {
+ "abc\xa4\xa2def".encode("ISO-8859-1", "EUC-JP")
+ }
+ assert_equal("UTF-8", err.source_encoding_name)
+ assert_equal("ISO-8859-1", err.destination_encoding_name)
+ assert_equal(Encoding::UTF_8, err.source_encoding)
+ assert_equal(Encoding::ISO_8859_1, err.destination_encoding)
+ assert_equal("\u{3042}", err.error_char)
+ end
+
+ def test_putback
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ ret = ec.primitive_convert(src="abc\xa1def", dst="", nil, 10)
+ assert_equal(:invalid_byte_sequence, ret)
+ assert_equal(["abc", "ef"], [dst, src])
+ src = ec.putback + src
+ assert_equal(["abc", "def"], [dst, src])
+ ret = ec.primitive_convert(src, dst, nil, 10)
+ assert_equal(:finished, ret)
+ assert_equal(["abcdef", ""], [dst, src])
+ end
+
+ def test_putback2
+ ec = Encoding::Converter.new("utf-16le", "euc-jp")
+ ret = ec.primitive_convert("\x00\xd8\x21\x00", "", nil, nil)
+ assert_equal(:invalid_byte_sequence, ret)
+ assert_equal("\x00".force_encoding("utf-16le"), ec.putback(1))
+ assert_equal("\x21".force_encoding("utf-16le"), ec.putback(1))
+ assert_equal("", ec.putback(1))
+ end
+
+ def test_invalid_replace
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", invalid: :replace)
+ ret = ec.primitive_convert(src="abc\x80def", dst="", nil, 100)
+ assert_equal(:finished, ret)
+ assert_equal("", src)
+ assert_equal("abc?def", dst)
+ end
+
+ def test_invalid_ignore
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", :invalid => :replace, :replace => "")
+ ret = ec.primitive_convert(src="abc\x80def", dst="", nil, 100)
+ assert_equal(:finished, ret)
+ assert_equal("", src)
+ assert_equal("abcdef", dst)
+ end
+
+ def test_undef_replace
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", :undef => :replace)
+ ret = ec.primitive_convert(src="abc\u{fffd}def", dst="", nil, 100)
+ assert_equal(:finished, ret)
+ assert_equal("", src)
+ assert_equal("abc?def", dst)
+ end
+
+ def test_undef_ignore
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", :undef => :replace, :replace => "")
+ ret = ec.primitive_convert(src="abc\u{fffd}def", dst="", nil, 100)
+ assert_equal(:finished, ret)
+ assert_equal("", src)
+ assert_equal("abcdef", dst)
+ end
+
+ def test_noconv
+ ec = Encoding::Converter.new("", "")
+ assert_equal(nil, ec.source_encoding)
+ assert_equal(nil, ec.destination_encoding)
+ assert_equal([:source_buffer_empty, nil, nil, nil, nil], ec.primitive_errinfo)
+ a = ["", "abcdefg", ec, nil, 2]
+ check_ec("ab", "cdefg", :destination_buffer_full, *a)
+ check_ec("abcd", "efg", :destination_buffer_full, *a)
+ check_ec("abcdef", "g", :destination_buffer_full, *a)
+ check_ec("abcdefg", "", :finished, *a)
+ end
+
+ def test_noconv_partial
+ ec = Encoding::Converter.new("", "")
+ a = ["", "abcdefg", ec, nil, 2, :partial_input=>true]
+ check_ec("ab", "cdefg", :destination_buffer_full, *a)
+ check_ec("abcd", "efg", :destination_buffer_full, *a)
+ check_ec("abcdef", "g", :destination_buffer_full, *a)
+ check_ec("abcdefg", "", :source_buffer_empty, *a)
+ end
+
+ def test_noconv_after_output
+ ec = Encoding::Converter.new("", "")
+ a = ["", "abcdefg", ec, nil, 2, :after_output=>true]
+ check_ec("a", "bcdefg", :after_output, *a)
+ check_ec("ab", "cdefg", :after_output, *a)
+ check_ec("abc", "defg", :after_output, *a)
+ check_ec("abcd", "efg", :after_output, *a)
+ check_ec("abcde", "fg", :after_output, *a)
+ check_ec("abcdef", "g", :after_output, *a)
+ check_ec("abcdefg", "", :after_output, *a)
+ check_ec("abcdefg", "", :finished, *a)
+ end
+
+ def test_noconv_insert_output
+ ec = Encoding::Converter.new("", "")
+ ec.insert_output("xyz")
+ ret = ec.primitive_convert(src="abc", dst="", nil, 20)
+ assert_equal(:finished, ret)
+ assert_equal(["xyzabc", ""], [dst, src])
+ end
+
+ def test_convert
+ ec = Encoding::Converter.new("utf-8", "euc-jp")
+ assert_raise(Encoding::InvalidByteSequenceError) { ec.convert("a\x80") }
+ assert_raise(Encoding::UndefinedConversionError) { ec.convert("\ufffd") }
+ ret = ec.primitive_convert(nil, "", nil, nil)
+ assert_equal(:finished, ret)
+ assert_raise(ArgumentError) { ec.convert("a") }
+ end
+
+ def test_finish_iso2022jp
+ ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
+ assert_equal("\e$B$\"".force_encoding("iso-2022-jp"), ec.convert("\u3042"))
+ assert_equal("\e(B".force_encoding("iso-2022-jp"), ec.finish)
+
+ end
+
+ def test_finish_incomplete_error
+ ec = Encoding::Converter.new("utf-8", "euc-jp")
+ ec.convert("\xEF")
+ assert_raise(Encoding::InvalidByteSequenceError) { ec.finish }
+ end
+
+ def test_last_error1
+ ec = Encoding::Converter.new("sjis", "euc-jp")
+ assert_equal(nil, ec.last_error)
+ assert_equal(:incomplete_input, ec.primitive_convert("fo\x81", "", nil, nil))
+ assert_kind_of(Encoding::InvalidByteSequenceError, ec.last_error)
+ end
+
+ def test_last_error2
+ ec = Encoding::Converter.new("sjis", "euc-jp")
+ assert_equal("fo", ec.convert("fo\x81"))
+ assert_raise(Encoding::InvalidByteSequenceError) { ec.finish }
+ assert_kind_of(Encoding::InvalidByteSequenceError, ec.last_error)
+ end
+
+ def test_us_ascii
+ ec = Encoding::Converter.new("UTF-8", "US-ASCII")
+ ec.primitive_convert("\u{3042}", "")
+ err = ec.last_error
+ assert_kind_of(Encoding::UndefinedConversionError, err)
+ assert_equal("\u{3042}", err.error_char)
+ end
+
+ def test_88591
+ ec = Encoding::Converter.new("UTF-8", "ISO-8859-1")
+ ec.primitive_convert("\u{3042}", "")
+ err = ec.last_error
+ assert_kind_of(Encoding::UndefinedConversionError, err)
+ assert_equal("\u{3042}", err.error_char)
+ end
+
+ def test_get_replacement
+ ec = Encoding::Converter.new("euc-jp", "iso-8859-1")
+ assert_equal("?", ec.replacement)
+
+ ec = Encoding::Converter.new("euc-jp", "utf-8")
+ assert_equal("\uFFFD", ec.replacement)
+ end
+
+ def test_set_replacement
+ ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace)
+ ec.replacement = "<undef>"
+ assert_equal("a <undef> b", ec.convert("a \u3042 b"))
+ end
+
+ def test_econv_new_hash
+ ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace)
+ assert_equal("a ? b", ec.convert("a \u3042 b"))
+ ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace, :replace => "X")
+ assert_equal("a X b", ec.convert("a \u3042 b"))
+ end
+
+ def test_hex_charref
+ ec = Encoding::Converter.new("UTF-8", "US-ASCII", Encoding::Converter::UNDEF_HEX_CHARREF)
+ assert_equal("&#x3042;", ec.convert("\u3042"))
+
+ ec = Encoding::Converter.new("UTF-8", "EUC-JP", Encoding::Converter::UNDEF_HEX_CHARREF)
+ assert_equal("\xa4\xcf\xa4\xa1\xa4\xa4&#x2665;\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&#x2665;\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("&#x4EA4;&#x63DB;&#x6CD5;&#x5247;: n&#xD7;m=m&#xD7;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("&#x4EA4;&#x63DB;&#x6CD5;&#x5247;: 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('&amp;<>"', ec.convert("&<>\""))
+ assert_equal('', ec.finish)
+
+ ec = Encoding::Converter.new("", "xml_text_escape")
+ assert_equal('&amp;&lt;&gt;"', 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('&quot;', ec.convert('"'))
+ assert_equal('', ec.finish)
+
+ ec = Encoding::Converter.new("", "xml_attr_content_escape")
+ assert_equal('&amp;&lt;&gt;&quot;', 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('&lt;&#x2665;&gt;&amp;"&#x2661;"', 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('"&lt;&#x2665;&gt;&amp;&quot;&#x2661;&quot;', ec.convert("<\u2665>&\"\u2661\""))
+ assert_equal('"', ec.finish)
+
+ ec = Encoding::Converter.new("utf-8", "iso-2022-jp", Encoding::Converter::XML_TEXT_DECORATOR)
+ assert_equal("&amp;\e$B$&\e(B&amp;".force_encoding("iso-2022-jp"), ec.convert("&\u3046&"))
+ assert_equal('', ec.finish)
+ end
+
+ def test_xml_hasharg
+ assert_equal("&amp;\e$B$&\e(B&#x2665;&amp;\"'".force_encoding("iso-2022-jp"),
+ "&\u3046\u2665&\"'".encode("iso-2022-jp", xml: :text))
+ assert_equal("\"&amp;\e$B$&\e(B&#x2661;&amp;&quot;'\"".force_encoding("iso-2022-jp"),
+ "&\u3046\u2661&\"'".encode("iso-2022-jp", xml: :attr))
+
+ assert_equal("&amp;\u3046\u2661&amp;\"'".force_encoding("utf-8"),
+ "&\u3046\u2661&\"'".encode("utf-8", xml: :text))
+ end
+
+ def test_iso2022jp_invalid_replace
+ assert_equal("?x".force_encoding("iso-2022-jp"),
+ "\222\xA1x".encode("iso-2022-jp", "stateless-iso-2022-jp", :invalid => :replace))
+ end
+
+ def test_convpath
+ eucjp = Encoding::EUC_JP
+ utf8 = Encoding::UTF_8
+ utf16be = Encoding::UTF_16BE
+ utf16le = Encoding::UTF_16LE
+ iso88591 = Encoding::ISO_8859_1
+ iso2022jp = Encoding::ISO_2022_JP
+ siso2022jp = Encoding::STATELESS_ISO_2022_JP
+
+ assert_equal([], Encoding::Converter.new("", "").convpath)
+ assert_equal([[eucjp, utf8], [utf8, iso88591]],
+ Encoding::Converter.new(eucjp, iso88591).convpath)
+ assert_equal([[eucjp, siso2022jp], [siso2022jp, iso2022jp]],
+ Encoding::Converter.new(eucjp, iso2022jp).convpath)
+ assert_equal([[iso2022jp, siso2022jp],
+ [siso2022jp, eucjp],
+ [eucjp, utf8],
+ [utf8, iso88591]],
+ Encoding::Converter.new(iso2022jp, iso88591).convpath)
+ assert_equal(["universal_newline", [utf8, utf16be]],
+ Encoding::Converter.new(utf8, utf16be, universal_newline: true).convpath)
+ assert_equal([[utf16be, utf8], "universal_newline"],
+ Encoding::Converter.new(utf16be, utf8, universal_newline: true).convpath)
+ assert_equal([[utf16be, utf8], "universal_newline", [utf8, utf16le]],
+ Encoding::Converter.new(utf16be, utf16le, universal_newline: true).convpath)
+ end
+
+ def test_search_convpath
+ eucjp = Encoding::EUC_JP
+ utf8 = Encoding::UTF_8
+ utf32be = Encoding::UTF_32BE
+ iso88591 = Encoding::ISO_8859_1
+ assert_equal([[iso88591,utf8], [utf8,eucjp]],
+ Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP"))
+ assert_equal([[iso88591,utf8], [utf8,eucjp]],
+ Encoding::Converter.search_convpath(iso88591, eucjp))
+ assert_equal([[iso88591,utf8], [utf8,eucjp], "universal_newline"],
+ Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP", universal_newline: true))
+ assert_equal([[iso88591,utf8], "universal_newline", [utf8,utf32be]],
+ Encoding::Converter.search_convpath("ISO-8859-1", "UTF-32BE", universal_newline: true))
+ end
+
+ def test_invalid_replace2
+ assert_raise(ArgumentError) {
+ broken = "\x80".force_encoding("euc-jp")
+ "".encode("euc-jp", :undef => :replace, :replace => broken)
+ }
+ end
+
+ def test_newline_option
+ ec1 = Encoding::Converter.new("", "", universal_newline: true)
+ ec2 = Encoding::Converter.new("", "", newline: :universal)
+ assert_equal(ec1, ec2)
+ assert_raise_with_message(ArgumentError, /\u{3042}/) {
+ Encoding::Converter.new("", "", newline: "\u{3042}".to_sym)
+ }
+ end
+
+ def test_default_external
+ Encoding.list.grep(->(enc) {/\AISO-8859-\d+\z/i =~ enc.name}) do |enc|
+ assert_separately(%W[--disable=gems -d - #{enc.name}], <<-EOS, ignore_stderr: true)
+ Encoding.default_external = ext = ARGV[0]
+ Encoding.default_internal = int ='utf-8'
+ assert_nothing_raised do
+ Encoding::Converter.new(ext, int)
+ end
+ EOS
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_encoding.rb b/jni/ruby/test/ruby/test_encoding.rb
new file mode 100644
index 0000000..63c56e2
--- /dev/null
+++ b/jni/ruby/test/ruby/test_encoding.rb
@@ -0,0 +1,123 @@
+require 'test/unit'
+
+class TestEncoding < Test::Unit::TestCase
+
+ # Test basic encoding methods: list, find, name
+ def test_encoding
+ encodings = Encoding.list
+ assert_equal(encodings.empty?, false)
+
+ encodings.each do |e|
+ assert_equal(e, Encoding.find(e.name))
+ assert_equal(e, Encoding.find(e.name.upcase))
+ assert_equal(e, Encoding.find(e.name.capitalize))
+ assert_equal(e, Encoding.find(e.name.downcase))
+ assert_equal(e, Encoding.find(e))
+ end
+ end
+
+ def test_enc_names
+ aliases = Encoding.aliases
+ aliases.each do |a, en|
+ e = Encoding.find(a)
+ assert_equal(e.name, en)
+ assert_include(e.names, a)
+ end
+ end
+
+ # Test that Encoding objects can't be copied
+ # And that they can be compared by object_id
+ def test_singleton
+ encodings = Encoding.list
+ encodings.each do |e|
+ assert_raise(TypeError) { e.dup }
+ assert_raise(TypeError) { e.clone }
+ assert_equal(e.object_id, Marshal.load(Marshal.dump(e)).object_id)
+ end
+ end
+
+ def test_find
+ assert_raise(ArgumentError) { Encoding.find("foobarbazqux") }
+ assert_nothing_raised{Encoding.find("locale")}
+ assert_nothing_raised{Encoding.find("filesystem")}
+
+ if /(?:ms|dar)win|mingw/ !~ RUBY_PLATFORM
+ # Unix's filesystem encoding is default_external
+ assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS')
+ exit Encoding.find("filesystem") == Encoding::UTF_8
+ Encoding.default_external = Encoding::EUC_JP
+ exit Encoding.find("filesystem") == Encoding::EUC_JP
+ EOS
+ end
+
+ bug5150 = '[ruby-dev:44327]'
+ assert_raise(TypeError, bug5150) {Encoding.find(1)}
+ end
+
+ def test_replicate
+ assert_instance_of(Encoding, Encoding::UTF_8.replicate('UTF-8-ANOTHER'))
+ assert_instance_of(Encoding, Encoding::ISO_2022_JP.replicate('ISO-2022-JP-ANOTHER'))
+ bug3127 = '[ruby-dev:40954]'
+ assert_raise(TypeError, bug3127) {Encoding::UTF_8.replicate(0)}
+ assert_raise(ArgumentError, bug3127) {Encoding::UTF_8.replicate("\0")}
+ end
+
+ def test_dummy_p
+ assert_equal(true, Encoding::ISO_2022_JP.dummy?)
+ assert_equal(false, Encoding::UTF_8.dummy?)
+ end
+
+ def test_ascii_compatible_p
+ assert_equal(true, Encoding::ASCII_8BIT.ascii_compatible?)
+ assert_equal(true, Encoding::UTF_8.ascii_compatible?)
+ assert_equal(false, Encoding::UTF_16BE.ascii_compatible?)
+ assert_equal(false, Encoding::ISO_2022_JP.ascii_compatible?)
+ end
+
+ def test_name_list
+ assert_instance_of(Array, Encoding.name_list)
+ Encoding.name_list.each do |x|
+ assert_instance_of(String, x)
+ end
+ end
+
+ def test_aliases
+ assert_instance_of(Hash, Encoding.aliases)
+ Encoding.aliases.each do |k, v|
+ assert_include(Encoding.name_list, k)
+ assert_include(Encoding.name_list, v)
+ assert_instance_of(String, k)
+ assert_instance_of(String, v)
+ end
+ end
+
+ def test_marshal
+ str = "".force_encoding("EUC-JP")
+ str2 = Marshal.load(Marshal.dump(str))
+ assert_equal(str, str2)
+ str2 = Marshal.load(Marshal.dump(str2))
+ assert_equal(str, str2, '[ruby-dev:38596]')
+ end
+
+ def test_compatible_p
+ ua = "abc".force_encoding(Encoding::UTF_8)
+ assert_equal(Encoding::UTF_8, Encoding.compatible?(ua, :abc))
+ assert_equal(nil, Encoding.compatible?(ua, 1))
+ bin = "a".force_encoding(Encoding::ASCII_8BIT)
+ asc = "b".force_encoding(Encoding::US_ASCII)
+ assert_equal(Encoding::ASCII_8BIT, Encoding.compatible?(bin, asc))
+ bin = "\xff".force_encoding(Encoding::ASCII_8BIT).to_sym
+ asc = "b".force_encoding(Encoding::ASCII_8BIT)
+ assert_equal(Encoding::ASCII_8BIT, Encoding.compatible?(bin, asc))
+ assert_equal(Encoding::UTF_8, Encoding.compatible?("\u{3042}".to_sym, ua.to_sym))
+ end
+
+ def test_errinfo_after_autoload
+ bug9038 = '[ruby-core:57949] [Bug #9038]'
+ assert_separately(%w[--disable=gems], <<-"end;")
+ assert_raise_with_message(SyntaxError, /unknown regexp option - Q/, #{bug9038.dump}) {
+ eval("/regexp/sQ")
+ }
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_enum.rb b/jni/ruby/test/ruby/test_enum.rb
new file mode 100644
index 0000000..53e24fc
--- /dev/null
+++ b/jni/ruby/test/ruby/test_enum.rb
@@ -0,0 +1,733 @@
+require 'test/unit'
+EnvUtil.suppress_warning {require 'continuation'}
+require 'stringio'
+
+class TestEnumerable < Test::Unit::TestCase
+ def setup
+ @obj = Object.new
+ class << @obj
+ include Enumerable
+ def each
+ yield 1
+ yield 2
+ yield 3
+ yield 1
+ yield 2
+ self
+ end
+ end
+ @empty = Object.new
+ class << @empty
+ attr_reader :block
+ include Enumerable
+ def each(&block)
+ @block = block
+ self
+ end
+ end
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def assert_not_warn
+ begin
+ org_stderr = $stderr
+ v = $VERBOSE
+ $stderr = StringIO.new(warn = '')
+ $VERBOSE = true
+ yield
+ ensure
+ $stderr = org_stderr
+ $VERBOSE = v
+ end
+ assert_equal("", warn)
+ end
+
+ def test_grep
+ assert_equal([1, 2, 1, 2], @obj.grep(1..2))
+ a = []
+ @obj.grep(2) {|x| a << x }
+ assert_equal([2, 2], a)
+
+ bug5801 = '[ruby-dev:45041]'
+ @empty.grep(//)
+ block = @empty.block
+ assert_nothing_raised(bug5801) {100.times {block.call}}
+
+ a = []
+ lambda = ->(x, i) {a << [x, i]}
+ @obj.each_with_index.grep(proc{|x,i|x==2}, &lambda)
+ assert_equal([[2, 1], [2, 4]], a)
+ end
+
+ def test_count
+ assert_equal(5, @obj.count)
+ assert_equal(2, @obj.count(1))
+ assert_equal(3, @obj.count {|x| x % 2 == 1 })
+ assert_equal(2, @obj.count(1) {|x| x % 2 == 1 })
+ assert_raise(ArgumentError) { @obj.count(0, 1) }
+
+ if RUBY_ENGINE == "ruby"
+ en = Class.new {
+ include Enumerable
+ alias :size :count
+ def each
+ yield 1
+ end
+ }
+ assert_equal(1, en.new.count, '[ruby-core:24794]')
+ end
+ end
+
+ def test_find
+ assert_equal(2, @obj.find {|x| x % 2 == 0 })
+ assert_equal(nil, @obj.find {|x| false })
+ assert_equal(:foo, @obj.find(proc { :foo }) {|x| false })
+ cond = ->(x, i) { x % 2 == 0 }
+ assert_equal([2, 1], @obj.each_with_index.find(&cond))
+ end
+
+ def test_find_index
+ assert_equal(1, @obj.find_index(2))
+ assert_equal(1, @obj.find_index {|x| x % 2 == 0 })
+ assert_equal(nil, @obj.find_index {|x| false })
+ assert_raise(ArgumentError) { @obj.find_index(0, 1) }
+ assert_equal(1, @obj.find_index(2) {|x| x == 1 })
+ end
+
+ def test_find_all
+ assert_equal([1, 3, 1], @obj.find_all {|x| x % 2 == 1 })
+ cond = ->(x, i) { x % 2 == 1 }
+ assert_equal([[1, 0], [3, 2], [1, 3]], @obj.each_with_index.find_all(&cond))
+ end
+
+ def test_reject
+ assert_equal([2, 3, 2], @obj.reject {|x| x < 2 })
+ cond = ->(x, i) {x < 2}
+ assert_equal([[2, 1], [3, 2], [2, 4]], @obj.each_with_index.reject(&cond))
+ end
+
+ def test_to_a
+ assert_equal([1, 2, 3, 1, 2], @obj.to_a)
+ end
+
+ def test_to_h
+ obj = Object.new
+ def obj.each(*args)
+ yield(*args)
+ yield [:key, :value]
+ yield :other_key, :other_value
+ kvp = Object.new
+ def kvp.to_ary
+ [:obtained, :via_to_ary]
+ end
+ yield kvp
+ end
+ obj.extend Enumerable
+ assert_equal({
+ :hello => :world,
+ :key => :value,
+ :other_key => :other_value,
+ :obtained => :via_to_ary,
+ }, obj.to_h(:hello, :world))
+
+ e = assert_raise(TypeError) {
+ obj.to_h(:not_an_array)
+ }
+ assert_equal "wrong element type Symbol (expected array)", e.message
+
+ e = assert_raise(ArgumentError) {
+ obj.to_h([1])
+ }
+ assert_equal "element has wrong array length (expected 2, was 1)", e.message
+ end
+
+ def test_inject
+ assert_equal(12, @obj.inject {|z, x| z * x })
+ assert_equal(48, @obj.inject {|z, x| z * 2 + x })
+ assert_equal(12, @obj.inject(:*))
+ assert_equal(24, @obj.inject(2) {|z, x| z * x })
+ assert_equal(24, @obj.inject(2, :*) {|z, x| z * x })
+ assert_equal(nil, @empty.inject() {9})
+ end
+
+ def test_partition
+ assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 })
+ cond = ->(x, i) { x % 2 == 1 }
+ assert_equal([[[1, 0], [3, 2], [1, 3]], [[2, 1], [2, 4]]], @obj.each_with_index.partition(&cond))
+ end
+
+ def test_group_by
+ h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] }
+ assert_equal(h, @obj.group_by {|x| x })
+
+ h = {1=>[[1, 0], [1, 3]], 2=>[[2, 1], [2, 4]], 3=>[[3, 2]]}
+ cond = ->(x, i) { x }
+ assert_equal(h, @obj.each_with_index.group_by(&cond))
+ end
+
+ def test_first
+ assert_equal(1, @obj.first)
+ assert_equal([1, 2, 3], @obj.first(3))
+ assert_nil(@empty.first)
+
+ bug5801 = '[ruby-dev:45041]'
+ assert_in_out_err([], <<-'end;', [], /unexpected break/)
+ empty = Object.new
+ class << empty
+ attr_reader :block
+ include Enumerable
+ def each(&block)
+ @block = block
+ self
+ end
+ end
+ empty.first
+ empty.block.call
+ end;
+ end
+
+ def test_sort
+ assert_equal([1, 1, 2, 2, 3], @obj.sort)
+ end
+
+ def test_sort_by
+ assert_equal([3, 2, 2, 1, 1], @obj.sort_by {|x| -x })
+ assert_equal((1..300).to_a.reverse, (1..300).sort_by {|x| -x })
+
+ cond = ->(x, i) { [-x, i] }
+ assert_equal([[3, 2], [2, 1], [2, 4], [1, 0], [1, 3]], @obj.each_with_index.sort_by(&cond))
+ end
+
+ def test_all
+ assert_equal(true, @obj.all? {|x| x <= 3 })
+ assert_equal(false, @obj.all? {|x| x < 3 })
+ assert_equal(true, @obj.all?)
+ assert_equal(false, [true, true, false].all?)
+ end
+
+ def test_any
+ assert_equal(true, @obj.any? {|x| x >= 3 })
+ assert_equal(false, @obj.any? {|x| x > 3 })
+ assert_equal(true, @obj.any?)
+ assert_equal(false, [false, false, false].any?)
+ end
+
+ def test_one
+ assert(@obj.one? {|x| x == 3 })
+ assert(!(@obj.one? {|x| x == 1 }))
+ assert(!(@obj.one? {|x| x == 4 }))
+ assert(%w{ant bear cat}.one? {|word| word.length == 4})
+ assert(!(%w{ant bear cat}.one? {|word| word.length > 4}))
+ assert(!(%w{ant bear cat}.one? {|word| word.length < 4}))
+ assert(!([ nil, true, 99 ].one?))
+ assert([ nil, true, false ].one?)
+ end
+
+ def test_none
+ assert(@obj.none? {|x| x == 4 })
+ assert(!(@obj.none? {|x| x == 1 }))
+ assert(!(@obj.none? {|x| x == 3 }))
+ assert(%w{ant bear cat}.none? {|word| word.length == 5})
+ assert(!(%w{ant bear cat}.none? {|word| word.length >= 4}))
+ assert([].none?)
+ assert([nil].none?)
+ assert([nil,false].none?)
+ end
+
+ def test_min
+ assert_equal(1, @obj.min)
+ assert_equal(3, @obj.min {|a,b| b <=> a })
+ cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
+ assert_equal([3, 2], @obj.each_with_index.min(&cond))
+ ary = %w(albatross dog horse)
+ assert_equal("albatross", ary.min)
+ assert_equal("dog", ary.min {|a,b| a.length <=> b.length })
+ assert_equal(1, [3,2,1].min)
+ assert_equal(%w[albatross dog], ary.min(2))
+ assert_equal(%w[dog horse],
+ ary.min(2) {|a,b| a.length <=> b.length })
+ end
+
+ def test_max
+ assert_equal(3, @obj.max)
+ assert_equal(1, @obj.max {|a,b| b <=> a })
+ cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
+ assert_equal([1, 3], @obj.each_with_index.max(&cond))
+ ary = %w(albatross dog horse)
+ assert_equal("horse", ary.max)
+ assert_equal("albatross", ary.max {|a,b| a.length <=> b.length })
+ assert_equal(1, [3,2,1].max{|a,b| b <=> a })
+ assert_equal(%w[horse dog], ary.max(2))
+ assert_equal(%w[albatross horse],
+ ary.max(2) {|a,b| a.length <=> b.length })
+ end
+
+ def test_minmax
+ assert_equal([1, 3], @obj.minmax)
+ assert_equal([3, 1], @obj.minmax {|a,b| b <=> a })
+ ary = %w(albatross dog horse)
+ assert_equal(["albatross", "horse"], ary.minmax)
+ assert_equal(["dog", "albatross"], ary.minmax {|a,b| a.length <=> b.length })
+ assert_equal([1, 3], [2,3,1].minmax)
+ assert_equal([3, 1], [2,3,1].minmax {|a,b| b <=> a })
+ assert_equal([1, 3], [2,2,3,3,1,1].minmax)
+ end
+
+ def test_min_by
+ assert_equal(3, @obj.min_by {|x| -x })
+ cond = ->(x, i) { -x }
+ assert_equal([3, 2], @obj.each_with_index.min_by(&cond))
+ a = %w(albatross dog horse)
+ assert_equal("dog", a.min_by {|x| x.length })
+ assert_equal(3, [2,3,1].min_by {|x| -x })
+ assert_equal(%w[dog horse], a.min_by(2) {|x| x.length })
+ end
+
+ def test_max_by
+ assert_equal(1, @obj.max_by {|x| -x })
+ cond = ->(x, i) { -x }
+ assert_equal([1, 0], @obj.each_with_index.max_by(&cond))
+ a = %w(albatross dog horse)
+ assert_equal("albatross", a.max_by {|x| x.length })
+ assert_equal(1, [2,3,1].max_by {|x| -x })
+ assert_equal(%w[albatross horse], a.max_by(2) {|x| x.length })
+ end
+
+ def test_minmax_by
+ assert_equal([3, 1], @obj.minmax_by {|x| -x })
+ cond = ->(x, i) { -x }
+ assert_equal([[3, 2], [1, 0]], @obj.each_with_index.minmax_by(&cond))
+ a = %w(albatross dog horse)
+ assert_equal(["dog", "albatross"], a.minmax_by {|x| x.length })
+ assert_equal([3, 1], [2,3,1].minmax_by {|x| -x })
+ end
+
+ def test_member
+ assert(@obj.member?(1))
+ assert(!(@obj.member?(4)))
+ assert([1,2,3].member?(1))
+ assert(!([1,2,3].member?(4)))
+ end
+
+ class Foo
+ include Enumerable
+ def each
+ yield 1
+ yield 1,2
+ end
+ end
+
+ def test_each_with_index
+ a = []
+ @obj.each_with_index {|x, i| a << [x, i] }
+ assert_equal([[1,0],[2,1],[3,2],[1,3],[2,4]], a)
+
+ hash = Hash.new
+ %w(cat dog wombat).each_with_index do |item, index|
+ hash[item] = index
+ end
+ assert_equal({"cat"=>0, "wombat"=>2, "dog"=>1}, hash)
+ assert_equal([[1, 0], [[1, 2], 1]], Foo.new.each_with_index.to_a)
+ end
+
+ def test_each_with_object
+ obj = [0, 1]
+ ret = (1..10).each_with_object(obj) {|i, memo|
+ memo[0] += i
+ memo[1] *= i
+ }
+ assert_same(obj, ret)
+ assert_equal([55, 3628800], ret)
+ assert_equal([[1, nil], [[1, 2], nil]], Foo.new.each_with_object(nil).to_a)
+ end
+
+ def test_each_entry
+ assert_equal([1, 2, 3], [1, 2, 3].each_entry.to_a)
+ assert_equal([1, [1, 2]], Foo.new.each_entry.to_a)
+ a = []
+ cond = ->(x, i) { a << x }
+ @obj.each_with_index.each_entry(&cond)
+ assert_equal([1, 2, 3, 1, 2], a)
+ end
+
+ def test_each_slice
+ ary = []
+ (1..10).each_slice(3) {|a| ary << a}
+ assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary)
+
+ bug9749 = '[ruby-core:62060] [Bug #9749]'
+ ary.clear
+ (1..10).each_slice(3, &lambda {|a, *| ary << a})
+ assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary, bug9749)
+ end
+
+ def test_each_cons
+ ary = []
+ (1..5).each_cons(3) {|a| ary << a}
+ assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary)
+
+ bug9749 = '[ruby-core:62060] [Bug #9749]'
+ ary.clear
+ (1..5).each_cons(3, &lambda {|a, *| ary << a})
+ assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary, bug9749)
+ end
+
+ def test_zip
+ assert_equal([[1,1],[2,2],[3,3],[1,1],[2,2]], @obj.zip(@obj))
+ a = []
+ @obj.zip([:a, :b, :c]) {|x,y| a << [x, y] }
+ assert_equal([[1,:a],[2,:b],[3,:c],[1,nil],[2,nil]], a)
+
+ a = []
+ cond = ->((x, i), y) { a << [x, y, i] }
+ @obj.each_with_index.zip([:a, :b, :c], &cond)
+ assert_equal([[1,:a,0],[2,:b,1],[3,:c,2],[1,nil,3],[2,nil,4]], a)
+
+ a = []
+ @obj.zip({a: "A", b: "B", c: "C"}) {|x,y| a << [x, y] }
+ assert_equal([[1,[:a,"A"]],[2,[:b,"B"]],[3,[:c,"C"]],[1,nil],[2,nil]], a)
+
+ ary = Object.new
+ def ary.to_a; [1, 2]; end
+ assert_raise(TypeError) {%w(a b).zip(ary)}
+ def ary.each; [3, 4].each{|e|yield e}; end
+ assert_equal([[1, 3], [2, 4], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
+ def ary.to_ary; [5, 6]; end
+ assert_equal([[1, 5], [2, 6], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
+ end
+
+ def test_take
+ assert_equal([1,2,3], @obj.take(3))
+ end
+
+ def test_take_while
+ assert_equal([1,2], @obj.take_while {|x| x <= 2})
+ cond = ->(x, i) {x <= 2}
+ assert_equal([[1, 0], [2, 1]], @obj.each_with_index.take_while(&cond))
+
+ bug5801 = '[ruby-dev:45040]'
+ @empty.take_while {true}
+ block = @empty.block
+ assert_nothing_raised(bug5801) {100.times {block.call}}
+ end
+
+ def test_drop
+ assert_equal([3,1,2], @obj.drop(2))
+ end
+
+ def test_drop_while
+ assert_equal([3,1,2], @obj.drop_while {|x| x <= 2})
+ cond = ->(x, i) {x <= 2}
+ assert_equal([[3, 2], [1, 3], [2, 4]], @obj.each_with_index.drop_while(&cond))
+ end
+
+ def test_cycle
+ assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10))
+ a = []
+ @obj.cycle(2) {|x| a << x}
+ assert_equal([1,2,3,1,2,1,2,3,1,2], a)
+ a = []
+ cond = ->(x, i) {a << x}
+ @obj.each_with_index.cycle(2, &cond)
+ assert_equal([1,2,3,1,2,1,2,3,1,2], a)
+ end
+
+ def test_callcc
+ assert_raise(RuntimeError) do
+ c = nil
+ @obj.sort_by {|x| callcc {|c2| c ||= c2 }; x }
+ c.call
+ end
+
+ assert_raise(RuntimeError) do
+ c = nil
+ o = Object.new
+ class << o; self; end.class_eval do
+ define_method(:<=>) do |x|
+ callcc {|c2| c ||= c2 }
+ 0
+ end
+ end
+ [o, o].sort_by {|x| x }
+ c.call
+ end
+
+ assert_raise(RuntimeError) do
+ c = nil
+ o = Object.new
+ class << o; self; end.class_eval do
+ define_method(:<=>) do |x|
+ callcc {|c2| c ||= c2 }
+ 0
+ end
+ end
+ [o, o, o].sort_by {|x| x }
+ c.call
+ end
+ end
+
+ def test_reverse_each
+ assert_equal([2,1,3,2,1], @obj.reverse_each.to_a)
+ end
+
+ def test_chunk
+ e = [].chunk {|elt| true }
+ assert_equal([], e.to_a)
+
+ e = @obj.chunk {|elt| elt & 2 == 0 ? false : true }
+ assert_equal([[false, [1]], [true, [2, 3]], [false, [1]], [true, [2]]], e.to_a)
+
+ e = @obj.chunk(acc: 0) {|elt, h| h[:acc] += elt; h[:acc].even? }
+ assert_equal([[false, [1,2]], [true, [3]], [false, [1,2]]], e.to_a)
+ assert_equal([[false, [1,2]], [true, [3]], [false, [1,2]]], e.to_a) # this tests h is duplicated.
+
+ hs = [{}]
+ e = [:foo].chunk(hs[0]) {|elt, h|
+ hs << h
+ true
+ }
+ assert_equal([[true, [:foo]]], e.to_a)
+ assert_equal([[true, [:foo]]], e.to_a)
+ assert_equal([{}, {}, {}], hs)
+ assert_not_same(hs[0], hs[1])
+ assert_not_same(hs[0], hs[2])
+ assert_not_same(hs[1], hs[2])
+
+ e = @obj.chunk {|elt| elt < 3 ? :_alone : true }
+ assert_equal([[:_alone, [1]],
+ [:_alone, [2]],
+ [true, [3]],
+ [:_alone, [1]],
+ [:_alone, [2]]], e.to_a)
+
+ e = @obj.chunk {|elt| elt == 3 ? :_separator : true }
+ assert_equal([[true, [1, 2]],
+ [true, [1, 2]]], e.to_a)
+
+ e = @obj.chunk {|elt| elt == 3 ? nil : true }
+ assert_equal([[true, [1, 2]],
+ [true, [1, 2]]], e.to_a)
+
+ e = @obj.chunk {|elt| :_foo }
+ assert_raise(RuntimeError) { e.to_a }
+ end
+
+ def test_slice_before
+ e = [].slice_before {|elt| true }
+ assert_equal([], e.to_a)
+
+ e = @obj.slice_before {|elt| elt.even? }
+ assert_equal([[1], [2,3,1], [2]], e.to_a)
+
+ e = @obj.slice_before {|elt| elt.odd? }
+ assert_equal([[1,2], [3], [1,2]], e.to_a)
+
+ e = @obj.slice_before(acc: 0) {|elt, h| h[:acc] += elt; h[:acc].even? }
+ assert_equal([[1,2], [3,1,2]], e.to_a)
+ assert_equal([[1,2], [3,1,2]], e.to_a) # this tests h is duplicated.
+
+ hs = [{}]
+ e = [:foo].slice_before(hs[0]) {|elt, h|
+ hs << h
+ true
+ }
+ assert_equal([[:foo]], e.to_a)
+ assert_equal([[:foo]], e.to_a)
+ assert_equal([{}, {}, {}], hs)
+ assert_not_same(hs[0], hs[1])
+ assert_not_same(hs[0], hs[2])
+ assert_not_same(hs[1], hs[2])
+
+ ss = %w[abc defg h ijk l mno pqr st u vw xy z]
+ assert_equal([%w[abc defg h], %w[ijk l], %w[mno], %w[pqr st u vw xy z]],
+ ss.slice_before(/\A...\z/).to_a)
+ assert_not_warn{ss.slice_before(/\A...\z/).to_a}
+ end
+
+ def test_slice_after0
+ assert_raise(ArgumentError) { [].slice_after }
+ end
+
+ def test_slice_after1
+ e = [].slice_after {|a| flunk "should not be called" }
+ assert_equal([], e.to_a)
+
+ e = [1,2].slice_after(1)
+ assert_equal([[1], [2]], e.to_a)
+
+ e = [1,2].slice_after(3)
+ assert_equal([[1, 2]], e.to_a)
+
+ [true, false].each {|b|
+ block_results = [true, b]
+ e = [1,2].slice_after {|a| block_results.shift }
+ assert_equal([[1], [2]], e.to_a)
+ assert_equal([], block_results)
+
+ block_results = [false, b]
+ e = [1,2].slice_after {|a| block_results.shift }
+ assert_equal([[1, 2]], e.to_a)
+ assert_equal([], block_results)
+ }
+ end
+
+ def test_slice_after_both_pattern_and_block
+ assert_raise(ArgumentError) { [].slice_after(1) {|a| true } }
+ end
+
+ def test_slice_after_continuation_lines
+ lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
+ e = lines.slice_after(/[^\\]\n\z/)
+ assert_equal([["foo\n"], ["bar\\\n", "baz\n"], ["\n", "qux\n"]], e.to_a)
+ end
+
+ def test_slice_before_empty_line
+ lines = ["foo", "", "bar"]
+ e = lines.slice_after(/\A\s*\z/)
+ assert_equal([["foo", ""], ["bar"]], e.to_a)
+ end
+
+ def test_slice_when_0
+ e = [].slice_when {|a, b| flunk "should not be called" }
+ assert_equal([], e.to_a)
+ end
+
+ def test_slice_when_1
+ e = [1].slice_when {|a, b| flunk "should not be called" }
+ assert_equal([[1]], e.to_a)
+ end
+
+ def test_slice_when_2
+ e = [1,2].slice_when {|a,b|
+ assert_equal(1, a)
+ assert_equal(2, b)
+ true
+ }
+ assert_equal([[1], [2]], e.to_a)
+
+ e = [1,2].slice_when {|a,b|
+ assert_equal(1, a)
+ assert_equal(2, b)
+ false
+ }
+ assert_equal([[1, 2]], e.to_a)
+ end
+
+ def test_slice_when_3
+ block_invocations = [
+ lambda {|a, b|
+ assert_equal(1, a)
+ assert_equal(2, b)
+ true
+ },
+ lambda {|a, b|
+ assert_equal(2, a)
+ assert_equal(3, b)
+ false
+ }
+ ]
+ e = [1,2,3].slice_when {|a,b|
+ block_invocations.shift.call(a, b)
+ }
+ assert_equal([[1], [2, 3]], e.to_a)
+ assert_equal([], block_invocations)
+ end
+
+ def test_slice_when_noblock
+ assert_raise(ArgumentError) { [].slice_when }
+ end
+
+ def test_slice_when_contiguously_increasing_integers
+ e = [1,4,9,10,11,12,15,16,19,20,21].slice_when {|i, j| i+1 != j }
+ assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a)
+ end
+
+ def test_detect
+ @obj = ('a'..'z')
+ assert_equal('c', @obj.detect {|x| x == 'c' })
+
+ proc = Proc.new {|x| x == 'c' }
+ assert_equal('c', @obj.detect(&proc))
+
+ lambda = ->(x) { x == 'c' }
+ assert_equal('c', @obj.detect(&lambda))
+
+ assert_equal(['c',2], @obj.each_with_index.detect {|x, i| x == 'c' })
+
+ proc2 = Proc.new {|x, i| x == 'c' }
+ assert_equal(['c',2], @obj.each_with_index.detect(&proc2))
+
+ bug9605 = '[ruby-core:61340]'
+ lambda2 = ->(x, i) { x == 'c' }
+ assert_equal(['c',2], @obj.each_with_index.detect(&lambda2))
+ end
+
+ def test_select
+ @obj = ('a'..'z')
+ assert_equal(['c'], @obj.select {|x| x == 'c' })
+
+ proc = Proc.new {|x| x == 'c' }
+ assert_equal(['c'], @obj.select(&proc))
+
+ lambda = ->(x) { x == 'c' }
+ assert_equal(['c'], @obj.select(&lambda))
+
+ assert_equal([['c',2]], @obj.each_with_index.select {|x, i| x == 'c' })
+
+ proc2 = Proc.new {|x, i| x == 'c' }
+ assert_equal([['c',2]], @obj.each_with_index.select(&proc2))
+
+ bug9605 = '[ruby-core:61340]'
+ lambda2 = ->(x, i) { x == 'c' }
+ assert_equal([['c',2]], @obj.each_with_index.select(&lambda2))
+ end
+
+ def test_map
+ @obj = ('a'..'e')
+ assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map {|x| x.upcase })
+
+ proc = Proc.new {|x| x.upcase }
+ assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&proc))
+
+ lambda = ->(x) { x.upcase }
+ assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&lambda))
+
+ assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
+ @obj.each_with_index.map {|x, i| [x.upcase, i] })
+
+ proc2 = Proc.new {|x, i| [x.upcase, i] }
+ assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
+ @obj.each_with_index.map(&proc2))
+
+ lambda2 = ->(x, i) { [x.upcase, i] }
+ assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
+ @obj.each_with_index.map(&lambda2))
+ end
+
+ def test_flat_map
+ @obj = [[1,2], [3,4]]
+ assert_equal([2,4,6,8], @obj.flat_map {|i| i.map{|j| j*2} })
+
+ proc = Proc.new {|i| i.map{|j| j*2} }
+ assert_equal([2,4,6,8], @obj.flat_map(&proc))
+
+ lambda = ->(i) { i.map{|j| j*2} }
+ assert_equal([2,4,6,8], @obj.flat_map(&lambda))
+
+ assert_equal([[1,2],0,[3,4],1],
+ @obj.each_with_index.flat_map {|x, i| [x,i] })
+
+ proc2 = Proc.new {|x, i| [x,i] }
+ assert_equal([[1,2],0,[3,4],1],
+ @obj.each_with_index.flat_map(&proc2))
+
+ lambda2 = ->(x, i) { [x,i] }
+ assert_equal([[1,2],0,[3,4],1],
+ @obj.each_with_index.flat_map(&lambda2))
+ end
+end
diff --git a/jni/ruby/test/ruby/test_enumerator.rb b/jni/ruby/test/ruby/test_enumerator.rb
new file mode 100644
index 0000000..b5ced3b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_enumerator.rb
@@ -0,0 +1,628 @@
+require 'test/unit'
+
+class TestEnumerator < Test::Unit::TestCase
+ def setup
+ @obj = Object.new
+ class << @obj
+ include Enumerable
+ def foo(*a)
+ a.each {|x| yield x }
+ end
+ end
+ @sized = @obj.clone
+ def @sized.size
+ 42
+ end
+ end
+
+ def enum_test obj
+ obj.map{|e|
+ e
+ }.sort
+ end
+
+ def test_iterators
+ assert_equal [0, 1, 2], enum_test(3.times)
+ assert_equal [:x, :y, :z], enum_test([:x, :y, :z].each)
+ assert_equal [[:x, 1], [:y, 2]], enum_test({:x=>1, :y=>2}.each)
+ end
+
+ ## Enumerator as Iterator
+
+ def test_next
+ e = 3.times
+ 3.times{|i|
+ assert_equal i, e.next
+ }
+ assert_raise(StopIteration){e.next}
+ end
+
+ def test_loop
+ e = 3.times
+ i = 0
+ loop{
+ assert_equal(i, e.next)
+ i += 1
+ }
+ end
+
+ def test_nested_iteration
+ def (o = Object.new).each
+ yield :ok1
+ yield [:ok2, :x].each.next
+ end
+ e = o.to_enum
+ assert_equal :ok1, e.next
+ assert_equal :ok2, e.next
+ assert_raise(StopIteration){e.next}
+ end
+
+
+ def test_initialize
+ assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).to_a)
+ _, err = capture_io do
+ assert_equal([1, 2, 3], Enumerator.new(@obj, :foo, 1, 2, 3).to_a)
+ end
+ assert_match 'Enumerator.new without a block is deprecated', err
+ assert_equal([1, 2, 3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3))
+ assert_raise(ArgumentError) { Enumerator.new }
+
+ enum = @obj.to_enum
+ assert_raise(NoMethodError) { enum.each {} }
+ enum.freeze
+ assert_raise(RuntimeError) {
+ capture_io do
+ # warning: Enumerator.new without a block is deprecated; use Object#to_enum
+ enum.__send__(:initialize, @obj, :foo)
+ end
+ }
+ end
+
+ def test_initialize_copy
+ assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).dup.to_a)
+ e = @obj.to_enum(:foo, 1, 2, 3)
+ assert_nothing_raised { assert_equal(1, e.next) }
+ assert_raise(TypeError) { e.dup }
+
+ e = Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.dup
+ assert_nothing_raised { assert_equal(1, e.next) }
+ assert_raise(TypeError) { e.dup }
+ end
+
+ def test_gc
+ assert_nothing_raised do
+ 1.times do
+ foo = [1,2,3].to_enum
+ GC.start
+ end
+ GC.start
+ end
+ end
+
+ def test_slice
+ assert_equal([[1,2,3],[4,5,6],[7,8,9],[10]], (1..10).each_slice(3).to_a)
+ end
+
+ def test_cons
+ a = [[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7], [6,7,8], [7,8,9], [8,9,10]]
+ assert_equal(a, (1..10).each_cons(3).to_a)
+ end
+
+ def test_with_index
+ assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a)
+ assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a)
+ end
+
+ def test_with_index_large_offset
+ bug8010 = '[ruby-dev:47131] [Bug #8010]'
+ s = 1 << (8*1.size-2)
+ assert_equal([[1,s],[2,s+1],[3,s+2]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010)
+ s <<= 1
+ assert_equal([[1,s],[2,s+1],[3,s+2]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010)
+ end
+
+ def test_with_index_nonnum_offset
+ bug8010 = '[ruby-dev:47131] [Bug #8010]'
+ s = Object.new
+ def s.to_int; 1 end
+ assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a, bug8010)
+ end
+
+ def test_with_index_string_offset
+ bug8010 = '[ruby-dev:47131] [Bug #8010]'
+ assert_raise(TypeError, bug8010){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a }
+ end
+
+ def test_with_index_dangling_memo
+ bug9178 = '[ruby-core:58692] [Bug #9178]'
+ assert_separately([], <<-"end;")
+ bug = "#{bug9178}"
+ e = [1].to_enum(:chunk).with_index {|c,i| i == 5}
+ assert_kind_of(Enumerator, e)
+ assert_equal([false, [1]], e.to_a[0], bug)
+ end;
+ end
+
+ def test_with_object
+ obj = [0, 1]
+ ret = (1..10).each.with_object(obj) {|i, memo|
+ memo[0] += i
+ memo[1] *= i
+ }
+ assert_same(obj, ret)
+ assert_equal([55, 3628800], ret)
+
+ a = [2,5,2,1,5,3,4,2,1,0]
+ obj = {}
+ ret = a.delete_if.with_object(obj) {|i, seen|
+ if seen.key?(i)
+ true
+ else
+ seen[i] = true
+ false
+ end
+ }
+ assert_same(obj, ret)
+ assert_equal([2, 5, 1, 3, 4, 0], a)
+ end
+
+ def test_next_rewind
+ e = @obj.to_enum(:foo, 1, 2, 3)
+ assert_equal(1, e.next)
+ assert_equal(2, e.next)
+ e.rewind
+ assert_equal(1, e.next)
+ assert_equal(2, e.next)
+ assert_equal(3, e.next)
+ assert_raise(StopIteration) { e.next }
+ end
+
+ def test_peek
+ a = [1]
+ e = a.each
+ assert_equal(1, e.peek)
+ assert_equal(1, e.peek)
+ assert_equal(1, e.next)
+ assert_raise(StopIteration) { e.peek }
+ assert_raise(StopIteration) { e.peek }
+ end
+
+ def test_peek_modify
+ o = Object.new
+ def o.each
+ yield 1,2
+ end
+ e = o.to_enum
+ a = e.peek
+ a << 3
+ assert_equal([1,2], e.peek)
+ end
+
+ def test_peek_values_modify
+ o = Object.new
+ def o.each
+ yield 1,2
+ end
+ e = o.to_enum
+ a = e.peek_values
+ a << 3
+ assert_equal([1,2], e.peek)
+ end
+
+ def test_next_after_stopiteration
+ a = [1]
+ e = a.each
+ assert_equal(1, e.next)
+ assert_raise(StopIteration) { e.next }
+ assert_raise(StopIteration) { e.next }
+ e.rewind
+ assert_equal(1, e.next)
+ assert_raise(StopIteration) { e.next }
+ assert_raise(StopIteration) { e.next }
+ end
+
+ def test_stop_result
+ a = [1]
+ res = a.each {}
+ e = a.each
+ assert_equal(1, e.next)
+ exc = assert_raise(StopIteration) { e.next }
+ assert_equal(res, exc.result)
+ end
+
+ def test_next_values
+ o = Object.new
+ def o.each
+ yield
+ yield 1
+ yield 1, 2
+ end
+ e = o.to_enum
+ assert_equal(nil, e.next)
+ assert_equal(1, e.next)
+ assert_equal([1,2], e.next)
+ e = o.to_enum
+ assert_equal([], e.next_values)
+ assert_equal([1], e.next_values)
+ assert_equal([1,2], e.next_values)
+ end
+
+ def test_peek_values
+ o = Object.new
+ def o.each
+ yield
+ yield 1
+ yield 1, 2
+ end
+ e = o.to_enum
+ assert_equal(nil, e.peek)
+ assert_equal(nil, e.next)
+ assert_equal(1, e.peek)
+ assert_equal(1, e.next)
+ assert_equal([1,2], e.peek)
+ assert_equal([1,2], e.next)
+ e = o.to_enum
+ assert_equal([], e.peek_values)
+ assert_equal([], e.next_values)
+ assert_equal([1], e.peek_values)
+ assert_equal([1], e.next_values)
+ assert_equal([1,2], e.peek_values)
+ assert_equal([1,2], e.next_values)
+ e = o.to_enum
+ assert_equal([], e.peek_values)
+ assert_equal(nil, e.next)
+ assert_equal([1], e.peek_values)
+ assert_equal(1, e.next)
+ assert_equal([1,2], e.peek_values)
+ assert_equal([1,2], e.next)
+ e = o.to_enum
+ assert_equal(nil, e.peek)
+ assert_equal([], e.next_values)
+ assert_equal(1, e.peek)
+ assert_equal([1], e.next_values)
+ assert_equal([1,2], e.peek)
+ assert_equal([1,2], e.next_values)
+ end
+
+ def test_each_arg
+ o = Object.new
+ def o.each(ary)
+ ary << 1
+ yield
+ end
+ ary = []
+ e = o.to_enum.each(ary)
+ e.next
+ assert_equal([1], ary)
+ end
+
+ def test_feed
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.next
+ e.feed 1
+ e.next
+ e.feed 2
+ e.next
+ e.feed 3
+ assert_raise(StopIteration) { e.next }
+ assert_equal([1,2,3], ary)
+ end
+
+ def test_feed_mixed
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.next
+ e.feed 1
+ e.next
+ e.next
+ e.feed 3
+ assert_raise(StopIteration) { e.next }
+ assert_equal([1,nil,3], ary)
+ end
+
+ def test_feed_twice
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.feed 1
+ assert_raise(TypeError) { e.feed 2 }
+ end
+
+ def test_feed_before_first_next
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.feed 1
+ e.next
+ e.next
+ assert_equal([1], ary)
+ end
+
+ def test_rewind_clear_feed
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.next
+ e.feed 1
+ e.next
+ e.feed 2
+ e.rewind
+ e.next
+ e.next
+ assert_equal([1,nil], ary)
+ end
+
+ def test_feed_yielder
+ x = nil
+ e = Enumerator.new {|y| x = y.yield; 10 }
+ e.next
+ e.feed 100
+ exc = assert_raise(StopIteration) { e.next }
+ assert_equal(100, x)
+ assert_equal(10, exc.result)
+ end
+
+ def test_inspect
+ e = (0..10).each_cons(2)
+ assert_equal("#<Enumerator: 0..10:each_cons(2)>", e.inspect)
+
+ e = Enumerator.new {|y| y.yield; 10 }
+ assert_match(/\A#<Enumerator: .*:each>/, e.inspect)
+
+ a = []
+ e = a.each_with_object(a)
+ a << e
+ assert_equal("#<Enumerator: [#<Enumerator: ...>]:each_with_object([#<Enumerator: ...>])>",
+ e.inspect)
+ end
+
+ def test_inspect_verbose
+ bug6214 = '[ruby-dev:45449]'
+ assert_warning("", bug6214) { "".bytes.inspect }
+ assert_warning("", bug6214) { [].lazy.inspect }
+ end
+
+ def test_inspect_encoding
+ c = Class.new{define_method("\u{3042}"){}}
+ e = c.new.enum_for("\u{3042}")
+ s = assert_nothing_raised(Encoding::CompatibilityError) {break e.inspect}
+ assert_equal(Encoding::UTF_8, s.encoding)
+ assert_match(/\A#<Enumerator: .*:\u{3042}>\z/, s)
+ end
+
+ def test_generator
+ # note: Enumerator::Generator is a class just for internal
+ g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
+ g2 = g.dup
+ a = []
+ assert_equal(:foo, g.each {|x| a << x })
+ assert_equal([1, 2, 3], a)
+ a = []
+ assert_equal(:foo, g2.each {|x| a << x })
+ assert_equal([1, 2, 3], a)
+
+ g.freeze
+ assert_raise(RuntimeError) {
+ g.__send__ :initialize, proc { |y| y << 4 << 5 }
+ }
+ end
+
+ def test_generator_args
+ g = Enumerator::Generator.new {|y, x| y << 1 << 2 << 3; x }
+ a = []
+ assert_equal(:bar, g.each(:bar) {|x| a << x })
+ assert_equal([1, 2, 3], a)
+ end
+
+ def test_yielder
+ # note: Enumerator::Yielder is a class just for internal
+ a = []
+ y = Enumerator::Yielder.new {|x| a << x }
+ assert_equal(y, y << 1 << 2 << 3)
+ assert_equal([1, 2, 3], a)
+
+ a = []
+ y = Enumerator::Yielder.new {|x| a << x }
+ assert_equal([1], y.yield(1))
+ assert_equal([1, 2], y.yield(2))
+ assert_equal([1, 2, 3], y.yield(3))
+
+ assert_raise(LocalJumpError) { Enumerator::Yielder.new }
+ end
+
+ def test_size
+ assert_equal nil, Enumerator.new{}.size
+ assert_equal 42, Enumerator.new(->{42}){}.size
+ obj = Object.new
+ def obj.call; 42; end
+ assert_equal 42, Enumerator.new(obj){}.size
+ assert_equal 42, Enumerator.new(42){}.size
+ assert_equal 1 << 70, Enumerator.new(1 << 70){}.size
+ assert_equal Float::INFINITY, Enumerator.new(Float::INFINITY){}.size
+ assert_equal nil, Enumerator.new(nil){}.size
+ assert_raise(TypeError) { Enumerator.new("42"){} }
+
+ assert_equal nil, @obj.to_enum(:foo, 0, 1).size
+ assert_equal 2, @obj.to_enum(:foo, 0, 1){ 2 }.size
+ end
+
+ def test_size_for_enum_created_by_enumerators
+ enum = to_enum{ 42 }
+ assert_equal 42, enum.with_index.size
+ assert_equal 42, enum.with_object(:foo).size
+ end
+
+ def test_size_for_enum_created_from_array
+ arr = %w[hello world]
+ %i[each each_with_index reverse_each sort_by! sort_by map map!
+ keep_if reject! reject select! select delete_if].each do |method|
+ assert_equal arr.size, arr.send(method).size
+ end
+ end
+
+ def test_size_for_enum_created_from_enumerable
+ %i[find_all reject map flat_map partition group_by sort_by min_by max_by
+ minmax_by each_with_index reverse_each each_entry].each do |method|
+ assert_equal nil, @obj.send(method).size
+ assert_equal 42, @sized.send(method).size
+ end
+ assert_equal nil, @obj.each_with_object(nil).size
+ assert_equal 42, @sized.each_with_object(nil).size
+ end
+
+ def test_size_for_enum_created_from_hash
+ h = {a: 1, b: 2, c: 3}
+ methods = %i[delete_if reject reject! select select! keep_if each each_key each_pair]
+ enums = methods.map {|method| h.send(method)}
+ s = enums.group_by(&:size)
+ assert_equal([3], s.keys, ->{s.reject!{|k| k==3}.inspect})
+ h[:d] = 4
+ s = enums.group_by(&:size)
+ assert_equal([4], s.keys, ->{s.reject!{|k| k==4}.inspect})
+ end
+
+ def test_size_for_enum_created_from_env
+ %i[each_pair reject! delete_if select select! keep_if].each do |method|
+ assert_equal ENV.size, ENV.send(method).size
+ end
+ end
+
+ def test_size_for_enum_created_from_struct
+ s = Struct.new(:foo, :bar, :baz).new(1, 2)
+ %i[each each_pair select].each do |method|
+ assert_equal 3, s.send(method).size
+ end
+ end
+
+ def check_consistency_for_combinatorics(method)
+ [ [], [:a, :b, :c, :d, :e] ].product([-2, 0, 2, 5, 6]) do |array, arg|
+ assert_equal array.send(method, arg).to_a.size, array.send(method, arg).size,
+ "inconsistent size for #{array}.#{method}(#{arg})"
+ end
+ end
+
+ def test_size_for_array_combinatorics
+ check_consistency_for_combinatorics(:permutation)
+ assert_equal 24, [0, 1, 2, 4].permutation.size
+ assert_equal 2933197128679486453788761052665610240000000,
+ (1..42).to_a.permutation(30).size # 1.upto(42).inject(:*) / 1.upto(12).inject(:*)
+
+ check_consistency_for_combinatorics(:combination)
+ assert_equal 28258808871162574166368460400,
+ (1..100).to_a.combination(42).size
+ # 1.upto(100).inject(:*) / 1.upto(42).inject(:*) / 1.upto(58).inject(:*)
+
+ check_consistency_for_combinatorics(:repeated_permutation)
+ assert_equal 291733167875766667063796853374976,
+ (1..42).to_a.repeated_permutation(20).size # 42 ** 20
+
+ check_consistency_for_combinatorics(:repeated_combination)
+ assert_equal 28258808871162574166368460400,
+ (1..59).to_a.repeated_combination(42).size
+ # 1.upto(100).inject(:*) / 1.upto(42).inject(:*) / 1.upto(58).inject(:*)
+ end
+
+ def test_size_for_cycle
+ assert_equal Float::INFINITY, [:foo].cycle.size
+ assert_equal 10, [:foo, :bar].cycle(5).size
+ assert_equal 0, [:foo, :bar].cycle(-10).size
+ assert_equal 0, [].cycle.size
+ assert_equal 0, [].cycle(5).size
+
+ assert_equal nil, @obj.cycle.size
+ assert_equal nil, @obj.cycle(5).size
+ assert_equal Float::INFINITY, @sized.cycle.size
+ assert_equal 126, @sized.cycle(3).size
+ end
+
+ def test_size_for_loops
+ assert_equal Float::INFINITY, loop.size
+ assert_equal 42, 42.times.size
+ end
+
+ def test_size_for_each_slice
+ assert_equal nil, @obj.each_slice(3).size
+ assert_equal 6, @sized.each_slice(7).size
+ assert_equal 5, @sized.each_slice(10).size
+ assert_equal 1, @sized.each_slice(70).size
+ assert_raise(ArgumentError){ @obj.each_slice(0).size }
+ end
+
+ def test_size_for_each_cons
+ assert_equal nil, @obj.each_cons(3).size
+ assert_equal 33, @sized.each_cons(10).size
+ assert_equal 0, @sized.each_cons(70).size
+ assert_raise(ArgumentError){ @obj.each_cons(0).size }
+ end
+
+ def test_size_for_step
+ assert_equal 42, 5.step(46).size
+ assert_equal 4, 1.step(10, 3).size
+ assert_equal 3, 1.step(9, 3).size
+ assert_equal 0, 1.step(-11).size
+ assert_equal 0, 1.step(-11, 2).size
+ assert_equal 7, 1.step(-11, -2).size
+ assert_equal 7, 1.step(-11.1, -2).size
+ assert_equal 0, 42.step(Float::INFINITY, -2).size
+ assert_equal 1, 42.step(55, Float::INFINITY).size
+ assert_equal 1, 42.step(Float::INFINITY, Float::INFINITY).size
+ assert_equal 14, 0.1.step(4.2, 0.3).size
+ assert_equal Float::INFINITY, 42.step(Float::INFINITY, 2).size
+
+ assert_equal 10, (1..10).step.size
+ assert_equal 4, (1..10).step(3).size
+ assert_equal 3, (1...10).step(3).size
+ assert_equal Float::INFINITY, (42..Float::INFINITY).step(2).size
+ assert_raise(ArgumentError){ (1..10).step(-2).size }
+ end
+
+ def test_size_for_downup_to
+ assert_equal 0, 1.upto(-100).size
+ assert_equal 102, 1.downto(-100).size
+ assert_equal Float::INFINITY, 42.upto(Float::INFINITY).size
+ end
+
+ def test_size_for_string
+ assert_equal 5, 'hello'.each_byte.size
+ assert_equal 5, 'hello'.each_char.size
+ assert_equal 5, 'hello'.each_codepoint.size
+ end
+
+ def test_peek_for_enumerator_objects
+ e = 2.times
+ assert_equal(0, e.peek)
+ e.next
+ assert_equal(1, e.peek)
+ e.next
+ assert_raise(StopIteration) { e.peek }
+ end
+end
+
diff --git a/jni/ruby/test/ruby/test_env.rb b/jni/ruby/test/ruby/test_env.rb
new file mode 100644
index 0000000..88a7631
--- /dev/null
+++ b/jni/ruby/test/ruby/test_env.rb
@@ -0,0 +1,552 @@
+require 'test/unit'
+
+class TestEnv < Test::Unit::TestCase
+ IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM
+ PATH_ENV = "PATH"
+
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @backup = ENV.to_hash
+ ENV.delete('test')
+ ENV.delete('TEST')
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ ENV.clear
+ @backup.each {|k, v| ENV[k] = v }
+ end
+
+ def test_bracket
+ assert_nil(ENV['test'])
+ assert_nil(ENV['TEST'])
+ ENV['test'] = 'foo'
+ assert_equal('foo', ENV['test'])
+ if IGNORE_CASE
+ assert_equal('foo', ENV['TEST'])
+ else
+ assert_nil(ENV['TEST'])
+ end
+ ENV['TEST'] = 'bar'
+ assert_equal('bar', ENV['TEST'])
+ if IGNORE_CASE
+ assert_equal('bar', ENV['test'])
+ else
+ assert_equal('foo', ENV['test'])
+ end
+
+ assert_raise(TypeError) {
+ tmp = ENV[1]
+ }
+ assert_raise(TypeError) {
+ ENV[1] = 'foo'
+ }
+ assert_raise(TypeError) {
+ ENV['test'] = 0
+ }
+ end
+
+ def test_has_value
+ val = 'a'
+ val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase)
+ ENV['test'] = val[0...-1]
+
+ assert_equal(false, ENV.has_value?(val))
+ assert_equal(false, ENV.has_value?(val.upcase))
+ ENV['test'] = val
+ assert_equal(true, ENV.has_value?(val))
+ assert_equal(false, ENV.has_value?(val.upcase))
+ ENV['test'] = val.upcase
+ assert_equal(false, ENV.has_value?(val))
+ assert_equal(true, ENV.has_value?(val.upcase))
+ end
+
+ def test_key
+ val = 'a'
+ val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase)
+ ENV['test'] = val[0...-1]
+
+ assert_nil(ENV.key(val))
+ assert_nil(ENV.index(val))
+ assert_nil(ENV.key(val.upcase))
+ ENV['test'] = val
+ if IGNORE_CASE
+ assert_equal('TEST', ENV.key(val).upcase)
+ else
+ assert_equal('test', ENV.key(val))
+ end
+ assert_nil(ENV.key(val.upcase))
+ ENV['test'] = val.upcase
+ assert_nil(ENV.key(val))
+ if IGNORE_CASE
+ assert_equal('TEST', ENV.key(val.upcase).upcase)
+ else
+ assert_equal('test', ENV.key(val.upcase))
+ end
+ end
+
+ def test_delete
+ assert_raise(ArgumentError) { ENV.delete("foo\0bar") }
+ assert_nil(ENV.delete("TEST"))
+ assert_nothing_raised { ENV.delete(PATH_ENV) }
+ end
+
+ def test_getenv
+ assert_raise(ArgumentError) { ENV["foo\0bar"] }
+ ENV[PATH_ENV] = ""
+ assert_equal("", ENV[PATH_ENV])
+ assert_nil(ENV[""])
+ end
+
+ def test_fetch
+ ENV["test"] = "foo"
+ assert_equal("foo", ENV.fetch("test"))
+ ENV.delete("test")
+ feature8649 = '[ruby-core:56062] [Feature #8649]'
+ assert_raise_with_message(KeyError, 'key not found: "test"', feature8649) do
+ ENV.fetch("test")
+ end
+ assert_equal("foo", ENV.fetch("test", "foo"))
+ assert_equal("bar", ENV.fetch("test") { "bar" })
+ assert_equal("bar", ENV.fetch("test", "foo") { "bar" })
+ assert_raise(ArgumentError) { ENV.fetch("foo\0bar") }
+ assert_nothing_raised { ENV.fetch(PATH_ENV, "foo") }
+ ENV[PATH_ENV] = ""
+ assert_equal("", ENV.fetch(PATH_ENV))
+ end
+
+ def test_aset
+ assert_nothing_raised { ENV["test"] = nil }
+ assert_equal(nil, ENV["test"])
+ assert_raise(ArgumentError) { ENV["foo\0bar"] = "test" }
+ assert_raise(ArgumentError) { ENV["test"] = "foo\0bar" }
+
+ begin
+ # setenv(3) allowed the name includes '=',
+ # but POSIX.1-2001 says it should fail with EINVAL.
+ # see also http://togetter.com/li/22380
+ ENV["foo=bar"] = "test"
+ assert_equal("test", ENV["foo=bar"])
+ assert_equal("test", ENV["foo"])
+ rescue Errno::EINVAL
+ end
+
+ ENV[PATH_ENV] = "/tmp/".taint
+ assert_equal("/tmp/", ENV[PATH_ENV])
+ end
+
+ def test_keys
+ a = ENV.keys
+ assert_kind_of(Array, a)
+ a.each {|k| assert_kind_of(String, k) }
+ end
+
+ def test_each_key
+ ENV.each_key {|k| assert_kind_of(String, k) }
+ end
+
+ def test_values
+ a = ENV.values
+ assert_kind_of(Array, a)
+ a.each {|k| assert_kind_of(String, k) }
+ end
+
+ def test_each_value
+ ENV.each_value {|k| assert_kind_of(String, k) }
+ end
+
+ def test_each_pair
+ ENV.each_pair do |k, v|
+ assert_kind_of(String, k)
+ assert_kind_of(String, v)
+ end
+ end
+
+ def test_reject_bang
+ h1 = {}
+ ENV.each_pair {|k, v| h1[k] = v }
+ ENV["test"] = "foo"
+ ENV.reject! {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }
+ h2 = {}
+ ENV.each_pair {|k, v| h2[k] = v }
+ assert_equal(h1, h2)
+
+ h1 = {}
+ ENV.each_pair {|k, v| h1[k] = v }
+ ENV["test"] = "foo"
+ ENV.delete_if {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }
+ h2 = {}
+ ENV.each_pair {|k, v| h2[k] = v }
+ assert_equal(h1, h2)
+ end
+
+ def test_select_bang
+ h1 = {}
+ ENV.each_pair {|k, v| h1[k] = v }
+ ENV["test"] = "foo"
+ ENV.select! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }
+ h2 = {}
+ ENV.each_pair {|k, v| h2[k] = v }
+ assert_equal(h1, h2)
+
+ h1 = {}
+ ENV.each_pair {|k, v| h1[k] = v }
+ ENV["test"] = "foo"
+ ENV.keep_if {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }
+ h2 = {}
+ ENV.each_pair {|k, v| h2[k] = v }
+ assert_equal(h1, h2)
+ end
+
+ def test_values_at
+ ENV["test"] = "foo"
+ assert_equal(["foo", "foo"], ENV.values_at("test", "test"))
+ end
+
+ def test_select
+ ENV["test"] = "foo"
+ h = ENV.select {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }
+ assert_equal(1, h.size)
+ k = h.keys.first
+ v = h.values.first
+ if IGNORE_CASE
+ assert_equal("TEST", k.upcase)
+ assert_equal("FOO", v.upcase)
+ else
+ assert_equal("test", k)
+ assert_equal("foo", v)
+ end
+ end
+
+ def test_clear
+ ENV.clear
+ assert_equal(0, ENV.size)
+ end
+
+ def test_to_s
+ assert_equal("ENV", ENV.to_s)
+ end
+
+ def test_inspect
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ s = ENV.inspect
+ if IGNORE_CASE
+ s = s.upcase
+ assert(s == '{"FOO"=>"BAR", "BAZ"=>"QUX"}' || s == '{"BAZ"=>"QUX", "FOO"=>"BAR"}')
+ else
+ assert(s == '{"foo"=>"bar", "baz"=>"qux"}' || s == '{"baz"=>"qux", "foo"=>"bar"}')
+ end
+ end
+
+ def test_to_a
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ a = ENV.to_a
+ assert_equal(2, a.size)
+ if IGNORE_CASE
+ a = a.map {|x| x.map {|y| y.upcase } }
+ assert(a == [%w(FOO BAR), %w(BAZ QUX)] || a == [%w(BAZ QUX), %w(FOO BAR)])
+ else
+ assert(a == [%w(foo bar), %w(baz qux)] || a == [%w(baz qux), %w(foo bar)])
+ end
+ end
+
+ def test_rehash
+ assert_nil(ENV.rehash)
+ end
+
+ def test_size
+ s = ENV.size
+ ENV["test"] = "foo"
+ assert_equal(s + 1, ENV.size)
+ end
+
+ def test_empty_p
+ ENV.clear
+ assert_predicate(ENV, :empty?)
+ ENV["test"] = "foo"
+ assert_not_predicate(ENV, :empty?)
+ end
+
+ def test_has_key
+ assert_not_send([ENV, :has_key?, "test"])
+ ENV["test"] = "foo"
+ assert_send([ENV, :has_key?, "test"])
+ assert_raise(ArgumentError) { ENV.has_key?("foo\0bar") }
+ end
+
+ def test_assoc
+ assert_nil(ENV.assoc("test"))
+ ENV["test"] = "foo"
+ k, v = ENV.assoc("test")
+ if IGNORE_CASE
+ assert_equal("TEST", k.upcase)
+ assert_equal("FOO", v.upcase)
+ else
+ assert_equal("test", k)
+ assert_equal("foo", v)
+ end
+ assert_raise(ArgumentError) { ENV.assoc("foo\0bar") }
+ end
+
+ def test_has_value2
+ ENV.clear
+ assert_not_send([ENV, :has_value?, "foo"])
+ ENV["test"] = "foo"
+ assert_send([ENV, :has_value?, "foo"])
+ end
+
+ def test_rassoc
+ ENV.clear
+ assert_nil(ENV.rassoc("foo"))
+ ENV["foo"] = "bar"
+ ENV["test"] = "foo"
+ ENV["baz"] = "qux"
+ k, v = ENV.rassoc("foo")
+ if IGNORE_CASE
+ assert_equal("TEST", k.upcase)
+ assert_equal("FOO", v.upcase)
+ else
+ assert_equal("test", k)
+ assert_equal("foo", v)
+ end
+ end
+
+ def test_to_hash
+ h = {}
+ ENV.each {|k, v| h[k] = v }
+ assert_equal(h, ENV.to_hash)
+ end
+
+ def test_to_h
+ assert_equal(ENV.to_hash, ENV.to_h)
+ end
+
+ def test_reject
+ h1 = {}
+ ENV.each_pair {|k, v| h1[k] = v }
+ ENV["test"] = "foo"
+ h2 = ENV.reject {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }
+ assert_equal(h1, h2)
+ end
+
+ def check(as, bs)
+ if IGNORE_CASE
+ as = as.map {|xs| xs.map {|x| x.upcase } }
+ bs = bs.map {|xs| xs.map {|x| x.upcase } }
+ end
+ assert_equal(as.sort, bs.sort)
+ end
+
+ def test_shift
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ a = ENV.shift
+ b = ENV.shift
+ check([a, b], [%w(foo bar), %w(baz qux)])
+ assert_nil(ENV.shift)
+ end
+
+ def test_invert
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ check(ENV.invert.to_a, [%w(bar foo), %w(qux baz)])
+ end
+
+ def test_replace
+ ENV["foo"] = "xxx"
+ ENV.replace({"foo"=>"bar", "baz"=>"qux"})
+ check(ENV.to_hash.to_a, [%w(foo bar), %w(baz qux)])
+ end
+
+ def test_update
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ ENV.update({"baz"=>"quux","a"=>"b"})
+ check(ENV.to_hash.to_a, [%w(foo bar), %w(baz quux), %w(a b)])
+
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "qux"
+ ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| v1 ? k + "_" + v1 + "_" + v2 : v2 }
+ check(ENV.to_hash.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)])
+ end
+
+ def test_huge_value
+ huge_value = "bar" * 40960
+ ENV["foo"] = "bar"
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ assert_raise(Errno::EINVAL) { ENV["foo"] = huge_value }
+ assert_equal("bar", ENV["foo"])
+ else
+ assert_nothing_raised { ENV["foo"] = huge_value }
+ assert_equal(huge_value, ENV["foo"])
+ end
+ end
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ def test_win32_blocksize
+ keys = []
+ len = 32767 - ENV.to_a.flatten.inject(0) {|r,e| r + e.bytesize + 1}
+ val = "bar" * 1000
+ key = nil
+ while (len -= val.size + (key="foo#{len}").size + 2) > 0
+ keys << key
+ ENV[key] = val
+ end
+ 1.upto(12) {|i|
+ assert_raise(Errno::EINVAL) { ENV[key] = val }
+ }
+ ensure
+ keys.each {|k| ENV.delete(k)}
+ end
+ end
+
+ def test_frozen
+ ENV[PATH_ENV] = "/"
+ ENV.each do |k, v|
+ assert_predicate(k, :frozen?)
+ assert_predicate(v, :frozen?)
+ end
+ ENV.each_key do |k|
+ assert_predicate(k, :frozen?)
+ end
+ ENV.each_value do |v|
+ assert_predicate(v, :frozen?)
+ end
+ ENV.each_key do |k|
+ assert_predicate(ENV[k], :frozen?, "[#{k.dump}]")
+ assert_predicate(ENV.fetch(k), :frozen?, "fetch(#{k.dump})")
+ end
+ end
+
+ def test_taint_aref
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV["FOO".taint]
+ end.call
+ end
+ end
+
+ def test_taint_fetch
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.fetch("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_assoc
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.assoc("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_rassoc
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.rassoc("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_key
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.key("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_key_p
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.key?("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_value_p
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV.value?("FOO".taint)
+ end.call
+ end
+ end
+
+ def test_taint_aset_value
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV["FOO"] = "BAR".taint
+ end.call
+ end
+ end
+
+ def test_taint_aset_key
+ assert_raise(SecurityError) do
+ proc do
+ $SAFE = 2
+ ENV["FOO".taint] = "BAR"
+ end.call
+ end
+ end
+
+ if RUBY_PLATFORM =~ /bccwin|mswin|mingw/
+ def test_memory_leak_aset
+ bug9977 = '[ruby-dev:48323] [Bug #9977]'
+ assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9977, limit: 2.0)
+ ENV.clear
+ k = 'FOO'
+ v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500)
+ doit = proc {ENV[k] = v}
+ 500.times(&doit)
+ end;
+ end
+
+ def test_memory_leak_select
+ bug9978 = '[ruby-dev:48325] [Bug #9978]'
+ assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9978, limit: 2.0)
+ ENV.clear
+ k = 'FOO'
+ (ENV[k] = 'bar'*5000 rescue 'bar'*1500)
+ doit = proc {ENV.select {break}}
+ 500.times(&doit)
+ end;
+ end
+
+ def test_memory_crash_select
+ assert_normal_exit(<<-'end;')
+ 1000.times {ENV["FOO#{i}"] = 'bar'}
+ ENV.select {ENV.clear}
+ end;
+ end
+
+ def test_memory_leak_shift
+ bug9983 = '[ruby-dev:48332] [Bug #9983]'
+ assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9983, limit: 2.0)
+ ENV.clear
+ k = 'FOO'
+ v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500)
+ doit = proc {ENV[k] = v; ENV.shift}
+ 500.times(&doit)
+ end;
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_eval.rb b/jni/ruby/test/ruby/test_eval.rb
new file mode 100644
index 0000000..9d8db30
--- /dev/null
+++ b/jni/ruby/test/ruby/test_eval.rb
@@ -0,0 +1,510 @@
+require 'test/unit'
+
+class TestEval < Test::Unit::TestCase
+
+ @ivar = 12
+ @@cvar = 13
+ $gvar__eval = 14
+ Const = 15
+
+ def ruby(*args)
+ args = ['-e', '$>.write($<.read)'] if args.empty?
+ ruby = EnvUtil.rubybin
+ f = IO.popen([ruby] + args, 'r+')
+ yield(f)
+ ensure
+ f.close unless !f || f.closed?
+ end
+
+ def test_eval_basic
+ assert_equal nil, eval("nil")
+ assert_equal true, eval("true")
+ assert_equal false, eval("false")
+ assert_equal self, eval("self")
+ assert_equal 1, eval("1")
+ assert_equal :sym, eval(":sym")
+
+ assert_equal 11, eval("11")
+ @ivar = 12
+ assert_equal 12, eval("@ivar")
+ assert_equal 13, eval("@@cvar")
+ assert_equal 14, eval("$gvar__eval")
+ assert_equal 15, eval("Const")
+
+ assert_equal 16, eval("7 + 9")
+ assert_equal 17, eval("17.to_i")
+ assert_equal "18", eval(%q("18"))
+ assert_equal "19", eval(%q("1#{9}"))
+
+ 1.times {
+ assert_equal 12, eval("@ivar")
+ assert_equal 13, eval("@@cvar")
+ assert_equal 14, eval("$gvar__eval")
+ assert_equal 15, eval("Const")
+ }
+ end
+
+ def test_eval_binding_basic
+ assert_equal nil, eval("nil", binding())
+ assert_equal true, eval("true", binding())
+ assert_equal false, eval("false", binding())
+ assert_equal self, eval("self", binding())
+ assert_equal 1, eval("1", binding())
+ assert_equal :sym, eval(":sym", binding())
+
+ assert_equal 11, eval("11", binding())
+ @ivar = 12
+ assert_equal 12, eval("@ivar", binding())
+ assert_equal 13, eval("@@cvar", binding())
+ assert_equal 14, eval("$gvar__eval", binding())
+ assert_equal 15, eval("Const", binding())
+
+ assert_equal 16, eval("7 + 9", binding())
+ assert_equal 17, eval("17.to_i", binding())
+ assert_equal "18", eval(%q("18"), binding())
+ assert_equal "19", eval(%q("1#{9}"), binding())
+
+ 1.times {
+ assert_equal 12, eval("@ivar")
+ assert_equal 13, eval("@@cvar")
+ assert_equal 14, eval("$gvar__eval")
+ assert_equal 15, eval("Const")
+ }
+ end
+
+ def test_module_eval_string_basic
+ c = self.class
+ assert_equal nil, c.module_eval("nil")
+ assert_equal true, c.module_eval("true")
+ assert_equal false, c.module_eval("false")
+ assert_equal c, c.module_eval("self")
+ assert_equal :sym, c.module_eval(":sym")
+ assert_equal 11, c.module_eval("11")
+ @ivar = 12
+ assert_equal 12, c.module_eval("@ivar")
+ assert_equal 13, c.module_eval("@@cvar")
+ assert_equal 14, c.module_eval("$gvar__eval")
+ assert_equal 15, c.module_eval("Const")
+ assert_equal 16, c.module_eval("7 + 9")
+ assert_equal 17, c.module_eval("17.to_i")
+ assert_equal "18", c.module_eval(%q("18"))
+ assert_equal "19", c.module_eval(%q("1#{9}"))
+
+ @ivar = 12
+ 1.times {
+ assert_equal 12, c.module_eval("@ivar")
+ assert_equal 13, c.module_eval("@@cvar")
+ assert_equal 14, c.module_eval("$gvar__eval")
+ assert_equal 15, c.module_eval("Const")
+ }
+ end
+
+ def test_module_eval_block_basic
+ c = self.class
+ assert_equal nil, c.module_eval { nil }
+ assert_equal true, c.module_eval { true }
+ assert_equal false, c.module_eval { false }
+ assert_equal c, c.module_eval { self }
+ assert_equal :sym, c.module_eval { :sym }
+ assert_equal 11, c.module_eval { 11 }
+ @ivar = 12
+ assert_equal 12, c.module_eval { @ivar }
+ assert_equal 13, c.module_eval { @@cvar }
+ assert_equal 14, c.module_eval { $gvar__eval }
+ assert_equal 15, c.module_eval { Const }
+ assert_equal 16, c.module_eval { 7 + 9 }
+ assert_equal 17, c.module_eval { "17".to_i }
+ assert_equal "18", c.module_eval { "18" }
+ assert_equal "19", c.module_eval { "1#{9}" }
+
+ @ivar = 12
+ 1.times {
+ assert_equal 12, c.module_eval { @ivar }
+ assert_equal 13, c.module_eval { @@cvar }
+ assert_equal 14, c.module_eval { $gvar__eval }
+ assert_equal 15, c.module_eval { Const }
+ }
+ end
+
+ def forall_TYPE
+ objects = [Object.new, [], nil, true, false] # TODO: check
+ objects.each do |obj|
+ obj.instance_variable_set :@ivar, 12 unless obj.frozen?
+ yield obj
+ end
+ end
+
+ def test_instance_eval_string_basic
+ forall_TYPE do |o|
+ assert_equal nil, o.instance_eval("nil")
+ assert_equal true, o.instance_eval("true")
+ assert_equal false, o.instance_eval("false")
+ assert_equal o, o.instance_eval("self")
+ assert_equal 1, o.instance_eval("1")
+ assert_equal :sym, o.instance_eval(":sym")
+
+ assert_equal 11, o.instance_eval("11")
+ assert_equal 12, o.instance_eval("@ivar") unless o.frozen?
+ assert_equal 13, o.instance_eval("@@cvar")
+ assert_equal 14, o.instance_eval("$gvar__eval")
+ assert_equal 15, o.instance_eval("Const")
+ assert_equal 16, o.instance_eval("7 + 9")
+ assert_equal 17, o.instance_eval("17.to_i")
+ assert_equal "18", o.instance_eval(%q("18"))
+ assert_equal "19", o.instance_eval(%q("1#{9}"))
+
+ 1.times {
+ assert_equal 12, o.instance_eval("@ivar") unless o.frozen?
+ assert_equal 13, o.instance_eval("@@cvar")
+ assert_equal 14, o.instance_eval("$gvar__eval")
+ assert_equal 15, o.instance_eval("Const")
+ }
+ end
+ end
+
+ def test_instance_eval_block_basic
+ forall_TYPE do |o|
+ assert_equal nil, o.instance_eval { nil }
+ assert_equal true, o.instance_eval { true }
+ assert_equal false, o.instance_eval { false }
+ assert_equal o, o.instance_eval { self }
+ assert_equal 1, o.instance_eval { 1 }
+ assert_equal :sym, o.instance_eval { :sym }
+
+ assert_equal 11, o.instance_eval { 11 }
+ assert_equal 12, o.instance_eval { @ivar } unless o.frozen?
+ assert_equal 13, o.instance_eval { @@cvar }
+ assert_equal 14, o.instance_eval { $gvar__eval }
+ assert_equal 15, o.instance_eval { Const }
+ assert_equal 16, o.instance_eval { 7 + 9 }
+ assert_equal 17, o.instance_eval { 17.to_i }
+ assert_equal "18", o.instance_eval { "18" }
+ assert_equal "19", o.instance_eval { "1#{9}" }
+
+ 1.times {
+ assert_equal 12, o.instance_eval { @ivar } unless o.frozen?
+ assert_equal 13, o.instance_eval { @@cvar }
+ assert_equal 14, o.instance_eval { $gvar__eval }
+ assert_equal 15, o.instance_eval { Const }
+ }
+ end
+ end
+
+ def test_instance_eval_block_self
+ # instance_eval(&block)'s self must not be sticky (jruby/jruby#2060)
+ pr = proc { self }
+ assert_equal self, pr.call
+ o = Object.new
+ assert_equal o, o.instance_eval(&pr)
+ assert_equal self, pr.call
+ end
+
+ def test_instance_eval_cvar
+ [Object.new, [], 7, :sym, true, false, nil].each do |obj|
+ assert_equal(13, obj.instance_eval("@@cvar"))
+ assert_equal(13, obj.instance_eval{@@cvar})
+ # assert_raise(NameError){obj.instance_eval("@@cvar")}
+ # assert_raise(NameError){obj.instance_eval{@@cvar}}
+ end
+ end
+
+ def test_instance_eval_method
+ bug2788 = '[ruby-core:28324]'
+ [Object.new, [], nil, true, false].each do |o|
+ assert_nothing_raised(TypeError, "#{bug2788} (#{o.inspect})") do
+ o.instance_eval {
+ def defd_using_instance_eval() :ok end
+ }
+ end
+ assert_equal(:ok, o.defd_using_instance_eval)
+ class << o
+ remove_method :defd_using_instance_eval
+ end
+ end
+ end
+
+ def test_instance_eval_on_argf_singleton_class
+ bug8188 = '[ruby-core:53839] [Bug #8188]'
+ assert_warning('', bug8188) do
+ ARGF.singleton_class.instance_eval{}
+ end
+ end
+
+ class Foo
+ Bar = 2
+ end
+
+ def test_instance_eval_const
+ bar = nil
+ assert_nothing_raised(NameError) do
+ bar = Foo.new.instance_eval("Bar")
+ end
+ assert_equal(2, bar)
+ end
+
+ #
+ # From ruby/test/ruby/test_eval.rb
+ #
+
+ def make_test_binding
+ local1 = "local1"
+ lambda {
+ local2 = "local2"
+ return binding
+ }.call
+ end
+
+ def test_eval_orig
+ assert_nil(eval(""))
+ bad=false
+ eval 'while false; bad = true; print "foo\n" end'
+ assert(!bad)
+
+ assert(eval('TRUE'))
+ assert(eval('true'))
+ assert(!eval('NIL'))
+ assert(!eval('nil'))
+ assert(!eval('FALSE'))
+ assert(!eval('false'))
+
+ $foo = 'assert(true)'
+ begin
+ eval $foo
+ rescue
+ assert(false)
+ end
+
+ assert_equal('assert(true)', eval("$foo"))
+ assert_equal(true, eval("true"))
+ i = 5
+ assert(eval("i == 5"))
+ assert_equal(5, eval("i"))
+ assert(eval("defined? i"))
+
+ x = make_test_binding
+ assert_equal("local1", eval("local1", x)) # normal local var
+ assert_equal("local2", eval("local2", x)) # nested local var
+ bad = true
+ begin
+ p eval("local1")
+ rescue NameError # must raise error
+ bad = false
+ end
+ assert(!bad)
+
+ # !! use class_eval to avoid nested definition
+ x = self.class.class_eval %q(
+ module EvTest
+ EVTEST1 = 25
+ evtest2 = 125
+ binding
+ end
+ )
+ assert_equal(25, eval("EVTEST1", x)) # constant in module
+ assert_equal(125, eval("evtest2", x)) # local var in module
+ bad = true
+ begin
+ eval("EVTEST1")
+ rescue NameError # must raise error
+ bad = false
+ end
+ assert(!bad)
+
+ if false
+ # Ruby 2.0 doesn't see Proc as Binding
+ x = proc{}
+ eval "i4 = 1", x
+ assert_equal(1, eval("i4", x))
+ x = proc{proc{}}.call
+ eval "i4 = 22", x
+ assert_equal(22, eval("i4", x))
+ t = []
+ x = proc{proc{}}.call
+ eval "(0..9).each{|i5| t[i5] = proc{i5*2}}", x
+ assert_equal(8, t[4].call)
+ end
+
+ x = binding
+ eval "i = 1", x
+ assert_equal(1, eval("i", x))
+ x = proc{binding}.call
+ eval "i = 22", x
+ assert_equal(22, eval("i", x))
+ t = []
+ x = proc{binding}.call
+ eval "(0..9).each{|i5| t[i5] = proc{i5*2}}", x
+ assert_equal(8, t[4].call)
+ x = proc{binding}.call
+ eval "for i6 in 1..1; j6=i6; end", x
+ assert(eval("defined? i6", x))
+ assert(eval("defined? j6", x))
+
+ proc {
+ p = binding
+ eval "foo11 = 1", p
+ foo22 = 5
+ proc{foo11=22}.call
+ proc{foo22=55}.call
+ # assert_equal(eval("foo11"), eval("foo11", p))
+ # assert_equal(1, eval("foo11"))
+ assert_equal(eval("foo22"), eval("foo22", p))
+ assert_equal(55, eval("foo22"))
+ }.call
+
+ if false
+ # Ruby 2.0 doesn't see Proc as Binding
+ p1 = proc{i7 = 0; proc{i7}}.call
+ assert_equal(0, p1.call)
+ eval "i7=5", p1
+ assert_equal(5, p1.call)
+ assert(!defined?(i7))
+ end
+
+ if false
+ # Ruby 2.0 doesn't see Proc as Binding
+ p1 = proc{i7 = 0; proc{i7}}.call
+ i7 = nil
+ assert_equal(0, p1.call)
+ eval "i7=1", p1
+ assert_equal(1, p1.call)
+ eval "i7=5", p1
+ assert_equal(5, p1.call)
+ assert_nil(i7)
+ end
+ end
+
+ def test_nil_instance_eval_cvar
+ def nil.test_binding
+ binding
+ end
+ bb = eval("nil.instance_eval \"binding\"", nil.test_binding)
+ assert_raise(NameError, "[ruby-dev:24103]") { eval("@@a", bb) }
+ class << nil
+ remove_method :test_binding
+ end
+ end
+
+ def test_fixnum_instance_eval_cvar
+ assert_raise(NameError, "[ruby-dev:24213]") { 1.instance_eval "@@a" }
+ end
+
+ def test_cvar_scope_with_instance_eval
+ # TODO: check
+ Fixnum.class_eval "@@test_cvar_scope_with_instance_eval = 1" # depends on [ruby-dev:24229]
+ @@test_cvar_scope_with_instance_eval = 4
+ assert_equal(4, 1.instance_eval("@@test_cvar_scope_with_instance_eval"), "[ruby-dev:24223]")
+ Fixnum.__send__(:remove_class_variable, :@@test_cvar_scope_with_instance_eval)
+ end
+
+ def test_eval_and_define_method
+ assert_nothing_raised("[ruby-dev:24228]") {
+ def temporally_method_for_test_eval_and_define_method(&block)
+ lambda {
+ class << Object.new; self end.send(:define_method, :zzz, &block)
+ }
+ end
+ v = eval("temporally_method_for_test_eval_and_define_method {}")
+ {}[0] = {}
+ v.call
+ }
+ end
+
+ def test_define_method_block
+ cc = Class.new do
+ define_method(:foo) {|&block|
+ block.call if block
+ }
+ end
+
+ c = cc.new
+ x = "ng"
+ c.foo() {x = "ok"}
+ assert_equal("ok", x)
+ end
+
+ def test_define_method_toplevel
+ feature6609 = '[ruby-core:45715]'
+ main = eval("self", TOPLEVEL_BINDING)
+ assert_nothing_raised(NoMethodError, feature6609) do
+ main.instance_eval do
+ define_method("feature6609_block") {feature6609}
+ end
+ end
+ assert_equal(feature6609, feature6609_block)
+
+ assert_nothing_raised(NoMethodError, feature6609) do
+ main.instance_eval do
+ define_method("feature6609_method", Object.instance_method(:feature6609_block))
+ end
+ end
+ assert_equal(feature6609, feature6609_method)
+ end
+
+ def test_eval_using_integer_as_binding
+ assert_raise(TypeError) { eval("", 1) }
+ end
+
+ def test_eval_raise
+ assert_raise(RuntimeError) { eval("raise ''") }
+ end
+
+ def test_eval_with_toplevel_binding # [ruby-dev:37142]
+ ruby("-e", "x = 0; eval('p x', TOPLEVEL_BINDING)") do |f|
+ f.close_write
+ assert_equal("0", f.read.chomp)
+ end
+ end
+
+ def test_eval_ascii_incompatible
+ assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-16be"))}
+ assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-16le"))}
+ assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-32be"))}
+ assert_raise(ArgumentError) {eval("__ENCODING__".encode("utf-32le"))}
+ end
+
+ def test_instance_eval_method_proc
+ bug3860 = Class.new do
+ def initialize(a);
+ @a=a
+ end
+ def get(*args)
+ @a
+ end
+ end
+ foo = bug3860.new 1
+ foo_pr = foo.method(:get).to_proc
+ result = foo.instance_eval(&foo_pr)
+ assert_equal(1, result, 'Bug #3786, Bug #3860, [ruby-core:32501]')
+ end
+
+ def test_file_encoding
+ fname = "\u{3042}".encode("euc-jp")
+ assert_equal(fname, eval("__FILE__", nil, fname, 1))
+ end
+
+ def test_eval_location_fstring
+ o = Object.new
+ o.instance_eval "def foo() end", "generated code"
+ o.instance_eval "def bar() end", "generated code"
+
+ a, b = o.method(:foo).source_location[0],
+ o.method(:bar).source_location[0]
+
+ assert_same a, b
+ end
+
+ def test_gced_binding_block
+ assert_normal_exit %q{
+ def m
+ binding
+ end
+ GC.stress = true
+ b = nil
+ tap do
+ b = m {}
+ end
+ 0.times.to_a
+ b.eval('yield')
+ }, '[Bug #10368]'
+ end
+end
diff --git a/jni/ruby/test/ruby/test_exception.rb b/jni/ruby/test/ruby/test_exception.rb
new file mode 100644
index 0000000..c68d226
--- /dev/null
+++ b/jni/ruby/test/ruby/test_exception.rb
@@ -0,0 +1,701 @@
+require 'test/unit'
+require 'tempfile'
+
+class TestException < Test::Unit::TestCase
+ def test_exception_rescued
+ begin
+ raise "this must be handled"
+ assert(false)
+ rescue
+ assert(true)
+ end
+ end
+
+ def test_exception_retry
+ bad = true
+ begin
+ raise "this must be handled no.2"
+ rescue
+ if bad
+ bad = false
+ retry
+ assert(false)
+ end
+ end
+ assert(true)
+ end
+
+ def test_exception_in_rescue
+ string = "this must be handled no.3"
+ assert_raise_with_message(RuntimeError, string) do
+ begin
+ raise "exception in rescue clause"
+ rescue
+ raise string
+ end
+ assert(false)
+ end
+ end
+
+ def test_exception_in_ensure
+ string = "exception in ensure clause"
+ assert_raise_with_message(RuntimeError, string) do
+ begin
+ raise "this must be handled no.4"
+ ensure
+ assert_instance_of(RuntimeError, $!)
+ assert_equal("this must be handled no.4", $!.message)
+ raise "exception in ensure clause"
+ end
+ assert(false)
+ end
+ end
+
+ def test_exception_ensure
+ bad = true
+ begin
+ begin
+ raise "this must be handled no.5"
+ ensure
+ bad = false
+ end
+ rescue
+ end
+ assert(!bad)
+ end
+
+ def test_exception_ensure_2 # just duplication?
+ bad = true
+ begin
+ begin
+ raise "this must be handled no.6"
+ ensure
+ bad = false
+ end
+ rescue
+ end
+ assert(!bad)
+ end
+
+ def test_errinfo_in_debug
+ bug9568 = EnvUtil.labeled_class("[ruby-core:61091] [Bug #9568]", RuntimeError) do
+ def to_s
+ require '\0'
+ rescue LoadError
+ self.class.to_s
+ end
+ end
+
+ err = EnvUtil.verbose_warning do
+ assert_raise(bug9568) do
+ $DEBUG, debug = true, $DEBUG
+ begin
+ raise bug9568
+ ensure
+ $DEBUG = debug
+ end
+ end
+ end
+ assert_include(err, bug9568.to_s)
+ end
+
+ def test_errinfo_encoding_in_debug
+ exc = Module.new {break class_eval("class C\u{30a8 30e9 30fc} < RuntimeError; self; end".encode(Encoding::EUC_JP))}
+ exc.inspect
+
+ err = EnvUtil.verbose_warning do
+ assert_raise(exc) do
+ $DEBUG, debug = true, $DEBUG
+ begin
+ raise exc
+ ensure
+ $DEBUG = debug
+ end
+ end
+ end
+ assert_include(err, exc.to_s)
+ end
+
+ def test_break_ensure
+ bad = true
+ while true
+ begin
+ break
+ ensure
+ bad = false
+ end
+ end
+ assert(!bad)
+ end
+
+ def test_catch_no_throw
+ assert_equal(:foo, catch {:foo})
+ end
+
+ def test_catch_throw
+ result = catch(:foo) {
+ loop do
+ loop do
+ throw :foo, true
+ break
+ end
+ assert(false, "should not reach here")
+ end
+ false
+ }
+ assert(result)
+ end
+
+ def test_catch_throw_noarg
+ assert_nothing_raised(UncaughtThrowError) {
+ result = catch {|obj|
+ throw obj, :ok
+ assert(false, "should not reach here")
+ }
+ assert_equal(:ok, result)
+ }
+ end
+
+ def test_uncaught_throw
+ tag = nil
+ e = assert_raise_with_message(UncaughtThrowError, /uncaught throw/) {
+ catch("foo") {|obj|
+ tag = obj.dup
+ throw tag, :ok
+ assert(false, "should not reach here")
+ }
+ assert(false, "should not reach here")
+ }
+ assert_not_nil(tag)
+ assert_same(tag, e.tag)
+ assert_equal(:ok, e.value)
+ end
+
+ def test_catch_throw_in_require
+ bug7185 = '[ruby-dev:46234]'
+ Tempfile.create(["dep", ".rb"]) {|t|
+ t.puts("throw :extdep, 42")
+ t.close
+ assert_equal(42, assert_throw(:extdep, bug7185) {require t.path}, bug7185)
+ }
+ end
+
+ def test_else_no_exception
+ begin
+ assert(true)
+ rescue
+ assert(false)
+ else
+ assert(true)
+ end
+ end
+
+ def test_else_raised
+ begin
+ assert(true)
+ raise
+ assert(false)
+ rescue
+ assert(true)
+ else
+ assert(false)
+ end
+ end
+
+ def test_else_nested_no_exception
+ begin
+ assert(true)
+ begin
+ assert(true)
+ rescue
+ assert(false)
+ else
+ assert(true)
+ end
+ assert(true)
+ rescue
+ assert(false)
+ else
+ assert(true)
+ end
+ end
+
+ def test_else_nested_rescued
+ begin
+ assert(true)
+ begin
+ assert(true)
+ raise
+ assert(false)
+ rescue
+ assert(true)
+ else
+ assert(false)
+ end
+ assert(true)
+ rescue
+ assert(false)
+ else
+ assert(true)
+ end
+ end
+
+ def test_else_nested_unrescued
+ begin
+ assert(true)
+ begin
+ assert(true)
+ rescue
+ assert(false)
+ else
+ assert(true)
+ end
+ assert(true)
+ raise
+ assert(false)
+ rescue
+ assert(true)
+ else
+ assert(false)
+ end
+ end
+
+ def test_else_nested_rescued_reraise
+ begin
+ assert(true)
+ begin
+ assert(true)
+ raise
+ assert(false)
+ rescue
+ assert(true)
+ else
+ assert(false)
+ end
+ assert(true)
+ raise
+ assert(false)
+ rescue
+ assert(true)
+ else
+ assert(false)
+ end
+ end
+
+ def test_raise_with_wrong_number_of_arguments
+ assert_raise(TypeError) { raise nil }
+ assert_raise(TypeError) { raise 1, 1 }
+ assert_raise(ArgumentError) { raise 1, 1, 1, 1 }
+ end
+
+ def test_type_error_message_encoding
+ c = eval("Module.new do break class C\u{4032}; self; end; end")
+ o = c.new
+ assert_raise_with_message(TypeError, /C\u{4032}/) do
+ ""[o]
+ end
+ c.class_eval {def to_int; self; end}
+ assert_raise_with_message(TypeError, /C\u{4032}/) do
+ ""[o]
+ end
+ c.class_eval {def to_a; self; end}
+ assert_raise_with_message(TypeError, /C\u{4032}/) do
+ [*o]
+ end
+ end
+
+ def test_errat
+ assert_in_out_err([], "p $@", %w(nil), [])
+
+ assert_in_out_err([], "$@ = 1", [], /\$! not set \(ArgumentError\)$/)
+
+ assert_in_out_err([], <<-INPUT, [], /backtrace must be Array of String \(TypeError\)$/)
+ begin
+ raise
+ rescue
+ $@ = 1
+ end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, [], /^foo: unhandled exception$/)
+ begin
+ raise
+ rescue
+ $@ = 'foo'
+ raise
+ end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, [], /^foo: unhandled exception\s+from bar\s+from baz$/)
+ begin
+ raise
+ rescue
+ $@ = %w(foo bar baz)
+ raise
+ end
+ INPUT
+ end
+
+ def test_thread_signal_location
+ _, stderr, _ = EnvUtil.invoke_ruby("--disable-gems -d", <<-RUBY, false, true)
+Thread.start do
+ begin
+ Process.kill(:INT, $$)
+ ensure
+ raise "in ensure"
+ end
+end.join
+ RUBY
+ assert_not_match(/:0/, stderr, "[ruby-dev:39116]")
+ end
+
+ def test_errinfo
+ begin
+ raise "foo"
+ assert(false)
+ rescue => e
+ assert_equal(e, $!)
+ 1.times { assert_equal(e, $!) }
+ end
+
+ assert_equal(nil, $!)
+ end
+
+ def test_inspect
+ assert_equal("#<Exception: Exception>", Exception.new.inspect)
+
+ e = Class.new(Exception)
+ e.class_eval do
+ def to_s; ""; end
+ end
+ assert_equal(e.inspect, e.new.inspect)
+ end
+
+ def test_to_s
+ e = StandardError.new("foo")
+ assert_equal("foo", e.to_s)
+
+ def (s = Object.new).to_s
+ "bar"
+ end
+ e = StandardError.new(s)
+ assert_equal("bar", e.to_s)
+ end
+
+ def test_set_backtrace
+ e = Exception.new
+
+ e.set_backtrace("foo")
+ assert_equal(["foo"], e.backtrace)
+
+ e.set_backtrace(%w(foo bar baz))
+ assert_equal(%w(foo bar baz), e.backtrace)
+
+ assert_raise(TypeError) { e.set_backtrace(1) }
+ assert_raise(TypeError) { e.set_backtrace([1]) }
+ end
+
+ def test_exit_success_p
+ begin
+ exit
+ rescue SystemExit => e
+ end
+ assert_send([e, :success?], "success by default")
+
+ begin
+ exit(true)
+ rescue SystemExit => e
+ end
+ assert_send([e, :success?], "true means success")
+
+ begin
+ exit(false)
+ rescue SystemExit => e
+ end
+ assert_not_send([e, :success?], "false means failure")
+
+ begin
+ abort
+ rescue SystemExit => e
+ end
+ assert_not_send([e, :success?], "abort means failure")
+ end
+
+ def test_nomethoderror
+ bug3237 = '[ruby-core:29948]'
+ str = "\u2600"
+ id = :"\u2604"
+ msg = "undefined method `#{id}' for #{str.inspect}:String"
+ assert_raise_with_message(NoMethodError, msg, bug3237) do
+ str.__send__(id)
+ end
+ end
+
+ def test_errno
+ assert_equal(Encoding.find("locale"), Errno::EINVAL.new.message.encoding)
+ end
+
+ def test_too_many_args_in_eval
+ bug5720 = '[ruby-core:41520]'
+ arg_string = (0...140000).to_a.join(", ")
+ assert_raise(SystemStackError, bug5720) {eval "raise(#{arg_string})"}
+ end
+
+ def test_systemexit_new
+ e0 = SystemExit.new
+ assert_equal(0, e0.status)
+ assert_equal("SystemExit", e0.message)
+ ei = SystemExit.new(3)
+ assert_equal(3, ei.status)
+ assert_equal("SystemExit", ei.message)
+ es = SystemExit.new("msg")
+ assert_equal(0, es.status)
+ assert_equal("msg", es.message)
+ eis = SystemExit.new(7, "msg")
+ assert_equal(7, eis.status)
+ assert_equal("msg", eis.message)
+
+ bug5728 = '[ruby-dev:44951]'
+ et = SystemExit.new(true)
+ assert_equal(true, et.success?, bug5728)
+ assert_equal("SystemExit", et.message, bug5728)
+ ef = SystemExit.new(false)
+ assert_equal(false, ef.success?, bug5728)
+ assert_equal("SystemExit", ef.message, bug5728)
+ ets = SystemExit.new(true, "msg")
+ assert_equal(true, ets.success?, bug5728)
+ assert_equal("msg", ets.message, bug5728)
+ efs = SystemExit.new(false, "msg")
+ assert_equal(false, efs.success?, bug5728)
+ assert_equal("msg", efs.message, bug5728)
+ end
+
+ def test_exception_in_name_error_to_str
+ bug5575 = '[ruby-core:41612]'
+ Tempfile.create(["test_exception_in_name_error_to_str", ".rb"]) do |t|
+ t.puts <<-EOC
+ begin
+ BasicObject.new.inspect
+ rescue
+ $!.inspect
+ end
+ EOC
+ t.close
+ assert_nothing_raised(NameError, bug5575) do
+ load(t.path)
+ end
+ end
+ end
+
+ def test_equal
+ bug5865 = '[ruby-core:41979]'
+ assert_equal(RuntimeError.new("a"), RuntimeError.new("a"), bug5865)
+ assert_not_equal(RuntimeError.new("a"), StandardError.new("a"), bug5865)
+ end
+
+ def test_exception_in_exception_equal
+ bug5865 = '[ruby-core:41979]'
+ Tempfile.create(["test_exception_in_exception_equal", ".rb"]) do |t|
+ t.puts <<-EOC
+ o = Object.new
+ def o.exception(arg)
+ end
+ _ = RuntimeError.new("a") == o
+ EOC
+ t.close
+ assert_nothing_raised(ArgumentError, bug5865) do
+ load(t.path)
+ end
+ end
+ end
+
+ Bug4438 = '[ruby-core:35364]'
+
+ def test_rescue_single_argument
+ assert_raise(TypeError, Bug4438) do
+ begin
+ raise
+ rescue 1
+ end
+ end
+ end
+
+ def test_rescue_splat_argument
+ assert_raise(TypeError, Bug4438) do
+ begin
+ raise
+ rescue *Array(1)
+ end
+ end
+ end
+
+ def test_to_s_taintness_propagation
+ for exc in [Exception, NameError]
+ m = "abcdefg"
+ e = exc.new(m)
+ e.taint
+ s = e.to_s
+ assert_equal(false, m.tainted?,
+ "#{exc}#to_s should not propagate taintness")
+ assert_equal(false, s.tainted?,
+ "#{exc}#to_s should not propagate taintness")
+ end
+
+ o = Object.new
+ def o.to_str
+ "foo"
+ end
+ o.taint
+ e = NameError.new(o)
+ s = e.to_s
+ assert_equal(false, s.tainted?)
+ end
+
+ def m
+ m(&->{return 0})
+ 42
+ end
+
+ def test_stackoverflow
+ feature6216 = '[ruby-core:43794] [Feature #6216]'
+ e = assert_raise(SystemStackError, feature6216) {m}
+ level = e.backtrace.size
+ assert_operator(level, :>, 10, feature6216)
+
+ feature6216 = '[ruby-core:63377] [Feature #6216]'
+ e = assert_raise(SystemStackError, feature6216) {raise e}
+ assert_equal(level, e.backtrace.size, feature6216)
+ end
+
+ def test_machine_stackoverflow
+ bug9109 = '[ruby-dev:47804] [Bug #9109]'
+ assert_separately(%w[--disable-gem], <<-SRC)
+ assert_raise(SystemStackError, #{bug9109.dump}) {
+ h = {a: ->{h[:a].call}}
+ h[:a].call
+ }
+ SRC
+ rescue SystemStackError
+ end
+
+ def test_machine_stackoverflow_by_define_method
+ bug9454 = '[ruby-core:60113] [Bug #9454]'
+ assert_separately(%w[--disable-gem], <<-SRC)
+ assert_raise(SystemStackError, #{bug9454.dump}) {
+ define_method(:foo) {self.foo}
+ self.foo
+ }
+ SRC
+ rescue SystemStackError
+ end
+
+ def test_cause
+ msg = "[Feature #8257]"
+ cause = nil
+ e = assert_raise(StandardError) {
+ begin
+ raise msg
+ rescue => e
+ cause = e.cause
+ raise StandardError
+ end
+ }
+ assert_nil(cause, msg)
+ cause = e.cause
+ assert_instance_of(RuntimeError, cause, msg)
+ assert_equal(msg, cause.message, msg)
+ end
+
+ def test_cause_reraised
+ msg = "[Feature #8257]"
+ e = assert_raise(RuntimeError) {
+ begin
+ raise msg
+ rescue => e
+ raise e
+ end
+ }
+ assert_not_same(e, e.cause, "#{msg}: should not be recursive")
+ end
+
+ def test_raise_with_cause
+ msg = "[Feature #8257]"
+ cause = ArgumentError.new("foobar")
+ e = assert_raise(RuntimeError) {raise msg, cause: cause}
+ assert_same(cause, e.cause)
+ end
+
+ def test_cause_with_no_arguments
+ cause = ArgumentError.new("foobar")
+ assert_raise_with_message(ArgumentError, /with no arguments/) do
+ raise cause: cause
+ end
+ end
+
+ def test_unknown_option
+ bug = '[ruby-core:63203] [Feature #8257] should pass unknown options'
+
+ exc = Class.new(RuntimeError) do
+ attr_reader :arg
+ def initialize(msg = nil)
+ @arg = msg
+ super(msg)
+ end
+ end
+
+ e = assert_raise(exc, bug) {raise exc, "foo" => "bar", foo: "bar"}
+ assert_equal({"foo" => "bar", foo: "bar"}, e.arg, bug)
+
+ e = assert_raise(exc, bug) {raise exc, "foo" => "bar", foo: "bar", cause: "zzz"}
+ assert_equal({"foo" => "bar", foo: "bar"}, e.arg, bug)
+
+ e = assert_raise(exc, bug) {raise exc, {}}
+ assert_equal({}, e.arg, bug)
+ end
+
+ def test_anonymous_message
+ assert_in_out_err([], "raise Class.new(RuntimeError), 'foo'", [], /foo\n/)
+ end
+
+ def test_name_error_info
+ obj = BasicObject.new
+ e = assert_raise(NameError) {
+ obj.instance_eval("Object")
+ }
+ assert_equal(:Object, e.name)
+ e = assert_raise(NameError) {
+ obj.instance_eval {foo}
+ }
+ assert_equal(:foo, e.name)
+ e = assert_raise(NoMethodError) {
+ obj.foo(1, 2)
+ }
+ assert_equal(:foo, e.name)
+ assert_equal([1, 2], e.args)
+ end
+
+ def test_output_string_encoding
+ # "\x82\xa0" in cp932 is "\u3042" (Japanese hiragana 'a')
+ # change $stderr to force calling rb_io_write() instead of fwrite()
+ assert_in_out_err(["-Eutf-8:cp932"], '# coding: cp932
+$stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
+ assert_equal 1, outs.size
+ assert_equal 0, errs.size
+ err = outs.first.force_encoding('utf-8')
+ assert err.valid_encoding?, 'must be valid encoding'
+ assert_match /\u3042/, err
+ end
+ end
+
+ def test_multibyte_and_newline
+ bug10727 = '[ruby-core:67473] [Bug #10727]'
+ assert_in_out_err([], <<-'end;', [], /\u{306b 307b 3093 3054} \(E\)\n\u{6539 884c}/, bug10727, encoding: "UTF-8")
+ class E < StandardError
+ def initialize
+ super("\u{306b 307b 3093 3054}\n\u{6539 884c}")
+ end
+ end
+ raise E
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_fiber.rb b/jni/ruby/test/ruby/test_fiber.rb
new file mode 100644
index 0000000..4684a65
--- /dev/null
+++ b/jni/ruby/test/ruby/test_fiber.rb
@@ -0,0 +1,347 @@
+require 'test/unit'
+require 'fiber'
+EnvUtil.suppress_warning {require 'continuation'}
+require 'tmpdir'
+
+class TestFiber < Test::Unit::TestCase
+ def test_normal
+ assert_equal(:ok2,
+ Fiber.new{|e|
+ assert_equal(:ok1, e)
+ Fiber.yield :ok2
+ }.resume(:ok1)
+ )
+ assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.resume(:a, :b))
+ end
+
+ def test_argument
+ assert_equal(4, Fiber.new {|i=4| i}.resume)
+ end
+
+ def test_term
+ assert_equal(:ok, Fiber.new{:ok}.resume)
+ assert_equal([:a, :b, :c, :d, :e],
+ Fiber.new{
+ Fiber.new{
+ Fiber.new{
+ Fiber.new{
+ [:a]
+ }.resume + [:b]
+ }.resume + [:c]
+ }.resume + [:d]
+ }.resume + [:e])
+ end
+
+ def test_many_fibers
+ max = 10_000
+ assert_equal(max, max.times{
+ Fiber.new{}
+ })
+ GC.start # force collect created fibers
+ assert_equal(max,
+ max.times{|i|
+ Fiber.new{
+ }.resume
+ }
+ )
+ GC.start # force collect created fibers
+ end
+
+ def test_many_fibers_with_threads
+ assert_normal_exit <<-SRC, timeout: 60
+ max = 1000
+ @cnt = 0
+ (1..100).map{|ti|
+ Thread.new{
+ max.times{|i|
+ Fiber.new{
+ @cnt += 1
+ }.resume
+ }
+ }
+ }.each{|t|
+ t.join
+ }
+ SRC
+ end
+
+ def test_error
+ assert_raise(ArgumentError){
+ Fiber.new # Fiber without block
+ }
+ assert_raise(FiberError){
+ f = Fiber.new{}
+ Thread.new{f.resume}.join # Fiber yielding across thread
+ }
+ assert_raise(FiberError){
+ f = Fiber.new{}
+ f.resume
+ f.resume
+ }
+ assert_raise(RuntimeError){
+ Fiber.new{
+ @c = callcc{|c| @c = c}
+ }.resume
+ @c.call # cross fiber callcc
+ }
+ assert_raise(RuntimeError){
+ Fiber.new{
+ raise
+ }.resume
+ }
+ assert_raise(FiberError){
+ Fiber.yield
+ }
+ assert_raise(FiberError){
+ fib = Fiber.new{
+ fib.resume
+ }
+ fib.resume
+ }
+ assert_raise(FiberError){
+ fib = Fiber.new{
+ Fiber.new{
+ fib.resume
+ }.resume
+ }
+ fib.resume
+ }
+ end
+
+ def test_return
+ assert_raise(LocalJumpError){
+ Fiber.new do
+ return
+ end.resume
+ }
+ end
+
+ def test_throw
+ assert_raise(UncaughtThrowError){
+ Fiber.new do
+ throw :a
+ end.resume
+ }
+ end
+
+ def test_transfer
+ ary = []
+ f2 = nil
+ f1 = Fiber.new{
+ ary << f2.transfer(:foo)
+ :ok
+ }
+ f2 = Fiber.new{
+ ary << f1.transfer(:baz)
+ :ng
+ }
+ assert_equal(:ok, f1.transfer)
+ assert_equal([:baz], ary)
+ end
+
+ def test_tls
+ #
+ def tvar(var, val)
+ old = Thread.current[var]
+ begin
+ Thread.current[var] = val
+ yield
+ ensure
+ Thread.current[var] = old
+ end
+ end
+
+ fb = Fiber.new {
+ assert_equal(nil, Thread.current[:v]); tvar(:v, :x) {
+ assert_equal(:x, Thread.current[:v]); Fiber.yield
+ assert_equal(:x, Thread.current[:v]); }
+ assert_equal(nil, Thread.current[:v]); Fiber.yield
+ raise # unreachable
+ }
+
+ assert_equal(nil, Thread.current[:v]); tvar(:v,1) {
+ assert_equal(1, Thread.current[:v]); tvar(:v,3) {
+ assert_equal(3, Thread.current[:v]); fb.resume
+ assert_equal(3, Thread.current[:v]); }
+ assert_equal(1, Thread.current[:v]); }
+ assert_equal(nil, Thread.current[:v]); fb.resume
+ assert_equal(nil, Thread.current[:v]);
+ end
+
+ def test_alive
+ fib = Fiber.new{Fiber.yield}
+ assert_equal(true, fib.alive?)
+ fib.resume
+ assert_equal(true, fib.alive?)
+ fib.resume
+ assert_equal(false, fib.alive?)
+ end
+
+ def test_resume_self
+ f = Fiber.new {f.resume}
+ assert_raise(FiberError, '[ruby-core:23651]') {f.transfer}
+ end
+
+ def test_fiber_transfer_segv
+ assert_normal_exit %q{
+ require 'fiber'
+ f2 = nil
+ f1 = Fiber.new{ f2.resume }
+ f2 = Fiber.new{ f1.resume }
+ f1.transfer
+ }, '[ruby-dev:40833]'
+ assert_normal_exit %q{
+ require 'fiber'
+ Fiber.new{}.resume
+ 1.times{Fiber.current.transfer}
+ }
+ end
+
+ def test_resume_root_fiber
+ assert_raise(FiberError) do
+ Thread.new do
+ Fiber.current.resume
+ end.join
+ end
+ end
+
+ def test_gc_root_fiber
+ bug4612 = '[ruby-core:35891]'
+
+ assert_normal_exit %q{
+ require 'fiber'
+ GC.stress = true
+ Thread.start{ Fiber.current; nil }.join
+ GC.start
+ }, bug4612
+ end
+
+ def test_no_valid_cfp
+ bug5083 = '[ruby-dev:44208]'
+ assert_equal([], Fiber.new(&Module.method(:nesting)).resume, bug5083)
+ assert_instance_of(Class, Fiber.new(&Class.new.method(:undef_method)).resume(:to_s), bug5083)
+ end
+
+ def test_prohibit_resume_transfered_fiber
+ assert_raise(FiberError){
+ root_fiber = Fiber.current
+ f = Fiber.new{
+ root_fiber.transfer
+ }
+ f.transfer
+ f.resume
+ }
+ assert_raise(FiberError){
+ g=nil
+ f=Fiber.new{
+ g.resume
+ g.resume
+ }
+ g=Fiber.new{
+ f.resume
+ f.resume
+ }
+ f.transfer
+ }
+ end
+
+ def test_fork_from_fiber
+ begin
+ pid = Process.fork{}
+ rescue NotImplementedError
+ return
+ else
+ Process.wait(pid)
+ end
+ bug5700 = '[ruby-core:41456]'
+ assert_nothing_raised(bug5700) do
+ Fiber.new{ pid = fork {} }.resume
+ end
+ pid, status = Process.waitpid2(pid)
+ assert_equal(0, status.exitstatus, bug5700)
+ assert_equal(false, status.signaled?, bug5700)
+ end
+
+ def test_exit_in_fiber
+ bug5993 = '[ruby-dev:45218]'
+ assert_nothing_raised(bug5993) do
+ Thread.new{ Fiber.new{ Thread.exit }.resume; raise "unreachable" }.join
+ end
+ end
+
+ def test_fatal_in_fiber
+ assert_in_out_err(["-r-test-/fatal/rb_fatal", "-e", <<-EOS], "", [], /ok/)
+ Fiber.new{
+ rb_fatal "ok"
+ }.resume
+ puts :ng # unreachable.
+ EOS
+ end
+
+ def invoke_rec script, vm_stack_size, machine_stack_size, use_length = true
+ env = {}
+ env['RUBY_FIBER_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size
+ env['RUBY_FIBER_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size
+ out, _ = Dir.mktmpdir("test_fiber") {|tmpdir|
+ EnvUtil.invoke_ruby([env, '-e', script], '', true, true, chdir: tmpdir)
+ }
+ use_length ? out.length : out
+ end
+
+ def test_stack_size
+ h_default = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', nil, nil, false))
+ h_0 = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 0, 0, false))
+ h_large = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 1024 * 1024 * 10, 1024 * 1024 * 10, false))
+
+ assert_operator(h_default[:fiber_vm_stack_size], :>, h_0[:fiber_vm_stack_size])
+ assert_operator(h_default[:fiber_vm_stack_size], :<, h_large[:fiber_vm_stack_size])
+ assert_operator(h_default[:fiber_machine_stack_size], :>=, h_0[:fiber_machine_stack_size])
+ assert_operator(h_default[:fiber_machine_stack_size], :<=, h_large[:fiber_machine_stack_size])
+
+ # check VM machine stack size
+ script = '$stdout.sync=true; def rec; print "."; rec; end; Fiber.new{rec}.resume'
+ size_default = invoke_rec script, nil, nil
+ assert_operator(size_default, :>, 0)
+ size_0 = invoke_rec script, 0, nil
+ assert_operator(size_default, :>, size_0)
+ size_large = invoke_rec script, 1024 * 1024 * 10, nil
+ assert_operator(size_default, :<, size_large)
+
+ return if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ # check machine stack size
+ # Note that machine stack size may not change size (depend on OSs)
+ script = '$stdout.sync=true; def rec; print "."; 1.times{1.times{1.times{rec}}}; end; Fiber.new{rec}.resume'
+ vm_stack_size = 1024 * 1024
+ size_default = invoke_rec script, vm_stack_size, nil
+ size_0 = invoke_rec script, vm_stack_size, 0
+ assert_operator(size_default, :>=, size_0)
+ size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10
+ assert_operator(size_default, :<=, size_large)
+ end
+
+ def test_separate_lastmatch
+ bug7678 = '[ruby-core:51331]'
+ /a/ =~ "a"
+ m1 = $~
+ m2 = nil
+ Fiber.new do
+ /b/ =~ "b"
+ m2 = $~
+ end.resume
+ assert_equal("b", m2[0])
+ assert_equal(m1, $~, bug7678)
+ end
+
+ def test_separate_lastline
+ bug7678 = '[ruby-core:51331]'
+ $_ = s1 = "outer"
+ s2 = nil
+ Fiber.new do
+ s2 = "inner"
+ end.resume
+ assert_equal("inner", s2)
+ assert_equal(s1, $_, bug7678)
+ end
+end
+
diff --git a/jni/ruby/test/ruby/test_file.rb b/jni/ruby/test/ruby/test_file.rb
new file mode 100644
index 0000000..601d19e
--- /dev/null
+++ b/jni/ruby/test/ruby/test_file.rb
@@ -0,0 +1,423 @@
+require 'test/unit'
+require 'tempfile'
+require "thread"
+require_relative 'ut_eof'
+
+class TestFile < Test::Unit::TestCase
+
+ # I don't know Ruby's spec about "unlink-before-close" exactly.
+ # This test asserts current behaviour.
+ def test_unlink_before_close
+ Dir.mktmpdir('rubytest-file') {|tmpdir|
+ filename = tmpdir + '/' + File.basename(__FILE__) + ".#{$$}"
+ w = File.open(filename, "w")
+ w << "foo"
+ w.close
+ r = File.open(filename, "r")
+ begin
+ if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+ assert_raise(Errno::EACCES) {File.unlink(filename)}
+ else
+ assert_nothing_raised {File.unlink(filename)}
+ end
+ ensure
+ r.close
+ File.unlink(filename) if File.exist?(filename)
+ end
+ }
+ end
+
+ include TestEOF
+ def open_file(content)
+ Tempfile.create("test-eof") {|f|
+ f << content
+ f.rewind
+ yield f
+ }
+ end
+ alias open_file_rw open_file
+
+ include TestEOF::Seek
+
+ def test_empty_file_bom
+ bug6487 = '[ruby-core:45203]'
+ Tempfile.create(__method__.to_s) {|f|
+ assert_file.exist?(f.path)
+ assert_nothing_raised(bug6487) {File.read(f.path, mode: 'r:utf-8')}
+ assert_nothing_raised(bug6487) {File.read(f.path, mode: 'r:bom|utf-8')}
+ }
+ end
+
+ def assert_bom(bytes, name)
+ bug6487 = '[ruby-core:45203]'
+
+ Tempfile.create(name.to_s) {|f|
+ f.sync = true
+ expected = ""
+ result = nil
+ bytes[0...-1].each do |x|
+ f.write x
+ f.write ' '
+ f.pos -= 1
+ expected << x
+ assert_nothing_raised(bug6487) {result = File.read(f.path, mode: 'rb:bom|utf-8')}
+ assert_equal("#{expected} ".force_encoding("utf-8"), result)
+ end
+ f.write bytes[-1]
+ assert_nothing_raised(bug6487) {result = File.read(f.path, mode: 'rb:bom|utf-8')}
+ assert_equal '', result, "valid bom"
+ }
+ end
+
+ def test_bom_8
+ assert_bom(["\xEF", "\xBB", "\xBF"], __method__)
+ end
+
+ def test_bom_16be
+ assert_bom(["\xFE", "\xFF"], __method__)
+ end
+
+ def test_bom_16le
+ assert_bom(["\xFF", "\xFE"], __method__)
+ end
+
+ def test_bom_32be
+ assert_bom(["\0", "\0", "\xFE", "\xFF"], __method__)
+ end
+
+ def test_bom_32le
+ assert_bom(["\xFF\xFE\0", "\0"], __method__)
+ end
+
+ def test_truncate_wbuf
+ Tempfile.create("test-truncate") {|f|
+ f.print "abc"
+ f.truncate(0)
+ f.print "def"
+ f.flush
+ assert_equal("\0\0\0def", File.read(f.path), "[ruby-dev:24191]")
+ }
+ end
+
+ def test_truncate_rbuf
+ Tempfile.create("test-truncate") {|f|
+ f.puts "abc"
+ f.puts "def"
+ f.rewind
+ assert_equal("abc\n", f.gets)
+ f.truncate(3)
+ assert_equal(nil, f.gets, "[ruby-dev:24197]")
+ }
+ end
+
+ def test_truncate_beyond_eof
+ Tempfile.create("test-truncate") {|f|
+ f.print "abc"
+ f.truncate 10
+ assert_equal("\0" * 7, f.read(100), "[ruby-dev:24532]")
+ }
+ end
+
+ def test_truncate_size
+ Tempfile.create("test-truncate") do |f|
+ q1 = Queue.new
+ q2 = Queue.new
+
+ th = Thread.new do
+ data = ''
+ 64.times do |i|
+ data << i.to_s
+ f.rewind
+ f.print data
+ f.truncate(data.bytesize)
+ q1.push data.bytesize
+ q2.pop
+ end
+ q1.push nil
+ end
+
+ while size = q1.pop
+ assert_equal size, File.size(f.path)
+ assert_equal size, f.size
+ q2.push true
+ end
+ th.join
+ end
+ end
+
+ def test_read_all_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ assert_equal("a", f.read, "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_gets_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ assert_equal("a", f.gets("a"), "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_gets_para_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "\na"
+ f.rewind
+ assert_equal("a", f.gets(""), "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_each_char_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ result = []
+ f.each_char {|b| result << b }
+ assert_equal([?a], result, "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_each_byte_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ result = []
+ f.each_byte {|b| result << b.chr }
+ assert_equal([?a], result, "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_getc_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ assert_equal(?a, f.getc, "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_getbyte_extended_file
+ [nil, {:textmode=>true}, {:binmode=>true}].each do |mode|
+ Tempfile.create("test-extended-file", mode) {|f|
+ assert_nil(f.getc)
+ f.print "a"
+ f.rewind
+ assert_equal(?a, f.getbyte.chr, "mode = <#{mode}>")
+ }
+ end
+ end
+
+ def test_s_chown
+ assert_nothing_raised { File.chown(-1, -1) }
+ assert_nothing_raised { File.chown nil, nil }
+ end
+
+ def test_chown
+ assert_nothing_raised {
+ File.open(__FILE__) {|f| f.chown(-1, -1) }
+ }
+ assert_nothing_raised("[ruby-dev:27140]") {
+ File.open(__FILE__) {|f| f.chown nil, nil }
+ }
+ end
+
+ def test_uninitialized
+ assert_raise(TypeError) { File::Stat.allocate.readable? }
+ assert_nothing_raised { File::Stat.allocate.inspect }
+ end
+
+ def test_realpath
+ Dir.mktmpdir('rubytest-realpath') {|tmpdir|
+ realdir = File.realpath(tmpdir)
+ tst = realdir + (File::SEPARATOR*3 + ".")
+ assert_equal(realdir, File.realpath(tst))
+ assert_equal(realdir, File.realpath(".", tst))
+ if File::ALT_SEPARATOR
+ bug2961 = '[ruby-core:28653]'
+ assert_equal(realdir, File.realpath(realdir.tr(File::SEPARATOR, File::ALT_SEPARATOR)), bug2961)
+ end
+ }
+ end
+
+ def test_realdirpath
+ Dir.mktmpdir('rubytest-realdirpath') {|tmpdir|
+ realdir = File.realpath(tmpdir)
+ tst = realdir + (File::SEPARATOR*3 + ".")
+ assert_equal(realdir, File.realdirpath(tst))
+ assert_equal(realdir, File.realdirpath(".", tst))
+ assert_equal(File.join(realdir, "foo"), File.realdirpath("foo", tst))
+ }
+ begin
+ result = File.realdirpath("bar", "//:/foo")
+ rescue SystemCallError
+ else
+ if result.start_with?("//")
+ assert_equal("//:/foo/bar", result)
+ end
+ end
+ end
+
+ def test_utime_with_minus_time_segv
+ bug5596 = '[ruby-dev:44838]'
+ assert_in_out_err([], <<-EOS, [bug5596], [])
+ require "tempfile"
+ t = Time.at(-1)
+ begin
+ Tempfile.create('test_utime_with_minus_time_segv') {|f|
+ File.utime(t, t, f)
+ }
+ rescue
+ end
+ puts '#{bug5596}'
+ EOS
+ end
+
+ def test_utime
+ bug6385 = '[ruby-core:44776]'
+
+ mod_time_contents = Time.at 1306527039
+
+ file = Tempfile.new("utime")
+ file.close
+ path = file.path
+
+ File.utime(File.atime(path), mod_time_contents, path)
+ stats = File.stat(path)
+
+ file.open
+ file_mtime = file.mtime
+ file.close(true)
+
+ assert_equal(mod_time_contents, file_mtime, bug6385)
+ assert_equal(mod_time_contents, stats.mtime, bug6385)
+ end
+
+ def test_stat
+ tb = Process.clock_gettime(Process::CLOCK_REALTIME)
+ Tempfile.create("stat") {|file|
+ tb = (tb + Process.clock_gettime(Process::CLOCK_REALTIME)) / 2
+ file.close
+ path = file.path
+
+ t0 = Process.clock_gettime(Process::CLOCK_REALTIME)
+ File.write(path, "foo")
+ sleep 2
+ File.write(path, "bar")
+ sleep 2
+ File.chmod(0644, path)
+ sleep 2
+ File.read(path)
+
+ delta = 1
+ stat = File.stat(path)
+ assert_in_delta tb, stat.birthtime.to_f, delta
+ assert_in_delta t0+2, stat.mtime.to_f, delta
+ if stat.birthtime != stat.ctime
+ assert_in_delta t0+4, stat.ctime.to_f, delta
+ end
+ unless /mswin|mingw/ =~ RUBY_PLATFORM
+ # Windows delays updating atime
+ assert_in_delta t0+6, stat.atime.to_f, delta
+ end
+ }
+ rescue NotImplementedError
+ end
+
+ def test_chmod_m17n
+ bug5671 = '[ruby-dev:44898]'
+ Dir.mktmpdir('test-file-chmod-m17n-') do |tmpdir|
+ file = File.join(tmpdir, "\u3042")
+ File.open(file, 'w'){}
+ assert_equal(File.chmod(0666, file), 1, bug5671)
+ end
+ end
+
+ def test_file_open_permissions
+ Dir.mktmpdir(__method__.to_s) do |tmpdir|
+ tmp = File.join(tmpdir, 'x')
+ File.open(tmp, :mode => IO::RDWR | IO::CREAT | IO::BINARY,
+ :encoding => Encoding::ASCII_8BIT) do |x|
+
+ assert_predicate(x, :autoclose?)
+ assert_equal Encoding::ASCII_8BIT, x.external_encoding
+ x.write 'hello'
+
+ x.seek 0, IO::SEEK_SET
+
+ assert_equal 'hello', x.read
+
+ end
+ end
+ end
+
+ def test_file_open_double_mode
+ assert_raise_with_message(ArgumentError, 'mode specified twice') {
+ File.open("a", 'w', :mode => 'rw+')
+ }
+ end
+
+ def test_conflicting_encodings
+ Dir.mktmpdir(__method__.to_s) do |tmpdir|
+ tmp = File.join(tmpdir, 'x')
+ File.open(tmp, 'wb', :encoding => Encoding::EUC_JP) do |x|
+ assert_equal Encoding::EUC_JP, x.external_encoding
+ end
+ end
+ end
+
+ def test_untainted_path
+ bug5374 = '[ruby-core:39745]'
+ cwd = ("./"*40+".".taint).dup.untaint
+ in_safe = proc {|safe| $SAFE = safe; File.stat(cwd)}
+ assert_not_send([cwd, :tainted?])
+ (0..1).each do |level|
+ assert_nothing_raised(SecurityError, bug5374) {in_safe[level]}
+ end
+ def (s = Object.new).to_path; "".taint; end
+ m = "\u{691c 67fb}"
+ (c = Class.new(File)).singleton_class.class_eval {alias_method m, :stat}
+ assert_raise_with_message(SecurityError, /#{m}/) {
+ proc {$SAFE = 3; c.__send__(m, s)}.call
+ }
+ end
+
+ if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
+ def test_long_unc
+ feature3399 = '[ruby-core:30623]'
+ path = File.expand_path(__FILE__)
+ path.sub!(%r'\A//', 'UNC/')
+ assert_nothing_raised(Errno::ENOENT, feature3399) do
+ File.stat("//?/#{path}")
+ end
+ end
+ end
+
+ def test_open_nul
+ Dir.mktmpdir(__method__.to_s) do |tmpdir|
+ path = File.join(tmpdir, "foo")
+ assert_raise(ArgumentError) do
+ open(path + "\0bar", "w") {}
+ end
+ assert_file.not_exist?(path)
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_file_exhaustive.rb b/jni/ruby/test/ruby/test_file_exhaustive.rb
new file mode 100644
index 0000000..b347e53
--- /dev/null
+++ b/jni/ruby/test/ruby/test_file_exhaustive.rb
@@ -0,0 +1,1238 @@
+require "test/unit"
+require "fileutils"
+require "tmpdir"
+
+class TestFileExhaustive < Test::Unit::TestCase
+ DRIVE = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i]
+
+ def assert_incompatible_encoding
+ d = "\u{3042}\u{3044}".encode("utf-16le")
+ assert_raise(Encoding::CompatibilityError) {yield d}
+ m = Class.new {define_method(:to_path) {d}}
+ assert_raise(Encoding::CompatibilityError) {yield m.new}
+ end
+
+ def setup
+ @dir = Dir.mktmpdir("rubytest-file")
+ @rootdir = "#{DRIVE}/"
+ File.chown(-1, Process.gid, @dir)
+ @file = make_tmp_filename("file")
+ @zerofile = make_tmp_filename("zerofile")
+ @nofile = make_tmp_filename("nofile")
+ @symlinkfile = make_tmp_filename("symlinkfile")
+ @hardlinkfile = make_tmp_filename("hardlinkfile")
+ make_file("foo", @file)
+ make_file("", @zerofile)
+ @time = Time.now
+ begin
+ File.symlink(@file, @symlinkfile)
+ rescue NotImplementedError
+ @symlinkfile = nil
+ end
+ begin
+ File.link(@file, @hardlinkfile)
+ rescue NotImplementedError, Errno::EINVAL # EINVAL for Windows Vista
+ @hardlinkfile = nil
+ end
+ end
+
+ def teardown
+ GC.start
+ FileUtils.remove_entry_secure @dir
+ end
+
+ def make_file(content, file = @file)
+ open(file, "w") {|fh| fh << content }
+ end
+
+ def make_tmp_filename(prefix)
+ "#{@dir}/#{prefix}#{File.basename(__FILE__)}.#{$$}.test"
+ end
+
+ def test_path
+ file = @file
+
+ assert_equal(file, File.open(file) {|f| f.path})
+ assert_equal(file, File.path(file))
+ o = Object.new
+ class << o; self; end.class_eval do
+ define_method(:to_path) { file }
+ end
+ assert_equal(file, File.path(o))
+ end
+
+ def assert_integer(n)
+ assert_kind_of(Integer, n)
+ end
+
+ def assert_integer_or_nil(n)
+ msg = ->{"#{n.inspect} is neither Fixnum nor nil."}
+ if n
+ assert_kind_of(Integer, n, msg)
+ else
+ assert_nil(n, msg)
+ end
+ end
+
+ def test_stat
+ sleep(@time - Time.now + 1.1)
+ make_file("foo", @file + "2")
+ fs1, fs2 = File.stat(@file), File.stat(@file + "2")
+ assert_nothing_raised do
+ assert_equal(0, fs1 <=> fs1)
+ assert_equal(-1, fs1 <=> fs2)
+ assert_equal(1, fs2 <=> fs1)
+ assert_nil(fs1 <=> nil)
+ assert_integer(fs1.dev)
+ assert_integer_or_nil(fs1.rdev)
+ assert_integer_or_nil(fs1.dev_major)
+ assert_integer_or_nil(fs1.dev_minor)
+ assert_integer_or_nil(fs1.rdev_major)
+ assert_integer_or_nil(fs1.rdev_minor)
+ assert_integer(fs1.ino)
+ assert_integer(fs1.mode)
+ unless /emx|mswin|mingw/ =~ RUBY_PLATFORM
+ # on Windows, nlink is always 1. but this behavior will be changed
+ # in the future.
+ assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink)
+ end
+ assert_integer(fs1.uid)
+ assert_integer(fs1.gid)
+ assert_equal(3, fs1.size)
+ assert_integer_or_nil(fs1.blksize)
+ assert_integer_or_nil(fs1.blocks)
+ assert_kind_of(Time, fs1.atime)
+ assert_kind_of(Time, fs1.mtime)
+ assert_kind_of(Time, fs1.ctime)
+ assert_kind_of(String, fs1.inspect)
+ end
+ assert_raise(Errno::ENOENT) { File.stat(@nofile) }
+ assert_kind_of(File::Stat, File.open(@file) {|f| f.stat})
+ assert_raise(Errno::ENOENT) { File.lstat(@nofile) }
+ assert_kind_of(File::Stat, File.open(@file) {|f| f.lstat})
+ end
+
+ def test_stat_drive_root
+ assert_nothing_raised { File.stat(DRIVE + "/") }
+ assert_nothing_raised { File.stat(DRIVE + "/.") }
+ assert_nothing_raised { File.stat(DRIVE + "/..") }
+ assert_raise(Errno::ENOENT) { File.stat(DRIVE + "/...") }
+ # want to test the root of empty drive, but there is no method to test it...
+ end if DRIVE
+
+ def test_stat_dotted_prefix
+ Dir.mktmpdir do |dir|
+ prefix = File.join(dir, "...a")
+ Dir.mkdir(prefix)
+ assert_file.exist?(prefix)
+
+ assert_nothing_raised { File.stat(prefix) }
+
+ Dir.chdir(dir) do
+ assert_nothing_raised { File.stat(File.basename(prefix)) }
+ end
+ end
+ end if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM
+
+ def test_directory_p
+ assert_file.directory?(@dir)
+ assert_file.not_directory?(@dir+"/...")
+ assert_file.not_directory?(@file)
+ assert_file.not_directory?(@nofile)
+ end
+
+ def test_pipe_p ## xxx
+ assert_file.not_pipe?(@dir)
+ assert_file.not_pipe?(@file)
+ assert_file.not_pipe?(@nofile)
+ end
+
+ def test_symlink_p
+ assert_file.not_symlink?(@dir)
+ assert_file.not_symlink?(@file)
+ assert_file.symlink?(@symlinkfile) if @symlinkfile
+ assert_file.not_symlink?(@hardlinkfile) if @hardlinkfile
+ assert_file.not_symlink?(@nofile)
+ end
+
+ def test_socket_p ## xxx
+ assert_file.not_socket?(@dir)
+ assert_file.not_socket?(@file)
+ assert_file.not_socket?(@nofile)
+ end
+
+ def test_blockdev_p ## xxx
+ assert_file.not_blockdev?(@dir)
+ assert_file.not_blockdev?(@file)
+ assert_file.not_blockdev?(@nofile)
+ end
+
+ def test_chardev_p ## xxx
+ assert_file.not_chardev?(@dir)
+ assert_file.not_chardev?(@file)
+ assert_file.not_chardev?(@nofile)
+ end
+
+ def test_exist_p
+ assert_file.exist?(@dir)
+ assert_file.exist?(@file)
+ assert_file.not_exist?(@nofile)
+ end
+
+ def test_readable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0200, @file)
+ assert_file.not_readable?(@file)
+ File.chmod(0600, @file)
+ assert_file.readable?(@file)
+ assert_file.not_readable?(@nofile)
+ end
+
+ def test_readable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0200, @file)
+ assert_file.not_readable_real?(@file)
+ File.chmod(0600, @file)
+ assert_file.readable_real?(@file)
+ assert_file.not_readable_real?(@nofile)
+ end
+
+ def test_world_readable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0006, @file)
+ assert_file.world_readable?(@file)
+ File.chmod(0060, @file)
+ assert_file.not_world_readable?(@file)
+ File.chmod(0600, @file)
+ assert_file.not_world_readable?(@file)
+ assert_file.not_world_readable?(@nofile)
+ end
+
+ def test_writable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0400, @file)
+ assert_file.not_writable?(@file)
+ File.chmod(0600, @file)
+ assert_file.writable?(@file)
+ assert_file.not_writable?(@nofile)
+ end
+
+ def test_writable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0400, @file)
+ assert_file.not_writable_real?(@file)
+ File.chmod(0600, @file)
+ assert_file.writable_real?(@file)
+ assert_file.not_writable_real?(@nofile)
+ end
+
+ def test_world_writable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0006, @file)
+ assert_file.world_writable?(@file)
+ File.chmod(0060, @file)
+ assert_file.not_world_writable?(@file)
+ File.chmod(0600, @file)
+ assert_file.not_world_writable?(@file)
+ assert_file.not_world_writable?(@nofile)
+ end
+
+ def test_executable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0100, @file)
+ assert_file.executable?(@file)
+ File.chmod(0600, @file)
+ assert_file.not_executable?(@file)
+ assert_file.not_executable?(@nofile)
+ end
+
+ def test_executable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0100, @file)
+ assert_file.executable_real?(@file)
+ File.chmod(0600, @file)
+ assert_file.not_executable_real?(@file)
+ assert_file.not_executable_real?(@nofile)
+ end
+
+ def test_file_p
+ assert_file.not_file?(@dir)
+ assert_file.file?(@file)
+ assert_file.not_file?(@nofile)
+ end
+
+ def test_zero_p
+ assert_nothing_raised { File.zero?(@dir) }
+ assert_file.not_zero?(@file)
+ assert_file.zero?(@zerofile)
+ assert_file.not_zero?(@nofile)
+ end
+
+ def test_size_p
+ assert_nothing_raised { File.size?(@dir) }
+ assert_equal(3, File.size?(@file))
+ assert_file.not_size?(@zerofile)
+ assert_file.not_size?(@nofile)
+ end
+
+ def test_owned_p ## xxx
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ assert_file.owned?(@file)
+ assert_file.grpowned?(@file)
+ end
+
+ def test_suid_sgid_sticky ## xxx
+ assert_file.not_setuid?(@file)
+ assert_file.not_setgid?(@file)
+ assert_file.not_sticky?(@file)
+ end
+
+ def test_path_identical_p
+ assert_file.identical?(@file, @file)
+ assert_file.not_identical?(@file, @zerofile)
+ assert_file.not_identical?(@file, @nofile)
+ assert_file.not_identical?(@nofile, @file)
+ end
+
+ def test_io_identical_p
+ open(@file) {|f|
+ assert_file.identical?(f, f)
+ assert_file.identical?(@file, f)
+ assert_file.identical?(f, @file)
+ }
+ end
+
+ def test_closed_io_identical_p
+ io = open(@file) {|f| f}
+ assert_raise(IOError) {
+ File.identical?(@file, io)
+ }
+ File.unlink(@file)
+ assert_file.not_exist?(@file)
+ end
+
+ def test_s_size
+ assert_integer(File.size(@dir))
+ assert_equal(3, File.size(@file))
+ assert_equal(0, File.size(@zerofile))
+ assert_raise(Errno::ENOENT) { File.size(@nofile) }
+ end
+
+ def test_ftype
+ assert_equal("directory", File.ftype(@dir))
+ assert_equal("file", File.ftype(@file))
+ assert_equal("link", File.ftype(@symlinkfile)) if @symlinkfile
+ assert_equal("file", File.ftype(@hardlinkfile)) if @hardlinkfile
+ assert_raise(Errno::ENOENT) { File.ftype(@nofile) }
+ end
+
+ def test_atime
+ t1 = File.atime(@file)
+ t2 = File.open(@file) {|f| f.atime}
+ assert_kind_of(Time, t1)
+ assert_kind_of(Time, t2)
+ assert_equal(t1, t2)
+ assert_raise(Errno::ENOENT) { File.atime(@nofile) }
+ end
+
+ def test_mtime
+ t1 = File.mtime(@file)
+ t2 = File.open(@file) {|f| f.mtime}
+ assert_kind_of(Time, t1)
+ assert_kind_of(Time, t2)
+ assert_equal(t1, t2)
+ assert_raise(Errno::ENOENT) { File.mtime(@nofile) }
+ end
+
+ def test_ctime
+ t1 = File.ctime(@file)
+ t2 = File.open(@file) {|f| f.ctime}
+ assert_kind_of(Time, t1)
+ assert_kind_of(Time, t2)
+ assert_equal(t1, t2)
+ assert_raise(Errno::ENOENT) { File.ctime(@nofile) }
+ end
+
+ def test_chmod
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ assert_equal(1, File.chmod(0444, @file))
+ assert_equal(0444, File.stat(@file).mode % 01000)
+ assert_equal(0, File.open(@file) {|f| f.chmod(0222)})
+ assert_equal(0222, File.stat(@file).mode % 01000)
+ File.chmod(0600, @file)
+ assert_raise(Errno::ENOENT) { File.chmod(0600, @nofile) }
+ end
+
+ def test_lchmod
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ assert_equal(1, File.lchmod(0444, @file))
+ assert_equal(0444, File.stat(@file).mode % 01000)
+ File.lchmod(0600, @file)
+ assert_raise(Errno::ENOENT) { File.lchmod(0600, @nofile) }
+ rescue NotImplementedError
+ end
+
+ def test_chown ## xxx
+ end
+
+ def test_lchown ## xxx
+ end
+
+ def test_symlink
+ return unless @symlinkfile
+ assert_equal("link", File.ftype(@symlinkfile))
+ assert_raise(Errno::EEXIST) { File.symlink(@file, @file) }
+ end
+
+ def test_utime
+ t = Time.local(2000)
+ File.utime(t + 1, t + 2, @zerofile)
+ assert_equal(t + 1, File.atime(@zerofile))
+ assert_equal(t + 2, File.mtime(@zerofile))
+ end
+
+ def test_hardlink
+ return unless @hardlinkfile
+ assert_equal("file", File.ftype(@hardlinkfile))
+ assert_raise(Errno::EEXIST) { File.link(@file, @file) }
+ end
+
+ def test_readlink
+ return unless @symlinkfile
+ assert_equal(@file, File.readlink(@symlinkfile))
+ assert_raise(Errno::EINVAL) { File.readlink(@file) }
+ assert_raise(Errno::ENOENT) { File.readlink(@nofile) }
+ if fs = Encoding.find("filesystem")
+ assert_equal(fs, File.readlink(@symlinkfile).encoding)
+ end
+ rescue NotImplementedError
+ end
+
+ def test_readlink_long_path
+ return unless @symlinkfile
+ bug9157 = '[ruby-core:58592] [Bug #9157]'
+ assert_separately(["-", @symlinkfile, bug9157], <<-"end;")
+ symlinkfile, bug9157 = *ARGV
+ 100.step(1000, 100) do |n|
+ File.unlink(symlinkfile)
+ link = "foo"*n
+ begin
+ File.symlink(link, symlinkfile)
+ rescue Errno::ENAMETOOLONG
+ break
+ end
+ assert_equal(link, File.readlink(symlinkfile), bug9157)
+ end
+ end;
+ end
+
+ def test_unlink
+ assert_equal(1, File.unlink(@file))
+ make_file("foo", @file)
+ assert_raise(Errno::ENOENT) { File.unlink(@nofile) }
+ end
+
+ def test_rename
+ assert_equal(0, File.rename(@file, @nofile))
+ assert_file.not_exist?(@file)
+ assert_file.exist?(@nofile)
+ assert_equal(0, File.rename(@nofile, @file))
+ assert_raise(Errno::ENOENT) { File.rename(@nofile, @file) }
+ end
+
+ def test_umask
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ prev = File.umask(0777)
+ assert_equal(0777, File.umask)
+ open(@nofile, "w") { }
+ assert_equal(0, File.stat(@nofile).mode % 01000)
+ File.unlink(@nofile)
+ assert_equal(0777, File.umask(prev))
+ assert_raise(ArgumentError) { File.umask(0, 1, 2) }
+ end
+
+ def test_expand_path
+ assert_equal(@file, File.expand_path(File.basename(@file), File.dirname(@file)))
+ case RUBY_PLATFORM
+ when /cygwin|mingw|mswin|bccwin/
+ assert_equal(@file, File.expand_path(@file + " "))
+ assert_equal(@file, File.expand_path(@file + "."))
+ assert_equal(@file, File.expand_path(@file + "::$DATA"))
+ assert_match(/\Ac:\//i, File.expand_path('c:'), '[ruby-core:31591]')
+ assert_match(/\Ac:\//i, File.expand_path('c:foo', 'd:/bar'))
+ assert_match(/\Ae:\//i, File.expand_path('e:foo', 'd:/bar'))
+ assert_match(%r'\Ac:/bar/foo\z'i, File.expand_path('c:foo', 'c:/bar'))
+ when /darwin/
+ ["\u{feff}", *"\u{2000}"..."\u{2100}"].each do |c|
+ file = @file + c
+ begin
+ open(file) {}
+ rescue
+ assert_equal(file, File.expand_path(file), c.dump)
+ else
+ assert_equal(@file, File.expand_path(file), c.dump)
+ end
+ end
+ end
+ if DRIVE
+ assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar"))
+ assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar"))
+ assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo'))
+ else
+ assert_equal("/foo", File.expand_path('/foo'))
+ end
+ end
+
+ def test_expand_path_memsize
+ bug9934 = '[ruby-core:63114] [Bug #9934]'
+ require "objspace"
+ path = File.expand_path("/foo")
+ assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], bug9934)
+ path = File.expand_path("/a"*25)
+ assert_equal(path.bytesize+1 + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], ObjectSpace.memsize_of(path), bug9934)
+ end
+
+ def test_expand_path_encoding
+ drive = (DRIVE ? 'C:' : '')
+ if Encoding.find("filesystem") == Encoding::CP1251
+ a = "#{drive}/\u3042\u3044\u3046\u3048\u304a".encode("cp932")
+ else
+ a = "#{drive}/\u043f\u0440\u0438\u0432\u0435\u0442".encode("cp1251")
+ end
+ assert_equal(a, File.expand_path(a))
+ a = "#{drive}/\225\\\\"
+ if File::ALT_SEPARATOR == '\\'
+ [%W"cp437 #{drive}/\225", %W"cp932 #{drive}/\225\\"]
+ else
+ [["cp437", a], ["cp932", a]]
+ end.each do |cp, expected|
+ assert_equal(expected.force_encoding(cp), File.expand_path(a.dup.force_encoding(cp)), cp)
+ end
+
+ path = "\u3042\u3044\u3046\u3048\u304a".encode("EUC-JP")
+ assert_equal("#{Dir.pwd}/#{path}".encode("CP932"), File.expand_path(path).encode("CP932"))
+
+ path = "\u3042\u3044\u3046\u3048\u304a".encode("CP51932")
+ assert_equal("#{Dir.pwd}/#{path}", File.expand_path(path))
+
+ assert_incompatible_encoding {|d| File.expand_path(d)}
+ end
+
+ def test_expand_path_encoding_filesystem
+ home = ENV["HOME"]
+ ENV["HOME"] = "#{DRIVE}/UserHome"
+
+ path = "~".encode("US-ASCII")
+ dir = "C:/".encode("IBM437")
+ fs = Encoding.find("filesystem")
+
+ assert_equal fs, File.expand_path(path).encoding
+ assert_equal fs, File.expand_path(path, dir).encoding
+ ensure
+ ENV["HOME"] = home
+ end
+
+ UnknownUserHome = "~foo_bar_baz_unknown_user_wahaha".freeze
+
+ def test_expand_path_home
+ assert_kind_of(String, File.expand_path("~")) if ENV["HOME"]
+ assert_raise(ArgumentError) { File.expand_path(UnknownUserHome) }
+ assert_raise(ArgumentError) { File.expand_path(UnknownUserHome, "/") }
+ begin
+ bug3630 = '[ruby-core:31537]'
+ home = ENV["HOME"]
+ home_drive = ENV["HOMEDRIVE"]
+ home_path = ENV["HOMEPATH"]
+ user_profile = ENV["USERPROFILE"]
+ ENV["HOME"] = nil
+ ENV["HOMEDRIVE"] = nil
+ ENV["HOMEPATH"] = nil
+ ENV["USERPROFILE"] = nil
+ assert_raise(ArgumentError) { File.expand_path("~") }
+ ENV["HOME"] = "~"
+ assert_raise(ArgumentError, bug3630) { File.expand_path("~") }
+ ENV["HOME"] = "."
+ assert_raise(ArgumentError, bug3630) { File.expand_path("~") }
+ ensure
+ ENV["HOME"] = home
+ ENV["HOMEDRIVE"] = home_drive
+ ENV["HOMEPATH"] = home_path
+ ENV["USERPROFILE"] = user_profile
+ end
+ end
+
+ def test_expand_path_home_dir_string
+ home = ENV["HOME"]
+ new_home = "#{DRIVE}/UserHome"
+ ENV["HOME"] = new_home
+ bug8034 = "[ruby-core:53168]"
+
+ assert_equal File.join(new_home, "foo"), File.expand_path("foo", "~"), bug8034
+ assert_equal File.join(new_home, "bar", "foo"), File.expand_path("foo", "~/bar"), bug8034
+
+ assert_raise(ArgumentError) { File.expand_path(".", UnknownUserHome) }
+ assert_nothing_raised(ArgumentError) { File.expand_path("#{DRIVE}/", UnknownUserHome) }
+ ensure
+ ENV["HOME"] = home
+ end
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ def test_expand_path_home_memory_leak_in_path
+ assert_no_memory_leak_at_expand_path_home('', 'in path')
+ end
+
+ def test_expand_path_home_memory_leak_in_base
+ assert_no_memory_leak_at_expand_path_home('".",', 'in base')
+ end
+
+ def assert_no_memory_leak_at_expand_path_home(arg, message)
+ prep = 'ENV["HOME"] = "foo"*100'
+ assert_no_memory_leak([], prep, <<-TRY, "memory leaked at non-absolute home #{message}")
+ 10000.times do
+ begin
+ File.expand_path(#{arg}"~/a")
+ rescue ArgumentError => e
+ next
+ ensure
+ abort("ArgumentError (non-absolute home) expected") unless e
+ end
+ end
+ GC.start
+ TRY
+ end
+ end
+
+
+ def test_expand_path_remove_trailing_alternative_data
+ assert_equal File.join(@rootdir, "aaa"), File.expand_path("#{@rootdir}/aaa::$DATA")
+ assert_equal File.join(@rootdir, "aa:a"), File.expand_path("#{@rootdir}/aa:a:$DATA")
+ assert_equal File.join(@rootdir, "aaa:$DATA"), File.expand_path("#{@rootdir}/aaa:$DATA")
+ end if DRIVE
+
+ def test_expand_path_resolve_empty_string_current_directory
+ assert_equal(Dir.pwd, File.expand_path(""))
+ end
+
+ def test_expand_path_resolve_dot_current_directory
+ assert_equal(Dir.pwd, File.expand_path("."))
+ end
+
+ def test_expand_path_resolve_file_name_relative_current_directory
+ assert_equal(File.join(Dir.pwd, "foo"), File.expand_path("foo"))
+ end
+
+ def test_ignore_nil_dir_string
+ assert_equal(File.join(Dir.pwd, "foo"), File.expand_path("foo", nil))
+ end
+
+ def test_expand_path_resolve_file_name_and_dir_string_relative
+ assert_equal(File.join(Dir.pwd, "bar", "foo"),
+ File.expand_path("foo", "bar"))
+ end
+
+ def test_expand_path_cleanup_dots_file_name
+ bug = "[ruby-talk:18512]"
+
+ assert_equal(File.join(Dir.pwd, ".a"), File.expand_path(".a"), bug)
+ assert_equal(File.join(Dir.pwd, "..a"), File.expand_path("..a"), bug)
+
+ if DRIVE
+ # cleanup dots only on Windows
+ assert_equal(File.join(Dir.pwd, "a"), File.expand_path("a."), bug)
+ assert_equal(File.join(Dir.pwd, "a"), File.expand_path("a.."), bug)
+ else
+ assert_equal(File.join(Dir.pwd, "a."), File.expand_path("a."), bug)
+ assert_equal(File.join(Dir.pwd, "a.."), File.expand_path("a.."), bug)
+ end
+ end
+
+ def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_a_complete_path
+ assert_equal(@dir, File.expand_path("", "#{@dir}"))
+ assert_equal(File.join(@dir, "a"), File.expand_path("a", "#{@dir}"))
+ assert_equal(File.join(@dir, "a"), File.expand_path("../a", "#{@dir}/xxx"))
+ assert_equal(@rootdir, File.expand_path(".", "#{@rootdir}"))
+ end
+
+ def test_expand_path_ignores_supplied_dir_if_path_contains_a_drive_letter
+ assert_equal(@rootdir, File.expand_path(@rootdir, "D:/"))
+ end if DRIVE
+
+ def test_expand_path_removes_trailing_slashes_from_absolute_path
+ assert_equal(File.join(@rootdir, "foo"), File.expand_path("#{@rootdir}foo/"))
+ assert_equal(File.join(@rootdir, "foo.rb"), File.expand_path("#{@rootdir}foo.rb/"))
+ end
+
+ def test_expand_path_removes_trailing_spaces_from_absolute_path
+ assert_equal(File.join(@rootdir, "a"), File.expand_path("#{@rootdir}a "))
+ end if DRIVE
+
+ def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_dir_s_drive
+ assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar"))
+ end if DRIVE
+
+ def test_expand_path_converts_a_pathname_which_starts_with_a_slash_and_unc_pathname
+ assert_equal("//foo", File.expand_path('//foo', "//bar"))
+ assert_equal("//bar/foo", File.expand_path('/foo', "//bar"))
+ assert_equal("//foo", File.expand_path('//foo', "/bar"))
+ end if DRIVE
+
+ def test_expand_path_converts_a_dot_with_unc_dir
+ assert_equal("//", File.expand_path('.', "//"))
+ end
+
+ def test_expand_path_preserves_unc_path_root
+ assert_equal("//", File.expand_path("//"))
+ assert_equal("//", File.expand_path("//."))
+ assert_equal("//", File.expand_path("//.."))
+ end
+
+ def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_host_share
+ assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar"))
+ end if DRIVE
+
+ def test_expand_path_converts_a_pathname_which_starts_with_a_slash_using_a_current_drive
+ assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo'))
+ end
+
+ def test_expand_path_returns_tainted_strings_or_not
+ assert_equal(true, File.expand_path('foo').tainted?)
+ assert_equal(true, File.expand_path('foo'.taint).tainted?)
+ assert_equal(true, File.expand_path('/foo'.taint).tainted?)
+ assert_equal(true, File.expand_path('foo', 'bar').tainted?)
+ assert_equal(true, File.expand_path('foo', '/bar'.taint).tainted?)
+ assert_equal(true, File.expand_path('foo'.taint, '/bar').tainted?)
+ assert_equal(true, File.expand_path('~').tainted?) if ENV["HOME"]
+
+ if DRIVE
+ assert_equal(true, File.expand_path('/foo').tainted?)
+ assert_equal(false, File.expand_path('//foo').tainted?)
+ assert_equal(true, File.expand_path('C:/foo'.taint).tainted?)
+ assert_equal(false, File.expand_path('C:/foo').tainted?)
+ assert_equal(true, File.expand_path('foo', '/bar').tainted?)
+ assert_equal(true, File.expand_path('foo', 'C:/bar'.taint).tainted?)
+ assert_equal(true, File.expand_path('foo'.taint, 'C:/bar').tainted?)
+ assert_equal(false, File.expand_path('foo', 'C:/bar').tainted?)
+ assert_equal(false, File.expand_path('C:/foo/../bar').tainted?)
+ assert_equal(false, File.expand_path('foo', '//bar').tainted?)
+ else
+ assert_equal(false, File.expand_path('/foo').tainted?)
+ assert_equal(false, File.expand_path('foo', '/bar').tainted?)
+ end
+ end
+
+ def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_home_as_base
+ old_home = ENV["HOME"]
+ home = ENV["HOME"] = "#{DRIVE}/UserHome"
+ assert_equal(home, File.expand_path("~"))
+ assert_equal(home, File.expand_path("~", "C:/FooBar"))
+ assert_equal(File.join(home, "a"), File.expand_path("~/a", "C:/FooBar"))
+ ensure
+ ENV["HOME"] = old_home
+ end
+
+ def test_expand_path_converts_a_pathname_to_an_absolute_pathname_using_unc_home
+ old_home = ENV["HOME"]
+ unc_home = ENV["HOME"] = "//UserHome"
+ assert_equal(unc_home, File.expand_path("~"))
+ ensure
+ ENV["HOME"] = old_home
+ end if DRIVE
+
+ def test_expand_path_does_not_modify_a_home_string_argument
+ old_home = ENV["HOME"]
+ home = ENV["HOME"] = "#{DRIVE}/UserHome"
+ str = "~/a"
+ assert_equal("#{home}/a", File.expand_path(str))
+ assert_equal("~/a", str)
+ ensure
+ ENV["HOME"] = old_home
+ end
+
+ def test_expand_path_raises_argument_error_for_any_supplied_username
+ bug = '[ruby-core:39597]'
+ assert_raise(ArgumentError, bug) { File.expand_path("~anything") }
+ end if DRIVE
+
+ def test_expand_path_for_existent_username
+ user = ENV['USER']
+ skip "ENV['USER'] is not set" unless user
+ assert_equal(ENV['HOME'], File.expand_path("~#{user}"))
+ end unless DRIVE
+
+ def test_expand_path_error_for_nonexistent_username
+ user = "\u{3086 3046 3066 3044}:\u{307F 3084 304A 3046}"
+ assert_raise_with_message(ArgumentError, /#{user}/) {File.expand_path("~#{user}")}
+ end unless DRIVE
+
+ def test_expand_path_error_for_non_absolute_home
+ old_home = ENV["HOME"]
+ ENV["HOME"] = "./UserHome"
+ assert_raise_with_message(ArgumentError, /non-absolute home/) {File.expand_path("~")}
+ ensure
+ ENV["HOME"] = old_home
+ end
+
+ def test_expand_path_raises_a_type_error_if_not_passed_a_string_type
+ assert_raise(TypeError) { File.expand_path(1) }
+ assert_raise(TypeError) { File.expand_path(nil) }
+ assert_raise(TypeError) { File.expand_path(true) }
+ end
+
+ def test_expand_path_expands_dot_dir
+ assert_equal("#{DRIVE}/dir", File.expand_path("#{DRIVE}/./dir"))
+ end
+
+ def test_expand_path_does_not_expand_wildcards
+ assert_equal("#{DRIVE}/*", File.expand_path("./*", "#{DRIVE}/"))
+ assert_equal("#{Dir.pwd}/*", File.expand_path("./*", Dir.pwd))
+ assert_equal("#{DRIVE}/?", File.expand_path("./?", "#{DRIVE}/"))
+ assert_equal("#{Dir.pwd}/?", File.expand_path("./?", Dir.pwd))
+ end if DRIVE
+
+ def test_expand_path_does_not_modify_the_string_argument
+ str = "./a/b/../c"
+ assert_equal("#{Dir.pwd}/a/c", File.expand_path(str, Dir.pwd))
+ assert_equal("./a/b/../c", str)
+ end
+
+ def test_expand_path_returns_a_string_when_passed_a_string_subclass
+ sub = Class.new(String)
+ str = sub.new "./a/b/../c"
+ path = File.expand_path(str, Dir.pwd)
+ assert_equal("#{Dir.pwd}/a/c", path)
+ assert_instance_of(String, path)
+ end
+
+ def test_expand_path_accepts_objects_that_have_a_to_path_method
+ klass = Class.new { def to_path; "a/b/c"; end }
+ obj = klass.new
+ assert_equal("#{Dir.pwd}/a/b/c", File.expand_path(obj))
+ end
+
+ def test_expand_path_with_drive_letter
+ bug10858 = '[ruby-core:68130] [Bug #10858]'
+ assert_match(%r'/bar/foo\z'i, File.expand_path('z:foo', 'bar'), bug10858)
+ assert_equal('z:/bar/foo', File.expand_path('z:foo', '/bar'), bug10858)
+ end if DRIVE
+
+ def test_basename
+ assert_equal(File.basename(@file).sub(/\.test$/, ""), File.basename(@file, ".test"))
+ assert_equal("", s = File.basename(""))
+ assert(!s.frozen?, '[ruby-core:24199]')
+ assert_equal("foo", s = File.basename("foo"))
+ assert(!s.frozen?, '[ruby-core:24199]')
+ assert_equal("foo", File.basename("foo", ".ext"))
+ assert_equal("foo", File.basename("foo.ext", ".ext"))
+ assert_equal("foo", File.basename("foo.ext", ".*"))
+ if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+ basename = File.basename(@file)
+ assert_equal(basename, File.basename(@file + " "))
+ assert_equal(basename, File.basename(@file + "."))
+ assert_equal(basename, File.basename(@file + "::$DATA"))
+ basename.chomp!(".test")
+ assert_equal(basename, File.basename(@file + " ", ".test"))
+ assert_equal(basename, File.basename(@file + ".", ".test"))
+ assert_equal(basename, File.basename(@file + "::$DATA", ".test"))
+ assert_equal(basename, File.basename(@file + " ", ".*"))
+ assert_equal(basename, File.basename(@file + ".", ".*"))
+ assert_equal(basename, File.basename(@file + "::$DATA", ".*"))
+ end
+ if File::ALT_SEPARATOR == '\\'
+ a = "foo/\225\\\\"
+ [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected|
+ assert_equal(expected.force_encoding(cp), File.basename(a.dup.force_encoding(cp)), cp)
+ end
+ end
+
+ assert_incompatible_encoding {|d| File.basename(d)}
+ assert_incompatible_encoding {|d| File.basename(d, ".*")}
+ assert_raise(Encoding::CompatibilityError) {File.basename("foo.ext", ".*".encode("utf-16le"))}
+
+ s = "foo\x93_a".force_encoding("cp932")
+ assert_equal(s, File.basename(s, "_a"))
+
+ s = "\u4032.\u3024"
+ assert_equal(s, File.basename(s, ".\x95\\".force_encoding("cp932")))
+ end
+
+ def test_dirname
+ assert(@file.start_with?(File.dirname(@file)))
+ assert_equal(".", File.dirname(""))
+ assert_incompatible_encoding {|d| File.dirname(d)}
+ if File::ALT_SEPARATOR == '\\'
+ a = "\225\\\\foo"
+ [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected|
+ assert_equal(expected.force_encoding(cp), File.dirname(a.dup.force_encoding(cp)), cp)
+ end
+ end
+ end
+
+ def test_extname
+ assert_equal(".test", File.extname(@file))
+ prefixes = ["", "/", ".", "/.", "bar/.", "/bar/."]
+ infixes = ["", " ", "."]
+ infixes2 = infixes + [".ext "]
+ appendixes = [""]
+ if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+ appendixes << " " << "." << "::$DATA" << "::$DATA.bar"
+ end
+ prefixes.each do |prefix|
+ appendixes.each do |appendix|
+ infixes.each do |infix|
+ path = "#{prefix}foo#{infix}#{appendix}"
+ assert_equal("", File.extname(path), "File.extname(#{path.inspect})")
+ end
+ infixes2.each do |infix|
+ path = "#{prefix}foo#{infix}.ext#{appendix}"
+ assert_equal(".ext", File.extname(path), "File.extname(#{path.inspect})")
+ end
+ end
+ end
+ bug3175 = '[ruby-core:29627]'
+ assert_equal(".rb", File.extname("/tmp//bla.rb"), bug3175)
+
+ assert_incompatible_encoding {|d| File.extname(d)}
+ end
+
+ def test_split
+ d, b = File.split(@file)
+ assert_equal(File.dirname(@file), d)
+ assert_equal(File.basename(@file), b)
+ end
+
+ def test_join
+ s = "foo" + File::SEPARATOR + "bar" + File::SEPARATOR + "baz"
+ assert_equal(s, File.join("foo", "bar", "baz"))
+ assert_equal(s, File.join(["foo", "bar", "baz"]))
+
+ o = Object.new
+ def o.to_path; "foo"; end
+ assert_equal(s, File.join(o, "bar", "baz"))
+ assert_equal(s, File.join("foo" + File::SEPARATOR, "bar", File::SEPARATOR + "baz"))
+ end
+
+ def test_join_alt_separator
+ if File::ALT_SEPARATOR == '\\'
+ a = "\225\\"
+ b = "foo"
+ [%W"cp437 \225\\foo", %W"cp932 \225\\/foo"].each do |cp, expected|
+ assert_equal(expected.force_encoding(cp), File.join(a.dup.force_encoding(cp), b.dup.force_encoding(cp)), cp)
+ end
+ end
+ end
+
+ def test_join_ascii_incompatible
+ bug7168 = '[ruby-core:48012]'
+ names = %w"a b".map {|s| s.encode(Encoding::UTF_16LE)}
+ assert_raise(Encoding::CompatibilityError, bug7168) {File.join(*names)}
+ assert_raise(Encoding::CompatibilityError, bug7168) {File.join(names)}
+
+ a = Object.new
+ b = names[1]
+ names = [a, "b"]
+ a.singleton_class.class_eval do
+ define_method(:to_path) do
+ names[1] = b
+ "a"
+ end
+ end
+ assert_raise(Encoding::CompatibilityError, bug7168) {File.join(names)}
+ end
+
+ def test_truncate
+ assert_equal(0, File.truncate(@file, 1))
+ assert_file.exist?(@file)
+ assert_equal(1, File.size(@file))
+ assert_equal(0, File.truncate(@file, 0))
+ assert_file.exist?(@file)
+ assert_file.zero?(@file)
+ make_file("foo", @file)
+ assert_raise(Errno::ENOENT) { File.truncate(@nofile, 0) }
+
+ f = File.new(@file, "w")
+ assert_equal(0, f.truncate(2))
+ assert_file.exist?(@file)
+ assert_equal(2, File.size(@file))
+ assert_equal(0, f.truncate(0))
+ assert_file.exist?(@file)
+ assert_file.zero?(@file)
+ f.close
+ make_file("foo", @file)
+
+ assert_raise(IOError) { File.open(@file) {|ff| ff.truncate(0)} }
+ rescue NotImplementedError
+ end
+
+ def test_flock ## xxx
+ f = File.new(@file, "r+")
+ f.flock(File::LOCK_EX)
+ f.flock(File::LOCK_SH)
+ f.flock(File::LOCK_UN)
+ f.close
+ rescue NotImplementedError
+ end
+
+ def test_test
+ sleep(@time - Time.now + 1.1)
+ make_file("foo", @file + "2")
+ [@dir, @file, @zerofile, @symlinkfile, @hardlinkfile].compact.each do |f|
+ assert_equal(File.atime(f), test(?A, f))
+ assert_equal(File.ctime(f), test(?C, f))
+ assert_equal(File.mtime(f), test(?M, f))
+ assert_equal(File.blockdev?(f), test(?b, f))
+ assert_equal(File.chardev?(f), test(?c, f))
+ assert_equal(File.directory?(f), test(?d, f))
+ assert_equal(File.exist?(f), test(?e, f))
+ assert_equal(File.file?(f), test(?f, f))
+ assert_equal(File.setgid?(f), test(?g, f))
+ assert_equal(File.grpowned?(f), test(?G, f))
+ assert_equal(File.sticky?(f), test(?k, f))
+ assert_equal(File.symlink?(f), test(?l, f))
+ assert_equal(File.owned?(f), test(?o, f))
+ assert_nothing_raised { test(?O, f) }
+ assert_equal(File.pipe?(f), test(?p, f))
+ assert_equal(File.readable?(f), test(?r, f))
+ assert_equal(File.readable_real?(f), test(?R, f))
+ assert_equal(File.size?(f), test(?s, f))
+ assert_equal(File.socket?(f), test(?S, f))
+ assert_equal(File.setuid?(f), test(?u, f))
+ assert_equal(File.writable?(f), test(?w, f))
+ assert_equal(File.writable_real?(f), test(?W, f))
+ assert_equal(File.executable?(f), test(?x, f))
+ assert_equal(File.executable_real?(f), test(?X, f))
+ assert_equal(File.zero?(f), test(?z, f))
+ end
+ assert_equal(false, test(?-, @dir, @file))
+ assert_equal(true, test(?-, @file, @file))
+ assert_equal(true, test(?=, @file, @file))
+ assert_equal(false, test(?>, @file, @file))
+ assert_equal(false, test(?<, @file, @file))
+ unless /cygwin/ =~ RUBY_PLATFORM
+ assert_equal(false, test(?=, @file, @file + "2"))
+ assert_equal(false, test(?>, @file, @file + "2"))
+ assert_equal(true, test(?>, @file + "2", @file))
+ assert_equal(true, test(?<, @file, @file + "2"))
+ assert_equal(false, test(?<, @file + "2", @file))
+ end
+ assert_raise(ArgumentError) { test }
+ assert_raise(Errno::ENOENT) { test(?A, @nofile) }
+ assert_raise(ArgumentError) { test(?a) }
+ assert_raise(ArgumentError) { test("\0".ord) }
+ end
+
+ def test_stat_init
+ sleep(@time - Time.now + 1.1)
+ make_file("foo", @file + "2")
+ fs1, fs2 = File::Stat.new(@file), File::Stat.new(@file + "2")
+ assert_nothing_raised do
+ assert_equal(0, fs1 <=> fs1)
+ assert_equal(-1, fs1 <=> fs2)
+ assert_equal(1, fs2 <=> fs1)
+ assert_nil(fs1 <=> nil)
+ assert_integer(fs1.dev)
+ assert_integer_or_nil(fs1.rdev)
+ assert_integer_or_nil(fs1.dev_major)
+ assert_integer_or_nil(fs1.dev_minor)
+ assert_integer_or_nil(fs1.rdev_major)
+ assert_integer_or_nil(fs1.rdev_minor)
+ assert_integer(fs1.ino)
+ assert_integer(fs1.mode)
+ unless /emx|mswin|mingw/ =~ RUBY_PLATFORM
+ # on Windows, nlink is always 1. but this behavior will be changed
+ # in the future.
+ assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink)
+ end
+ assert_integer(fs1.uid)
+ assert_integer(fs1.gid)
+ assert_equal(3, fs1.size)
+ assert_integer_or_nil(fs1.blksize)
+ assert_integer_or_nil(fs1.blocks)
+ assert_kind_of(Time, fs1.atime)
+ assert_kind_of(Time, fs1.mtime)
+ assert_kind_of(Time, fs1.ctime)
+ assert_kind_of(String, fs1.inspect)
+ end
+ assert_raise(Errno::ENOENT) { File::Stat.new(@nofile) }
+ assert_kind_of(File::Stat, File::Stat.new(@file).dup)
+ assert_raise(TypeError) do
+ File::Stat.new(@file).instance_eval { initialize_copy(0) }
+ end
+ end
+
+ def test_stat_ftype
+ assert_equal("directory", File::Stat.new(@dir).ftype)
+ assert_equal("file", File::Stat.new(@file).ftype)
+ # File::Stat uses stat
+ assert_equal("file", File::Stat.new(@symlinkfile).ftype) if @symlinkfile
+ assert_equal("file", File::Stat.new(@hardlinkfile).ftype) if @hardlinkfile
+ end
+
+ def test_stat_directory_p
+ assert(File::Stat.new(@dir).directory?)
+ assert(!(File::Stat.new(@file).directory?))
+ end
+
+ def test_stat_pipe_p ## xxx
+ assert(!(File::Stat.new(@dir).pipe?))
+ assert(!(File::Stat.new(@file).pipe?))
+ end
+
+ def test_stat_symlink_p
+ assert(!(File::Stat.new(@dir).symlink?))
+ assert(!(File::Stat.new(@file).symlink?))
+ # File::Stat uses stat
+ assert(!(File::Stat.new(@symlinkfile).symlink?)) if @symlinkfile
+ assert(!(File::Stat.new(@hardlinkfile).symlink?)) if @hardlinkfile
+ end
+
+ def test_stat_socket_p ## xxx
+ assert(!(File::Stat.new(@dir).socket?))
+ assert(!(File::Stat.new(@file).socket?))
+ end
+
+ def test_stat_blockdev_p ## xxx
+ assert(!(File::Stat.new(@dir).blockdev?))
+ assert(!(File::Stat.new(@file).blockdev?))
+ end
+
+ def test_stat_chardev_p ## xxx
+ assert(!(File::Stat.new(@dir).chardev?))
+ assert(!(File::Stat.new(@file).chardev?))
+ end
+
+ def test_stat_readable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0200, @file)
+ assert(!(File::Stat.new(@file).readable?))
+ File.chmod(0600, @file)
+ assert(File::Stat.new(@file).readable?)
+ end
+
+ def test_stat_readable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0200, @file)
+ assert(!(File::Stat.new(@file).readable_real?))
+ File.chmod(0600, @file)
+ assert(File::Stat.new(@file).readable_real?)
+ end
+
+ def test_stat_world_readable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0006, @file)
+ assert(File::Stat.new(@file).world_readable?)
+ File.chmod(0060, @file)
+ assert(!(File::Stat.new(@file).world_readable?))
+ File.chmod(0600, @file)
+ assert(!(File::Stat.new(@file).world_readable?))
+ end
+
+ def test_stat_writable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0400, @file)
+ assert(!(File::Stat.new(@file).writable?))
+ File.chmod(0600, @file)
+ assert(File::Stat.new(@file).writable?)
+ end
+
+ def test_stat_writable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ return if Process.euid == 0
+ File.chmod(0400, @file)
+ assert(!(File::Stat.new(@file).writable_real?))
+ File.chmod(0600, @file)
+ assert(File::Stat.new(@file).writable_real?)
+ end
+
+ def test_stat_world_writable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0006, @file)
+ assert(File::Stat.new(@file).world_writable?)
+ File.chmod(0060, @file)
+ assert(!(File::Stat.new(@file).world_writable?))
+ File.chmod(0600, @file)
+ assert(!(File::Stat.new(@file).world_writable?))
+ end
+
+ def test_stat_executable_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0100, @file)
+ assert(File::Stat.new(@file).executable?)
+ File.chmod(0600, @file)
+ assert(!(File::Stat.new(@file).executable?))
+ end
+
+ def test_stat_executable_real_p
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ File.chmod(0100, @file)
+ assert(File::Stat.new(@file).executable_real?)
+ File.chmod(0600, @file)
+ assert(!(File::Stat.new(@file).executable_real?))
+ end
+
+ def test_stat_file_p
+ assert(!(File::Stat.new(@dir).file?))
+ assert(File::Stat.new(@file).file?)
+ end
+
+ def test_stat_zero_p
+ assert_nothing_raised { File::Stat.new(@dir).zero? }
+ assert(!(File::Stat.new(@file).zero?))
+ assert(File::Stat.new(@zerofile).zero?)
+ end
+
+ def test_stat_size_p
+ assert_nothing_raised { File::Stat.new(@dir).size? }
+ assert_equal(3, File::Stat.new(@file).size?)
+ assert(!(File::Stat.new(@zerofile).size?))
+ end
+
+ def test_stat_owned_p ## xxx
+ return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ assert(File::Stat.new(@file).owned?)
+ assert(File::Stat.new(@file).grpowned?)
+ end
+
+ def test_stat_suid_sgid_sticky ## xxx
+ assert(!(File::Stat.new(@file).setuid?))
+ assert(!(File::Stat.new(@file).setgid?))
+ assert(!(File::Stat.new(@file).sticky?))
+ end
+
+ def test_stat_size
+ assert_integer(File::Stat.new(@dir).size)
+ assert_equal(3, File::Stat.new(@file).size)
+ assert_equal(0, File::Stat.new(@zerofile).size)
+ end
+
+ def test_stat_special_file
+ # test for special files such as pagefile.sys on Windows
+ assert_nothing_raised do
+ Dir::glob("C:/*.sys") {|f| File::Stat.new(f) }
+ end
+ end if DRIVE
+
+ def test_path_check
+ assert_nothing_raised { ENV["PATH"] }
+ end
+
+ def test_size
+ assert_equal(3, File.open(@file) {|f| f.size })
+ File.open(@file, "a") do |f|
+ f.write("bar")
+ assert_equal(6, f.size)
+ end
+ end
+
+ def test_absolute_path
+ assert_equal(File.join(Dir.pwd, "~foo"), File.absolute_path("~foo"))
+ dir = File.expand_path("/bar")
+ assert_equal(File.join(dir, "~foo"), File.absolute_path("~foo", dir))
+ end
+end
diff --git a/jni/ruby/test/ruby/test_fixnum.rb b/jni/ruby/test/ruby/test_fixnum.rb
new file mode 100644
index 0000000..8b2cf2e
--- /dev/null
+++ b/jni/ruby/test/ruby/test_fixnum.rb
@@ -0,0 +1,315 @@
+require 'test/unit'
+
+class TestFixnum < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_pow
+ [1, 2, 2**64, 2**63*3, 2**64*3].each do |y|
+ [-1, 0, 1].each do |x|
+ z1 = x**y
+ z2 = (-x)**y
+ if y % 2 == 1
+ assert_equal(z2, -z1)
+ else
+ assert_equal(z2, z1)
+ end
+ end
+ end
+ end
+
+ def test_succ
+ assert_equal(0x40000000, 0x3fffffff.succ, "[ruby-dev:31189]")
+ assert_equal(0x4000000000000000, 0x3fffffffffffffff.succ, "[ruby-dev:31190]")
+ end
+
+ def test_pred
+ assert_equal(-0x40000001, (-0x40000000).pred)
+ assert_equal(-0x4000000000000001, (-0x4000000000000000).pred)
+ end
+
+ def test_plus
+ assert_equal(0x40000000, 0x3fffffff+1)
+ assert_equal(0x4000000000000000, 0x3fffffffffffffff+1)
+ assert_equal(-0x40000001, (-0x40000000)+(-1))
+ assert_equal(-0x4000000000000001, (-0x4000000000000000)+(-1))
+ assert_equal(-0x80000000, (-0x40000000)+(-0x40000000))
+ end
+
+ def test_sub
+ assert_equal(0x40000000, 0x3fffffff-(-1))
+ assert_equal(0x4000000000000000, 0x3fffffffffffffff-(-1))
+ assert_equal(-0x40000001, (-0x40000000)-1)
+ assert_equal(-0x4000000000000001, (-0x4000000000000000)-1)
+ assert_equal(-0x80000000, (-0x40000000)-0x40000000)
+ end
+
+ def test_mult
+ assert_equal(0x40000000, 0x20000000*2)
+ assert_equal(0x4000000000000000, 0x2000000000000000*2)
+ assert_equal(-0x40000001, 33025*(-32513))
+ assert_equal(-0x4000000000000001, 1380655685*(-3340214413))
+ assert_equal(0x40000000, (-0x40000000)*(-1))
+ end
+
+ def test_div
+ assert_equal(2, 5/2)
+ assert_equal(0, 1/2)
+ assert_equal(-1, -1/2)
+ assert_equal(0, -(1/2))
+ assert_equal(-1, (-1)/2)
+ assert_equal(0, (-1)/(-2))
+ assert_equal(-1, 1/(-2))
+ assert_equal(1, -(1/(-2)))
+ assert_equal(0x3fffffff, 0xbffffffd/3)
+ assert_equal(0x40000000, 0xc0000000/3)
+ assert_equal(0x4000000000000000, 0xc000000000000000/3)
+ assert_equal(-0x40000001, 0xc0000003/(-3))
+ assert_equal(-0x4000000000000001, 0xc000000000000003/(-3))
+ assert_equal(0x40000000, (-0x40000000)/(-1), "[ruby-dev:31210]")
+ assert_equal(0x4000000000000000, (-0x4000000000000000)/(-1))
+ assert_raise(FloatDomainError) { 2.div(Float::NAN).nan? }
+ end
+
+ def test_mod
+ assert_equal(2, (-0x40000000) % 3)
+ assert_equal(0, (-0x40000000) % (-1))
+ end
+
+ def test_divmod
+ (-5).upto(5) {|a|
+ (-5).upto(5) {|b|
+ next if b == 0
+ q, r = a.divmod(b)
+ assert_equal(a, b*q+r)
+ assert_operator(r.abs, :<, b.abs)
+ if 0 < b
+ assert_operator(r, :>=, 0)
+ assert_operator(r, :<, b)
+ else
+ assert_operator(r, :>, b)
+ assert_operator(r, :<=, 0)
+ end
+ assert_equal(q, a/b)
+ assert_equal(q, a.div(b))
+ assert_equal(r, a%b)
+ assert_equal(r, a.modulo(b))
+ }
+ }
+ assert_raise(FloatDomainError) { 2.divmod(Float::NAN) }
+ end
+
+ def test_not
+ assert_equal(-0x40000000, ~0x3fffffff)
+ assert_equal(0x3fffffff, ~-0x40000000)
+ end
+
+ def test_lshift
+ assert_equal(0x40000000, 0x20000000 << 1)
+ assert_equal(-0x40000000, (-0x20000000) << 1)
+ assert_equal(-0x80000000, (-0x40000000) << 1)
+ end
+
+ def test_rshift
+ assert_equal(0x20000000, 0x40000000 >> 1)
+ assert_equal(-0x20000000, (-0x40000000) >> 1)
+ assert_equal(-0x40000000, (-0x80000000) >> 1)
+ end
+
+ def test_abs
+ assert_equal(0x40000000, (-0x40000000).abs)
+ assert_equal(0x4000000000000000, (-0x4000000000000000).abs)
+ end
+
+ def test_to_s
+ assert_equal("1010", 10.to_s(2))
+ assert_equal("a", 10.to_s(36))
+ assert_raise(ArgumentError) { 10.to_s(1) }
+ end
+
+ def test_plus2
+ assert_equal(2, 1 + 1)
+ assert_equal(4294967297, 1 + 2**32)
+ assert_equal(2.0, 1 + 1.0)
+ assert_raise(TypeError) { 1 + nil }
+ end
+
+ def test_minus
+ assert_equal(0, 1 - 1)
+ assert_equal(-4294967295, 1 - 2**32)
+ assert_equal(0.0, 1 - 1.0)
+ assert_raise(TypeError) { 1 - nil }
+ end
+
+ def test_mul
+ assert_equal(6, 2.send(:*, 3))
+ a = 2**30-1
+ assert_equal(1152921502459363329, a.send(:*, a))
+
+ assert_equal(6.0, 2 * 3.0)
+ assert_raise(TypeError) { 2 * nil }
+ end
+
+ def test_divide
+ assert_equal(2.0, 4.quo(2))
+ assert_equal(2.0, 4 / 2)
+ assert_equal(2.0, 4.div(2))
+
+ assert_equal(0.5**32, 1.quo(2**32))
+ assert_equal(0, 1 / (2**32))
+ assert_equal(0, 1.div(2**32))
+
+ assert_kind_of(Float, 1.quo(2.0))
+ assert_equal(0.5, 1.quo(2.0))
+ assert_equal(0.5, 1 / 2.0)
+ assert_equal(0, 1.div(2.0))
+
+ ### rational changes the behavior of Fixnum#quo
+ #assert_raise(TypeError) { 2.quo(nil) }
+ assert_raise(TypeError, NoMethodError) { 2.quo(nil) }
+ assert_raise(TypeError) { 2 / nil }
+ assert_raise(TypeError) { 2.div(nil) }
+
+ assert_equal(0, 4.modulo(2))
+ assert_equal(1, 1.modulo(2**32))
+ assert_equal(1, 1.modulo(2.0))
+ assert_raise(TypeError) { 2.modulo(nil) }
+
+ assert_equal([2, 0], 4.divmod(2))
+ assert_equal([0, 1], 1.divmod(2**32))
+ assert_equal([0, 1], 1.divmod(2.0))
+ assert_raise(TypeError) { 2.divmod(nil) }
+ end
+
+ def test_pow2
+ assert_equal(65536, 2**16)
+ assert_equal(4294967296, 2**32)
+ assert_equal(0.5**16, 2**-16)
+ assert_equal(1, (-1)**4294967296)
+ assert_equal(-1, (-1)**4294967295)
+ assert_equal(4, 2**((2**32).coerce(2).first))
+ assert_equal(2, 4**0.5)
+ assert_equal(0, 0**0.5)
+ assert_equal(1, (0**-1.0).infinite?)
+ ### rational changes the behavior of Fixnum#**
+ #assert_raise(TypeError) { 1 ** nil }
+ assert_raise(TypeError, NoMethodError) { 1 ** nil }
+ end
+
+ def test_cmp
+ assert_operator(1, :!=, nil)
+
+ assert_equal(0, 1 <=> 1)
+ assert_equal(-1, 1 <=> 4294967296)
+ assert_equal(0, 1 <=> 1.0)
+ assert_nil(1 <=> nil)
+
+ assert_operator(1, :>, 0)
+ assert_not_operator(1, :>, 1)
+ assert_not_operator(1, :>, 2)
+ assert_not_operator(1, :>, 4294967296)
+ assert_operator(1, :>, 0.0)
+ assert_raise(ArgumentError) { 1 > nil }
+
+ assert_operator(1, :>=, 0)
+ assert_operator(1, :>=, 1)
+ assert_not_operator(1, :>=, 2)
+ assert_not_operator(1, :>=, 4294967296)
+ assert_operator(1, :>=, 0.0)
+ assert_raise(ArgumentError) { 1 >= nil }
+
+ assert_not_operator(1, :<, 0)
+ assert_not_operator(1, :<, 1)
+ assert_operator(1, :<, 2)
+ assert_operator(1, :<, 4294967296)
+ assert_not_operator(1, :<, 0.0)
+ assert_raise(ArgumentError) { 1 < nil }
+
+ assert_not_operator(1, :<=, 0)
+ assert_operator(1, :<=, 1)
+ assert_operator(1, :<=, 2)
+ assert_operator(1, :<=, 4294967296)
+ assert_not_operator(1, :<=, 0.0)
+ assert_raise(ArgumentError) { 1 <= nil }
+ end
+
+ class DummyNumeric < Numeric
+ def to_int
+ 1
+ end
+ end
+
+ def test_and_with_float
+ assert_raise(TypeError) { 1 & 1.5 }
+ end
+
+ def test_and_with_rational
+ assert_raise(TypeError, "#1792") { 1 & Rational(3, 2) }
+ end
+
+ def test_and_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { 1 & DummyNumeric.new }
+ end
+
+ def test_or_with_float
+ assert_raise(TypeError) { 1 | 1.5 }
+ end
+
+ def test_or_with_rational
+ assert_raise(TypeError, "#1792") { 1 | Rational(3, 2) }
+ end
+
+ def test_or_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { 1 | DummyNumeric.new }
+ end
+
+ def test_xor_with_float
+ assert_raise(TypeError) { 1 ^ 1.5 }
+ end
+
+ def test_xor_with_rational
+ assert_raise(TypeError, "#1792") { 1 ^ Rational(3, 2) }
+ end
+
+ def test_xor_with_nonintegral_numeric
+ assert_raise(TypeError, "#1792") { 1 ^ DummyNumeric.new }
+ end
+
+ def test_singleton_method
+ assert_raise(TypeError) { a = 1; def a.foo; end }
+ end
+
+ def test_frozen
+ assert_equal(true, 1.frozen?)
+ end
+
+ def assert_eql(a, b, mess)
+ assert a.eql?(b), "expected #{a} & #{b} to be eql? #{mess}"
+ end
+
+ def test_power_of_1_and_minus_1
+ bug5715 = '[ruby-core:41498]'
+ big = 1 << 66
+ assert_eql 1, 1 ** -big , bug5715
+ assert_eql 1, (-1) ** -big , bug5715
+ assert_eql -1, (-1) ** -(big+1) , bug5715
+ end
+
+ def test_power_of_0
+ bug5713 = '[ruby-core:41494]'
+ big = 1 << 66
+ assert_raise(ZeroDivisionError, bug5713) { 0 ** -big }
+ assert_raise(ZeroDivisionError, bug5713) { 0 ** Rational(-2,3) }
+ end
+
+ def test_remainder
+ assert_equal(1, 5.remainder(4))
+ assert_predicate(4.remainder(Float::NAN), :nan?)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_flip.rb b/jni/ruby/test/ruby/test_flip.rb
new file mode 100644
index 0000000..84f7bf0
--- /dev/null
+++ b/jni/ruby/test/ruby/test_flip.rb
@@ -0,0 +1,41 @@
+require 'test/unit'
+
+class TestFlip < Test::Unit::TestCase
+ def test_hidden_key
+ bug6899 = '[ruby-core:47253]'
+ foo = "foor"
+ bar = "bar"
+ assert_nothing_raised(NotImplementedError, bug6899) do
+ 2000.times {eval %[(foo..bar) ? 1 : 2]}
+ end
+ end
+
+ def test_shared_eval
+ bug7671 = '[ruby-core:51296]'
+ vs = (1..9).to_a
+ vs.select {|n| if n==2..n==16 then 1 end}
+ v = eval("vs.select {|n| if n==3..n==6 then 1 end}")
+ assert_equal([*3..6], v, bug7671)
+ end
+
+ def test_shared_thread
+ ff = proc {|n| true if n==3..n==5}
+ v = 1..9
+ a = true
+ th = Thread.new {
+ v.select {|i|
+ Thread.pass while a
+ ff[i].tap {a = true}
+ }
+ }
+ v1 = v.select {|i|
+ Thread.pass until a
+ ff[i].tap {a = false}
+ }
+ v2 = th.value
+ expected = [3, 4, 5]
+ mesg = 'flip-flop should be separated per threads'
+ assert_equal(expected, v1, mesg)
+ assert_equal(expected, v2, mesg)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_float.rb b/jni/ruby/test/ruby/test_float.rb
new file mode 100644
index 0000000..eab4d12
--- /dev/null
+++ b/jni/ruby/test/ruby/test_float.rb
@@ -0,0 +1,683 @@
+require 'test/unit'
+
+class TestFloat < Test::Unit::TestCase
+ include EnvUtil
+
+ def test_float
+ assert_equal(2, 2.6.floor)
+ assert_equal(-3, (-2.6).floor)
+ assert_equal(3, 2.6.ceil)
+ assert_equal(-2, (-2.6).ceil)
+ assert_equal(2, 2.6.truncate)
+ assert_equal(-2, (-2.6).truncate)
+ assert_equal(3, 2.6.round)
+ assert_equal(-2, (-2.4).truncate)
+ assert_in_delta(13.4 % 1, 0.4, 0.0001)
+ assert_equal(36893488147419111424,
+ 36893488147419107329.0.to_i)
+ end
+
+ def nan_test(x,y)
+ extend Test::Unit::Assertions
+ assert_operator(x, :!=, y)
+ assert_not_operator(x, :<, y)
+ assert_not_operator(x, :>, y)
+ assert_not_operator(x, :<=, y)
+ assert_not_operator(x, :>=, y)
+ end
+ def test_nan
+ nan = Float::NAN
+ nan_test(nan, nan)
+ nan_test(nan, 0)
+ nan_test(nan, 1)
+ nan_test(nan, -1)
+ nan_test(nan, 1000)
+ nan_test(nan, -1000)
+ nan_test(nan, 1_000_000_000_000)
+ nan_test(nan, -1_000_000_000_000)
+ nan_test(nan, 100.0);
+ nan_test(nan, -100.0);
+ nan_test(nan, 0.001);
+ nan_test(nan, -0.001);
+ nan_test(nan, 1.0/0);
+ nan_test(nan, -1.0/0);
+ end
+
+ def test_precision
+ u = 3.7517675036461267e+17
+ v = sprintf("%.16e", u).to_f
+ assert_in_delta(u, v, u.abs * Float::EPSILON)
+ assert_in_delta(u, v, v.abs * Float::EPSILON)
+ end
+
+ def test_symmetry_bignum # [ruby-bugs-ja:118]
+ a = 100000000000000000000000
+ b = 100000000000000000000000.0
+ assert_equal(a == b, b == a)
+ end
+
+ def test_cmp_int
+ 100.times {|i|
+ int0 = 1 << i
+ [int0, -int0].each {|int|
+ flt = int.to_f
+ bigger = int + 1
+ smaller = int - 1
+ assert_operator(flt, :==, int)
+ assert_operator(flt, :>, smaller)
+ assert_operator(flt, :>=, smaller)
+ assert_operator(flt, :<, bigger)
+ assert_operator(flt, :<=, bigger)
+ assert_equal(0, flt <=> int)
+ assert_equal(-1, flt <=> bigger)
+ assert_equal(1, flt <=> smaller)
+ assert_operator(int, :==, flt)
+ assert_operator(bigger, :>, flt)
+ assert_operator(bigger, :>=, flt)
+ assert_operator(smaller, :<, flt)
+ assert_operator(smaller, :<=, flt)
+ assert_equal(0, int <=> flt)
+ assert_equal(-1, smaller <=> flt)
+ assert_equal(1, bigger <=> flt)
+ [
+ [int, flt + 0.5, bigger],
+ [smaller, flt - 0.5, int]
+ ].each {|smaller2, flt2, bigger2|
+ next if flt2 == flt2.round
+ assert_operator(flt2, :!=, smaller2)
+ assert_operator(flt2, :!=, bigger2)
+ assert_operator(flt2, :>, smaller2)
+ assert_operator(flt2, :>=, smaller2)
+ assert_operator(flt2, :<, bigger2)
+ assert_operator(flt2, :<=, bigger2)
+ assert_equal(-1, flt2 <=> bigger2)
+ assert_equal(1, flt2 <=> smaller2)
+ assert_operator(smaller2, :!=, flt2)
+ assert_operator(bigger2, :!=, flt2)
+ assert_operator(bigger2, :>, flt2)
+ assert_operator(bigger2, :>=, flt2)
+ assert_operator(smaller2, :<, flt2)
+ assert_operator(smaller2, :<=, flt2)
+ assert_equal(-1, smaller2 <=> flt2)
+ assert_equal(1, bigger2 <=> flt2)
+ }
+ }
+ }
+ end
+
+ def test_strtod
+ a = Float("0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("0.0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("+0.0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("-0.0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("0.0000000000000000001")
+ assert_not_equal(0.0, a)
+ a = Float("+0.0000000000000000001")
+ assert_not_equal(0.0, a)
+ a = Float("-0.0000000000000000001")
+ assert_not_equal(0.0, a)
+ a = Float(".0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("+.0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ a = Float("-.0")
+ assert_in_delta(a, 0, Float::EPSILON)
+ assert_raise(ArgumentError){Float("0.")}
+ assert_raise(ArgumentError){Float("+0.")}
+ assert_raise(ArgumentError){Float("-0.")}
+ assert_raise(ArgumentError){Float(".")}
+ assert_raise(ArgumentError){Float("+")}
+ assert_raise(ArgumentError){Float("+.")}
+ assert_raise(ArgumentError){Float("-")}
+ assert_raise(ArgumentError){Float("-.")}
+ assert_raise(ArgumentError){Float("1e")}
+ assert_raise(ArgumentError){Float("1__1")}
+ assert_raise(ArgumentError){Float("1.")}
+ assert_raise(ArgumentError){Float("1.e+00")}
+ assert_raise(ArgumentError){Float("0x1.p+0")}
+ # add expected behaviour here.
+ assert_equal(10, Float("1_0"))
+
+ assert_equal([ 0.0].pack('G'), [Float(" 0x0p+0").to_f].pack('G'))
+ assert_equal([-0.0].pack('G'), [Float("-0x0p+0").to_f].pack('G'))
+ assert_equal(255.0, Float("0Xff"))
+ assert_equal(1024.0, Float("0x1p10"))
+ assert_equal(1024.0, Float("0x1p+10"))
+ assert_equal(0.0009765625, Float("0x1p-10"))
+ assert_equal(2.6881171418161356e+43, Float("0x1.3494a9b171bf5p+144"))
+ assert_equal(-3.720075976020836e-44, Float("-0x1.a8c1f14e2af5dp-145"))
+ assert_equal(31.0*2**1019, Float("0x0."+("0"*268)+"1fp2099"))
+ assert_equal(31.0*2**1019, Float("0x0."+("0"*600)+"1fp3427"))
+ assert_equal(-31.0*2**1019, Float("-0x0."+("0"*268)+"1fp2099"))
+ assert_equal(-31.0*2**1019, Float("-0x0."+("0"*600)+"1fp3427"))
+ suppress_warning do
+ assert_equal(31.0*2**-1027, Float("0x1f"+("0"*268)+".0p-2099"))
+ assert_equal(31.0*2**-1027, Float("0x1f"+("0"*600)+".0p-3427"))
+ assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*268)+".0p-2099"))
+ assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*600)+".0p-3427"))
+ end
+ end
+
+ def test_divmod
+ assert_equal([2, 3.5], 11.5.divmod(4))
+ assert_equal([-3, -0.5], 11.5.divmod(-4))
+ assert_equal([-3, 0.5], (-11.5).divmod(4))
+ assert_equal([2, -3.5], (-11.5).divmod(-4))
+ assert_raise(FloatDomainError) { Float::NAN.divmod(2) }
+ assert_raise(FloatDomainError) { Float::INFINITY.divmod(2) }
+ end
+
+ def test_div
+ assert_equal(2, 11.5.div(4))
+ assert_equal(-3, 11.5.div(-4))
+ assert_equal(-3, (-11.5).div(4))
+ assert_equal(2, (-11.5).div(-4))
+ assert_raise(FloatDomainError) { 11.5.div(Float::NAN).nan? }
+ assert_raise(FloatDomainError) { Float::NAN.div(2).nan? }
+ assert_raise(FloatDomainError) { Float::NAN.div(11.5).nan? }
+ end
+
+ def test_modulo
+ assert_equal(3.5, 11.5.modulo(4))
+ assert_equal(-0.5, 11.5.modulo(-4))
+ assert_equal(0.5, (-11.5).modulo(4))
+ assert_equal(-3.5, (-11.5).modulo(-4))
+ end
+
+ def test_remainder
+ assert_equal(3.5, 11.5.remainder(4))
+ assert_equal(3.5, 11.5.remainder(-4))
+ assert_equal(-3.5, (-11.5).remainder(4))
+ assert_equal(-3.5, (-11.5).remainder(-4))
+ assert_predicate(Float::NAN.remainder(4), :nan?)
+ assert_predicate(4.remainder(Float::NAN), :nan?)
+ end
+
+ def test_to_s
+ inf = Float::INFINITY
+ assert_equal("Infinity", inf.to_s)
+ assert_equal("-Infinity", (-inf).to_s)
+ assert_equal("NaN", (inf / inf).to_s)
+
+ assert_equal("1.0e+18", 1000_00000_00000_00000.0.to_s)
+
+ bug3273 = '[ruby-core:30145]'
+ [0.21611564636388508, 0.56].each do |f|
+ s = f.to_s
+ assert_equal(f, s.to_f, bug3273)
+ assert_not_equal(f, s.chop.to_f, bug3273)
+ end
+ end
+
+ def test_coerce
+ assert_equal(Float, 1.0.coerce(1).first.class)
+ end
+
+ def test_plus
+ assert_equal(4.0, 2.0.send(:+, 2))
+ assert_equal(4.0, 2.0.send(:+, (2**32).coerce(2).first))
+ assert_equal(4.0, 2.0.send(:+, 2.0))
+ assert_equal(Float::INFINITY, 2.0.send(:+, Float::INFINITY))
+ assert_predicate(2.0.send(:+, Float::NAN), :nan?)
+ assert_raise(TypeError) { 2.0.send(:+, nil) }
+ end
+
+ def test_minus
+ assert_equal(0.0, 2.0.send(:-, 2))
+ assert_equal(0.0, 2.0.send(:-, (2**32).coerce(2).first))
+ assert_equal(0.0, 2.0.send(:-, 2.0))
+ assert_equal(-Float::INFINITY, 2.0.send(:-, Float::INFINITY))
+ assert_predicate(2.0.send(:-, Float::NAN), :nan?)
+ assert_raise(TypeError) { 2.0.send(:-, nil) }
+ end
+
+ def test_mul
+ assert_equal(4.0, 2.0.send(:*, 2))
+ assert_equal(4.0, 2.0.send(:*, (2**32).coerce(2).first))
+ assert_equal(4.0, 2.0.send(:*, 2.0))
+ assert_equal(Float::INFINITY, 2.0.send(:*, Float::INFINITY))
+ assert_raise(TypeError) { 2.0.send(:*, nil) }
+ end
+
+ def test_div2
+ assert_equal(1.0, 2.0.send(:/, 2))
+ assert_equal(1.0, 2.0.send(:/, (2**32).coerce(2).first))
+ assert_equal(1.0, 2.0.send(:/, 2.0))
+ assert_equal(0.0, 2.0.send(:/, Float::INFINITY))
+ assert_raise(TypeError) { 2.0.send(:/, nil) }
+ end
+
+ def test_modulo2
+ assert_equal(0.0, 2.0.send(:%, 2))
+ assert_equal(0.0, 2.0.send(:%, (2**32).coerce(2).first))
+ assert_equal(0.0, 2.0.send(:%, 2.0))
+ assert_raise(TypeError) { 2.0.send(:%, nil) }
+ end
+
+ def test_modulo3
+ bug6048 = '[ruby-core:42726]'
+ assert_equal(4.2, 4.2.send(:%, Float::INFINITY), bug6048)
+ assert_equal(4.2, 4.2 % Float::INFINITY, bug6048)
+ assert_is_minus_zero(-0.0 % 4.2)
+ assert_is_minus_zero(-0.0.send :%, 4.2)
+ assert_raise(ZeroDivisionError, bug6048) { 4.2.send(:%, 0.0) }
+ assert_raise(ZeroDivisionError, bug6048) { 4.2 % 0.0 }
+ assert_raise(ZeroDivisionError, bug6048) { 42.send(:%, 0) }
+ assert_raise(ZeroDivisionError, bug6048) { 42 % 0 }
+ end
+
+ def test_modulo4
+ assert_predicate((0.0).modulo(Float::NAN), :nan?)
+ assert_predicate((1.0).modulo(Float::NAN), :nan?)
+ assert_predicate(Float::INFINITY.modulo(1), :nan?)
+ end
+
+ def test_divmod2
+ assert_equal([1.0, 0.0], 2.0.divmod(2))
+ assert_equal([1.0, 0.0], 2.0.divmod((2**32).coerce(2).first))
+ assert_equal([1.0, 0.0], 2.0.divmod(2.0))
+ assert_raise(TypeError) { 2.0.divmod(nil) }
+
+ inf = Float::INFINITY
+ assert_raise(ZeroDivisionError) {inf.divmod(0)}
+
+ a, b = (2.0**32).divmod(1.0)
+ assert_equal(2**32, a)
+ assert_equal(0, b)
+ end
+
+ def test_pow
+ assert_equal(1.0, 1.0 ** (2**32))
+ assert_equal(1.0, 1.0 ** 1.0)
+ assert_raise(TypeError) { 1.0 ** nil }
+ end
+
+ def test_eql
+ inf = Float::INFINITY
+ nan = Float::NAN
+ assert_operator(1.0, :eql?, 1.0)
+ assert_operator(inf, :eql?, inf)
+ assert_not_operator(nan, :eql?, nan)
+ assert_not_operator(1.0, :eql?, nil)
+
+ assert_equal(1.0, 1)
+ assert_not_equal(1.0, 2**32)
+ assert_not_equal(1.0, nan)
+ assert_not_equal(1.0, nil)
+ end
+
+ def test_cmp
+ inf = Float::INFINITY
+ nan = Float::NAN
+ assert_equal(0, 1.0 <=> 1.0)
+ assert_equal(1, 1.0 <=> 0.0)
+ assert_equal(-1, 1.0 <=> 2.0)
+ assert_nil(1.0 <=> nil)
+ assert_nil(1.0 <=> nan)
+ assert_nil(nan <=> 1.0)
+
+ assert_equal(0, 1.0 <=> 1)
+ assert_equal(1, 1.0 <=> 0)
+ assert_equal(-1, 1.0 <=> 2)
+
+ assert_equal(-1, 1.0 <=> 2**32)
+
+ assert_equal(1, inf <=> (Float::MAX.to_i*2))
+ assert_equal(-1, -inf <=> (-Float::MAX.to_i*2))
+ assert_equal(-1, (Float::MAX.to_i*2) <=> inf)
+ assert_equal(1, (-Float::MAX.to_i*2) <=> -inf)
+
+ bug3609 = '[ruby-core:31470]'
+ def (pinf = Object.new).infinite?; +1 end
+ def (ninf = Object.new).infinite?; -1 end
+ def (fin = Object.new).infinite?; nil end
+ nonum = Object.new
+ assert_equal(0, inf <=> pinf, bug3609)
+ assert_equal(1, inf <=> fin, bug3609)
+ assert_equal(1, inf <=> ninf, bug3609)
+ assert_nil(inf <=> nonum, bug3609)
+ assert_equal(-1, -inf <=> pinf, bug3609)
+ assert_equal(-1, -inf <=> fin, bug3609)
+ assert_equal(0, -inf <=> ninf, bug3609)
+ assert_nil(-inf <=> nonum, bug3609)
+
+ assert_raise(ArgumentError) { 1.0 > nil }
+ assert_raise(ArgumentError) { 1.0 >= nil }
+ assert_raise(ArgumentError) { 1.0 < nil }
+ assert_raise(ArgumentError) { 1.0 <= nil }
+ end
+
+ def test_zero_p
+ assert_predicate(0.0, :zero?)
+ assert_not_predicate(1.0, :zero?)
+ end
+
+ def test_infinite_p
+ inf = Float::INFINITY
+ assert_equal(1, inf.infinite?)
+ assert_equal(-1, (-inf).infinite?)
+ assert_nil(1.0.infinite?)
+ end
+
+ def test_finite_p
+ inf = Float::INFINITY
+ assert_not_predicate(inf, :finite?)
+ assert_not_predicate(-inf, :finite?)
+ assert_predicate(1.0, :finite?)
+ end
+
+ def test_floor_ceil_round_truncate
+ assert_equal(1, 1.5.floor)
+ assert_equal(2, 1.5.ceil)
+ assert_equal(2, 1.5.round)
+ assert_equal(1, 1.5.truncate)
+
+ assert_equal(2, 2.0.floor)
+ assert_equal(2, 2.0.ceil)
+ assert_equal(2, 2.0.round)
+ assert_equal(2, 2.0.truncate)
+
+ assert_equal(-2, (-1.5).floor)
+ assert_equal(-1, (-1.5).ceil)
+ assert_equal(-2, (-1.5).round)
+ assert_equal(-1, (-1.5).truncate)
+
+ assert_equal(-2, (-2.0).floor)
+ assert_equal(-2, (-2.0).ceil)
+ assert_equal(-2, (-2.0).round)
+ assert_equal(-2, (-2.0).truncate)
+
+ inf = Float::INFINITY
+ assert_raise(FloatDomainError) { inf.floor }
+ assert_raise(FloatDomainError) { inf.ceil }
+ assert_raise(FloatDomainError) { inf.round }
+ assert_raise(FloatDomainError) { inf.truncate }
+ end
+
+ def test_round_with_precision
+ assert_equal(1.100, 1.111.round(1))
+ assert_equal(1.110, 1.111.round(2))
+ assert_equal(11110.0, 11111.1.round(-1))
+ assert_equal(11100.0, 11111.1.round(-2))
+
+ assert_equal(10**300, 1.1e300.round(-300))
+ assert_equal(-10**300, -1.1e300.round(-300))
+ assert_equal(1.0e-300, 1.1e-300.round(300))
+ assert_equal(-1.0e-300, -1.1e-300.round(300))
+
+ bug5227 = '[ruby-core:39093]'
+ assert_equal(42.0, 42.0.round(308), bug5227)
+ assert_equal(1.0e307, 1.0e307.round(2), bug5227)
+
+ assert_raise(TypeError) {1.0.round("4")}
+ assert_raise(TypeError) {1.0.round(nil)}
+ def (prec = Object.new).to_int; 2; end
+ assert_equal(1.0, 0.998.round(prec))
+ end
+
+ VS = [
+ 18446744073709551617.0,
+ 18446744073709551616.0,
+ 18446744073709551615.8,
+ 18446744073709551615.5,
+ 18446744073709551615.2,
+ 18446744073709551615.0,
+ 18446744073709551614.0,
+
+ 4611686018427387905.0,
+ 4611686018427387904.0,
+ 4611686018427387903.8,
+ 4611686018427387903.5,
+ 4611686018427387903.2,
+ 4611686018427387903.0,
+ 4611686018427387902.0,
+
+ 4294967297.0,
+ 4294967296.0,
+ 4294967295.8,
+ 4294967295.5,
+ 4294967295.2,
+ 4294967295.0,
+ 4294967294.0,
+
+ 1073741825.0,
+ 1073741824.0,
+ 1073741823.8,
+ 1073741823.5,
+ 1073741823.2,
+ 1073741823.0,
+ 1073741822.0,
+
+ -1073741823.0,
+ -1073741824.0,
+ -1073741824.2,
+ -1073741824.5,
+ -1073741824.8,
+ -1073741825.0,
+ -1073741826.0,
+
+ -4294967295.0,
+ -4294967296.0,
+ -4294967296.2,
+ -4294967296.5,
+ -4294967296.8,
+ -4294967297.0,
+ -4294967298.0,
+
+ -4611686018427387903.0,
+ -4611686018427387904.0,
+ -4611686018427387904.2,
+ -4611686018427387904.5,
+ -4611686018427387904.8,
+ -4611686018427387905.0,
+ -4611686018427387906.0,
+
+ -18446744073709551615.0,
+ -18446744073709551616.0,
+ -18446744073709551616.2,
+ -18446744073709551616.5,
+ -18446744073709551616.8,
+ -18446744073709551617.0,
+ -18446744073709551618.0,
+ ]
+
+ def test_truncate
+ VS.each {|f|
+ i = f.truncate
+ assert_equal(i, f.to_i)
+ if f < 0
+ assert_operator(i, :<, 0)
+ else
+ assert_operator(i, :>, 0)
+ end
+ assert_operator(i.abs, :<=, f.abs)
+ d = f.abs - i.abs
+ assert_operator(0, :<=, d)
+ assert_operator(d, :<, 1)
+ }
+ end
+
+ def test_ceil
+ VS.each {|f|
+ i = f.ceil
+ if f < 0
+ assert_operator(i, :<, 0)
+ else
+ assert_operator(i, :>, 0)
+ end
+ assert_operator(i, :>=, f)
+ d = f - i
+ assert_operator(-1, :<, d)
+ assert_operator(d, :<=, 0)
+ }
+ end
+
+ def test_floor
+ VS.each {|f|
+ i = f.floor
+ if f < 0
+ assert_operator(i, :<, 0)
+ else
+ assert_operator(i, :>, 0)
+ end
+ assert_operator(i, :<=, f)
+ d = f - i
+ assert_operator(0, :<=, d)
+ assert_operator(d, :<, 1)
+ }
+ end
+
+ def test_round
+ VS.each {|f|
+ msg = "round(#{f})"
+ i = f.round
+ if f < 0
+ assert_operator(i, :<, 0, msg)
+ else
+ assert_operator(i, :>, 0, msg)
+ end
+ d = f - i
+ assert_operator(-0.5, :<=, d, msg)
+ assert_operator(d, :<=, 0.5, msg)
+ }
+ end
+
+ def test_Float
+ assert_in_delta(0.125, Float("0.1_2_5"), 0.00001)
+ assert_in_delta(0.125, "0.1_2_5__".to_f, 0.00001)
+ assert_equal(1, suppress_warning {Float(([1] * 10000).join)}.infinite?)
+ assert_not_predicate(Float(([1] * 10000).join("_")), :infinite?) # is it really OK?
+ assert_raise(ArgumentError) { Float("1.0\x001") }
+ assert_equal(15.9375, Float('0xf.fp0'))
+ assert_raise(ArgumentError) { Float('0x') }
+ assert_equal(15, Float('0xf'))
+ assert_equal(15, Float('0xfp0'))
+ assert_raise(ArgumentError) { Float('0xfp') }
+ assert_raise(ArgumentError) { Float('0xf.') }
+ assert_raise(ArgumentError) { Float('0xf.p') }
+ assert_raise(ArgumentError) { Float('0xf.p0') }
+ assert_raise(ArgumentError) { Float('0xf.f') }
+ assert_raise(ArgumentError) { Float('0xf.fp') }
+ assert_equal(Float::INFINITY, Float('0xf.fp1000000000000000'))
+ assert_equal(1, suppress_warning {Float("1e10_00")}.infinite?)
+ assert_raise(TypeError) { Float(nil) }
+ o = Object.new
+ def o.to_f; inf = Float::INFINITY; inf/inf; end
+ assert_predicate(Float(o), :nan?)
+ end
+
+ def test_invalid_str
+ bug4310 = '[ruby-core:34820]'
+ assert_raise(ArgumentError, bug4310) {under_gc_stress {Float('a'*10000)}}
+ end
+
+ def test_num2dbl
+ assert_raise(ArgumentError) do
+ 1.0.step(2.0, "0.5") {}
+ end
+ assert_raise(TypeError) do
+ 1.0.step(2.0, nil) {}
+ end
+ end
+
+ def test_sleep_with_Float
+ assert_nothing_raised("[ruby-core:23282]") do
+ sleep(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1)
+ end
+ end
+
+ def test_step
+ 1000.times do
+ a = rand
+ b = a+rand*1000
+ s = (b - a) / 10
+ assert_equal(11, (a..b).step(s).to_a.length)
+ end
+
+ (1.0..12.7).step(1.3).each do |n|
+ assert_operator(n, :<=, 12.7)
+ end
+
+ assert_equal([5.0, 4.0, 3.0, 2.0], 5.0.step(1.5, -1).to_a)
+ end
+
+ def test_step2
+ assert_equal([0.0], 0.0.step(1.0, Float::INFINITY).to_a)
+ end
+
+ def test_step_excl
+ 1000.times do
+ a = rand
+ b = a+rand*1000
+ s = (b - a) / 10
+ assert_equal(10, (a...b).step(s).to_a.length)
+ end
+
+ assert_equal([1.0, 2.9, 4.8, 6.699999999999999], (1.0...6.8).step(1.9).to_a)
+
+ e = 1+1E-12
+ (1.0 ... e).step(1E-16) do |n|
+ assert_operator(n, :<=, e)
+ end
+ end
+
+ def test_singleton_method
+ # flonum on 64bit platform
+ assert_raise(TypeError) { a = 1.0; def a.foo; end }
+ # always not flonum
+ assert_raise(TypeError) { a = Float::INFINITY; def a.foo; end }
+ end
+
+ def test_long_string
+ assert_separately([], <<-'end;')
+ assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9)
+ end;
+ end
+
+ def test_next_float
+ smallest = 0.0.next_float
+ assert_equal(-Float::MAX, (-Float::INFINITY).next_float)
+ assert_operator(-Float::MAX, :<, (-Float::MAX).next_float)
+ assert_equal(Float::EPSILON/2, (-1.0).next_float + 1.0)
+ assert_operator(0.0, :<, smallest)
+ assert_operator([0.0, smallest], :include?, smallest/2)
+ assert_equal(Float::EPSILON, 1.0.next_float - 1.0)
+ assert_equal(Float::INFINITY, Float::MAX.next_float)
+ assert_equal(Float::INFINITY, Float::INFINITY.next_float)
+ assert_predicate(Float::NAN.next_float, :nan?)
+ end
+
+ def test_prev_float
+ smallest = 0.0.next_float
+ assert_equal(-Float::INFINITY, (-Float::INFINITY).prev_float)
+ assert_equal(-Float::INFINITY, (-Float::MAX).prev_float)
+ assert_equal(-Float::EPSILON, (-1.0).prev_float + 1.0)
+ assert_equal(-smallest, 0.0.prev_float)
+ assert_operator([0.0, 0.0.prev_float], :include?, 0.0.prev_float/2)
+ assert_equal(-Float::EPSILON/2, 1.0.prev_float - 1.0)
+ assert_operator(Float::MAX, :>, Float::MAX.prev_float)
+ assert_equal(Float::MAX, Float::INFINITY.prev_float)
+ assert_predicate(Float::NAN.prev_float, :nan?)
+ end
+
+ def test_next_prev_float_zero
+ z = 0.0.next_float.prev_float
+ assert_equal(0.0, z)
+ assert_equal(Float::INFINITY, 1.0/z)
+ z = 0.0.prev_float.next_float
+ assert_equal(0.0, z)
+ assert_equal(-Float::INFINITY, 1.0/z)
+ end
+
+ def test_hash_0
+ bug10979 = '[ruby-core:68541] [Bug #10979]'
+ assert_equal(+0.0.hash, -0.0.hash)
+ assert_operator(+0.0, :eql?, -0.0)
+ h = {0.0 => bug10979}
+ assert_equal(bug10979, h[-0.0])
+ end
+end
diff --git a/jni/ruby/test/ruby/test_fnmatch.rb b/jni/ruby/test/ruby/test_fnmatch.rb
new file mode 100644
index 0000000..a0eab54
--- /dev/null
+++ b/jni/ruby/test/ruby/test_fnmatch.rb
@@ -0,0 +1,131 @@
+require 'test/unit'
+
+class TestFnmatch < Test::Unit::TestCase
+
+ def bracket_test(s, t) # `s' should start with neither '!' nor '^'
+ 0x21.upto(0x7E) do |i|
+ assert_equal(t.include?(i.chr), File.fnmatch("[#{s}]", i.chr, File::FNM_DOTMATCH))
+ assert_equal(t.include?(i.chr), !File.fnmatch("[^#{s}]", i.chr, File::FNM_DOTMATCH))
+ assert_equal(t.include?(i.chr), !File.fnmatch("[!#{s}]", i.chr, File::FNM_DOTMATCH))
+ end
+ end
+ def test_fnmatch
+ assert_file.for("[ruby-dev:22819]").fnmatch('\[1\]' , '[1]')
+ assert_file.for("[ruby-dev:22815]").fnmatch('*?', 'a')
+ assert_file.fnmatch('*/', 'a/')
+ assert_file.fnmatch('\[1\]' , '[1]', File::FNM_PATHNAME)
+ assert_file.fnmatch('*?', 'a', File::FNM_PATHNAME)
+ assert_file.fnmatch('*/', 'a/', File::FNM_PATHNAME)
+ # text
+ assert_file.fnmatch('cat', 'cat')
+ assert_file.not_fnmatch('cat', 'category')
+ assert_file.not_fnmatch('cat', 'wildcat')
+ # '?' matches any one character
+ assert_file.fnmatch('?at', 'cat')
+ assert_file.fnmatch('c?t', 'cat')
+ assert_file.fnmatch('ca?', 'cat')
+ assert_file.fnmatch('?a?', 'cat')
+ assert_file.not_fnmatch('c??t', 'cat')
+ assert_file.not_fnmatch('??at', 'cat')
+ assert_file.not_fnmatch('ca??', 'cat')
+ # '*' matches any number (including 0) of any characters
+ assert_file.fnmatch('c*', 'cats')
+ assert_file.fnmatch('c*ts', 'cats')
+ assert_file.fnmatch('*ts', 'cats')
+ assert_file.fnmatch('*c*a*t*s*', 'cats')
+ assert_file.not_fnmatch('c*t', 'cats')
+ assert_file.not_fnmatch('*abc', 'abcabz')
+ assert_file.fnmatch('*abz', 'abcabz')
+ assert_file.not_fnmatch('a*abc', 'abc')
+ assert_file.fnmatch('a*bc', 'abc')
+ assert_file.not_fnmatch('a*bc', 'abcd')
+ # [seq] : matches any character listed between bracket
+ # [!seq] or [^seq] : matches any character except those listed between bracket
+ bracket_test("bd-gikl-mosv-x", "bdefgiklmosvwx")
+ # escaping character
+ assert_file.fnmatch('\?', '?')
+ assert_file.not_fnmatch('\?', '\?')
+ assert_file.not_fnmatch('\?', 'a')
+ assert_file.not_fnmatch('\?', '\a')
+ assert_file.fnmatch('\*', '*')
+ assert_file.not_fnmatch('\*', '\*')
+ assert_file.not_fnmatch('\*', 'cats')
+ assert_file.not_fnmatch('\*', '\cats')
+ assert_file.fnmatch('\a', 'a')
+ assert_file.not_fnmatch('\a', '\a')
+ assert_file.fnmatch('[a\-c]', 'a')
+ assert_file.fnmatch('[a\-c]', '-')
+ assert_file.fnmatch('[a\-c]', 'c')
+ assert_file.not_fnmatch('[a\-c]', 'b')
+ assert_file.not_fnmatch('[a\-c]', '\\')
+ # escaping character loses its meaning if FNM_NOESCAPE is set
+ assert_file.not_fnmatch('\?', '?', File::FNM_NOESCAPE)
+ assert_file.fnmatch('\?', '\?', File::FNM_NOESCAPE)
+ assert_file.not_fnmatch('\?', 'a', File::FNM_NOESCAPE)
+ assert_file.fnmatch('\?', '\a', File::FNM_NOESCAPE)
+ assert_file.not_fnmatch('\*', '*', File::FNM_NOESCAPE)
+ assert_file.fnmatch('\*', '\*', File::FNM_NOESCAPE)
+ assert_file.not_fnmatch('\*', 'cats', File::FNM_NOESCAPE)
+ assert_file.fnmatch('\*', '\cats', File::FNM_NOESCAPE)
+ assert_file.not_fnmatch('\a', 'a', File::FNM_NOESCAPE)
+ assert_file.fnmatch('\a', '\a', File::FNM_NOESCAPE)
+ assert_file.fnmatch('[a\-c]', 'a', File::FNM_NOESCAPE)
+ assert_file.not_fnmatch('[a\-c]', '-', File::FNM_NOESCAPE)
+ assert_file.fnmatch('[a\-c]', 'c', File::FNM_NOESCAPE)
+ assert_file.fnmatch('[a\-c]', 'b', File::FNM_NOESCAPE) # '\\' < 'b' < 'c'
+ assert_file.fnmatch('[a\-c]', '\\', File::FNM_NOESCAPE)
+ # case is ignored if FNM_CASEFOLD is set
+ assert_file.not_fnmatch('cat', 'CAT')
+ assert_file.fnmatch('cat', 'CAT', File::FNM_CASEFOLD)
+ assert_file.not_fnmatch('[a-z]', 'D')
+ assert_file.fnmatch('[a-z]', 'D', File::FNM_CASEFOLD)
+ assert_file.not_fnmatch('[abc]', 'B')
+ assert_file.fnmatch('[abc]', 'B', File::FNM_CASEFOLD)
+ # wildcard doesn't match '/' if FNM_PATHNAME is set
+ assert_file.fnmatch('foo?boo', 'foo/boo')
+ assert_file.fnmatch('foo*', 'foo/boo')
+ assert_file.not_fnmatch('foo?boo', 'foo/boo', File::FNM_PATHNAME)
+ assert_file.not_fnmatch('foo*', 'foo/boo', File::FNM_PATHNAME)
+ # wildcard matches leading period if FNM_DOTMATCH is set
+ assert_file.not_fnmatch('*', '.profile')
+ assert_file.fnmatch('*', '.profile', File::FNM_DOTMATCH)
+ assert_file.fnmatch('.*', '.profile')
+ assert_file.fnmatch('*', 'dave/.profile')
+ assert_file.fnmatch('*/*', 'dave/.profile')
+ assert_file.not_fnmatch('*/*', 'dave/.profile', File::FNM_PATHNAME)
+ assert_file.fnmatch('*/*', 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH)
+ # recursive matching
+ assert_file.fnmatch('**/foo', 'a/b/c/foo', File::FNM_PATHNAME)
+ assert_file.fnmatch('**/foo', '/foo', File::FNM_PATHNAME)
+ assert_file.not_fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME)
+ assert_file.fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH)
+ assert_file.fnmatch('**/foo', '/root/foo', File::FNM_PATHNAME)
+ assert_file.fnmatch('**/foo', 'c:/root/foo', File::FNM_PATHNAME)
+ end
+
+ def test_extglob
+ feature5422 = '[ruby-core:40037]'
+ assert_file.for(feature5422).not_fnmatch?( "{.g,t}*", ".gem")
+ assert_file.for(feature5422).fnmatch?("{.g,t}*", ".gem", File::FNM_EXTGLOB)
+ end
+
+ def test_unmatched_encoding
+ bug7911 = '[ruby-dev:47069] [Bug #7911]'
+ path = "\u{3042}"
+ pattern_ascii = 'a'.encode('US-ASCII')
+ pattern_eucjp = path.encode('EUC-JP')
+ assert_nothing_raised(ArgumentError, bug7911) do
+ assert_file.not_fnmatch(pattern_ascii, path)
+ assert_file.not_fnmatch(pattern_eucjp, path)
+ assert_file.not_fnmatch(pattern_ascii, path, File::FNM_CASEFOLD)
+ assert_file.not_fnmatch(pattern_eucjp, path, File::FNM_CASEFOLD)
+ assert_file.fnmatch("{*,#{pattern_ascii}}", path, File::FNM_EXTGLOB)
+ assert_file.fnmatch("{*,#{pattern_eucjp}}", path, File::FNM_EXTGLOB)
+ end
+ end
+
+ def test_unicode
+ assert_file.fnmatch("[a-\u3042]*", "\u3042")
+ assert_file.not_fnmatch("[a-\u3042]*", "\u3043")
+ end
+end
diff --git a/jni/ruby/test/ruby/test_gc.rb b/jni/ruby/test/ruby/test_gc.rb
new file mode 100644
index 0000000..e9e4bdc
--- /dev/null
+++ b/jni/ruby/test/ruby/test_gc.rb
@@ -0,0 +1,379 @@
+require 'test/unit'
+
+class TestGc < Test::Unit::TestCase
+ class S
+ def initialize(a)
+ @a = a
+ end
+ end
+
+ def test_gc
+ prev_stress = GC.stress
+ GC.stress = false
+
+ assert_nothing_raised do
+ 1.upto(10000) {
+ tmp = [0,1,2,3,4,5,6,7,8,9]
+ }
+ tmp = nil
+ end
+ l=nil
+ 100000.times {
+ l = S.new(l)
+ }
+ GC.start
+ assert true # reach here or dumps core
+ l = []
+ 100000.times {
+ l.push([l])
+ }
+ GC.start
+ assert true # reach here or dumps core
+
+ GC.stress = prev_stress
+ end
+
+ def use_rgengc?
+ GC::OPTS.include? 'USE_RGENGC'.freeze
+ end
+
+ def test_enable_disable
+ GC.enable
+ assert_equal(false, GC.enable)
+ assert_equal(false, GC.disable)
+ assert_equal(true, GC.disable)
+ assert_equal(true, GC.disable)
+ assert_nil(GC.start)
+ assert_equal(true, GC.enable)
+ assert_equal(false, GC.enable)
+ ensure
+ GC.enable
+ end
+
+ def test_start_full_mark
+ return unless use_rgengc?
+
+ GC.start(full_mark: false)
+ assert_nil GC.latest_gc_info(:major_by)
+
+ GC.start(full_mark: true)
+ assert_not_nil GC.latest_gc_info(:major_by)
+ end
+
+ def test_start_immediate_sweep
+ GC.start(immediate_sweep: false)
+ assert_equal false, GC.latest_gc_info(:immediate_sweep)
+
+ GC.start(immediate_sweep: true)
+ assert_equal true, GC.latest_gc_info(:immediate_sweep)
+ end
+
+ def test_count
+ c = GC.count
+ GC.start
+ assert_operator(c, :<, GC.count)
+ end
+
+ def test_stat
+ res = GC.stat
+ assert_equal(false, res.empty?)
+ assert_kind_of(Integer, res[:count])
+
+ arg = Hash.new
+ res = GC.stat(arg)
+ assert_equal(arg, res)
+ assert_equal(false, res.empty?)
+ assert_kind_of(Integer, res[:count])
+
+ stat, count = {}, {}
+ GC.start
+ GC.stat(stat)
+ ObjectSpace.count_objects(count)
+ assert_equal(count[:TOTAL]-count[:FREE], stat[:heap_live_slots])
+ assert_equal(count[:FREE], stat[:heap_free_slots])
+
+ # measure again without GC.start
+ 1000.times{ "a" + "b" }
+ GC.stat(stat)
+ ObjectSpace.count_objects(count)
+ assert_equal(count[:FREE], stat[:heap_free_slots])
+ end
+
+ def test_stat_argument
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {GC.stat(:"\u{30eb 30d3 30fc}")}
+ end
+
+ def test_stat_single
+ stat = GC.stat
+ assert_equal stat[:count], GC.stat(:count)
+ assert_raise(ArgumentError){ GC.stat(:invalid) }
+ end
+
+ def test_stat_constraints
+ stat = GC.stat
+ assert_equal stat[:total_allocated_pages], stat[:heap_allocated_pages] + stat[:total_freed_pages]
+ assert_operator stat[:heap_sorted_length], :>=, stat[:heap_eden_pages] + stat[:heap_allocatable_pages], "stat is: " + stat.inspect
+ assert_equal stat[:heap_available_slots], stat[:heap_live_slots] + stat[:heap_free_slots] + stat[:heap_final_slots]
+ assert_equal stat[:heap_live_slots], stat[:total_allocated_objects] - stat[:total_freed_objects] - stat[:heap_final_slots]
+ assert_equal stat[:heap_allocated_pages], stat[:heap_eden_pages] + stat[:heap_tomb_pages]
+
+ if use_rgengc?
+ assert_equal stat[:count], stat[:major_gc_count] + stat[:minor_gc_count]
+ end
+ end
+
+ def test_latest_gc_info
+ assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom'
+ GC.start
+ count = GC.stat(:heap_free_slots) + GC.stat(:heap_allocatable_pages) * GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT]
+ count.times{ "a" + "b" }
+ assert_equal :newobj, GC.latest_gc_info[:gc_by]
+ eom
+
+ GC.start
+ assert_equal :force, GC.latest_gc_info[:major_by] if use_rgengc?
+ assert_equal :method, GC.latest_gc_info[:gc_by]
+ assert_equal true, GC.latest_gc_info[:immediate_sweep]
+
+ GC.stress = true
+ assert_equal :force, GC.latest_gc_info[:major_by]
+ ensure
+ GC.stress = false
+ end
+
+ def test_latest_gc_info_argument
+ info = {}
+ GC.latest_gc_info(info)
+
+ assert_not_empty info
+ assert_equal info[:gc_by], GC.latest_gc_info(:gc_by)
+ assert_raises(ArgumentError){ GC.latest_gc_info(:invalid) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {GC.latest_gc_info(:"\u{30eb 30d3 30fc}")}
+ end
+
+ def test_singleton_method
+ assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:42832]")
+ GC.stress = true
+ 10.times do
+ obj = Object.new
+ def obj.foo() end
+ def obj.bar() raise "obj.foo is called, but this is obj.bar" end
+ obj.foo
+ end
+ EOS
+ end
+
+ def test_singleton_method_added
+ assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:44436]")
+ class BasicObject
+ undef singleton_method_added
+ def singleton_method_added(mid)
+ raise
+ end
+ end
+ b = proc {}
+ class << b; end
+ b.clone rescue nil
+ GC.start
+ EOS
+ end
+
+ def test_gc_parameter
+ env = {
+ "RUBY_GC_MALLOC_LIMIT" => "60000000",
+ "RUBY_GC_HEAP_INIT_SLOTS" => "100000"
+ }
+ assert_normal_exit("exit", "[ruby-core:39777]", :child_env => env)
+
+ env = {
+ "RUBYOPT" => "",
+ "RUBY_GC_HEAP_INIT_SLOTS" => "100000"
+ }
+ assert_in_out_err([env, "-e", "exit"], "", [], [], "[ruby-core:39795]")
+ assert_in_out_err([env, "-W0", "-e", "exit"], "", [], [], "[ruby-core:39795]")
+ assert_in_out_err([env, "-W1", "-e", "exit"], "", [], [], "[ruby-core:39795]")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_INIT_SLOTS=100000/, "[ruby-core:39795]")
+
+ env = {
+ "RUBY_GC_HEAP_GROWTH_FACTOR" => "2.0",
+ "RUBY_GC_HEAP_GROWTH_MAX_SLOTS" => "10000"
+ }
+ assert_normal_exit("exit", "", :child_env => env)
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_FACTOR=2.0/, "")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_MAX_SLOTS=10000/, "[ruby-core:57928]")
+
+ env = {
+ "RUBY_GC_HEAP_INIT_SLOTS" => "100000",
+ "RUBY_GC_HEAP_FREE_SLOTS" => "10000",
+ "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" => "0.9",
+ }
+ assert_normal_exit("exit", "", :child_env => env)
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=0\.9/, "")
+
+ # always full GC when RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR < 1.0
+ assert_in_out_err([env, "-e", "1000_000.times{Object.new}; p(GC.stat[:minor_gc_count] < GC.stat[:major_gc_count])"], "", ['true'], //, "") if use_rgengc?
+
+ # check obsolete
+ assert_in_out_err([{'RUBY_FREE_MIN' => '100'}, '-w', '-eexit'], '', [],
+ /RUBY_FREE_MIN is obsolete. Use RUBY_GC_HEAP_FREE_SLOTS instead/)
+ assert_in_out_err([{'RUBY_HEAP_MIN_SLOTS' => '100'}, '-w', '-eexit'], '', [],
+ /RUBY_HEAP_MIN_SLOTS is obsolete. Use RUBY_GC_HEAP_INIT_SLOTS instead/)
+
+ env = {
+ "RUBY_GC_MALLOC_LIMIT" => "60000000",
+ "RUBY_GC_MALLOC_LIMIT_MAX" => "160000000",
+ "RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR" => "2.0"
+ }
+ assert_normal_exit("exit", "", :child_env => env)
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT=6000000/, "")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT_MAX=16000000/, "")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=2.0/, "")
+
+ if use_rgengc?
+ env = {
+ "RUBY_GC_OLDMALLOC_LIMIT" => "60000000",
+ "RUBY_GC_OLDMALLOC_LIMIT_MAX" => "160000000",
+ "RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR" => "2.0"
+ }
+ assert_normal_exit("exit", "", :child_env => env)
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT=6000000/, "")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_MAX=16000000/, "")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=2.0/, "")
+ end
+ end
+
+ def test_profiler_enabled
+ GC::Profiler.enable
+ assert_equal(true, GC::Profiler.enabled?)
+ GC::Profiler.disable
+ assert_equal(false, GC::Profiler.enabled?)
+ ensure
+ GC::Profiler.disable
+ end
+
+ def test_profiler_clear
+ assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom'
+ GC::Profiler.enable
+
+ GC.start
+ assert_equal(1, GC::Profiler.raw_data.size)
+ GC::Profiler.clear
+ assert_equal(0, GC::Profiler.raw_data.size)
+
+ 200.times{ GC.start }
+ assert_equal(200, GC::Profiler.raw_data.size)
+ GC::Profiler.clear
+ assert_equal(0, GC::Profiler.raw_data.size)
+ eom
+ end
+
+ def test_profiler_total_time
+ GC::Profiler.enable
+ GC::Profiler.clear
+
+ GC.start
+ assert_operator(GC::Profiler.total_time, :>=, 0)
+ ensure
+ GC::Profiler.disable
+ end
+
+ def test_finalizing_main_thread
+ assert_in_out_err(%w[--disable-gems], <<-EOS, ["\"finalize\""], [], "[ruby-dev:46647]")
+ ObjectSpace.define_finalizer(Thread.main) { p 'finalize' }
+ EOS
+ end
+
+ def test_expand_heap
+ assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom'
+ GC.start
+ base_length = GC.stat[:heap_eden_pages]
+ (base_length * 500).times{ 'a' }
+ GC.start
+ assert_in_delta base_length, (v = GC.stat[:heap_eden_pages]), 1,
+ "invalid heap expanding (base_length: #{base_length}, GC.stat[:heap_eden_pages]: #{v})"
+
+ a = []
+ (base_length * 500).times{ a << 'a'; nil }
+ GC.start
+ assert_operator base_length, :<, GC.stat[:heap_eden_pages] + 1
+ eom
+ end
+
+ def test_gc_internals
+ assert_not_nil GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT]
+ assert_not_nil GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
+ end
+
+ def test_sweep_in_finalizer
+ bug9205 = '[ruby-core:58833] [Bug #9205]'
+ 2.times do
+ assert_ruby_status([], <<-'end;', bug9205, timeout: 60)
+ raise_proc = proc do |id|
+ GC.start
+ end
+ 1000.times do
+ ObjectSpace.define_finalizer(Object.new, raise_proc)
+ end
+ end;
+ end
+ end
+
+ def test_exception_in_finalizer
+ bug9168 = '[ruby-core:58652] [Bug #9168]'
+ assert_normal_exit(<<-'end;', bug9168)
+ raise_proc = proc {raise}
+ 10000.times do
+ ObjectSpace.define_finalizer(Object.new, raise_proc)
+ Thread.handle_interrupt(RuntimeError => :immediate) {break}
+ Thread.handle_interrupt(RuntimeError => :on_blocking) {break}
+ Thread.handle_interrupt(RuntimeError => :never) {break}
+ end
+ end;
+ end
+
+ def test_interrupt_in_finalizer
+ bug10595 = '[ruby-core:66825] [Bug #10595]'
+ src = <<-'end;'
+ pid = $$
+ Thread.start do
+ 10.times {
+ sleep 0.1
+ Process.kill("INT", pid) rescue break
+ }
+ sleep 5
+ Process.kill("SEGV", pid) rescue nil
+ Process.kill("KILL", pid) rescue nil
+ end
+ f = proc {1000.times {}}
+ loop do
+ ObjectSpace.define_finalizer(Object.new, f)
+ end
+ end;
+ status = assert_in_out_err(["-e", src], "", [], /Interrupt/, bug10595)
+ unless /mswin|mingw/ =~ RUBY_PLATFORM
+ assert_equal("INT", Signal.signame(status.termsig))
+ end
+ end
+
+ def test_verify_internal_consistency
+ assert_nil(GC.verify_internal_consistency)
+ end
+
+ def test_gc_stress_on_realloc
+ assert_normal_exit(<<-'end;', '[Bug #9859]')
+ class C
+ def initialize
+ @a = nil
+ @b = nil
+ @c = nil
+ @d = nil
+ @e = nil
+ @f = nil
+ end
+ end
+
+ GC.stress = true
+ C.new
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_hash.rb b/jni/ruby/test/ruby/test_hash.rb
new file mode 100644
index 0000000..1bb32f6
--- /dev/null
+++ b/jni/ruby/test/ruby/test_hash.rb
@@ -0,0 +1,1300 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+EnvUtil.suppress_warning {require 'continuation'}
+
+class TestHash < Test::Unit::TestCase
+
+ def test_hash
+ x = @cls[1=>2, 2=>4, 3=>6]
+ y = @cls[1=>2, 2=>4, 3=>6] # y = {1, 2, 2, 4, 3, 6} # 1.9 doesn't support
+
+ assert_equal(2, x[1])
+
+ assert(begin
+ for k,v in y
+ raise if k*2 != v
+ end
+ true
+ rescue
+ false
+ end)
+
+ assert_equal(3, x.length)
+ assert_send([x, :has_key?, 1])
+ assert_send([x, :has_value?, 4])
+ assert_equal([4,6], x.values_at(2,3))
+ assert_equal({1=>2, 2=>4, 3=>6}, x)
+
+ z = y.keys.join(":")
+ assert_equal("1:2:3", z)
+
+ z = y.values.join(":")
+ assert_equal("2:4:6", z)
+ assert_equal(x, y)
+
+ y.shift
+ assert_equal(2, y.length)
+
+ z = [1,2]
+ y[z] = 256
+ assert_equal(256, y[z])
+
+ x = Hash.new(0)
+ x[1] = 1
+ assert_equal(1, x[1])
+ assert_equal(0, x[2])
+
+ x = Hash.new([])
+ assert_equal([], x[22])
+ assert_same(x[22], x[22])
+
+ x = Hash.new{[]}
+ assert_equal([], x[22])
+ assert_not_same(x[22], x[22])
+
+ x = Hash.new{|h,kk| z = kk; h[kk] = kk*2}
+ z = 0
+ assert_equal(44, x[22])
+ assert_equal(22, z)
+ z = 0
+ assert_equal(44, x[22])
+ assert_equal(0, z)
+ x.default = 5
+ assert_equal(5, x[23])
+
+ x = Hash.new
+ def x.default(k)
+ $z = k
+ self[k] = k*2
+ end
+ $z = 0
+ assert_equal(44, x[22])
+ assert_equal(22, $z)
+ $z = 0
+ assert_equal(44, x[22])
+ assert_equal(0, $z)
+ end
+
+ # From rubicon
+
+ def setup
+ @cls ||= Hash
+ @h = @cls[
+ 1 => 'one', 2 => 'two', 3 => 'three',
+ self => 'self', true => 'true', nil => 'nil',
+ 'nil' => nil
+ ]
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_bad_initialize_copy
+ h = Class.new(Hash) {
+ def initialize_copy(h)
+ super(Object.new)
+ end
+ }.new
+ assert_raise(TypeError) { h.dup }
+ end
+
+ def test_clear_initialize_copy
+ h = @cls[1=>2]
+ h.instance_eval {initialize_copy({})}
+ assert_empty(h)
+ end
+
+ def test_self_initialize_copy
+ h = @cls[1=>2]
+ h.instance_eval {initialize_copy(h)}
+ assert_equal(2, h[1])
+ end
+
+ def test_dup_will_rehash
+ set1 = @cls[]
+ set2 = @cls[set1 => true]
+
+ set1[set1] = true
+
+ assert_equal set2, set2.dup
+ end
+
+ def test_s_AREF
+ h = @cls["a" => 100, "b" => 200]
+ assert_equal(100, h['a'])
+ assert_equal(200, h['b'])
+ assert_nil(h['c'])
+
+ h = @cls.[]("a" => 100, "b" => 200)
+ assert_equal(100, h['a'])
+ assert_equal(200, h['b'])
+ assert_nil(h['c'])
+ end
+
+ def test_s_new
+ h = @cls.new
+ assert_instance_of(@cls, h)
+ assert_nil(h.default)
+ assert_nil(h['spurious'])
+
+ h = @cls.new('default')
+ assert_instance_of(@cls, h)
+ assert_equal('default', h.default)
+ assert_equal('default', h['spurious'])
+
+ end
+
+ def test_AREF # '[]'
+ t = Time.now
+ h = @cls[
+ 1 => 'one', 2 => 'two', 3 => 'three',
+ self => 'self', t => 'time', nil => 'nil',
+ 'nil' => nil
+ ]
+
+ assert_equal('one', h[1])
+ assert_equal('two', h[2])
+ assert_equal('three', h[3])
+ assert_equal('self', h[self])
+ assert_equal('time', h[t])
+ assert_equal('nil', h[nil])
+ assert_equal(nil, h['nil'])
+ assert_equal(nil, h['koala'])
+
+ h1 = h.dup
+ h1.default = :default
+
+ assert_equal('one', h1[1])
+ assert_equal('two', h1[2])
+ assert_equal('three', h1[3])
+ assert_equal('self', h1[self])
+ assert_equal('time', h1[t])
+ assert_equal('nil', h1[nil])
+ assert_equal(nil, h1['nil'])
+ assert_equal(:default, h1['koala'])
+
+
+ end
+
+ def test_ASET # '[]='
+ t = Time.now
+ h = @cls.new
+ h[1] = 'one'
+ h[2] = 'two'
+ h[3] = 'three'
+ h[self] = 'self'
+ h[t] = 'time'
+ h[nil] = 'nil'
+ h['nil'] = nil
+ assert_equal('one', h[1])
+ assert_equal('two', h[2])
+ assert_equal('three', h[3])
+ assert_equal('self', h[self])
+ assert_equal('time', h[t])
+ assert_equal('nil', h[nil])
+ assert_equal(nil, h['nil'])
+ assert_equal(nil, h['koala'])
+
+ h[1] = 1
+ h[nil] = 99
+ h['nil'] = nil
+ z = [1,2]
+ h[z] = 256
+ assert_equal(1, h[1])
+ assert_equal('two', h[2])
+ assert_equal('three', h[3])
+ assert_equal('self', h[self])
+ assert_equal('time', h[t])
+ assert_equal(99, h[nil])
+ assert_equal(nil, h['nil'])
+ assert_equal(nil, h['koala'])
+ assert_equal(256, h[z])
+ end
+
+ def test_AREF_fstring_key
+ h = {"abc" => 1}
+ before = GC.stat(:total_allocated_objects)
+ 5.times{ h["abc"] }
+ assert_equal before, GC.stat(:total_allocated_objects)
+ end
+
+ def test_ASET_fstring_key
+ a, b = {}, {}
+ assert_equal 1, a["abc"] = 1
+ assert_equal 1, b["abc"] = 1
+ assert_same a.keys[0], b.keys[0]
+ end
+
+ def test_NEWHASH_fstring_key
+ a = {"ABC" => :t}
+ b = {"ABC" => :t}
+ assert_same a.keys[0], b.keys[0]
+ assert_same "ABC".freeze, a.keys[0]
+ end
+
+ def test_EQUAL # '=='
+ h1 = @cls[ "a" => 1, "c" => 2 ]
+ h2 = @cls[ "a" => 1, "c" => 2, 7 => 35 ]
+ h3 = @cls[ "a" => 1, "c" => 2, 7 => 35 ]
+ h4 = @cls[ ]
+ assert_equal(h1, h1)
+ assert_equal(h2, h2)
+ assert_equal(h3, h3)
+ assert_equal(h4, h4)
+ assert_not_equal(h1, h2)
+ assert_equal(h2, h3)
+ assert_not_equal(h3, h4)
+ end
+
+ def test_clear
+ assert_operator(@h.size, :>, 0)
+ @h.clear
+ assert_equal(0, @h.size)
+ assert_nil(@h[1])
+ end
+
+ def test_clone
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = @h.clone
+ a.taint if taint
+ a.freeze if frozen
+ b = a.clone
+
+ assert_equal(a, b)
+ assert_not_same(a, b)
+ assert_equal(a.frozen?, b.frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+ end
+
+ def test_default
+ assert_nil(@h.default)
+ h = @cls.new(:xyzzy)
+ assert_equal(:xyzzy, h.default)
+ end
+
+ def test_default=
+ assert_nil(@h.default)
+ @h.default = :xyzzy
+ assert_equal(:xyzzy, @h.default)
+ end
+
+ def test_delete
+ h1 = @cls[ 1 => 'one', 2 => 'two', true => 'true' ]
+ h2 = @cls[ 1 => 'one', 2 => 'two' ]
+ h3 = @cls[ 2 => 'two' ]
+
+ assert_equal('true', h1.delete(true))
+ assert_equal(h2, h1)
+
+ assert_equal('one', h1.delete(1))
+ assert_equal(h3, h1)
+
+ assert_equal('two', h1.delete(2))
+ assert_equal(@cls[], h1)
+
+ assert_nil(h1.delete(99))
+ assert_equal(@cls[], h1)
+
+ assert_equal('default 99', h1.delete(99) {|i| "default #{i}" })
+ end
+
+ def test_delete_if
+ base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ]
+ h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ]
+ h2 = @cls[ 2 => false, 'cat' => 99 ]
+ h3 = @cls[ 2 => false ]
+
+ h = base.dup
+ assert_equal(h, h.delete_if { false })
+ assert_equal(@cls[], h.delete_if { true })
+
+ h = base.dup
+ assert_equal(h1, h.delete_if {|k,v| k.instance_of?(String) })
+ assert_equal(h1, h)
+
+ h = base.dup
+ assert_equal(h2, h.delete_if {|k,v| v.instance_of?(String) })
+ assert_equal(h2, h)
+
+ h = base.dup
+ assert_equal(h3, h.delete_if {|k,v| v })
+ assert_equal(h3, h)
+
+ h = base.dup
+ n = 0
+ h.delete_if {|*a|
+ n += 1
+ assert_equal(2, a.size)
+ assert_equal(base[a[0]], a[1])
+ h.shift
+ true
+ }
+ assert_equal(base.size, n)
+ end
+
+ def test_keep_if
+ h = @cls[1=>2,3=>4,5=>6]
+ assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
+ h = @cls[1=>2,3=>4,5=>6]
+ assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
+ end
+
+ def test_dup
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = @h.dup
+ a.taint if taint
+ a.freeze if frozen
+ b = a.dup
+
+ assert_equal(a, b)
+ assert_not_same(a, b)
+ assert_equal(false, b.frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+ end
+
+ def test_dup_equality
+ h = @cls['k' => 'v']
+ assert_equal(h, h.dup)
+ h1 = @cls[h => 1]
+ assert_equal(h1, h1.dup)
+ h[1] = 2
+ assert_equal(h1, h1.dup)
+ end
+
+ def test_each
+ count = 0
+ @cls[].each { |k, v| count + 1 }
+ assert_equal(0, count)
+
+ h = @h
+ h.each do |k, v|
+ assert_equal(v, h.delete(k))
+ end
+ assert_equal(@cls[], h)
+
+ h = @cls[]
+ h[1] = 1
+ h[2] = 2
+ assert_equal([[1,1],[2,2]], h.each.to_a)
+ end
+
+ def test_each_key
+ count = 0
+ @cls[].each_key { |k| count + 1 }
+ assert_equal(0, count)
+
+ h = @h
+ h.each_key do |k|
+ h.delete(k)
+ end
+ assert_equal(@cls[], h)
+ end
+
+ def test_each_pair
+ count = 0
+ @cls[].each_pair { |k, v| count + 1 }
+ assert_equal(0, count)
+
+ h = @h
+ h.each_pair do |k, v|
+ assert_equal(v, h.delete(k))
+ end
+ assert_equal(@cls[], h)
+ end
+
+ def test_each_value
+ res = []
+ @cls[].each_value { |v| res << v }
+ assert_equal(0, [].length)
+
+ @h.each_value { |v| res << v }
+ assert_equal(0, [].length)
+
+ expected = []
+ @h.each { |k, v| expected << v }
+
+ assert_equal([], expected - res)
+ assert_equal([], res - expected)
+ end
+
+ def test_empty?
+ assert_empty(@cls[])
+ assert_not_empty(@h)
+ end
+
+ def test_fetch
+ assert_equal('gumbygumby', @h.fetch('gumby') {|k| k * 2 })
+ assert_equal('pokey', @h.fetch('gumby', 'pokey'))
+
+ assert_equal('one', @h.fetch(1))
+ assert_equal(nil, @h.fetch('nil'))
+ assert_equal('nil', @h.fetch(nil))
+ end
+
+ def test_fetch_error
+ assert_raise(KeyError) { @cls[].fetch(1) }
+ assert_raise(KeyError) { @h.fetch('gumby') }
+ e = assert_raise(KeyError) { @h.fetch('gumby'*20) }
+ assert_match(/key not found: "gumbygumby/, e.message)
+ assert_match(/\.\.\.\z/, e.message)
+ end
+
+ def test_key2?
+ assert_not_send([@cls[], :key?, 1])
+ assert_not_send([@cls[], :key?, nil])
+ assert_send([@h, :key?, nil])
+ assert_send([@h, :key?, 1])
+ assert_not_send([@h, :key?, 'gumby'])
+ end
+
+ def test_value?
+ assert_not_send([@cls[], :value?, 1])
+ assert_not_send([@cls[], :value?, nil])
+ assert_send([@h, :value?, 'one'])
+ assert_send([@h, :value?, nil])
+ assert_not_send([@h, :value?, 'gumby'])
+ end
+
+ def test_include?
+ assert_not_send([@cls[], :include?, 1])
+ assert_not_send([@cls[], :include?, nil])
+ assert_send([@h, :include?, nil])
+ assert_send([@h, :include?, 1])
+ assert_not_send([@h, :include?, 'gumby'])
+ end
+
+ def test_key
+ assert_equal(1, @h.key('one'))
+ assert_equal(nil, @h.key('nil'))
+ assert_equal('nil', @h.key(nil))
+
+ assert_equal(nil, @h.key('gumby'))
+ assert_equal(nil, @cls[].key('gumby'))
+ end
+
+ def test_values_at
+ res = @h.values_at('dog', 'cat', 'horse')
+ assert_equal(3, res.length)
+ assert_equal([nil, nil, nil], res)
+
+ res = @h.values_at
+ assert_equal(0, res.length)
+
+ res = @h.values_at(3, 2, 1, nil)
+ assert_equal 4, res.length
+ assert_equal %w( three two one nil ), res
+
+ res = @h.values_at(3, 99, 1, nil)
+ assert_equal 4, res.length
+ assert_equal ['three', nil, 'one', 'nil'], res
+ end
+
+
+ def test_invert
+ h = @h.invert
+ assert_equal(1, h['one'])
+ assert_equal(true, h['true'])
+ assert_equal(nil, h['nil'])
+
+ h.each do |k, v|
+ assert_send([@h, :key?, v]) # not true in general, but works here
+ end
+
+ h = @cls[ 'a' => 1, 'b' => 2, 'c' => 1].invert
+ assert_equal(2, h.length)
+ assert_include(%w[a c], h[1])
+ assert_equal('b', h[2])
+ end
+
+ def test_key?
+ assert_not_send([@cls[], :key?, 1])
+ assert_not_send([@cls[], :key?, nil])
+ assert_send([@h, :key?, nil])
+ assert_send([@h, :key?, 1])
+ assert_not_send([@h, :key?, 'gumby'])
+ end
+
+ def test_keys
+ assert_equal([], @cls[].keys)
+
+ keys = @h.keys
+ expected = []
+ @h.each { |k, v| expected << k }
+ assert_equal([], keys - expected)
+ assert_equal([], expected - keys)
+ end
+
+ def test_length
+ assert_equal(0, @cls[].length)
+ assert_equal(7, @h.length)
+ end
+
+ def test_member?
+ assert_not_send([@cls[], :member?, 1])
+ assert_not_send([@cls[], :member?, nil])
+ assert_send([@h, :member?, nil])
+ assert_send([@h, :member?, 1])
+ assert_not_send([@h, :member?, 'gumby'])
+ end
+
+ def test_rehash
+ a = [ "a", "b" ]
+ c = [ "c", "d" ]
+ h = @cls[ a => 100, c => 300 ]
+ assert_equal(100, h[a])
+ a[0] = "z"
+ assert_nil(h[a])
+ h.rehash
+ assert_equal(100, h[a])
+ end
+
+ def test_reject
+ assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].reject {|k, v| k + v < 7 })
+
+ base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ]
+ h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ]
+ h2 = @cls[ 2 => false, 'cat' => 99 ]
+ h3 = @cls[ 2 => false ]
+
+ h = base.dup
+ assert_equal(h, h.reject { false })
+ assert_equal(@cls[], h.reject { true })
+
+ h = base.dup
+ assert_equal(h1, h.reject {|k,v| k.instance_of?(String) })
+
+ assert_equal(h2, h.reject {|k,v| v.instance_of?(String) })
+
+ assert_equal(h3, h.reject {|k,v| v })
+ assert_equal(base, h)
+
+ h.instance_variable_set(:@foo, :foo)
+ h.default = 42
+ h.taint
+ h = EnvUtil.suppress_warning {h.reject {false}}
+ assert_instance_of(Hash, h)
+ assert_not_predicate(h, :tainted?)
+ assert_nil(h.default)
+ assert_not_send([h, :instance_variable_defined?, :@foo])
+ end
+
+ def test_reject!
+ base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ]
+ h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ]
+ h2 = @cls[ 2 => false, 'cat' => 99 ]
+ h3 = @cls[ 2 => false ]
+
+ h = base.dup
+ assert_equal(nil, h.reject! { false })
+ assert_equal(@cls[], h.reject! { true })
+
+ h = base.dup
+ assert_equal(h1, h.reject! {|k,v| k.instance_of?(String) })
+ assert_equal(h1, h)
+
+ h = base.dup
+ assert_equal(h2, h.reject! {|k,v| v.instance_of?(String) })
+ assert_equal(h2, h)
+
+ h = base.dup
+ assert_equal(h3, h.reject! {|k,v| v })
+ assert_equal(h3, h)
+ end
+
+ def test_replace
+ h = @cls[ 1 => 2, 3 => 4 ]
+ h1 = h.replace(@cls[ 9 => 8, 7 => 6 ])
+ assert_equal(h, h1)
+ assert_equal(8, h[9])
+ assert_equal(6, h[7])
+ assert_nil(h[1])
+ assert_nil(h[2])
+ end
+
+ def test_replace_bug9230
+ h = @cls[]
+ h.replace(@cls[])
+ assert_empty h
+
+ h = @cls[]
+ h.replace(@cls[].compare_by_identity)
+ assert_predicate(h, :compare_by_identity?)
+ end
+
+ def test_shift
+ h = @h.dup
+
+ @h.length.times {
+ k, v = h.shift
+ assert_send([@h, :key?, k])
+ assert_equal(@h[k], v)
+ }
+
+ assert_equal(0, h.length)
+ end
+
+ def test_size
+ assert_equal(0, @cls[].length)
+ assert_equal(7, @h.length)
+ end
+
+ def test_sort
+ h = @cls[].sort
+ assert_equal([], h)
+
+ h = @cls[ 1 => 1, 2 => 1 ].sort
+ assert_equal([[1,1], [2,1]], h)
+
+ h = @cls[ 'cat' => 'feline', 'ass' => 'asinine', 'bee' => 'beeline' ]
+ h1 = h.sort
+ assert_equal([ %w(ass asinine), %w(bee beeline), %w(cat feline)], h1)
+ end
+
+ def test_store
+ t = Time.now
+ h = @cls.new
+ h.store(1, 'one')
+ h.store(2, 'two')
+ h.store(3, 'three')
+ h.store(self, 'self')
+ h.store(t, 'time')
+ h.store(nil, 'nil')
+ h.store('nil', nil)
+ assert_equal('one', h[1])
+ assert_equal('two', h[2])
+ assert_equal('three', h[3])
+ assert_equal('self', h[self])
+ assert_equal('time', h[t])
+ assert_equal('nil', h[nil])
+ assert_equal(nil, h['nil'])
+ assert_equal(nil, h['koala'])
+
+ h.store(1, 1)
+ h.store(nil, 99)
+ h.store('nil', nil)
+ assert_equal(1, h[1])
+ assert_equal('two', h[2])
+ assert_equal('three', h[3])
+ assert_equal('self', h[self])
+ assert_equal('time', h[t])
+ assert_equal(99, h[nil])
+ assert_equal(nil, h['nil'])
+ assert_equal(nil, h['koala'])
+ end
+
+ def test_to_a
+ assert_equal([], @cls[].to_a)
+ assert_equal([[1,2]], @cls[ 1=>2 ].to_a)
+ a = @cls[ 1=>2, 3=>4, 5=>6 ].to_a
+ assert_equal([1,2], a.delete([1,2]))
+ assert_equal([3,4], a.delete([3,4]))
+ assert_equal([5,6], a.delete([5,6]))
+ assert_equal(0, a.length)
+
+ h = @cls[ 1=>2, 3=>4, 5=>6 ]
+ h.taint
+ a = h.to_a
+ assert_equal(true, a.tainted?)
+ end
+
+ def test_to_hash
+ h = @h.to_hash
+ assert_equal(@h, h)
+ assert_instance_of(@cls, h)
+ end
+
+ def test_to_h
+ h = @h.to_h
+ assert_equal(@h, h)
+ assert_instance_of(Hash, h)
+ end
+
+ def test_nil_to_h
+ h = nil.to_h
+ assert_equal({}, h)
+ assert_nil(h.default)
+ assert_nil(h.default_proc)
+ end
+
+ def test_to_s
+ h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ]
+ assert_equal(h.inspect, h.to_s)
+ $, = ":"
+ assert_equal(h.inspect, h.to_s)
+ h = @cls[]
+ assert_equal(h.inspect, h.to_s)
+ ensure
+ $, = nil
+ end
+
+ def test_update
+ h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ]
+ h2 = @cls[ 2 => 'two', 4 => 'four' ]
+
+ ha = @cls[ 1 => 2, 2 => 'two', 3 => 4, 4 => 'four' ]
+ hb = @cls[ 1 => 2, 2 => 3, 3 => 4, 4 => 'four' ]
+
+ assert_equal(ha, h1.update(h2))
+ assert_equal(ha, h1)
+
+ h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ]
+ h2 = @cls[ 2 => 'two', 4 => 'four' ]
+
+ assert_equal(hb, h2.update(h1))
+ assert_equal(hb, h2)
+ end
+
+ def test_value2?
+ assert_not_send([@cls[], :value?, 1])
+ assert_not_send([@cls[], :value?, nil])
+ assert_send([@h, :value?, nil])
+ assert_send([@h, :value?, 'one'])
+ assert_not_send([@h, :value?, 'gumby'])
+ end
+
+ def test_values
+ assert_equal([], @cls[].values)
+
+ vals = @h.values
+ expected = []
+ @h.each { |k, v| expected << v }
+ assert_equal([], vals - expected)
+ assert_equal([], expected - vals)
+ end
+
+ def test_intialize_wrong_arguments
+ assert_raise(ArgumentError) do
+ Hash.new(0) { }
+ end
+ end
+
+ def test_create
+ assert_equal({1=>2, 3=>4}, @cls[[[1,2],[3,4]]])
+ assert_raise(ArgumentError) { Hash[0, 1, 2] }
+ assert_warning(/wrong element type Fixnum at 1 /) {@cls[[[1, 2], 3]]}
+ bug5406 = '[ruby-core:39945]'
+ assert_raise(ArgumentError, bug5406) { @cls[[[1, 2], [3, 4, 5]]] }
+ assert_equal({1=>2, 3=>4}, @cls[1,2,3,4])
+ o = Object.new
+ def o.to_hash() {1=>2} end
+ assert_equal({1=>2}, @cls[o], "[ruby-dev:34555]")
+ end
+
+ def test_rehash2
+ h = @cls[1 => 2, 3 => 4]
+ assert_equal(h.dup, h.rehash)
+ assert_raise(RuntimeError) { h.each { h.rehash } }
+ assert_equal({}, @cls[].rehash)
+ end
+
+ def test_fetch2
+ assert_equal(:bar, @h.fetch(0, :foo) { :bar })
+ end
+
+ def test_default_proc
+ h = @cls.new {|hh, k| hh + k + "baz" }
+ assert_equal("foobarbaz", h.default_proc.call("foo", "bar"))
+ assert_nil(h.default_proc = nil)
+ assert_nil(h.default_proc)
+ h.default_proc = ->(_,_){ true }
+ assert_equal(true, h[:nope])
+ h = @cls[]
+ assert_nil(h.default_proc)
+ end
+
+ def test_shift2
+ h = @cls.new {|hh, k| :foo }
+ h[1] = 2
+ assert_equal([1, 2], h.shift)
+ assert_equal(:foo, h.shift)
+ assert_equal(:foo, h.shift)
+
+ h = @cls.new(:foo)
+ h[1] = 2
+ assert_equal([1, 2], h.shift)
+ assert_equal(:foo, h.shift)
+ assert_equal(:foo, h.shift)
+
+ h =@cls[1=>2]
+ h.each { assert_equal([1, 2], h.shift) }
+ end
+
+ def test_shift_none
+ h = @cls.new {|hh, k| "foo"}
+ def h.default(k = nil)
+ super.upcase
+ end
+ assert_equal("FOO", h.shift)
+ end
+
+ def test_reject_bang2
+ assert_equal({1=>2}, @cls[1=>2,3=>4].reject! {|k, v| k + v == 7 })
+ assert_nil(@cls[1=>2,3=>4].reject! {|k, v| k == 5 })
+ assert_nil(@cls[].reject! { })
+ end
+
+ def test_select
+ assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].select {|k, v| k + v >= 7 })
+
+ base = @cls[ 1 => 'one', '2' => false, true => 'true', 'cat' => 99 ]
+ h1 = @cls[ '2' => false, 'cat' => 99 ]
+ h2 = @cls[ 1 => 'one', true => 'true' ]
+ h3 = @cls[ 1 => 'one', true => 'true', 'cat' => 99 ]
+
+ h = base.dup
+ assert_equal(h, h.select { true })
+ assert_equal(@cls[], h.select { false })
+
+ h = base.dup
+ assert_equal(h1, h.select {|k,v| k.instance_of?(String) })
+
+ assert_equal(h2, h.select {|k,v| v.instance_of?(String) })
+
+ assert_equal(h3, h.select {|k,v| v })
+ assert_equal(base, h)
+
+ h.instance_variable_set(:@foo, :foo)
+ h.default = 42
+ h.taint
+ h = h.select {true}
+ assert_instance_of(Hash, h)
+ assert_not_predicate(h, :tainted?)
+ assert_nil(h.default)
+ assert_not_send([h, :instance_variable_defined?, :@foo])
+ end
+
+ def test_select!
+ h = @cls[1=>2,3=>4,5=>6]
+ assert_equal(h, h.select! {|k, v| k + v >= 7 })
+ assert_equal({3=>4,5=>6}, h)
+ h = @cls[1=>2,3=>4,5=>6]
+ assert_equal(nil, h.select!{true})
+ end
+
+ def test_clear2
+ assert_equal({}, @cls[1=>2,3=>4,5=>6].clear)
+ h = @cls[1=>2,3=>4,5=>6]
+ h.each { h.clear }
+ assert_equal({}, h)
+ end
+
+ def test_replace2
+ h1 = @cls.new { :foo }
+ h2 = @cls.new
+ h2.replace h1
+ assert_equal(:foo, h2[0])
+
+ assert_raise(ArgumentError) { h2.replace() }
+ assert_raise(TypeError) { h2.replace(1) }
+ h2.freeze
+ assert_raise(ArgumentError) { h2.replace() }
+ assert_raise(RuntimeError) { h2.replace(h1) }
+ assert_raise(RuntimeError) { h2.replace(42) }
+ end
+
+ def test_size2
+ assert_equal(0, @cls[].size)
+ end
+
+ def test_equal2
+ assert_not_equal(0, @cls[])
+ o = Object.new
+ o.instance_variable_set(:@cls, @cls)
+ def o.to_hash; @cls[]; end
+ def o.==(x); true; end
+ assert_equal({}, o)
+ def o.==(x); false; end
+ assert_not_equal({}, o)
+
+ h1 = @cls[1=>2]; h2 = @cls[3=>4]
+ assert_not_equal(h1, h2)
+ h1 = @cls[1=>2]; h2 = @cls[1=>4]
+ assert_not_equal(h1, h2)
+ end
+
+ def test_eql
+ assert_not_send([@cls[], :eql?, 0])
+ o = Object.new
+ o.instance_variable_set(:@cls, @cls)
+ def o.to_hash; @cls[]; end
+ def o.eql?(x); true; end
+ assert_send([@cls[], :eql?, o])
+ def o.eql?(x); false; end
+ assert_not_send([@cls[], :eql?, o])
+ end
+
+ def test_hash2
+ assert_kind_of(Integer, @cls[].hash)
+ h = @cls[1=>2]
+ h.shift
+ assert_equal({}.hash, h.hash, '[ruby-core:38650]')
+ bug9231 = '[ruby-core:58993] [Bug #9231]'
+ assert_not_equal(0, @cls[].hash, bug9231)
+ end
+
+ def test_update2
+ h1 = @cls[1=>2, 3=>4]
+ h2 = {1=>3, 5=>7}
+ h1.update(h2) {|k, v1, v2| k + v1 + v2 }
+ assert_equal({1=>6, 3=>4, 5=>7}, h1)
+ end
+
+ def test_merge
+ h1 = @cls[1=>2, 3=>4]
+ h2 = {1=>3, 5=>7}
+ assert_equal({1=>3, 3=>4, 5=>7}, h1.merge(h2))
+ assert_equal({1=>6, 3=>4, 5=>7}, h1.merge(h2) {|k, v1, v2| k + v1 + v2 })
+ end
+
+ def test_assoc
+ assert_equal([3,4], @cls[1=>2, 3=>4, 5=>6].assoc(3))
+ assert_nil(@cls[1=>2, 3=>4, 5=>6].assoc(4))
+ assert_equal([1.0,1], @cls[1.0=>1].assoc(1))
+ end
+
+ def test_assoc_compare_by_identity
+ h = @cls[]
+ h.compare_by_identity
+ h["a"] = 1
+ h["a".dup] = 2
+ assert_equal(["a",1], h.assoc("a"))
+ end
+
+ def test_rassoc
+ assert_equal([3,4], @cls[1=>2, 3=>4, 5=>6].rassoc(4))
+ assert_nil({1=>2, 3=>4, 5=>6}.rassoc(3))
+ end
+
+ def test_flatten
+ assert_equal([[1], [2]], @cls[[1] => [2]].flatten)
+
+ a = @cls[1=> "one", 2 => [2,"two"], 3 => [3, ["three"]]]
+ assert_equal([1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten)
+ assert_equal([[1, "one"], [2, [2, "two"]], [3, [3, ["three"]]]], a.flatten(0))
+ assert_equal([1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten(1))
+ assert_equal([1, "one", 2, 2, "two", 3, 3, ["three"]], a.flatten(2))
+ assert_equal([1, "one", 2, 2, "two", 3, 3, "three"], a.flatten(3))
+ assert_equal([1, "one", 2, 2, "two", 3, 3, "three"], a.flatten(-1))
+ assert_raise(TypeError){ a.flatten(Object) }
+ end
+
+ def test_callcc
+ h = @cls[1=>2]
+ c = nil
+ f = false
+ h.each { callcc {|c2| c = c2 } }
+ unless f
+ f = true
+ c.call
+ end
+ assert_raise(RuntimeError) { h.each { h.rehash } }
+
+ h = @cls[1=>2]
+ c = nil
+ assert_raise(RuntimeError) do
+ h.each { callcc {|c2| c = c2 } }
+ h.clear
+ c.call
+ end
+ end
+
+ def test_callcc_iter_level
+ bug9105 = '[ruby-dev:47803] [Bug #9105]'
+ h = @cls[1=>2, 3=>4]
+ c = nil
+ f = false
+ h.each {callcc {|c2| c = c2}}
+ unless f
+ f = true
+ c.call
+ end
+ assert_nothing_raised(RuntimeError, bug9105) do
+ h.each {|i, j|
+ h.delete(i);
+ assert_not_equal(false, i, bug9105)
+ }
+ end
+ end
+
+ def test_callcc_escape
+ bug9105 = '[ruby-dev:47803] [Bug #9105]'
+ assert_nothing_raised(RuntimeError, bug9105) do
+ h=@cls[]
+ cnt=0
+ c = callcc {|cc|cc}
+ h[cnt] = true
+ h.each{|i|
+ cnt+=1
+ c.call if cnt == 1
+ }
+ end
+ end
+
+ def test_callcc_reenter
+ bug9105 = '[ruby-dev:47803] [Bug #9105]'
+ assert_nothing_raised(RuntimeError, bug9105) do
+ h = @cls[1=>2,3=>4]
+ c = nil
+ f = false
+ h.each { |i|
+ callcc {|c2| c = c2 } unless c
+ h.delete(1) if f
+ }
+ unless f
+ f = true
+ c.call
+ end
+ end
+ end
+
+ def test_threaded_iter_level
+ bug9105 = '[ruby-dev:47807] [Bug #9105]'
+ h = @cls[1=>2]
+ 2.times.map {
+ f = false
+ th = Thread.start {h.each {f = true; sleep}}
+ Thread.pass until f
+ Thread.pass until th.stop?
+ th
+ }.each {|th| th.run; th.join}
+ assert_nothing_raised(RuntimeError, bug9105) do
+ h[5] = 6
+ end
+ assert_equal(6, h[5], bug9105)
+ end
+
+ def test_compare_by_identity
+ a = "foo"
+ assert_not_predicate(@cls[], :compare_by_identity?)
+ h = @cls[a => "bar"]
+ assert_not_predicate(h, :compare_by_identity?)
+ h.compare_by_identity
+ assert_predicate(h, :compare_by_identity?)
+ #assert_equal("bar", h[a])
+ assert_nil(h["foo"])
+
+ bug8703 = '[ruby-core:56256] [Bug #8703] copied identhash'
+ h.clear
+ assert_predicate(h.dup, :compare_by_identity?, bug8703)
+ end
+
+ def test_same_key
+ bug9646 = '[ruby-dev:48047] [Bug #9646] Infinite loop at Hash#each'
+ h = @cls[a=[], 1]
+ a << 1
+ h[[]] = 2
+ a.clear
+ cnt = 0
+ r = h.each{ break nil if (cnt+=1) > 100 }
+ assert_not_nil(r,bug9646)
+ end
+
+ class ObjWithHash
+ def initialize(value, hash)
+ @value = value
+ @hash = hash
+ end
+ attr_reader :value, :hash
+
+ def eql?(other)
+ @value == other.value
+ end
+ end
+
+ def test_hash_hash
+ assert_equal({0=>2,11=>1}.hash, @cls[11=>1,0=>2].hash)
+ o1 = ObjWithHash.new(0,1)
+ o2 = ObjWithHash.new(11,1)
+ assert_equal({o1=>1,o2=>2}.hash, @cls[o2=>2,o1=>1].hash)
+ end
+
+ def test_hash_bignum_hash
+ x = 2<<(32-3)-1
+ assert_equal({x=>1}.hash, @cls[x=>1].hash)
+ x = 2<<(64-3)-1
+ assert_equal({x=>1}.hash, @cls[x=>1].hash)
+
+ o = Object.new
+ def o.hash; 2 << 100; end
+ assert_equal({o=>1}.hash, @cls[o=>1].hash)
+ end
+
+ def test_hash_poped
+ assert_nothing_raised { eval("a = 1; @cls[a => a]; a") }
+ end
+
+ def test_recursive_key
+ h = @cls[]
+ assert_nothing_raised { h[h] = :foo }
+ h.rehash
+ assert_equal(:foo, h[h])
+ end
+
+ def test_inverse_hash
+ feature4262 = '[ruby-core:34334]'
+ [@cls[1=>2], @cls[123=>"abc"]].each do |h|
+ assert_not_equal(h.hash, h.invert.hash, feature4262)
+ end
+ end
+
+ def test_recursive_hash_value_struct
+ bug9151 = '[ruby-core:58567] [Bug #9151]'
+
+ s = Struct.new(:x) {def hash; [x,""].hash; end}
+ a = s.new
+ b = s.new
+ a.x = b
+ b.x = a
+ assert_nothing_raised(SystemStackError, bug9151) {a.hash}
+ assert_nothing_raised(SystemStackError, bug9151) {b.hash}
+
+ h = @cls[]
+ h[[a,"hello"]] = 1
+ assert_equal(1, h.size)
+ h[[b,"world"]] = 2
+ assert_equal(2, h.size)
+
+ obj = Object.new
+ h = @cls[a => obj]
+ assert_same(obj, h[b])
+ end
+
+ def test_recursive_hash_value_array
+ h = @cls[]
+ h[[[1]]] = 1
+ assert_equal(1, h.size)
+ h[[[2]]] = 1
+ assert_equal(2, h.size)
+
+ a = []
+ a << a
+
+ h = @cls[]
+ h[[a, 1]] = 1
+ assert_equal(1, h.size)
+ h[[a, 2]] = 2
+ assert_equal(2, h.size)
+ h[[a, a]] = 3
+ assert_equal(3, h.size)
+
+ obj = Object.new
+ h = @cls[a => obj]
+ assert_same(obj, h[[[a]]])
+ end
+
+ def test_recursive_hash_value_array_hash
+ h = @cls[]
+ rec = [h]
+ h[:x] = rec
+
+ obj = Object.new
+ h2 = {rec => obj}
+ [h, {x: rec}].each do |k|
+ k = [k]
+ assert_same(obj, h2[k], ->{k.inspect})
+ end
+ end
+
+ def test_recursive_hash_value_hash_array
+ h = @cls[]
+ rec = [h]
+ h[:x] = rec
+
+ obj = Object.new
+ h2 = {h => obj}
+ [rec, [h]].each do |k|
+ k = {x: k}
+ assert_same(obj, h2[k], ->{k.inspect})
+ end
+ end
+
+ def test_exception_in_rehash
+ return unless @cls == Hash
+
+ bug9187 = '[ruby-core:58728] [Bug #9187]'
+
+ prepare = <<-EOS
+ class Foo
+ def initialize
+ @raise = false
+ end
+
+ def hash
+ raise if @raise
+ @raise = true
+ return 0
+ end
+ end
+ h = {Foo.new => true}
+ EOS
+
+ code = <<-EOS
+ 10_0000.times do
+ h.rehash rescue nil
+ end
+ GC.start
+ EOS
+
+ assert_no_memory_leak([], prepare, code, bug9187)
+ end
+
+ def test_wrapper_of_special_const
+ bug9381 = '[ruby-core:59638] [Bug #9381]'
+
+ wrapper = Class.new do
+ def initialize(obj)
+ @obj = obj
+ end
+
+ def hash
+ @obj.hash
+ end
+
+ def eql?(other)
+ @obj.eql?(other)
+ end
+ end
+
+ bad = [
+ 5, true, false, nil,
+ 0.0, 1.72723e-77,
+ ].select do |x|
+ hash = {x => bug9381}
+ hash[wrapper.new(x)] != bug9381
+ end
+ assert_empty(bad, bug9381)
+ end
+
+ def test_label_syntax
+ return unless @cls == Hash
+
+ feature4935 = '[ruby-core:37553] [Feature #4935]'
+ x = 'world'
+ hash = assert_nothing_raised(SyntaxError) do
+ break eval(%q({foo: 1, "foo-bar": 2, "hello-#{x}": 3, 'hello-#{x}': 4, 'bar': {}}))
+ end
+ assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4, :bar => {}}, hash)
+ end
+
+ class TestSubHash < TestHash
+ class SubHash < Hash
+ def reject(*)
+ super
+ end
+ end
+
+ def setup
+ @cls = SubHash
+ super
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_ifunless.rb b/jni/ruby/test/ruby/test_ifunless.rb
new file mode 100644
index 0000000..e144ff8
--- /dev/null
+++ b/jni/ruby/test/ruby/test_ifunless.rb
@@ -0,0 +1,14 @@
+require 'test/unit'
+
+class TestIfunless < Test::Unit::TestCase
+ def test_if_unless
+ x = 'test';
+ assert(if x == x then true else false end)
+ bad = false
+ unless x == x
+ bad = true
+ end
+ assert(!bad)
+ assert(unless x != x then true else false end)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_integer.rb b/jni/ruby/test/ruby/test_integer.rb
new file mode 100644
index 0000000..3dbf365
--- /dev/null
+++ b/jni/ruby/test/ruby/test_integer.rb
@@ -0,0 +1,280 @@
+require 'test/unit'
+
+class TestInteger < Test::Unit::TestCase
+ BDSIZE = 0x4000000000000000.coerce(0)[0].size
+ def self.bdsize(x)
+ ((x + 1) / 8 + BDSIZE) / BDSIZE * BDSIZE
+ end
+ def bdsize(x)
+ self.class.bdsize(x)
+ end
+
+ def test_aref
+ # assert_equal(1, (1 << 0x40000000)[0x40000000], "[ruby-dev:31271]")
+ # assert_equal(0, (-1 << 0x40000001)[0x40000000], "[ruby-dev:31271]")
+ big_zero = 0x40000000.coerce(0)[0]
+ assert_equal(0, (-0x40000002)[big_zero], "[ruby-dev:31271]")
+ assert_equal(1, 0x400000001[big_zero], "[ruby-dev:31271]")
+ end
+
+ def test_pow
+ assert_not_equal(0, begin
+ 0**-1
+ rescue
+ nil
+ end, "[ruby-dev:32084] [ruby-dev:34547]")
+ end
+
+ def test_lshift
+ assert_equal(0, 1 << -0x40000000)
+ assert_equal(0, 1 << -0x40000001)
+ assert_equal(0, 1 << -0x80000000)
+ assert_equal(0, 1 << -0x80000001)
+ # assert_equal(bdsize(0x80000000), (1 << 0x80000000).size)
+ end
+
+ def test_rshift
+ # assert_equal(bdsize(0x40000001), (1 >> -0x40000001).size)
+ assert_predicate((1 >> 0x80000000), :zero?)
+ assert_predicate((1 >> 0xffffffff), :zero?)
+ assert_predicate((1 >> 0x100000000), :zero?)
+ # assert_equal((1 << 0x40000000), (1 >> -0x40000000))
+ # assert_equal((1 << 0x40000001), (1 >> -0x40000001))
+ end
+
+ def test_Integer
+ assert_raise(ArgumentError) {Integer("0x-1")}
+ assert_raise(ArgumentError) {Integer("-0x-1")}
+ assert_raise(ArgumentError) {Integer("0x 123")}
+ assert_raise(ArgumentError) {Integer("0x 123")}
+ assert_raise(ArgumentError) {Integer("0x0x5")}
+ assert_raise(ArgumentError) {Integer("0x0x000000005")}
+ assert_nothing_raised(ArgumentError) {
+ assert_equal(1540841, "0x0x5".to_i(36))
+ }
+ assert_raise(ArgumentError) { Integer("--0") }
+ assert_raise(ArgumentError) { Integer("-+0") }
+ assert_raise(ArgumentError) { Integer("++1") }
+ assert_raise(ArgumentError) { Integer("") }
+ assert_raise(ArgumentError) { Integer("10 x") }
+ assert_raise(ArgumentError) { Integer("1__2") }
+ assert_raise(ArgumentError) { Integer("1z") }
+ assert_raise(ArgumentError) { Integer("46116860184273__87904") }
+ assert_raise(ArgumentError) { Integer("4611686018427387904_") }
+ assert_raise(ArgumentError) { Integer("4611686018427387904 :") }
+ assert_equal(0x4000000000000000, Integer("46_11_686_0184273_87904"))
+ assert_raise(ArgumentError) { Integer("\0") }
+ assert_nothing_raised(ArgumentError, "[ruby-core:13873]") {
+ assert_equal(0, Integer("0 "))
+ }
+ assert_nothing_raised(ArgumentError, "[ruby-core:14139]") {
+ assert_equal(0377, Integer("0_3_7_7"))
+ }
+ assert_raise(ArgumentError, "[ruby-core:14139]") {Integer("0__3_7_7")}
+ assert_equal(1234, Integer(1234))
+ assert_equal(1, Integer(1.234))
+
+ # base argument
+ assert_equal(1234, Integer("1234", 10))
+ assert_equal(668, Integer("1234", 8))
+ assert_equal(4660, Integer("1234", 16))
+ assert_equal(49360, Integer("1234", 36))
+ # decimal, not octal
+ assert_equal(1234, Integer("01234", 10))
+ assert_raise(ArgumentError) { Integer("0x123", 10) }
+ assert_raise(ArgumentError) { Integer(1234, 10) }
+ assert_raise(ArgumentError) { Integer(12.34, 10) }
+ assert_raise(ArgumentError) { Integer(Object.new, 1) }
+
+ assert_raise(ArgumentError) { Integer(1, 1, 1) }
+
+ assert_equal(2 ** 50, Integer(2.0 ** 50))
+ assert_raise(TypeError) { Integer(nil) }
+
+ bug6192 = '[ruby-core:43566]'
+ assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16be"))}
+ assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16le"))}
+ assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32be"))}
+ assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32le"))}
+ assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("iso-2022-jp"))}
+ end
+
+ def test_int_p
+ assert_not_predicate(1.0, :integer?)
+ assert_predicate(1, :integer?)
+ end
+
+ def test_odd_p_even_p
+ Fixnum.class_eval do
+ alias odd_bak odd?
+ alias even_bak even?
+ remove_method :odd?, :even?
+ end
+
+ assert_predicate(1, :odd?)
+ assert_not_predicate(2, :odd?)
+ assert_not_predicate(1, :even?)
+ assert_predicate(2, :even?)
+
+ ensure
+ Fixnum.class_eval do
+ alias odd? odd_bak
+ alias even? even_bak
+ remove_method :odd_bak, :even_bak
+ end
+ end
+
+ def test_succ
+ assert_equal(2, 1.send(:succ))
+
+ Fixnum.class_eval do
+ alias succ_bak succ
+ remove_method :succ
+ end
+
+ assert_equal(2, 1.succ)
+ assert_equal(4294967297, 4294967296.succ)
+
+ ensure
+ Fixnum.class_eval do
+ alias succ succ_bak
+ remove_method :succ_bak
+ end
+ end
+
+ def test_chr
+ assert_equal("a", "a".ord.chr)
+ assert_raise(RangeError) { (-1).chr }
+ assert_raise(RangeError) { 0x100.chr }
+ end
+
+ def test_upto
+ a = []
+ 1.upto(3) {|x| a << x }
+ assert_equal([1, 2, 3], a)
+
+ a = []
+ 1.upto(0) {|x| a << x }
+ assert_equal([], a)
+
+ y = 2**30 - 1
+ a = []
+ y.upto(y+2) {|x| a << x }
+ assert_equal([y, y+1, y+2], a)
+ end
+
+ def test_downto
+ a = []
+ -1.downto(-3) {|x| a << x }
+ assert_equal([-1, -2, -3], a)
+
+ a = []
+ 1.downto(2) {|x| a << x }
+ assert_equal([], a)
+
+ y = -(2**30)
+ a = []
+ y.downto(y-2) {|x| a << x }
+ assert_equal([y, y-1, y-2], a)
+ end
+
+ def test_times
+ (2**32).times do |i|
+ break if i == 2
+ end
+ end
+
+ def test_round
+ assert_equal(11111, 11111.round)
+ assert_equal(Fixnum, 11111.round.class)
+ assert_equal(11111, 11111.round(0))
+ assert_equal(Fixnum, 11111.round(0).class)
+
+ assert_equal(11111.0, 11111.round(1))
+ assert_equal(Float, 11111.round(1).class)
+ assert_equal(11111.0, 11111.round(2))
+ assert_equal(Float, 11111.round(2).class)
+
+ assert_equal(11110, 11111.round(-1))
+ assert_equal(Fixnum, 11111.round(-1).class)
+ assert_equal(11100, 11111.round(-2))
+ assert_equal(Fixnum, 11111.round(-2).class)
+
+ assert_equal(1111_1111_1111_1111_1111_1111_1111_1110, 1111_1111_1111_1111_1111_1111_1111_1111.round(-1))
+ assert_equal(Bignum, 1111_1111_1111_1111_1111_1111_1111_1111.round(-1).class)
+ assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1))
+ assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class)
+ end
+
+ def test_bitwise_and_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { 3 & obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(3 & 10, 3 & obj)
+ end
+
+ def test_bitwise_or_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { 3 | obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(3 | 10, 3 | obj)
+ end
+
+ def test_bitwise_xor_with_integer_mimic_object
+ def (obj = Object.new).to_int
+ 10
+ end
+ assert_raise(TypeError, '[ruby-core:39491]') { 3 ^ obj }
+
+ def obj.coerce(other)
+ [other, 10]
+ end
+ assert_equal(3 ^ 10, 3 ^ obj)
+ end
+
+ def test_bit_length
+ assert_equal(13, (-2**12-1).bit_length)
+ assert_equal(12, (-2**12).bit_length)
+ assert_equal(12, (-2**12+1).bit_length)
+ assert_equal(9, -0x101.bit_length)
+ assert_equal(8, -0x100.bit_length)
+ assert_equal(8, -0xff.bit_length)
+ assert_equal(1, -2.bit_length)
+ assert_equal(0, -1.bit_length)
+ assert_equal(0, 0.bit_length)
+ assert_equal(1, 1.bit_length)
+ assert_equal(8, 0xff.bit_length)
+ assert_equal(9, 0x100.bit_length)
+ assert_equal(9, 0x101.bit_length)
+ assert_equal(12, (2**12-1).bit_length)
+ assert_equal(13, (2**12).bit_length)
+ assert_equal(13, (2**12+1).bit_length)
+
+ assert_equal(10001, (-2**10000-1).bit_length)
+ assert_equal(10000, (-2**10000).bit_length)
+ assert_equal(10000, (-2**10000+1).bit_length)
+ assert_equal(10000, (2**10000-1).bit_length)
+ assert_equal(10001, (2**10000).bit_length)
+ assert_equal(10001, (2**10000+1).bit_length)
+
+ 2.upto(1000) {|i|
+ n = 2**i
+ assert_equal(i+1, (-n-1).bit_length, "(#{-n-1}).bit_length")
+ assert_equal(i, (-n).bit_length, "(#{-n}).bit_length")
+ assert_equal(i, (-n+1).bit_length, "(#{-n+1}).bit_length")
+ assert_equal(i, (n-1).bit_length, "#{n-1}.bit_length")
+ assert_equal(i+1, (n).bit_length, "#{n}.bit_length")
+ assert_equal(i+1, (n+1).bit_length, "#{n+1}.bit_length")
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_integer_comb.rb b/jni/ruby/test/ruby/test_integer_comb.rb
new file mode 100644
index 0000000..e00e758
--- /dev/null
+++ b/jni/ruby/test/ruby/test_integer_comb.rb
@@ -0,0 +1,631 @@
+require 'test/unit'
+
+class TestIntegerComb < Test::Unit::TestCase
+ VS = [
+ -0x1000000000000000000000000000000000000000000000002,
+ -0x1000000000000000000000000000000000000000000000001,
+ -0x1000000000000000000000000000000000000000000000000,
+ -0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ -0x1000000000000000000000002,
+ -0x1000000000000000000000001,
+ -0x1000000000000000000000000,
+ -0xffffffffffffffffffffffff,
+ -0x10000000000000002,
+ -0x10000000000000001,
+ -0x10000000000000000,
+ -0xffffffffffffffff,
+ -0x4000000000000002,
+ -0x4000000000000001,
+ -0x4000000000000000,
+ -0x3fffffffffffffff,
+ -0x100000002,
+ -0x100000001,
+ -0x100000000,
+ -0xffffffff,
+ -0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001
+ -0x80000002,
+ -0x80000001,
+ -0x80000000,
+ -0x7fffffff,
+ -0x524b2245,
+ -0x40000002,
+ -0x40000001,
+ -0x40000000,
+ -0x3fffffff,
+ -0x10002,
+ -0x10001,
+ -0x10000,
+ -0xffff,
+ -0x8101, # 0x8101 * 0x7f01 = 0x40000001
+ -0x8002,
+ -0x8001,
+ -0x8000,
+ -0x7fff,
+ -0x7f01,
+ -65,
+ -64,
+ -63,
+ -62,
+ -33,
+ -32,
+ -31,
+ -30,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 30,
+ 31,
+ 32,
+ 33,
+ 62,
+ 63,
+ 64,
+ 65,
+ 0x7f01,
+ 0x7ffe,
+ 0x7fff,
+ 0x8000,
+ 0x8001,
+ 0x8101,
+ 0xfffe,
+ 0xffff,
+ 0x10000,
+ 0x10001,
+ 0x3ffffffe,
+ 0x3fffffff,
+ 0x40000000,
+ 0x40000001,
+ 0x524b2245,
+ 0x7ffffffe,
+ 0x7fffffff,
+ 0x80000000,
+ 0x80000001,
+ 0xc717a08d,
+ 0xfffffffe,
+ 0xffffffff,
+ 0x100000000,
+ 0x100000001,
+ 0x3ffffffffffffffe,
+ 0x3fffffffffffffff,
+ 0x4000000000000000,
+ 0x4000000000000001,
+ 0xfffffffffffffffe,
+ 0xffffffffffffffff,
+ 0x10000000000000000,
+ 0x10000000000000001,
+ 0xffffffffffffffffffffffff,
+ 0x1000000000000000000000000,
+ 0x1000000000000000000000001,
+ 0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ 0x1000000000000000000000000000000000000000000000000,
+ 0x1000000000000000000000000000000000000000000000001
+ ]
+
+ #VS.map! {|v| 0x4000000000000000.coerce(v)[0] }
+ #VS.concat VS.find_all {|v| Fixnum === v }.map {|v| 0x4000000000000000.coerce(v)[0] }
+ #VS.sort! {|a, b| a.abs <=> b.abs }
+
+ min = -1
+ min *= 2 while min.class == Fixnum
+ FIXNUM_MIN = min/2
+ max = 1
+ max *= 2 while (max-1).class == Fixnum
+ FIXNUM_MAX = max/2-1
+
+ def test_fixnum_range
+ assert_instance_of(Bignum, FIXNUM_MIN-1)
+ assert_instance_of(Fixnum, FIXNUM_MIN)
+ assert_instance_of(Fixnum, FIXNUM_MAX)
+ assert_instance_of(Bignum, FIXNUM_MAX+1)
+ end
+
+ def check_class(n)
+ if FIXNUM_MIN <= n && n <= FIXNUM_MAX
+ assert_instance_of(Fixnum, n)
+ else
+ assert_instance_of(Bignum, n)
+ end
+ end
+
+ def test_aref
+ VS.each {|a|
+ 100.times {|i|
+ assert_equal((a >> i).odd? ? 1 : 0, a[i], "(#{a})[#{i}]")
+ }
+ }
+ VS.each {|a|
+ VS.each {|b|
+ c = nil
+ assert_nothing_raised("(#{a})[#{b}]") { c = a[b] }
+ check_class(c)
+ if b < 0
+ assert_equal(0, c, "(#{a})[#{b}]")
+ else
+ assert_equal((a >> b).odd? ? 1 : 0, c, "(#{a})[#{b}]")
+ end
+ }
+ }
+ end
+
+ def test_plus
+ VS.each {|a|
+ VS.each {|b|
+ c = a + b
+ check_class(c)
+ assert_equal(b + a, c, "#{a} + #{b}")
+ assert_equal(a, c - b, "(#{a} + #{b}) - #{b}")
+ assert_equal(a-~b-1, c, "#{a} + #{b}") # Hacker's Delight
+ assert_equal((a^b)+2*(a&b), c, "#{a} + #{b}") # Hacker's Delight
+ assert_equal((a|b)+(a&b), c, "#{a} + #{b}") # Hacker's Delight
+ assert_equal(2*(a|b)-(a^b), c, "#{a} + #{b}") # Hacker's Delight
+ }
+ }
+ end
+
+ def test_minus
+ VS.each {|a|
+ VS.each {|b|
+ c = a - b
+ check_class(c)
+ assert_equal(a, c + b, "(#{a} - #{b}) + #{b}")
+ assert_equal(-b, c - a, "(#{a} - #{b}) - #{a}")
+ assert_equal(a+~b+1, c, "#{a} - #{b}") # Hacker's Delight
+ assert_equal((a^b)-2*(b&~a), c, "#{a} - #{b}") # Hacker's Delight
+ assert_equal((a&~b)-(b&~a), c, "#{a} - #{b}") # Hacker's Delight
+ assert_equal(2*(a&~b)-(a^b), c, "#{a} - #{b}") # Hacker's Delight
+ }
+ }
+ end
+
+ def test_mult
+ VS.each {|a|
+ VS.each {|b|
+ c = a * b
+ check_class(c)
+ assert_equal(b * a, c, "#{a} * #{b}")
+ assert_equal(b.send(:*, a), c, "#{a} * #{b}")
+ assert_equal(b, c / a, "(#{a} * #{b}) / #{a}") if a != 0
+ assert_equal(a.abs * b.abs, (a * b).abs, "(#{a} * #{b}).abs")
+ assert_equal((a-100)*(b-100)+(a-100)*100+(b-100)*100+10000, c, "#{a} * #{b}")
+ assert_equal((a+100)*(b+100)-(a+100)*100-(b+100)*100+10000, c, "#{a} * #{b}")
+ }
+ }
+ end
+
+ def test_divmod
+ VS.each {|a|
+ VS.each {|b|
+ if b == 0
+ assert_raise(ZeroDivisionError) { a.divmod(b) }
+ else
+ q, r = a.divmod(b)
+ check_class(q)
+ check_class(r)
+ assert_equal(a, b*q+r)
+ assert_operator(r.abs, :<, b.abs)
+ if 0 < b
+ assert_operator(r, :>=, 0)
+ assert_operator(r, :<, b)
+ else
+ assert_operator(r, :>, b)
+ assert_operator(r, :<=, 0)
+ end
+ assert_equal(q, a/b)
+ assert_equal(q, a.div(b))
+ assert_equal(r, a%b)
+ assert_equal(r, a.modulo(b))
+ end
+ }
+ }
+ end
+
+ def test_pow
+ small_values = VS.find_all {|v| 0 <= v && v < 1000 }
+ VS.each {|a|
+ small_values.each {|b|
+ c = a ** b
+ check_class(c)
+ d = 1
+ b.times { d *= a }
+ assert_equal(d, c, "(#{a}) ** #{b}")
+ if a != 0
+ d = c
+ b.times { d /= a }
+ assert_equal(1, d, "((#{a}) ** #{b}) / #{a} / ...(#{b} times)...")
+ end
+ }
+ }
+ end
+
+ def test_not
+ VS.each {|a|
+ b = ~a
+ check_class(b)
+ assert_equal(-1 ^ a, b, "~#{a}")
+ assert_equal(-a-1, b, "~#{a}") # Hacker's Delight
+ assert_equal(0, a & b, "#{a} & ~#{a}")
+ assert_equal(-1, a | b, "#{a} | ~#{a}")
+ }
+ end
+
+ def test_or
+ VS.each {|a|
+ VS.each {|b|
+ c = a | b
+ check_class(c)
+ assert_equal(b | a, c, "#{a} | #{b}")
+ assert_equal(a + b - (a&b), c, "#{a} | #{b}")
+ assert_equal((a & ~b) + b, c, "#{a} | #{b}") # Hacker's Delight
+ assert_equal(-1, c | ~a, "(#{a} | #{b}) | ~#{a})")
+ }
+ }
+ end
+
+ def test_and
+ VS.each {|a|
+ VS.each {|b|
+ c = a & b
+ check_class(c)
+ assert_equal(b & a, c, "#{a} & #{b}")
+ assert_equal(a + b - (a|b), c, "#{a} & #{b}")
+ assert_equal((~a | b) - ~a, c, "#{a} & #{b}") # Hacker's Delight
+ assert_equal(0, c & ~a, "(#{a} & #{b}) & ~#{a}")
+ }
+ }
+ end
+
+ def test_xor
+ VS.each {|a|
+ VS.each {|b|
+ c = a ^ b
+ check_class(c)
+ assert_equal(b ^ a, c, "#{a} ^ #{b}")
+ assert_equal((a|b)-(a&b), c, "#{a} ^ #{b}") # Hacker's Delight
+ assert_equal(b, c ^ a, "(#{a} ^ #{b}) ^ #{a}")
+ }
+ }
+ end
+
+ def test_lshift
+ small_values = VS.find_all {|v| v < 8000 }
+ VS.each {|a|
+ small_values.each {|b|
+ c = a << b
+ check_class(c)
+ if 0 <= b
+ assert_equal(a, c >> b, "(#{a} << #{b}) >> #{b}")
+ assert_equal(a * 2**b, c, "#{a} << #{b}")
+ end
+ 0.upto(c.size*8+10) {|nth|
+ assert_equal(a[nth-b], c[nth], "(#{a} << #{b})[#{nth}]")
+ }
+ }
+ }
+ end
+
+ def test_rshift
+ small_values = VS.find_all {|v| -8000 < v }
+ VS.each {|a|
+ small_values.each {|b|
+ c = a >> b
+ check_class(c)
+ if b <= 0
+ assert_equal(a, c << b, "(#{a} >> #{b}) << #{b}")
+ assert_equal(a * 2**(-b), c, "#{a} >> #{b}")
+ end
+ 0.upto(c.size*8+10) {|nth|
+ assert_equal(a[nth+b], c[nth], "(#{a} >> #{b})[#{nth}]")
+ }
+ }
+ }
+ end
+
+ def test_succ
+ VS.each {|a|
+ b = a.succ
+ check_class(b)
+ assert_equal(a+1, b, "(#{a}).succ")
+ assert_equal(a, b.pred, "(#{a}).succ.pred")
+ assert_equal(a, b-1, "(#{a}).succ - 1")
+ }
+ end
+
+ def test_pred
+ VS.each {|a|
+ b = a.pred
+ check_class(b)
+ assert_equal(a-1, b, "(#{a}).pred")
+ assert_equal(a, b.succ, "(#{a}).pred.succ")
+ assert_equal(a, b + 1, "(#{a}).pred + 1")
+ }
+ end
+
+ def test_unary_plus
+ VS.each {|a|
+ b = +a
+ check_class(b)
+ assert_equal(a, b, "+(#{a})")
+ }
+ end
+
+ def test_unary_minus
+ VS.each {|a|
+ b = -a
+ check_class(b)
+ assert_equal(0-a, b, "-(#{a})")
+ assert_equal(~a+1, b, "-(#{a})")
+ assert_equal(0, a+b, "#{a}+(-(#{a}))")
+ }
+ end
+
+ def test_cmp
+ VS.each_with_index {|a, i|
+ VS.each_with_index {|b, j|
+ assert_equal(i <=> j, a <=> b, "#{a} <=> #{b}")
+ assert_equal(i < j, a < b, "#{a} < #{b}")
+ assert_equal(i <= j, a <= b, "#{a} <= #{b}")
+ assert_equal(i > j, a > b, "#{a} > #{b}")
+ assert_equal(i >= j, a >= b, "#{a} >= #{b}")
+ }
+ }
+ end
+
+ def test_eq
+ VS.each_with_index {|a, i|
+ VS.each_with_index {|b, j|
+ c = a == b
+ assert_equal(b == a, c, "#{a} == #{b}")
+ assert_equal(i == j, c, "#{a} == #{b}")
+ }
+ }
+ end
+
+ def test_abs
+ VS.each {|a|
+ b = a.abs
+ check_class(b)
+ if a < 0
+ assert_equal(-a, b, "(#{a}).abs")
+ else
+ assert_equal(a, b, "(#{a}).abs")
+ end
+ }
+ end
+
+ def test_ceil
+ VS.each {|a|
+ b = a.ceil
+ check_class(b)
+ assert_equal(a, b, "(#{a}).ceil")
+ }
+ end
+
+ def test_floor
+ VS.each {|a|
+ b = a.floor
+ check_class(b)
+ assert_equal(a, b, "(#{a}).floor")
+ }
+ end
+
+ def test_round
+ VS.each {|a|
+ b = a.round
+ check_class(b)
+ assert_equal(a, b, "(#{a}).round")
+ }
+ end
+
+ def test_truncate
+ VS.each {|a|
+ b = a.truncate
+ check_class(b)
+ assert_equal(a, b, "(#{a}).truncate")
+ }
+ end
+
+ def test_remainder
+ VS.each {|a|
+ VS.each {|b|
+ if b == 0
+ assert_raise(ZeroDivisionError) { a.divmod(b) }
+ else
+ r = a.remainder(b)
+ check_class(r)
+ if a < 0
+ assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})")
+ assert_operator(0, :>=, r, "#{a}.remainder(#{b})")
+ elsif 0 < a
+ assert_operator(0, :<=, r, "#{a}.remainder(#{b})")
+ assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})")
+ else
+ assert_equal(0, r, "#{a}.remainder(#{b})")
+ end
+ end
+ }
+ }
+ end
+
+ def test_zero_nonzero
+ VS.each {|a|
+ z = a.zero?
+ n = a.nonzero?
+ if a == 0
+ assert_equal(true, z, "(#{a}).zero?")
+ assert_equal(nil, n, "(#{a}).nonzero?")
+ else
+ assert_equal(false, z, "(#{a}).zero?")
+ assert_equal(a, n, "(#{a}).nonzero?")
+ check_class(n)
+ end
+ assert(z ^ n, "(#{a}).zero? ^ (#{a}).nonzero?")
+ }
+ end
+
+ def test_even_odd
+ VS.each {|a|
+ e = a.even?
+ o = a.odd?
+ assert_equal((a % 2) == 0, e, "(#{a}).even?")
+ assert_equal((a % 2) == 1, o, "(#{a}).odd")
+ assert_equal((a & 1) == 0, e, "(#{a}).even?")
+ assert_equal((a & 1) == 1, o, "(#{a}).odd")
+ assert(e ^ o, "(#{a}).even? ^ (#{a}).odd?")
+ }
+ end
+
+ def test_to_s
+ 2.upto(36) {|radix|
+ VS.each {|a|
+ s = a.to_s(radix)
+ b = s.to_i(radix)
+ assert_equal(a, b, "(#{a}).to_s(#{radix}).to_i(#{radix})")
+ }
+ }
+ end
+
+ def test_printf_x
+ VS.reverse_each {|a|
+ s = sprintf("%x", a)
+ if /\A\.\./ =~ s
+ b = -($'.tr('0123456789abcdef', 'fedcba9876543210').to_i(16) + 1)
+ else
+ b = s.to_i(16)
+ end
+ assert_equal(a, b, "sprintf('%x', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_x_sign
+ VS.reverse_each {|a|
+ s = sprintf("%+x", a)
+ b = s.to_i(16)
+ assert_equal(a, b, "sprintf('%+x', #{a}) = #{s.inspect}")
+ s = sprintf("% x", a)
+ b = s.to_i(16)
+ assert_equal(a, b, "sprintf('% x', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_o
+ VS.reverse_each {|a|
+ s = sprintf("%o", a)
+ if /\A\.\./ =~ s
+ b = -($'.tr('01234567', '76543210').to_i(8) + 1)
+ else
+ b = s.to_i(8)
+ end
+ assert_equal(a, b, "sprintf('%o', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_o_sign
+ VS.reverse_each {|a|
+ s = sprintf("%+o", a)
+ b = s.to_i(8)
+ assert_equal(a, b, "sprintf('%+o', #{a}) = #{s.inspect}")
+ s = sprintf("% o", a)
+ b = s.to_i(8)
+ assert_equal(a, b, "sprintf('% o', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_b
+ VS.reverse_each {|a|
+ s = sprintf("%b", a)
+ if /\A\.\./ =~ s
+ b = -($'.tr('01', '10').to_i(2) + 1)
+ else
+ b = s.to_i(2)
+ end
+ assert_equal(a, b, "sprintf('%b', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_b_sign
+ VS.reverse_each {|a|
+ s = sprintf("%+b", a)
+ b = s.to_i(2)
+ assert_equal(a, b, "sprintf('%+b', #{a}) = #{s.inspect}")
+ s = sprintf("% b", a)
+ b = s.to_i(2)
+ assert_equal(a, b, "sprintf('% b', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_printf_diu
+ VS.reverse_each {|a|
+ s = sprintf("%d", a)
+ b = s.to_i
+ assert_equal(a, b, "sprintf('%d', #{a}) = #{s.inspect}")
+ s = sprintf("%i", a)
+ b = s.to_i
+ assert_equal(a, b, "sprintf('%i', #{a}) = #{s.inspect}")
+ s = sprintf("%u", a)
+ b = s.to_i
+ assert_equal(a, b, "sprintf('%u', #{a}) = #{s.inspect}")
+ }
+ end
+
+ def test_marshal
+ VS.reverse_each {|a|
+ s = Marshal.dump(a)
+ b = Marshal.load(s)
+ assert_equal(a, b, "Marshal.load(Marshal.dump(#{a}))")
+ }
+ end
+
+ def test_pack
+ %w[c C s S s! S! i I i! I! l L l! L! q Q n N v V].each {|template|
+ size = [0].pack(template).size
+ mask = (1 << (size * 8)) - 1
+ if /[A-Znv]/ =~ template
+ min = 0
+ max = (1 << (size * 8))-1
+ else
+ min = -(1 << (size * 8 - 1))
+ max = (1 << (size * 8 - 1)) - 1
+ end
+ VS.reverse_each {|a|
+ s = [a].pack(template)
+ b = s.unpack(template)[0]
+ if min <= a && a <= max
+ assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})[0]")
+ end
+ assert_operator(min, :<=, b)
+ assert_operator(b, :<=, max)
+ assert_equal(a & mask, b & mask, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})[0] & #{mask}")
+ }
+ }
+ end
+
+ def test_pack_ber
+ template = "w"
+ VS.reverse_each {|a|
+ if a < 0
+ assert_raise(ArgumentError) { [a].pack(template) }
+ else
+ s = [a].pack(template)
+ b = s.unpack(template)[0]
+ assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
+ end
+ }
+ end
+
+ def test_pack_utf8
+ template = "U"
+ VS.reverse_each {|a|
+ if a < 0 || 0x7fffffff < a
+ assert_raise(RangeError) { [a].pack(template) }
+ else
+ s = [a].pack(template)
+ b = s.unpack(template)[0]
+ assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
+ end
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_io.rb b/jni/ruby/test/ruby/test_io.rb
new file mode 100644
index 0000000..d0ca5e6
--- /dev/null
+++ b/jni/ruby/test/ruby/test_io.rb
@@ -0,0 +1,3171 @@
+# coding: US-ASCII
+require 'test/unit'
+require 'tmpdir'
+require "fcntl"
+require 'io/nonblock'
+require 'socket'
+require 'stringio'
+require 'timeout'
+require 'tempfile'
+require 'weakref'
+
+class TestIO < Test::Unit::TestCase
+ module Feature
+ def have_close_on_exec?
+ $stdin.close_on_exec?
+ true
+ rescue NotImplementedError
+ false
+ end
+
+ def have_nonblock?
+ IO.method_defined?("nonblock=")
+ end
+ end
+
+ include Feature
+ extend Feature
+
+ def pipe(wp, rp)
+ re, we = nil, nil
+ r, w = IO.pipe
+ rt = Thread.new do
+ begin
+ rp.call(r)
+ rescue Exception
+ r.close
+ re = $!
+ end
+ end
+ wt = Thread.new do
+ begin
+ wp.call(w)
+ rescue Exception
+ w.close
+ we = $!
+ end
+ end
+ flunk("timeout") unless wt.join(10) && rt.join(10)
+ ensure
+ w.close unless !w || w.closed?
+ r.close unless !r || r.closed?
+ (wt.kill; wt.join) if wt
+ (rt.kill; rt.join) if rt
+ raise we if we
+ raise re if re
+ end
+
+ def with_pipe
+ r, w = IO.pipe
+ begin
+ yield r, w
+ ensure
+ r.close unless r.closed?
+ w.close unless w.closed?
+ end
+ end
+
+ def with_read_pipe(content)
+ pipe(proc do |w|
+ w << content
+ w.close
+ end, proc do |r|
+ yield r
+ end)
+ end
+
+ def mkcdtmpdir
+ Dir.mktmpdir {|d|
+ Dir.chdir(d) {
+ yield
+ }
+ }
+ end
+
+ def trapping_usr1
+ @usr1_rcvd = 0
+ trap(:USR1) { @usr1_rcvd += 1 }
+ yield
+ ensure
+ trap(:USR1, "DEFAULT")
+ end
+
+ def test_pipe
+ r, w = IO.pipe
+ assert_instance_of(IO, r)
+ assert_instance_of(IO, w)
+ [
+ Thread.start{
+ w.print "abc"
+ w.close
+ },
+ Thread.start{
+ assert_equal("abc", r.read)
+ r.close
+ }
+ ].each{|thr| thr.join}
+ end
+
+ def test_pipe_block
+ x = nil
+ ret = IO.pipe {|r, w|
+ x = [r,w]
+ assert_instance_of(IO, r)
+ assert_instance_of(IO, w)
+ [
+ Thread.start do
+ w.print "abc"
+ w.close
+ end,
+ Thread.start do
+ assert_equal("abc", r.read)
+ end
+ ].each{|thr| thr.join}
+ assert_not_predicate(r, :closed?)
+ assert_predicate(w, :closed?)
+ :foooo
+ }
+ assert_equal(:foooo, ret)
+ assert_predicate(x[0], :closed?)
+ assert_predicate(x[1], :closed?)
+ end
+
+ def test_pipe_block_close
+ 4.times {|i|
+ x = nil
+ IO.pipe {|r, w|
+ x = [r,w]
+ r.close if (i&1) == 0
+ w.close if (i&2) == 0
+ }
+ assert_predicate(x[0], :closed?)
+ assert_predicate(x[1], :closed?)
+ }
+ end
+
+ def test_gets_rs
+ # default_rs
+ pipe(proc do |w|
+ w.print "aaa\nbbb\n"
+ w.close
+ end, proc do |r|
+ assert_equal "aaa\n", r.gets
+ assert_equal "bbb\n", r.gets
+ assert_nil r.gets
+ r.close
+ end)
+
+ # nil
+ pipe(proc do |w|
+ w.print "a\n\nb\n\n"
+ w.close
+ end, proc do |r|
+ assert_equal "a\n\nb\n\n", r.gets(nil)
+ assert_nil r.gets("")
+ r.close
+ end)
+
+ # "\377"
+ pipe(proc do |w|
+ w.print "\377xyz"
+ w.close
+ end, proc do |r|
+ r.binmode
+ assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]")
+ r.close
+ end)
+
+ # ""
+ pipe(proc do |w|
+ w.print "a\n\nb\n\n"
+ w.close
+ end, proc do |r|
+ assert_equal "a\n\n", r.gets(""), "[ruby-core:03771]"
+ assert_equal "b\n\n", r.gets("")
+ assert_nil r.gets("")
+ r.close
+ end)
+ end
+
+ def test_gets_limit_extra_arg
+ pipe(proc do |w|
+ w << "0123456789\n0123456789"
+ w.close
+ end, proc do |r|
+ assert_equal("0123456789\n0", r.gets(nil, 12))
+ assert_raise(TypeError) { r.gets(3,nil) }
+ end)
+ end
+
+ # This test cause SEGV.
+ def test_ungetc
+ pipe(proc do |w|
+ w.close
+ end, proc do |r|
+ s = "a" * 1000
+ assert_raise(IOError, "[ruby-dev:31650]") { 200.times { r.ungetc s } }
+ end)
+ end
+
+ def test_ungetbyte
+ make_tempfile {|t|
+ t.open
+ t.binmode
+ t.ungetbyte(0x41)
+ assert_equal(-1, t.pos)
+ assert_equal(0x41, t.getbyte)
+ t.rewind
+ assert_equal(0, t.pos)
+ t.ungetbyte("qux")
+ assert_equal(-3, t.pos)
+ assert_equal("quxfoo\n", t.gets)
+ assert_equal(4, t.pos)
+ t.set_encoding("utf-8")
+ t.ungetbyte(0x89)
+ t.ungetbyte(0x8e)
+ t.ungetbyte("\xe7")
+ t.ungetbyte("\xe7\xb4\x85")
+ assert_equal(-2, t.pos)
+ assert_equal("\u7d05\u7389bar\n", t.gets)
+ }
+ end
+
+ def test_each_byte
+ pipe(proc do |w|
+ w << "abc def"
+ w.close
+ end, proc do |r|
+ r.each_byte {|byte| break if byte == 32 }
+ assert_equal("def", r.read, "[ruby-dev:31659]")
+ end)
+ end
+
+ def test_each_byte_with_seek
+ make_tempfile {|t|
+ bug5119 = '[ruby-core:38609]'
+ i = 0
+ open(t.path) do |f|
+ f.each_byte {i = f.pos}
+ end
+ assert_equal(12, i, bug5119)
+ }
+ end
+
+ def test_each_codepoint
+ make_tempfile {|t|
+ bug2959 = '[ruby-core:28650]'
+ a = ""
+ File.open(t, 'rt') {|f|
+ f.each_codepoint {|c| a << c}
+ }
+ assert_equal("foo\nbar\nbaz\n", a, bug2959)
+ }
+ end
+
+ def test_codepoints
+ make_tempfile {|t|
+ bug2959 = '[ruby-core:28650]'
+ a = ""
+ File.open(t, 'rt') {|f|
+ assert_warn(/deprecated/) {
+ f.codepoints {|c| a << c}
+ }
+ }
+ assert_equal("foo\nbar\nbaz\n", a, bug2959)
+ }
+ end
+
+ def test_rubydev33072
+ t = make_tempfile
+ path = t.path
+ t.close!
+ assert_raise(Errno::ENOENT, "[ruby-dev:33072]") do
+ File.read(path, nil, nil, {})
+ end
+ end
+
+ def with_srccontent(content = "baz")
+ src = "src"
+ mkcdtmpdir {
+ File.open(src, "w") {|f| f << content }
+ yield src, content
+ }
+ end
+
+ def test_copy_stream_small
+ with_srccontent("foobar") {|src, content|
+ ret = IO.copy_stream(src, "dst")
+ assert_equal(content.bytesize, ret)
+ assert_equal(content, File.read("dst"))
+ }
+ end
+
+ def test_copy_stream_smaller
+ with_srccontent {|src, content|
+
+ # overwrite by smaller file.
+ dst = "dst"
+ File.open(dst, "w") {|f| f << "foobar"}
+
+ ret = IO.copy_stream(src, dst)
+ assert_equal(content.bytesize, ret)
+ assert_equal(content, File.read(dst))
+
+ ret = IO.copy_stream(src, dst, 2)
+ assert_equal(2, ret)
+ assert_equal(content[0,2], File.read(dst))
+
+ ret = IO.copy_stream(src, dst, 0)
+ assert_equal(0, ret)
+ assert_equal("", File.read(dst))
+
+ ret = IO.copy_stream(src, dst, nil, 1)
+ assert_equal(content.bytesize-1, ret)
+ assert_equal(content[1..-1], File.read(dst))
+ }
+ end
+
+ def test_copy_stream_noent
+ with_srccontent {|src, content|
+ assert_raise(Errno::ENOENT) {
+ IO.copy_stream("nodir/foo", "dst")
+ }
+
+ assert_raise(Errno::ENOENT) {
+ IO.copy_stream(src, "nodir/bar")
+ }
+ }
+ end
+
+ def test_copy_stream_pipe
+ with_srccontent {|src, content|
+ pipe(proc do |w|
+ ret = IO.copy_stream(src, w)
+ assert_equal(content.bytesize, ret)
+ w.close
+ end, proc do |r|
+ assert_equal(content, r.read)
+ end)
+ }
+ end
+
+ def test_copy_stream_write_pipe
+ with_srccontent {|src, content|
+ with_pipe {|r, w|
+ w.close
+ assert_raise(IOError) { IO.copy_stream(src, w) }
+ }
+ }
+ end
+
+ def with_pipecontent
+ mkcdtmpdir {
+ yield "abc"
+ }
+ end
+
+ def test_copy_stream_pipe_to_file
+ with_pipecontent {|pipe_content|
+ dst = "dst"
+ with_read_pipe(pipe_content) {|r|
+ ret = IO.copy_stream(r, dst)
+ assert_equal(pipe_content.bytesize, ret)
+ assert_equal(pipe_content, File.read(dst))
+ }
+ }
+ end
+
+ def test_copy_stream_read_pipe
+ with_pipecontent {|pipe_content|
+ with_read_pipe(pipe_content) {|r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ w2.sync = false
+ w2 << "def"
+ ret = IO.copy_stream(r1, w2)
+ assert_equal(2, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("defbc", r2.read)
+ end)
+ }
+
+ with_read_pipe(pipe_content) {|r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ w2.sync = false
+ w2 << "def"
+ ret = IO.copy_stream(r1, w2, 1)
+ assert_equal(1, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("defb", r2.read)
+ end)
+ }
+
+ with_read_pipe(pipe_content) {|r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ ret = IO.copy_stream(r1, w2)
+ assert_equal(2, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("bc", r2.read)
+ end)
+ }
+
+ with_read_pipe(pipe_content) {|r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ ret = IO.copy_stream(r1, w2, 1)
+ assert_equal(1, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("b", r2.read)
+ end)
+ }
+
+ with_read_pipe(pipe_content) {|r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ ret = IO.copy_stream(r1, w2, 0)
+ assert_equal(0, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("", r2.read)
+ end)
+ }
+
+ pipe(proc do |w1|
+ w1 << "abc"
+ w1 << "def"
+ w1.close
+ end, proc do |r1|
+ assert_equal("a", r1.getc)
+ pipe(proc do |w2|
+ ret = IO.copy_stream(r1, w2)
+ assert_equal(5, ret)
+ w2.close
+ end, proc do |r2|
+ assert_equal("bcdef", r2.read)
+ end)
+ end)
+ }
+ end
+
+ def test_copy_stream_file_to_pipe
+ with_srccontent {|src, content|
+ pipe(proc do |w|
+ ret = IO.copy_stream(src, w, 1, 1)
+ assert_equal(1, ret)
+ w.close
+ end, proc do |r|
+ assert_equal(content[1,1], r.read)
+ end)
+ }
+ end
+
+ if have_nonblock?
+ def test_copy_stream_pipe_nonblock
+ mkcdtmpdir {
+ with_read_pipe("abc") {|r1|
+ assert_equal("a", r1.getc)
+ with_pipe {|r2, w2|
+ begin
+ w2.nonblock = true
+ rescue Errno::EBADF
+ skip "nonblocking IO for pipe is not implemented"
+ break
+ end
+ s = w2.syswrite("a" * 100000)
+ t = Thread.new { sleep 0.1; r2.read }
+ ret = IO.copy_stream(r1, w2)
+ w2.close
+ assert_equal(2, ret)
+ assert_equal("a" * s + "bc", t.value)
+ }
+ }
+ }
+ end
+ end
+
+ def with_bigcontent
+ yield "abc" * 123456
+ end
+
+ def with_bigsrc
+ mkcdtmpdir {
+ with_bigcontent {|bigcontent|
+ bigsrc = "bigsrc"
+ File.open("bigsrc", "w") {|f| f << bigcontent }
+ yield bigsrc, bigcontent
+ }
+ }
+ end
+
+ def test_copy_stream_bigcontent
+ with_bigsrc {|bigsrc, bigcontent|
+ ret = IO.copy_stream(bigsrc, "bigdst")
+ assert_equal(bigcontent.bytesize, ret)
+ assert_equal(bigcontent, File.read("bigdst"))
+ }
+ end
+
+ def test_copy_stream_bigcontent_chop
+ with_bigsrc {|bigsrc, bigcontent|
+ ret = IO.copy_stream(bigsrc, "bigdst", nil, 100)
+ assert_equal(bigcontent.bytesize-100, ret)
+ assert_equal(bigcontent[100..-1], File.read("bigdst"))
+ }
+ end
+
+ def test_copy_stream_bigcontent_mid
+ with_bigsrc {|bigsrc, bigcontent|
+ ret = IO.copy_stream(bigsrc, "bigdst", 30000, 100)
+ assert_equal(30000, ret)
+ assert_equal(bigcontent[100, 30000], File.read("bigdst"))
+ }
+ end
+
+ def test_copy_stream_bigcontent_fpos
+ with_bigsrc {|bigsrc, bigcontent|
+ File.open(bigsrc) {|f|
+ begin
+ assert_equal(0, f.pos)
+ ret = IO.copy_stream(f, "bigdst", nil, 10)
+ assert_equal(bigcontent.bytesize-10, ret)
+ assert_equal(bigcontent[10..-1], File.read("bigdst"))
+ assert_equal(0, f.pos)
+ ret = IO.copy_stream(f, "bigdst", 40, 30)
+ assert_equal(40, ret)
+ assert_equal(bigcontent[30, 40], File.read("bigdst"))
+ assert_equal(0, f.pos)
+ rescue NotImplementedError
+ #skip "pread(2) is not implemtented."
+ end
+ }
+ }
+ end
+
+ def test_copy_stream_closed_pipe
+ with_srccontent {|src,|
+ with_pipe {|r, w|
+ w.close
+ assert_raise(IOError) { IO.copy_stream(src, w) }
+ }
+ }
+ end
+
+ def with_megacontent
+ yield "abc" * 1234567
+ end
+
+ def with_megasrc
+ mkcdtmpdir {
+ with_megacontent {|megacontent|
+ megasrc = "megasrc"
+ File.open(megasrc, "w") {|f| f << megacontent }
+ yield megasrc, megacontent
+ }
+ }
+ end
+
+ if have_nonblock?
+ def test_copy_stream_megacontent_nonblock
+ with_megacontent {|megacontent|
+ with_pipe {|r1, w1|
+ with_pipe {|r2, w2|
+ begin
+ r1.nonblock = true
+ w2.nonblock = true
+ rescue Errno::EBADF
+ skip "nonblocking IO for pipe is not implemented"
+ end
+ t1 = Thread.new { w1 << megacontent; w1.close }
+ t2 = Thread.new { r2.read }
+ t3 = Thread.new {
+ ret = IO.copy_stream(r1, w2)
+ assert_equal(megacontent.bytesize, ret)
+ w2.close
+ }
+ _, t2_value, _ = assert_join_threads([t1, t2, t3])
+ assert_equal(megacontent, t2_value)
+ }
+ }
+ }
+ end
+ end
+
+ def test_copy_stream_megacontent_pipe_to_file
+ with_megasrc {|megasrc, megacontent|
+ with_pipe {|r1, w1|
+ with_pipe {|r2, w2|
+ t1 = Thread.new { w1 << megacontent; w1.close }
+ t2 = Thread.new { r2.read }
+ t3 = Thread.new {
+ ret = IO.copy_stream(r1, w2)
+ assert_equal(megacontent.bytesize, ret)
+ w2.close
+ }
+ _, t2_value, _ = assert_join_threads([t1, t2, t3])
+ assert_equal(megacontent, t2_value)
+ }
+ }
+ }
+ end
+
+ def test_copy_stream_megacontent_file_to_pipe
+ with_megasrc {|megasrc, megacontent|
+ with_pipe {|r, w|
+ t1 = Thread.new { r.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream(megasrc, w)
+ assert_equal(megacontent.bytesize, ret)
+ w.close
+ }
+ t1_value, _ = assert_join_threads([t1, t2])
+ assert_equal(megacontent, t1_value)
+ }
+ }
+ end
+
+ def test_copy_stream_rbuf
+ mkcdtmpdir {
+ begin
+ pipe(proc do |w|
+ File.open("foo", "w") {|f| f << "abcd" }
+ File.open("foo") {|f|
+ f.read(1)
+ assert_equal(3, IO.copy_stream(f, w, 10, 1))
+ }
+ w.close
+ end, proc do |r|
+ assert_equal("bcd", r.read)
+ end)
+ rescue NotImplementedError
+ skip "pread(2) is not implemtented."
+ end
+ }
+ end
+
+ def with_socketpair
+ s1, s2 = UNIXSocket.pair
+ begin
+ yield s1, s2
+ ensure
+ s1.close unless s1.closed?
+ s2.close unless s2.closed?
+ end
+ end
+
+ def test_copy_stream_socket1
+ with_srccontent("foobar") {|src, content|
+ with_socketpair {|s1, s2|
+ ret = IO.copy_stream(src, s1)
+ assert_equal(content.bytesize, ret)
+ s1.close
+ assert_equal(content, s2.read)
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket2
+ with_bigsrc {|bigsrc, bigcontent|
+ with_socketpair {|s1, s2|
+ t1 = Thread.new { s2.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream(bigsrc, s1)
+ assert_equal(bigcontent.bytesize, ret)
+ s1.close
+ }
+ result, _ = assert_join_threads([t1, t2])
+ assert_equal(bigcontent, result)
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket3
+ with_bigsrc {|bigsrc, bigcontent|
+ with_socketpair {|s1, s2|
+ t1 = Thread.new { s2.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream(bigsrc, s1, 10000)
+ assert_equal(10000, ret)
+ s1.close
+ }
+ result, _ = assert_join_threads([t1, t2])
+ assert_equal(bigcontent[0,10000], result)
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket4
+ with_bigsrc {|bigsrc, bigcontent|
+ File.open(bigsrc) {|f|
+ assert_equal(0, f.pos)
+ with_socketpair {|s1, s2|
+ t1 = Thread.new { s2.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream(f, s1, nil, 100)
+ assert_equal(bigcontent.bytesize-100, ret)
+ assert_equal(0, f.pos)
+ s1.close
+ }
+ result, _ = assert_join_threads([t1, t2])
+ assert_equal(bigcontent[100..-1], result)
+ }
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket5
+ with_bigsrc {|bigsrc, bigcontent|
+ File.open(bigsrc) {|f|
+ assert_equal(bigcontent[0,100], f.read(100))
+ assert_equal(100, f.pos)
+ with_socketpair {|s1, s2|
+ t1 = Thread.new { s2.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream(f, s1)
+ assert_equal(bigcontent.bytesize-100, ret)
+ assert_equal(bigcontent.length, f.pos)
+ s1.close
+ }
+ result, _ = assert_join_threads([t1, t2])
+ assert_equal(bigcontent[100..-1], result)
+ }
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket6
+ mkcdtmpdir {
+ megacontent = "abc" * 1234567
+ File.open("megasrc", "w") {|f| f << megacontent }
+
+ with_socketpair {|s1, s2|
+ begin
+ s1.nonblock = true
+ rescue Errno::EBADF
+ skip "nonblocking IO for pipe is not implemented"
+ end
+ t1 = Thread.new { s2.read }
+ t2 = Thread.new {
+ ret = IO.copy_stream("megasrc", s1)
+ assert_equal(megacontent.bytesize, ret)
+ s1.close
+ }
+ result, _ = assert_join_threads([t1, t2])
+ assert_equal(megacontent, result)
+ }
+ }
+ end if defined? UNIXSocket
+
+ def test_copy_stream_socket7
+ GC.start
+ mkcdtmpdir {
+ megacontent = "abc" * 1234567
+ File.open("megasrc", "w") {|f| f << megacontent }
+
+ with_socketpair {|s1, s2|
+ begin
+ s1.nonblock = true
+ rescue Errno::EBADF
+ skip "nonblocking IO for pipe is not implemented"
+ end
+ trapping_usr1 do
+ nr = 30
+ begin
+ pid = fork do
+ s1.close
+ IO.select([s2])
+ Process.kill(:USR1, Process.ppid)
+ s2.read
+ end
+ s2.close
+ nr.times do
+ assert_equal megacontent.bytesize, IO.copy_stream("megasrc", s1)
+ end
+ assert_equal(1, @usr1_rcvd)
+ ensure
+ s1.close
+ _, status = Process.waitpid2(pid) if pid
+ end
+ assert_predicate(status, :success?)
+ end
+ }
+ }
+ end if defined? UNIXSocket and IO.method_defined?("nonblock=")
+
+ def test_copy_stream_strio
+ src = StringIO.new("abcd")
+ dst = StringIO.new
+ ret = IO.copy_stream(src, dst)
+ assert_equal(4, ret)
+ assert_equal("abcd", dst.string)
+ assert_equal(4, src.pos)
+ end
+
+ def test_copy_stream_strio_len
+ src = StringIO.new("abcd")
+ dst = StringIO.new
+ ret = IO.copy_stream(src, dst, 3)
+ assert_equal(3, ret)
+ assert_equal("abc", dst.string)
+ assert_equal(3, src.pos)
+ end
+
+ def test_copy_stream_strio_off
+ src = StringIO.new("abcd")
+ with_pipe {|r, w|
+ assert_raise(ArgumentError) {
+ IO.copy_stream(src, w, 3, 1)
+ }
+ }
+ end
+
+ def test_copy_stream_fname_to_strio
+ mkcdtmpdir {
+ File.open("foo", "w") {|f| f << "abcd" }
+ src = "foo"
+ dst = StringIO.new
+ ret = IO.copy_stream(src, dst, 3)
+ assert_equal(3, ret)
+ assert_equal("abc", dst.string)
+ }
+ end
+
+ def test_copy_stream_strio_to_fname
+ mkcdtmpdir {
+ # StringIO to filename
+ src = StringIO.new("abcd")
+ ret = IO.copy_stream(src, "fooo", 3)
+ assert_equal(3, ret)
+ assert_equal("abc", File.read("fooo"))
+ assert_equal(3, src.pos)
+ }
+ end
+
+ def test_copy_stream_io_to_strio
+ mkcdtmpdir {
+ # IO to StringIO
+ File.open("bar", "w") {|f| f << "abcd" }
+ File.open("bar") {|src|
+ dst = StringIO.new
+ ret = IO.copy_stream(src, dst, 3)
+ assert_equal(3, ret)
+ assert_equal("abc", dst.string)
+ assert_equal(3, src.pos)
+ }
+ }
+ end
+
+ def test_copy_stream_strio_to_io
+ mkcdtmpdir {
+ # StringIO to IO
+ src = StringIO.new("abcd")
+ ret = File.open("baz", "w") {|dst|
+ IO.copy_stream(src, dst, 3)
+ }
+ assert_equal(3, ret)
+ assert_equal("abc", File.read("baz"))
+ assert_equal(3, src.pos)
+ }
+ end
+
+ def test_copy_stream_write_in_binmode
+ bug8767 = '[ruby-core:56518] [Bug #8767]'
+ mkcdtmpdir {
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ # StringIO to object with to_path
+ bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT)
+ src = StringIO.new(bytes)
+ dst = Object.new
+ def dst.to_path
+ "qux"
+ end
+ assert_nothing_raised(bug8767) {
+ IO.copy_stream(src, dst)
+ }
+ assert_equal(bytes, File.binread("qux"), bug8767)
+ assert_equal(4, src.pos, bug8767)
+ end
+ }
+ end
+
+ def test_copy_stream_read_in_binmode
+ bug8767 = '[ruby-core:56518] [Bug #8767]'
+ mkcdtmpdir {
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ # StringIO to object with to_path
+ bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT)
+ File.binwrite("qux", bytes)
+ dst = StringIO.new
+ src = Object.new
+ def src.to_path
+ "qux"
+ end
+ assert_nothing_raised(bug8767) {
+ IO.copy_stream(src, dst)
+ }
+ assert_equal(bytes, dst.string.b, bug8767)
+ assert_equal(4, dst.pos, bug8767)
+ end
+ }
+ end
+
+ class Rot13IO
+ def initialize(io)
+ @io = io
+ end
+
+ def readpartial(*args)
+ ret = @io.readpartial(*args)
+ ret.tr!('a-zA-Z', 'n-za-mN-ZA-M')
+ ret
+ end
+
+ def write(str)
+ @io.write(str.tr('a-zA-Z', 'n-za-mN-ZA-M'))
+ end
+
+ def to_io
+ @io
+ end
+ end
+
+ def test_copy_stream_io_to_rot13
+ mkcdtmpdir {
+ File.open("bar", "w") {|f| f << "vex" }
+ File.open("bar") {|src|
+ File.open("baz", "w") {|dst0|
+ dst = Rot13IO.new(dst0)
+ ret = IO.copy_stream(src, dst, 3)
+ assert_equal(3, ret)
+ }
+ assert_equal("irk", File.read("baz"))
+ }
+ }
+ end
+
+ def test_copy_stream_rot13_to_io
+ mkcdtmpdir {
+ File.open("bar", "w") {|f| f << "flap" }
+ File.open("bar") {|src0|
+ src = Rot13IO.new(src0)
+ File.open("baz", "w") {|dst|
+ ret = IO.copy_stream(src, dst, 4)
+ assert_equal(4, ret)
+ }
+ }
+ assert_equal("sync", File.read("baz"))
+ }
+ end
+
+ def test_copy_stream_rot13_to_rot13
+ mkcdtmpdir {
+ File.open("bar", "w") {|f| f << "bin" }
+ File.open("bar") {|src0|
+ src = Rot13IO.new(src0)
+ File.open("baz", "w") {|dst0|
+ dst = Rot13IO.new(dst0)
+ ret = IO.copy_stream(src, dst, 3)
+ assert_equal(3, ret)
+ }
+ }
+ assert_equal("bin", File.read("baz"))
+ }
+ end
+
+ def test_copy_stream_strio_flush
+ with_pipe {|r, w|
+ w.sync = false
+ w.write "zz"
+ src = StringIO.new("abcd")
+ IO.copy_stream(src, w)
+ t1 = Thread.new {
+ w.close
+ }
+ t2 = Thread.new { r.read }
+ _, result = assert_join_threads([t1, t2])
+ assert_equal("zzabcd", result)
+ }
+ end
+
+ def test_copy_stream_strio_rbuf
+ pipe(proc do |w|
+ w << "abcd"
+ w.close
+ end, proc do |r|
+ assert_equal("a", r.read(1))
+ sio = StringIO.new
+ IO.copy_stream(r, sio)
+ assert_equal("bcd", sio.string)
+ end)
+ end
+
+ def test_copy_stream_src_wbuf
+ mkcdtmpdir {
+ pipe(proc do |w|
+ File.open("foe", "w+") {|f|
+ f.write "abcd\n"
+ f.rewind
+ f.write "xy"
+ IO.copy_stream(f, w)
+ }
+ assert_equal("xycd\n", File.read("foe"))
+ w.close
+ end, proc do |r|
+ assert_equal("cd\n", r.read)
+ r.close
+ end)
+ }
+ end
+
+ class Bug5237
+ attr_reader :count
+ def initialize
+ @count = 0
+ end
+
+ def read(bytes, buffer)
+ @count += 1
+ buffer.replace "this is a test"
+ nil
+ end
+ end
+
+ def test_copy_stream_broken_src_read_eof
+ src = Bug5237.new
+ dst = StringIO.new
+ assert_equal 0, src.count
+ th = Thread.new { IO.copy_stream(src, dst) }
+ flunk("timeout") unless th.join(10)
+ assert_equal 1, src.count
+ end
+
+ def test_copy_stream_dst_rbuf
+ mkcdtmpdir {
+ pipe(proc do |w|
+ w << "xyz"
+ w.close
+ end, proc do |r|
+ File.open("fom", "w+b") {|f|
+ f.write "abcd\n"
+ f.rewind
+ assert_equal("abc", f.read(3))
+ f.ungetc "c"
+ IO.copy_stream(r, f)
+ }
+ assert_equal("abxyz", File.read("fom"))
+ end)
+ }
+ end
+
+ def ruby(*args)
+ args = ['-e', '$>.write($<.read)'] if args.empty?
+ ruby = EnvUtil.rubybin
+ f = IO.popen([ruby] + args, 'r+')
+ pid = f.pid
+ yield(f)
+ ensure
+ f.close unless !f || f.closed?
+ begin
+ Process.wait(pid)
+ rescue Errno::ECHILD, Errno::ESRCH
+ end
+ end
+
+ def test_try_convert
+ assert_equal(STDOUT, IO.try_convert(STDOUT))
+ assert_equal(nil, IO.try_convert("STDOUT"))
+ end
+
+ def test_ungetc2
+ f = false
+ pipe(proc do |w|
+ Thread.pass until f
+ w.write("1" * 10000)
+ w.close
+ end, proc do |r|
+ r.ungetc("0" * 10000)
+ f = true
+ assert_equal("0" * 10000 + "1" * 10000, r.read)
+ end)
+ end
+
+ def test_write_non_writable
+ with_pipe do |r, w|
+ assert_raise(IOError) do
+ r.write "foobarbaz"
+ end
+ end
+ end
+
+ def test_dup
+ ruby do |f|
+ begin
+ f2 = f.dup
+ f.puts "foo"
+ f2.puts "bar"
+ f.close_write
+ f2.close_write
+ assert_equal("foo\nbar\n", f.read)
+ assert_equal("", f2.read)
+ ensure
+ f2.close
+ end
+ end
+ end
+
+ def test_dup_many
+ ruby('-e', <<-'End') {|f|
+ ok = 0
+ a = []
+ begin
+ loop {a << IO.pipe}
+ rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM
+ ok += 1
+ end
+ print "no" if ok != 1
+ begin
+ loop {a << [a[-1][0].dup, a[-1][1].dup]}
+ rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM
+ ok += 1
+ end
+ print "no" if ok != 2
+ print "ok"
+ End
+ assert_equal("ok", f.read)
+ }
+ end
+
+ def test_inspect
+ with_pipe do |r, w|
+ assert_match(/^#<IO:fd \d+>$/, r.inspect)
+ r.freeze
+ assert_match(/^#<IO:fd \d+>$/, r.inspect)
+ end
+ end
+
+ def test_readpartial
+ pipe(proc do |w|
+ w.write "foobarbaz"
+ w.close
+ end, proc do |r|
+ assert_raise(ArgumentError) { r.readpartial(-1) }
+ assert_equal("fooba", r.readpartial(5))
+ r.readpartial(5, s = "")
+ assert_equal("rbaz", s)
+ end)
+ end
+
+ def test_readpartial_lock
+ with_pipe do |r, w|
+ s = ""
+ t = Thread.new { r.readpartial(5, s) }
+ Thread.pass until t.stop?
+ assert_raise(RuntimeError) { s.clear }
+ w.write "foobarbaz"
+ w.close
+ assert_equal("fooba", t.value)
+ end
+ end
+
+ def test_readpartial_pos
+ mkcdtmpdir {
+ open("foo", "w") {|f| f << "abc" }
+ open("foo") {|f|
+ f.seek(0)
+ assert_equal("ab", f.readpartial(2))
+ assert_equal(2, f.pos)
+ }
+ }
+ end
+
+ def test_readpartial_with_not_empty_buffer
+ pipe(proc do |w|
+ w.write "foob"
+ w.close
+ end, proc do |r|
+ r.readpartial(5, s = "01234567")
+ assert_equal("foob", s)
+ end)
+ end
+
+ def test_readpartial_buffer_error
+ with_pipe do |r, w|
+ s = ""
+ t = Thread.new { r.readpartial(5, s) }
+ Thread.pass until t.stop?
+ t.kill
+ t.value
+ assert_equal("", s)
+ end
+ end
+
+ def test_read
+ pipe(proc do |w|
+ w.write "foobarbaz"
+ w.close
+ end, proc do |r|
+ assert_raise(ArgumentError) { r.read(-1) }
+ assert_equal("fooba", r.read(5))
+ r.read(nil, s = "")
+ assert_equal("rbaz", s)
+ end)
+ end
+
+ def test_read_lock
+ with_pipe do |r, w|
+ s = ""
+ t = Thread.new { r.read(5, s) }
+ Thread.pass until t.stop?
+ assert_raise(RuntimeError) { s.clear }
+ w.write "foobarbaz"
+ w.close
+ assert_equal("fooba", t.value)
+ end
+ end
+
+ def test_read_with_not_empty_buffer
+ pipe(proc do |w|
+ w.write "foob"
+ w.close
+ end, proc do |r|
+ r.read(nil, s = "01234567")
+ assert_equal("foob", s)
+ end)
+ end
+
+ def test_read_buffer_error
+ with_pipe do |r, w|
+ s = ""
+ t = Thread.new { r.read(5, s) }
+ Thread.pass until t.stop?
+ t.kill
+ t.value
+ assert_equal("", s)
+ end
+ with_pipe do |r, w|
+ s = "xxx"
+ t = Thread.new {r.read(2, s)}
+ Thread.pass until t.stop?
+ t.kill
+ t.value
+ assert_equal("xxx", s)
+ end
+ end
+
+ def test_write_nonblock
+ pipe(proc do |w|
+ w.write_nonblock(1)
+ w.close
+ end, proc do |r|
+ assert_equal("1", r.read)
+ end)
+ end
+
+ def test_read_nonblock_with_not_empty_buffer
+ with_pipe {|r, w|
+ w.write "foob"
+ w.close
+ r.read_nonblock(5, s = "01234567")
+ assert_equal("foob", s)
+ }
+ end
+
+ def test_write_nonblock_simple_no_exceptions
+ pipe(proc do |w|
+ w.write_nonblock('1', exception: false)
+ w.close
+ end, proc do |r|
+ assert_equal("1", r.read)
+ end)
+ end
+
+ def test_read_nonblock_error
+ return if !have_nonblock?
+ with_pipe {|r, w|
+ begin
+ r.read_nonblock 4096
+ rescue Errno::EWOULDBLOCK
+ assert_kind_of(IO::WaitReadable, $!)
+ end
+ }
+
+ with_pipe {|r, w|
+ begin
+ r.read_nonblock 4096, ""
+ rescue Errno::EWOULDBLOCK
+ assert_kind_of(IO::WaitReadable, $!)
+ end
+ }
+ end
+
+ def test_read_nonblock_no_exceptions
+ return if !have_nonblock?
+ with_pipe {|r, w|
+ assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
+ w.puts "HI!"
+ assert_equal "HI!\n", r.read_nonblock(4096, exception: false)
+ w.close
+ assert_equal nil, r.read_nonblock(4096, exception: false)
+ }
+ end
+
+ def test_read_nonblock_with_buffer_no_exceptions
+ return if !have_nonblock?
+ with_pipe {|r, w|
+ assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
+ w.puts "HI!"
+ buf = "buf"
+ value = r.read_nonblock(4096, buf, exception: false)
+ assert_equal value, "HI!\n"
+ assert_same(buf, value)
+ w.close
+ assert_equal nil, r.read_nonblock(4096, "", exception: false)
+ }
+ end
+
+ def test_write_nonblock_error
+ return if !have_nonblock?
+ with_pipe {|r, w|
+ begin
+ loop {
+ w.write_nonblock "a"*100000
+ }
+ rescue Errno::EWOULDBLOCK
+ assert_kind_of(IO::WaitWritable, $!)
+ end
+ }
+ end
+
+ def test_write_nonblock_no_exceptions
+ return if !have_nonblock?
+ with_pipe {|r, w|
+ loop {
+ ret = w.write_nonblock("a"*100000, exception: false)
+ if ret.is_a?(Symbol)
+ assert_equal :wait_writable, ret
+ break
+ end
+ }
+ }
+ end
+
+ def test_gets
+ pipe(proc do |w|
+ w.write "foobarbaz"
+ w.close
+ end, proc do |r|
+ assert_equal("", r.gets(0))
+ assert_equal("foobarbaz", r.gets(9))
+ end)
+ end
+
+ def test_close_read
+ ruby do |f|
+ f.close_read
+ f.write "foobarbaz"
+ assert_raise(IOError) { f.read }
+ end
+ end
+
+ def test_close_read_pipe
+ with_pipe do |r, w|
+ r.close_read
+ assert_raise(Errno::EPIPE) { w.write "foobarbaz" }
+ end
+ end
+
+ def test_write_epipe_nosync
+ assert_separately([], <<-"end;")
+ r, w = IO.pipe
+ r.close
+ w.sync = false
+ assert_raise(Errno::EPIPE) {
+ loop { w.write "a" }
+ }
+ end;
+ end
+
+ def test_close_read_non_readable
+ with_pipe do |r, w|
+ assert_raise(IOError) do
+ w.close_read
+ end
+ end
+ end
+
+ def test_close_write
+ ruby do |f|
+ f.write "foobarbaz"
+ f.close_write
+ assert_equal("foobarbaz", f.read)
+ end
+ end
+
+ def test_close_write_non_readable
+ with_pipe do |r, w|
+ assert_raise(IOError) do
+ r.close_write
+ end
+ end
+ end
+
+ def test_close_read_write_separately
+ bug = '[ruby-list:49598]'
+ (1..10).each do |i|
+ assert_nothing_raised(IOError, "#{bug} trying ##{i}") do
+ IO.popen(EnvUtil.rubybin, "r+") {|f|
+ th = Thread.new {f.close_write}
+ f.close_read
+ th.join
+ }
+ end
+ end
+ end
+
+ def test_pid
+ IO.pipe {|r, w|
+ assert_equal(nil, r.pid)
+ assert_equal(nil, w.pid)
+ }
+
+ begin
+ pipe = IO.popen(EnvUtil.rubybin, "r+")
+ pid1 = pipe.pid
+ pipe.puts "p $$"
+ pipe.close_write
+ pid2 = pipe.read.chomp.to_i
+ assert_equal(pid2, pid1)
+ assert_equal(pid2, pipe.pid)
+ ensure
+ pipe.close
+ end
+ assert_raise(IOError) { pipe.pid }
+ end
+
+ def test_pid_after_close_read
+ pid1 = pid2 = nil
+ IO.popen("exit ;", "r+") do |io|
+ pid1 = io.pid
+ io.close_read
+ pid2 = io.pid
+ end
+ assert_not_nil(pid1)
+ assert_equal(pid1, pid2)
+ end
+
+ def make_tempfile
+ t = Tempfile.new("test_io")
+ t.binmode
+ t.puts "foo"
+ t.puts "bar"
+ t.puts "baz"
+ t.close
+ if block_given?
+ begin
+ yield t
+ ensure
+ t.close(true)
+ end
+ else
+ t
+ end
+ end
+
+ def test_set_lineno
+ make_tempfile {|t|
+ ruby("-e", <<-SRC, t.path) do |f|
+ open(ARGV[0]) do |f|
+ p $.
+ f.gets; p $.
+ f.gets; p $.
+ f.lineno = 1000; p $.
+ f.gets; p $.
+ f.gets; p $.
+ f.rewind; p $.
+ f.gets; p $.
+ f.gets; p $.
+ f.gets; p $.
+ f.gets; p $.
+ end
+ SRC
+ assert_equal("0,1,2,2,1001,1001,1001,1,2,3,3", f.read.chomp.gsub("\n", ","))
+ end
+
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ r.gets; assert_equal(1, $.)
+ r.gets; assert_equal(2, $.)
+ r.lineno = 1000; assert_equal(2, $.)
+ r.gets; assert_equal(1001, $.)
+ r.gets; assert_equal(1001, $.)
+ end)
+ }
+ end
+
+ def test_readline
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ r.readline; assert_equal(1, $.)
+ r.readline; assert_equal(2, $.)
+ r.lineno = 1000; assert_equal(2, $.)
+ r.readline; assert_equal(1001, $.)
+ assert_raise(EOFError) { r.readline }
+ end)
+ end
+
+ def test_each_char
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ a = []
+ r.each_char {|c| a << c }
+ assert_equal(%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"], a)
+ end)
+ end
+
+ def test_lines
+ verbose, $VERBOSE = $VERBOSE, nil
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ e = nil
+ assert_warn(/deprecated/) {
+ e = r.lines
+ }
+ assert_equal("foo\n", e.next)
+ assert_equal("bar\n", e.next)
+ assert_equal("baz\n", e.next)
+ assert_raise(StopIteration) { e.next }
+ end)
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_bytes
+ verbose, $VERBOSE = $VERBOSE, nil
+ pipe(proc do |w|
+ w.binmode
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ e = nil
+ assert_warn(/deprecated/) {
+ e = r.bytes
+ }
+ (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
+ assert_equal(c.ord, e.next)
+ end
+ assert_raise(StopIteration) { e.next }
+ end)
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_chars
+ verbose, $VERBOSE = $VERBOSE, nil
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ e = nil
+ assert_warn(/deprecated/) {
+ e = r.chars
+ }
+ (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
+ assert_equal(c, e.next)
+ end
+ assert_raise(StopIteration) { e.next }
+ end)
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_readbyte
+ pipe(proc do |w|
+ w.binmode
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ r.binmode
+ (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
+ assert_equal(c.ord, r.readbyte)
+ end
+ assert_raise(EOFError) { r.readbyte }
+ end)
+ end
+
+ def test_readchar
+ pipe(proc do |w|
+ w.puts "foo"
+ w.puts "bar"
+ w.puts "baz"
+ w.close
+ end, proc do |r|
+ (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
+ assert_equal(c, r.readchar)
+ end
+ assert_raise(EOFError) { r.readchar }
+ end)
+ end
+
+ def test_close_on_exec
+ skip "IO\#close_on_exec is not implemented." unless have_close_on_exec?
+ ruby do |f|
+ assert_equal(true, f.close_on_exec?)
+ f.close_on_exec = false
+ assert_equal(false, f.close_on_exec?)
+ f.close_on_exec = true
+ assert_equal(true, f.close_on_exec?)
+ f.close_on_exec = false
+ assert_equal(false, f.close_on_exec?)
+ end
+
+ with_pipe do |r, w|
+ assert_equal(true, r.close_on_exec?)
+ r.close_on_exec = false
+ assert_equal(false, r.close_on_exec?)
+ r.close_on_exec = true
+ assert_equal(true, r.close_on_exec?)
+ r.close_on_exec = false
+ assert_equal(false, r.close_on_exec?)
+
+ assert_equal(true, w.close_on_exec?)
+ w.close_on_exec = false
+ assert_equal(false, w.close_on_exec?)
+ w.close_on_exec = true
+ assert_equal(true, w.close_on_exec?)
+ w.close_on_exec = false
+ assert_equal(false, w.close_on_exec?)
+ end
+ end
+
+ def test_pos
+ make_tempfile {|t|
+
+ open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
+ f.write "Hello"
+ assert_equal(5, f.pos)
+ end
+ open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
+ f.sync = true
+ f.read
+ f.write "Hello"
+ assert_equal(5, f.pos)
+ end
+ }
+ end
+
+ def test_pos_with_getc
+ _bug6179 = '[ruby-core:43497]'
+ make_tempfile {|t|
+ ["", "t", "b"].each do |mode|
+ open(t.path, "w#{mode}") do |f|
+ f.write "0123456789\n"
+ end
+
+ open(t.path, "r#{mode}") do |f|
+ assert_equal 0, f.pos, "mode=r#{mode}"
+ assert_equal '0', f.getc, "mode=r#{mode}"
+ assert_equal 1, f.pos, "mode=r#{mode}"
+ assert_equal '1', f.getc, "mode=r#{mode}"
+ assert_equal 2, f.pos, "mode=r#{mode}"
+ assert_equal '2', f.getc, "mode=r#{mode}"
+ assert_equal 3, f.pos, "mode=r#{mode}"
+ assert_equal '3', f.getc, "mode=r#{mode}"
+ assert_equal 4, f.pos, "mode=r#{mode}"
+ assert_equal '4', f.getc, "mode=r#{mode}"
+ end
+ end
+ }
+ end
+
+ def can_seek_data(f)
+ if /linux/ =~ RUBY_PLATFORM
+ require "-test-/file"
+ # lseek(2)
+ case Bug::File::Fs.fsname(f.path)
+ when "btrfs"
+ return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,1]) >= 0
+ when "ocfs"
+ return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,2]) >= 0
+ when "xfs"
+ return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,5]) >= 0
+ when "ext4"
+ return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0
+ when "tmpfs"
+ return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0
+ end
+ end
+ false
+ end
+
+ def test_seek
+ make_tempfile {|t|
+ open(t.path) { |f|
+ f.seek(9)
+ assert_equal("az\n", f.read)
+ }
+
+ open(t.path) { |f|
+ f.seek(9, IO::SEEK_SET)
+ assert_equal("az\n", f.read)
+ }
+
+ open(t.path) { |f|
+ f.seek(-4, IO::SEEK_END)
+ assert_equal("baz\n", f.read)
+ }
+
+ open(t.path) { |f|
+ assert_equal("foo\n", f.gets)
+ f.seek(2, IO::SEEK_CUR)
+ assert_equal("r\nbaz\n", f.read)
+ }
+
+ if defined?(IO::SEEK_DATA)
+ open(t.path) { |f|
+ break unless can_seek_data(f)
+ assert_equal("foo\n", f.gets)
+ f.seek(0, IO::SEEK_DATA)
+ assert_equal("foo\nbar\nbaz\n", f.read)
+ }
+ open(t.path, 'r+') { |f|
+ break unless can_seek_data(f)
+ f.seek(100*1024, IO::SEEK_SET)
+ f.print("zot\n")
+ f.seek(50*1024, IO::SEEK_DATA)
+ assert_operator(f.pos, :>=, 50*1024)
+ assert_match(/\A\0*zot\n\z/, f.read)
+ }
+ end
+
+ if defined?(IO::SEEK_HOLE)
+ open(t.path) { |f|
+ break unless can_seek_data(f)
+ assert_equal("foo\n", f.gets)
+ f.seek(0, IO::SEEK_HOLE)
+ assert_operator(f.pos, :>, 20)
+ f.seek(100*1024, IO::SEEK_HOLE)
+ assert_equal("", f.read)
+ }
+ end
+ }
+ end
+
+ def test_seek_symwhence
+ make_tempfile {|t|
+ open(t.path) { |f|
+ f.seek(9, :SET)
+ assert_equal("az\n", f.read)
+ }
+
+ open(t.path) { |f|
+ f.seek(-4, :END)
+ assert_equal("baz\n", f.read)
+ }
+
+ open(t.path) { |f|
+ assert_equal("foo\n", f.gets)
+ f.seek(2, :CUR)
+ assert_equal("r\nbaz\n", f.read)
+ }
+
+ if defined?(IO::SEEK_DATA)
+ open(t.path) { |f|
+ break unless can_seek_data(f)
+ assert_equal("foo\n", f.gets)
+ f.seek(0, :DATA)
+ assert_equal("foo\nbar\nbaz\n", f.read)
+ }
+ open(t.path, 'r+') { |f|
+ break unless can_seek_data(f)
+ f.seek(100*1024, :SET)
+ f.print("zot\n")
+ f.seek(50*1024, :DATA)
+ assert_operator(f.pos, :>=, 50*1024)
+ assert_match(/\A\0*zot\n\z/, f.read)
+ }
+ end
+
+ if defined?(IO::SEEK_HOLE)
+ open(t.path) { |f|
+ break unless can_seek_data(f)
+ assert_equal("foo\n", f.gets)
+ f.seek(0, :HOLE)
+ assert_operator(f.pos, :>, 20)
+ f.seek(100*1024, :HOLE)
+ assert_equal("", f.read)
+ }
+ end
+ }
+ end
+
+ def test_sysseek
+ make_tempfile {|t|
+ open(t.path) do |f|
+ f.sysseek(-4, IO::SEEK_END)
+ assert_equal("baz\n", f.read)
+ end
+
+ open(t.path) do |f|
+ a = [f.getc, f.getc, f.getc]
+ a.reverse_each {|c| f.ungetc c }
+ assert_raise(IOError) { f.sysseek(1) }
+ end
+ }
+ end
+
+ def test_syswrite
+ make_tempfile {|t|
+ open(t.path, "w") do |f|
+ o = Object.new
+ def o.to_s; "FOO\n"; end
+ f.syswrite(o)
+ end
+ assert_equal("FOO\n", File.read(t.path))
+ }
+ end
+
+ def test_sysread
+ make_tempfile {|t|
+ open(t.path) do |f|
+ a = [f.getc, f.getc, f.getc]
+ a.reverse_each {|c| f.ungetc c }
+ assert_raise(IOError) { f.sysread(1) }
+ end
+ }
+ end
+
+ def test_sysread_with_not_empty_buffer
+ pipe(proc do |w|
+ w.write "foob"
+ w.close
+ end, proc do |r|
+ r.sysread( 5, s = "01234567" )
+ assert_equal( "foob", s )
+ end)
+ end
+
+ def test_flag
+ make_tempfile {|t|
+ assert_raise(ArgumentError) do
+ open(t.path, "z") { }
+ end
+
+ assert_raise(ArgumentError) do
+ open(t.path, "rr") { }
+ end
+ }
+ end
+
+ def test_sysopen
+ make_tempfile {|t|
+ fd = IO.sysopen(t.path)
+ assert_kind_of(Integer, fd)
+ f = IO.for_fd(fd)
+ assert_equal("foo\nbar\nbaz\n", f.read)
+ f.close
+
+ fd = IO.sysopen(t.path, "w", 0666)
+ assert_kind_of(Integer, fd)
+ if defined?(Fcntl::F_GETFL)
+ f = IO.for_fd(fd)
+ else
+ f = IO.for_fd(fd, 0666)
+ end
+ f.write("FOO\n")
+ f.close
+
+ fd = IO.sysopen(t.path, "r")
+ assert_kind_of(Integer, fd)
+ f = IO.for_fd(fd)
+ assert_equal("FOO\n", f.read)
+ f.close
+ }
+ end
+
+ def try_fdopen(fd, autoclose = true, level = 50)
+ if level > 0
+ begin
+ 1.times {return try_fdopen(fd, autoclose, level - 1)}
+ ensure
+ GC.start
+ end
+ else
+ WeakRef.new(IO.for_fd(fd, autoclose: autoclose))
+ end
+ end
+
+ def test_autoclose
+ feature2250 = '[ruby-core:26222]'
+ pre = 'ft2250'
+
+ Dir.mktmpdir {|d|
+ t = open("#{d}/#{pre}", "w")
+ f = IO.for_fd(t.fileno)
+ assert_equal(true, f.autoclose?)
+ f.autoclose = false
+ assert_equal(false, f.autoclose?)
+ f.close
+ assert_nothing_raised(Errno::EBADF, feature2250) {t.close}
+
+ t = open("#{d}/#{pre}", "w")
+ f = IO.for_fd(t.fileno, autoclose: false)
+ assert_equal(false, f.autoclose?)
+ f.autoclose = true
+ assert_equal(true, f.autoclose?)
+ f.close
+ assert_raise(Errno::EBADF, feature2250) {t.close}
+ }
+ end
+
+ def test_autoclose_true_closed_by_finalizer
+ feature2250 = '[ruby-core:26222]'
+ pre = 'ft2250'
+ t = Tempfile.new(pre)
+ w = try_fdopen(t.fileno)
+ begin
+ w.close
+ begin
+ t.close
+ rescue Errno::EBADF
+ end
+ skip "expect IO object was GC'ed but not recycled yet"
+ rescue WeakRef::RefError
+ assert_raise(Errno::EBADF, feature2250) {t.close}
+ end
+ ensure
+ t.close!
+ end
+
+ def test_autoclose_false_closed_by_finalizer
+ feature2250 = '[ruby-core:26222]'
+ pre = 'ft2250'
+ t = Tempfile.new(pre)
+ w = try_fdopen(t.fileno, false)
+ begin
+ w.close
+ t.close
+ skip "expect IO object was GC'ed but not recycled yet"
+ rescue WeakRef::RefError
+ assert_nothing_raised(Errno::EBADF, feature2250) {t.close}
+ end
+ ensure
+ t.close!
+ end
+
+ def test_open_redirect
+ o = Object.new
+ def o.to_open; self; end
+ assert_equal(o, open(o))
+ o2 = nil
+ open(o) do |f|
+ o2 = f
+ end
+ assert_equal(o, o2)
+ end
+
+ def test_open_pipe
+ open("|" + EnvUtil.rubybin, "r+") do |f|
+ f.puts "puts 'foo'"
+ f.close_write
+ assert_equal("foo\n", f.read)
+ end
+ end
+
+ def test_reopen
+ make_tempfile {|t|
+ open(__FILE__) do |f|
+ f.gets
+ assert_nothing_raised {
+ f.reopen(t.path)
+ assert_equal("foo\n", f.gets)
+ }
+ end
+
+ open(__FILE__) do |f|
+ f.gets
+ f2 = open(t.path)
+ begin
+ f2.gets
+ assert_nothing_raised {
+ f.reopen(f2)
+ assert_equal("bar\n", f.gets, '[ruby-core:24240]')
+ }
+ ensure
+ f2.close
+ end
+ end
+
+ open(__FILE__) do |f|
+ f2 = open(t.path)
+ begin
+ f.reopen(f2)
+ assert_equal("foo\n", f.gets)
+ assert_equal("bar\n", f.gets)
+ f.reopen(f2)
+ assert_equal("baz\n", f.gets, '[ruby-dev:39479]')
+ ensure
+ f2.close
+ end
+ end
+ }
+ end
+
+ def test_reopen_inherit
+ mkcdtmpdir {
+ system(EnvUtil.rubybin, '-e', <<"End")
+ f = open("out", "w")
+ STDOUT.reopen(f)
+ STDERR.reopen(f)
+ system(#{EnvUtil.rubybin.dump}, '-e', 'STDOUT.print "out"')
+ system(#{EnvUtil.rubybin.dump}, '-e', 'STDERR.print "err"')
+End
+ assert_equal("outerr", File.read("out"))
+ }
+ end
+
+ def test_reopen_stdio
+ mkcdtmpdir {
+ fname = 'bug11319'
+ File.write(fname, 'hello')
+ system(EnvUtil.rubybin, '-e', "STDOUT.reopen('#{fname}', 'w+')")
+ assert_equal('', File.read(fname))
+ }
+ end
+
+ def test_reopen_mode
+ feature7067 = '[ruby-core:47694]'
+ make_tempfile {|t|
+ open(__FILE__) do |f|
+ assert_nothing_raised {
+ f.reopen(t.path, "r")
+ assert_equal("foo\n", f.gets)
+ }
+ end
+
+ open(__FILE__) do |f|
+ assert_nothing_raised(feature7067) {
+ f.reopen(t.path, File::RDONLY)
+ assert_equal("foo\n", f.gets)
+ }
+ end
+ }
+ end
+
+ def test_reopen_opt
+ feature7103 = '[ruby-core:47806]'
+ make_tempfile {|t|
+ open(__FILE__) do |f|
+ assert_nothing_raised(feature7103) {
+ f.reopen(t.path, "r", binmode: true)
+ }
+ assert_equal("foo\n", f.gets)
+ end
+
+ open(__FILE__) do |f|
+ assert_nothing_raised(feature7103) {
+ f.reopen(t.path, autoclose: false)
+ }
+ assert_equal("foo\n", f.gets)
+ end
+ }
+ end
+
+ def make_tempfile_for_encoding
+ t = make_tempfile
+ open(t.path, "rb+:utf-8") {|f| f.puts "\u7d05\u7389bar\n"}
+ if block_given?
+ yield t
+ else
+ t
+ end
+ ensure
+ t.close(true) if t and block_given?
+ end
+
+ def test_reopen_encoding
+ make_tempfile_for_encoding {|t|
+ open(__FILE__) {|f|
+ f.reopen(t.path, "r:utf-8")
+ s = f.gets
+ assert_equal(Encoding::UTF_8, s.encoding)
+ assert_equal("\u7d05\u7389bar\n", s)
+ }
+
+ open(__FILE__) {|f|
+ f.reopen(t.path, "r:UTF-8:EUC-JP")
+ s = f.gets
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s)
+ }
+ }
+ end
+
+ def test_reopen_opt_encoding
+ feature7103 = '[ruby-core:47806]'
+ make_tempfile_for_encoding {|t|
+ open(__FILE__) {|f|
+ assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "ASCII-8BIT")}
+ s = f.gets
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xe7\xb4\x85\xe7\x8e\x89bar\n", s)
+ }
+
+ open(__FILE__) {|f|
+ assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "UTF-8:EUC-JP")}
+ s = f.gets
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s)
+ }
+ }
+ end
+
+ def test_foreach
+ a = []
+ IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x }
+ assert_equal(["foo\n", "bar\n", "baz\n"], a)
+
+ make_tempfile {|t|
+ a = []
+ IO.foreach(t.path) {|x| a << x }
+ assert_equal(["foo\n", "bar\n", "baz\n"], a)
+
+ a = []
+ IO.foreach(t.path, {:mode => "r" }) {|x| a << x }
+ assert_equal(["foo\n", "bar\n", "baz\n"], a)
+
+ a = []
+ IO.foreach(t.path, {:open_args => [] }) {|x| a << x }
+ assert_equal(["foo\n", "bar\n", "baz\n"], a)
+
+ a = []
+ IO.foreach(t.path, {:open_args => ["r"] }) {|x| a << x }
+ assert_equal(["foo\n", "bar\n", "baz\n"], a)
+
+ a = []
+ IO.foreach(t.path, "b") {|x| a << x }
+ assert_equal(["foo\nb", "ar\nb", "az\n"], a)
+
+ a = []
+ IO.foreach(t.path, 3) {|x| a << x }
+ assert_equal(["foo", "\n", "bar", "\n", "baz", "\n"], a)
+
+ a = []
+ IO.foreach(t.path, "b", 3) {|x| a << x }
+ assert_equal(["foo", "\nb", "ar\n", "b", "az\n"], a)
+
+ bug = '[ruby-dev:31525]'
+ assert_raise(ArgumentError, bug) {IO.foreach}
+
+ a = nil
+ assert_nothing_raised(ArgumentError, bug) {a = IO.foreach(t.path).to_a}
+ assert_equal(["foo\n", "bar\n", "baz\n"], a, bug)
+
+ bug6054 = '[ruby-dev:45267]'
+ assert_raise_with_message(IOError, /not opened for reading/, bug6054) do
+ IO.foreach(t.path, mode:"w").next
+ end
+ }
+ end
+
+ def test_s_readlines
+ make_tempfile {|t|
+ assert_equal(["foo\n", "bar\n", "baz\n"], IO.readlines(t.path))
+ assert_equal(["foo\nb", "ar\nb", "az\n"], IO.readlines(t.path, "b"))
+ assert_equal(["fo", "o\n", "ba", "r\n", "ba", "z\n"], IO.readlines(t.path, 2))
+ assert_equal(["fo", "o\n", "b", "ar", "\nb", "az", "\n"], IO.readlines(t.path, "b", 2))
+ }
+ end
+
+ def test_printf
+ pipe(proc do |w|
+ printf(w, "foo %s baz\n", "bar")
+ w.close_write
+ end, proc do |r|
+ assert_equal("foo bar baz\n", r.read)
+ end)
+ end
+
+ def test_print
+ make_tempfile {|t|
+ assert_in_out_err(["-", t.path],
+ "print while $<.gets",
+ %w(foo bar baz), [])
+ }
+ end
+
+ def test_print_separators
+ $, = ':'
+ $\ = "\n"
+ pipe(proc do |w|
+ w.print('a')
+ w.print('a','b','c')
+ w.close
+ end, proc do |r|
+ assert_equal("a\n", r.gets)
+ assert_equal("a:b:c\n", r.gets)
+ assert_nil r.gets
+ r.close
+ end)
+ ensure
+ $, = nil
+ $\ = nil
+ end
+
+ def test_putc
+ pipe(proc do |w|
+ w.putc "A"
+ w.putc "BC"
+ w.putc 68
+ w.close_write
+ end, proc do |r|
+ assert_equal("ABD", r.read)
+ end)
+
+ assert_in_out_err([], "putc 65", %w(A), [])
+ end
+
+ def test_puts_recursive_array
+ a = ["foo"]
+ a << a
+ pipe(proc do |w|
+ w.puts a
+ w.close
+ end, proc do |r|
+ assert_equal("foo\n[...]\n", r.read)
+ end)
+ end
+
+ def test_display
+ pipe(proc do |w|
+ "foo".display(w)
+ w.close
+ end, proc do |r|
+ assert_equal("foo", r.read)
+ end)
+
+ assert_in_out_err([], "'foo'.display", %w(foo), [])
+ end
+
+ def test_set_stdout
+ assert_raise(TypeError) { $> = Object.new }
+
+ assert_in_out_err([], "$> = $stderr\nputs 'foo'", [], %w(foo))
+
+ assert_separately(%w[-Eutf-8], <<-"end;") # do
+ alias $\u{6a19 6e96 51fa 529b} $stdout
+ x = eval("class X\u{307b 3052}; self; end".encode("euc-jp"))
+ assert_raise_with_message(TypeError, /\\$\u{6a19 6e96 51fa 529b} must.*, X\u{307b 3052} given/) do
+ $\u{6a19 6e96 51fa 529b} = x.new
+ end
+ end;
+ end
+
+ def test_initialize
+ return unless defined?(Fcntl::F_GETFL)
+
+ make_tempfile {|t|
+
+ fd = IO.sysopen(t.path, "w")
+ assert_kind_of(Integer, fd)
+ %w[r r+ w+ a+].each do |mode|
+ assert_raise(Errno::EINVAL, "#{mode} [ruby-dev:38571]") {IO.new(fd, mode)}
+ end
+ f = IO.new(fd, "w")
+ f.write("FOO\n")
+ f.close
+
+ assert_equal("FOO\n", File.read(t.path))
+ }
+ end
+
+ def test_reinitialize
+ make_tempfile {|t|
+ f = open(t.path)
+ begin
+ assert_raise(RuntimeError) do
+ f.instance_eval { initialize }
+ end
+ ensure
+ f.close
+ end
+ }
+ end
+
+ def test_new_with_block
+ assert_in_out_err([], "r, w = IO.pipe; r.autoclose=false; IO.new(r.fileno) {}.close", [], /^.+$/)
+ n = "IO\u{5165 51fa 529b}"
+ c = eval("class #{n} < IO; self; end")
+ IO.pipe do |r, w|
+ assert_warning(/#{n}/) {
+ r.autoclose=false
+ io = c.new(r.fileno) {}
+ io.close
+ }
+ end
+ end
+
+ def test_readline2
+ assert_in_out_err(["-e", <<-SRC], "foo\nbar\nbaz\n", %w(foo bar baz end), [])
+ puts readline
+ puts readline
+ puts readline
+ begin
+ puts readline
+ rescue EOFError
+ puts "end"
+ end
+ SRC
+ end
+
+ def test_readlines
+ assert_in_out_err(["-e", "p readlines"], "foo\nbar\nbaz\n",
+ ["[\"foo\\n\", \"bar\\n\", \"baz\\n\"]"], [])
+ end
+
+ def test_s_read
+ make_tempfile {|t|
+ assert_equal("foo\nbar\nbaz\n", File.read(t.path))
+ assert_equal("foo\nba", File.read(t.path, 6))
+ assert_equal("bar\n", File.read(t.path, 4, 4))
+ }
+ end
+
+ def test_uninitialized
+ assert_raise(IOError) { IO.allocate.print "" }
+ end
+
+ def test_nofollow
+ # O_NOFOLLOW is not standard.
+ return if /freebsd|linux/ !~ RUBY_PLATFORM
+ return unless defined? File::NOFOLLOW
+ mkcdtmpdir {
+ open("file", "w") {|f| f << "content" }
+ begin
+ File.symlink("file", "slnk")
+ rescue NotImplementedError
+ return
+ end
+ assert_raise(Errno::EMLINK, Errno::ELOOP) {
+ open("slnk", File::RDONLY|File::NOFOLLOW) {}
+ }
+ assert_raise(Errno::EMLINK, Errno::ELOOP) {
+ File.foreach("slnk", :open_args=>[File::RDONLY|File::NOFOLLOW]) {}
+ }
+ }
+ end
+
+ def test_tainted
+ make_tempfile {|t|
+ assert_predicate(File.read(t.path, 4), :tainted?, '[ruby-dev:38826]')
+ assert_predicate(File.open(t.path) {|f| f.read(4)}, :tainted?, '[ruby-dev:38826]')
+ }
+ end
+
+ def test_binmode_after_closed
+ make_tempfile {|t|
+ assert_raise(IOError) {t.binmode}
+ }
+ end
+
+ def test_threaded_flush
+ bug3585 = '[ruby-core:31348]'
+ src = %q{\
+ t = Thread.new { sleep 3 }
+ Thread.new {sleep 1; t.kill; p 'hi!'}
+ t.join
+ }.gsub(/^\s+/, '')
+ 10.times.map do
+ Thread.start do
+ assert_in_out_err([], src) {|stdout, stderr|
+ assert_no_match(/hi.*hi/, stderr.join, bug3585)
+ }
+ end
+ end.each {|th| th.join}
+ end
+
+ def test_flush_in_finalizer1
+ require 'tempfile'
+ bug3910 = '[ruby-dev:42341]'
+ t = Tempfile.open("bug3910") {|t|
+ path = t.path
+ t.close
+ fds = []
+ assert_nothing_raised(TypeError, bug3910) do
+ 500.times {
+ f = File.open(path, "w")
+ f.instance_variable_set(:@test_flush_in_finalizer1, true)
+ fds << f.fileno
+ f.print "hoge"
+ }
+ end
+ t
+ }
+ ensure
+ ObjectSpace.each_object(File) {|f|
+ if f.instance_variables.include?(:@test_flush_in_finalizer1)
+ f.close
+ end
+ }
+ t.close!
+ end
+
+ def test_flush_in_finalizer2
+ require 'tempfile'
+ bug3910 = '[ruby-dev:42341]'
+ Tempfile.open("bug3910") {|t|
+ path = t.path
+ t.close
+ begin
+ 1.times do
+ io = open(path,"w")
+ io.instance_variable_set(:@test_flush_in_finalizer2, true)
+ io.print "hoge"
+ end
+ assert_nothing_raised(TypeError, bug3910) do
+ GC.start
+ end
+ ensure
+ ObjectSpace.each_object(File) {|f|
+ if f.instance_variables.include?(:@test_flush_in_finalizer2)
+ f.close
+ end
+ }
+ end
+ t.close!
+ }
+ end
+
+ def test_readlines_limit_0
+ bug4024 = '[ruby-dev:42538]'
+ make_tempfile {|t|
+ open(t.path, "r") do |io|
+ assert_raise(ArgumentError, bug4024) do
+ io.readlines(0)
+ end
+ end
+ }
+ end
+
+ def test_each_line_limit_0
+ bug4024 = '[ruby-dev:42538]'
+ make_tempfile {|t|
+ open(t.path, "r") do |io|
+ assert_raise(ArgumentError, bug4024) do
+ io.each_line(0).next
+ end
+ end
+ }
+ end
+
+ def os_and_fs(path)
+ uname = Etc.uname
+ os = "#{uname[:sysname]} #{uname[:release]}"
+
+ fs = nil
+ if uname[:sysname] == 'Linux'
+ # [ruby-dev:45703] Old Linux's fadvice() doesn't work on tmpfs.
+ mount = `mount`
+ mountpoints = []
+ mount.scan(/ on (\S+) type (\S+) /) {
+ mountpoints << [$1, $2]
+ }
+ mountpoints.sort_by {|mountpoint, fstype| mountpoint.length }.reverse_each {|mountpoint, fstype|
+ if path == mountpoint
+ fs = fstype
+ break
+ end
+ mountpoint += "/" if %r{/\z} !~ mountpoint
+ if path.start_with?(mountpoint)
+ fs = fstype
+ break
+ end
+ }
+ end
+
+ if fs
+ "#{fs} on #{os}"
+ else
+ os
+ end
+ end
+
+ def test_advise
+ make_tempfile {|tf|
+ assert_raise(ArgumentError, "no arguments") { tf.advise }
+ %w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv|
+ [[0,0], [0, 20], [400, 2]].each do |offset, len|
+ open(tf.path) do |t|
+ ret = assert_nothing_raised(lambda { os_and_fs(tf.path) }) {
+ begin
+ t.advise(adv, offset, len)
+ rescue Errno::EINVAL => e
+ if /linux/ =~ RUBY_PLATFORM && (Etc.uname[:release].split('.').map(&:to_i) <=> [3,6]) < 0
+ next # [ruby-core:65355] tmpfs is not supported
+ else
+ raise e
+ end
+ end
+ }
+ assert_nil(ret)
+ assert_raise(ArgumentError, "superfluous arguments") do
+ t.advise(adv, offset, len, offset)
+ end
+ assert_raise(TypeError, "wrong type for first argument") do
+ t.advise(adv.to_s, offset, len)
+ end
+ assert_raise(TypeError, "wrong type for last argument") do
+ t.advise(adv, offset, Array(len))
+ end
+ assert_raise(RangeError, "last argument too big") do
+ t.advise(adv, offset, 9999e99)
+ end
+ end
+ assert_raise(IOError, "closed file") do
+ make_tempfile {|tf2|
+ tf2.advise(adv.to_sym, offset, len)
+ }
+ end
+ end
+ end
+ }
+ end
+
+ def test_invalid_advise
+ feature4204 = '[ruby-dev:42887]'
+ make_tempfile {|tf|
+ %W{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv|
+ [[0,0], [0, 20], [400, 2]].each do |offset, len|
+ open(tf.path) do |t|
+ assert_raise_with_message(NotImplementedError, /#{Regexp.quote(adv.inspect)}/, feature4204) { t.advise(adv, offset, len) }
+ end
+ end
+ end
+ }
+ end
+
+ def test_fcntl_lock_linux
+ return if /x86_64-linux/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform
+ return if [nil].pack("p").bytesize != 8 # Return if x32 platform.
+
+ pad=0
+ Tempfile.create(self.class.name) do |f|
+ r, w = IO.pipe
+ pid = fork do
+ r.close
+ lock = [Fcntl::F_WRLCK, IO::SEEK_SET, pad, 12, 34, 0].pack("s!s!i!L!L!i!")
+ f.fcntl Fcntl::F_SETLKW, lock
+ w.syswrite "."
+ sleep
+ end
+ w.close
+ assert_equal ".", r.read(1)
+ r.close
+ pad = 0
+ getlock = [Fcntl::F_WRLCK, 0, pad, 0, 0, 0].pack("s!s!i!L!L!i!")
+ f.fcntl Fcntl::F_GETLK, getlock
+
+ ptype, whence, pad, start, len, lockpid = getlock.unpack("s!s!i!L!L!i!")
+
+ assert_equal(ptype, Fcntl::F_WRLCK)
+ assert_equal(whence, IO::SEEK_SET)
+ assert_equal(start, 12)
+ assert_equal(len, 34)
+ assert_equal(pid, lockpid)
+
+ Process.kill :TERM, pid
+ Process.waitpid2(pid)
+ end
+ end
+
+ def test_fcntl_lock_freebsd
+ return if /freebsd/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform
+
+ start = 12
+ len = 34
+ sysid = 0
+ Tempfile.create(self.class.name) do |f|
+ r, w = IO.pipe
+ pid = fork do
+ r.close
+ lock = [start, len, 0, Fcntl::F_WRLCK, IO::SEEK_SET, sysid].pack("qqis!s!i!")
+ f.fcntl Fcntl::F_SETLKW, lock
+ w.syswrite "."
+ sleep
+ end
+ w.close
+ assert_equal ".", r.read(1)
+ r.close
+
+ getlock = [0, 0, 0, Fcntl::F_WRLCK, 0, 0].pack("qqis!s!i!")
+ f.fcntl Fcntl::F_GETLK, getlock
+
+ start, len, lockpid, ptype, whence, sysid = getlock.unpack("qqis!s!i!")
+
+ assert_equal(ptype, Fcntl::F_WRLCK)
+ assert_equal(whence, IO::SEEK_SET)
+ assert_equal(start, 12)
+ assert_equal(len, 34)
+ assert_equal(pid, lockpid)
+
+ Process.kill :TERM, pid
+ Process.waitpid2(pid)
+ end
+ end
+
+ def test_fcntl_dupfd
+ Tempfile.create(self.class.name) do |f|
+ fd = f.fcntl(Fcntl::F_DUPFD, 63)
+ begin
+ assert_operator(fd, :>=, 63)
+ ensure
+ IO.for_fd(fd).close
+ end
+ end
+ end
+
+ def test_cross_thread_close_fd
+ with_pipe do |r,w|
+ read_thread = Thread.new do
+ begin
+ r.read(1)
+ rescue => e
+ e
+ end
+ end
+
+ sleep(0.1) until read_thread.stop?
+ r.close
+ read_thread.join
+ assert_kind_of(IOError, read_thread.value)
+ end
+ end
+
+ def test_cross_thread_close_stdio
+ assert_separately([], <<-'end;')
+ IO.pipe do |r,w|
+ $stdin.reopen(r)
+ r.close
+ read_thread = Thread.new do
+ $stdin.read(1)
+ end
+ sleep(0.1) until read_thread.stop?
+ $stdin.close
+ assert_raise(IOError) {read_thread.join}
+ end
+ end;
+ end
+
+ def test_open_mode
+ feature4742 = "[ruby-core:36338]"
+ bug6055 = '[ruby-dev:45268]'
+
+ mkcdtmpdir do
+ assert_not_nil(f = File.open('symbolic', 'w'))
+ f.close
+ assert_not_nil(f = File.open('numeric', File::WRONLY|File::TRUNC|File::CREAT))
+ f.close
+ assert_not_nil(f = File.open('hash-symbolic', :mode => 'w'))
+ f.close
+ assert_not_nil(f = File.open('hash-numeric', :mode => File::WRONLY|File::TRUNC|File::CREAT), feature4742)
+ f.close
+ assert_nothing_raised(bug6055) {f = File.open('hash-symbolic', binmode: true)}
+ f.close
+ end
+ end
+
+ def test_s_write
+ mkcdtmpdir do
+ path = "test_s_write"
+ File.write(path, "foo\nbar\nbaz")
+ assert_equal("foo\nbar\nbaz", File.read(path))
+ File.write(path, "FOO", 0)
+ assert_equal("FOO\nbar\nbaz", File.read(path))
+ File.write(path, "BAR")
+ assert_equal("BAR", File.read(path))
+ File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP")
+ assert_equal("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP"))
+ File.delete path
+ assert_equal(6, File.write(path, 'string', 2))
+ File.delete path
+ assert_raise(Errno::EINVAL) { File.write('nonexisting','string', -2) }
+ assert_equal(6, File.write(path, 'string'))
+ assert_equal(3, File.write(path, 'sub', 1))
+ assert_equal("ssubng", File.read(path))
+ File.delete path
+ assert_equal(3, File.write(path, "foo", encoding: "UTF-8"))
+ File.delete path
+ assert_equal(3, File.write(path, "foo", 0, encoding: "UTF-8"))
+ assert_equal("foo", File.read(path))
+ assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8"))
+ assert_equal("ffo", File.read(path))
+ File.delete path
+ assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8"))
+ assert_equal("\00f", File.read(path))
+ assert_equal(1, File.write(path, "f", 0, encoding: "UTF-8"))
+ assert_equal("ff", File.read(path))
+ assert_raise(TypeError) {
+ File.write(path, "foo", Object.new => Object.new)
+ }
+ end
+ end
+
+ def test_s_binwrite
+ mkcdtmpdir do
+ path = "test_s_binwrite"
+ File.binwrite(path, "foo\nbar\nbaz")
+ assert_equal("foo\nbar\nbaz", File.read(path))
+ File.binwrite(path, "FOO", 0)
+ assert_equal("FOO\nbar\nbaz", File.read(path))
+ File.binwrite(path, "BAR")
+ assert_equal("BAR", File.read(path))
+ File.binwrite(path, "\u{3042}")
+ assert_equal("\u{3042}".force_encoding("ASCII-8BIT"), File.binread(path))
+ File.delete path
+ assert_equal(6, File.binwrite(path, 'string', 2))
+ File.delete path
+ assert_equal(6, File.binwrite(path, 'string'))
+ assert_equal(3, File.binwrite(path, 'sub', 1))
+ assert_equal("ssubng", File.binread(path))
+ assert_equal(6, File.size(path))
+ assert_raise(Errno::EINVAL) { File.binwrite('nonexisting', 'string', -2) }
+ assert_nothing_raised(TypeError) { File.binwrite(path, "string", mode: "w", encoding: "EUC-JP") }
+ end
+ end
+
+ def test_race_between_read
+ Tempfile.create("test") {|file|
+ begin
+ path = file.path
+ file.close
+ write_file = File.open(path, "wt")
+ read_file = File.open(path, "rt")
+
+ threads = []
+ 10.times do |i|
+ threads << Thread.new {write_file.print(i)}
+ threads << Thread.new {read_file.read}
+ end
+ assert_join_threads(threads)
+ assert(true, "[ruby-core:37197]")
+ ensure
+ read_file.close
+ write_file.close
+ end
+ }
+ end
+
+ def test_warn
+ assert_warning "warning\n" do
+ warn "warning"
+ end
+
+ assert_warning '' do
+ warn
+ end
+
+ assert_warning "[Feature #5029]\n[ruby-core:38070]\n" do
+ warn "[Feature #5029]", "[ruby-core:38070]"
+ end
+ end
+
+ def test_cloexec
+ return unless defined? Fcntl::FD_CLOEXEC
+ open(__FILE__) {|f|
+ assert_predicate(f, :close_on_exec?)
+ g = f.dup
+ begin
+ assert_predicate(g, :close_on_exec?)
+ f.reopen(g)
+ assert_predicate(f, :close_on_exec?)
+ ensure
+ g.close
+ end
+ g = IO.new(f.fcntl(Fcntl::F_DUPFD))
+ begin
+ assert_predicate(g, :close_on_exec?)
+ ensure
+ g.close
+ end
+ }
+ IO.pipe {|r,w|
+ assert_predicate(r, :close_on_exec?)
+ assert_predicate(w, :close_on_exec?)
+ }
+ end
+
+ def test_ioctl_linux
+ return if /linux/ !~ RUBY_PLATFORM
+ # Alpha, mips, sparc and ppc have an another ioctl request number scheme.
+ # So, hardcoded 0x80045200 may fail.
+ return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM
+
+ assert_nothing_raised do
+ File.open('/dev/urandom'){|f1|
+ entropy_count = ""
+ # RNDGETENTCNT(0x80045200) mean "get entropy count".
+ f1.ioctl(0x80045200, entropy_count)
+ }
+ end
+
+ buf = ''
+ assert_nothing_raised do
+ fionread = 0x541B
+ File.open(__FILE__){|f1|
+ f1.ioctl(fionread, buf)
+ }
+ end
+ assert_equal(File.size(__FILE__), buf.unpack('i!')[0])
+ end
+
+ def test_ioctl_linux2
+ return if /linux/ !~ RUBY_PLATFORM
+ return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM
+
+ return unless system('tty', '-s') # stdin is not a terminal
+ File.open('/dev/tty') { |f|
+ tiocgwinsz=0x5413
+ winsize=""
+ assert_nothing_raised {
+ f.ioctl(tiocgwinsz, winsize)
+ }
+ }
+ end
+
+ def test_setpos
+ mkcdtmpdir {
+ File.open("tmp.txt", "wb") {|f|
+ f.puts "a"
+ f.puts "bc"
+ f.puts "def"
+ }
+ pos1 = pos2 = pos3 = nil
+ File.open("tmp.txt", "rb") {|f|
+ assert_equal("a\n", f.gets)
+ pos1 = f.pos
+ assert_equal("bc\n", f.gets)
+ pos2 = f.pos
+ assert_equal("def\n", f.gets)
+ pos3 = f.pos
+ assert_equal(nil, f.gets)
+ }
+ File.open("tmp.txt", "rb") {|f|
+ f.pos = pos1
+ assert_equal("bc\n", f.gets)
+ assert_equal("def\n", f.gets)
+ assert_equal(nil, f.gets)
+ }
+ File.open("tmp.txt", "rb") {|f|
+ f.pos = pos2
+ assert_equal("def\n", f.gets)
+ assert_equal(nil, f.gets)
+ }
+ File.open("tmp.txt", "rb") {|f|
+ f.pos = pos3
+ assert_equal(nil, f.gets)
+ }
+ File.open("tmp.txt", "rb") {|f|
+ f.pos = File.size("tmp.txt")
+ s = "not empty string "
+ assert_equal("", f.read(0,s))
+ }
+ }
+ end
+
+ def test_std_fileno
+ assert_equal(0, STDIN.fileno)
+ assert_equal(1, STDOUT.fileno)
+ assert_equal(2, STDERR.fileno)
+ assert_equal(0, $stdin.fileno)
+ assert_equal(1, $stdout.fileno)
+ assert_equal(2, $stderr.fileno)
+ end
+
+ def test_frozen_fileno
+ bug9865 = '[ruby-dev:48241] [Bug #9865]'
+ with_pipe do |r,w|
+ fd = r.fileno
+ assert_equal(fd, r.freeze.fileno, bug9865)
+ end
+ end
+
+ def test_frozen_autoclose
+ with_pipe do |r,w|
+ fd = r.fileno
+ assert_equal(true, r.freeze.autoclose?)
+ end
+ end
+
+ def test_sysread_locktmp
+ bug6099 = '[ruby-dev:45297]'
+ buf = " " * 100
+ data = "a" * 100
+ with_pipe do |r,w|
+ th = Thread.new {r.sysread(100, buf)}
+ Thread.pass until th.stop?
+ buf.replace("")
+ assert_empty(buf, bug6099)
+ w.write(data)
+ Thread.pass while th.alive?
+ th.join
+ end
+ assert_equal(data, buf, bug6099)
+ end
+
+ def test_readpartial_locktmp
+ bug6099 = '[ruby-dev:45297]'
+ buf = " " * 100
+ data = "a" * 100
+ th = nil
+ with_pipe do |r,w|
+ r.nonblock = true
+ th = Thread.new {r.readpartial(100, buf)}
+
+ Thread.pass until th.stop?
+
+ assert_equal 100, buf.bytesize
+
+ begin
+ buf.replace("")
+ rescue RuntimeError => e
+ assert_match(/can't modify string; temporarily locked/, e.message)
+ Thread.pass
+ end until buf.empty?
+
+ assert_empty(buf, bug6099)
+ assert_predicate(th, :alive?)
+ w.write(data)
+ Thread.pass while th.alive?
+ th.join
+ end
+ assert_equal(data, buf, bug6099)
+ end
+
+ def test_advise_pipe
+ # we don't know if other platforms have a real posix_fadvise()
+ return if /linux/ !~ RUBY_PLATFORM
+ with_pipe do |r,w|
+ # Linux 2.6.15 and earlier returned EINVAL instead of ESPIPE
+ assert_raise(Errno::ESPIPE, Errno::EINVAL) { r.advise(:willneed) }
+ assert_raise(Errno::ESPIPE, Errno::EINVAL) { w.advise(:willneed) }
+ end
+ end
+
+ def assert_buffer_not_raise_shared_string_error
+ bug6764 = '[ruby-core:46586]'
+ bug9847 = '[ruby-core:62643] [Bug #9847]'
+ size = 28
+ data = [*"a".."z", *"A".."Z"].shuffle.join("")
+ t = Tempfile.new("test_io")
+ t.write(data)
+ t.close
+ w = []
+ assert_nothing_raised(RuntimeError, bug6764) do
+ buf = ''
+ File.open(t.path, "r") do |r|
+ while yield(r, size, buf)
+ w << buf.dup
+ end
+ end
+ end
+ assert_equal(data, w.join(""), bug9847)
+ ensure
+ t.close!
+ end
+
+ def test_read_buffer_not_raise_shared_string_error
+ assert_buffer_not_raise_shared_string_error do |r, size, buf|
+ r.read(size, buf)
+ end
+ end
+
+ def test_sysread_buffer_not_raise_shared_string_error
+ assert_buffer_not_raise_shared_string_error do |r, size, buf|
+ begin
+ r.sysread(size, buf)
+ rescue EOFError
+ nil
+ end
+ end
+ end
+
+ def test_readpartial_buffer_not_raise_shared_string_error
+ assert_buffer_not_raise_shared_string_error do |r, size, buf|
+ begin
+ r.readpartial(size, buf)
+ rescue EOFError
+ nil
+ end
+ end
+ end
+
+ def test_puts_recursive_ary
+ bug5986 = '[ruby-core:42444]'
+ c = Class.new {
+ def to_ary
+ [self]
+ end
+ }
+ s = StringIO.new
+ s.puts(c.new)
+ assert_equal("[...]\n", s.string, bug5986)
+ end
+
+ def test_io_select_with_many_files
+ bug8080 = '[ruby-core:53349]'
+
+ assert_normal_exit %q{
+ require "tempfile"
+
+ # try to raise RLIM_NOFILE to >FD_SETSIZE
+ # Unfortunately, ruby export FD_SETSIZE. then we assume it's 1024.
+ fd_setsize = 1024
+
+ begin
+ Process.setrlimit(Process::RLIMIT_NOFILE, fd_setsize+10)
+ rescue =>e
+ # Process::RLIMIT_NOFILE couldn't be raised. skip the test
+ exit 0
+ end
+
+ tempfiles = []
+ (0..fd_setsize+1).map {|i|
+ tempfiles << Tempfile.open("test_io_select_with_many_files")
+ }
+
+ IO.select(tempfiles)
+ }, bug8080, timeout: 30
+ end
+
+ def test_read_32bit_boundary
+ bug8431 = '[ruby-core:55098] [Bug #8431]'
+ make_tempfile {|t|
+ assert_separately(["-", bug8431, t.path], <<-"end;")
+ msg = ARGV.shift
+ f = open(ARGV[0], "rb")
+ f.seek(0xffff_ffff)
+ assert_nil(f.read(1), msg)
+ end;
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_write_32bit_boundary
+ bug8431 = '[ruby-core:55098] [Bug #8431]'
+ make_tempfile {|t|
+ def t.close(unlink_now = false)
+ # TODO: Tempfile should deal with this delay on Windows?
+ # NOTE: re-opening with O_TEMPORARY does not work.
+ path = self.path
+ ret = super
+ if unlink_now
+ begin
+ File.unlink(path)
+ rescue Errno::ENOENT
+ rescue Errno::EACCES
+ sleep(2)
+ retry
+ end
+ end
+ ret
+ end
+
+ begin
+ assert_separately(["-", bug8431, t.path], <<-"end;", timeout: 30)
+ msg = ARGV.shift
+ f = open(ARGV[0], "wb")
+ f.seek(0xffff_ffff)
+ begin
+ # this will consume very long time or fail by ENOSPC on a
+ # filesystem which sparse file is not supported
+ f.write('1')
+ pos = f.tell
+ rescue Errno::ENOSPC
+ skip "non-sparse file system"
+ rescue SystemCallError
+ else
+ assert_equal(0x1_0000_0000, pos, msg)
+ end
+ end;
+ rescue Timeout::Error
+ skip "Timeout because of slow file writing"
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_unlocktmp_ensure
+ bug8669 = '[ruby-core:56121] [Bug #8669]'
+
+ str = ""
+ IO.pipe {|r,|
+ t = Thread.new { r.read(nil, str) }
+ sleep 0.1 until t.stop?
+ t.raise
+ sleep 0.1 while t.alive?
+ assert_nothing_raised(RuntimeError, bug8669) { str.clear }
+ assert_raise(RuntimeError) { t.join }
+ }
+ end
+
+ def test_readpartial_unlocktmp_ensure
+ bug8669 = '[ruby-core:56121] [Bug #8669]'
+
+ str = ""
+ IO.pipe {|r, w|
+ t = Thread.new { r.readpartial(4096, str) }
+ sleep 0.1 until t.stop?
+ t.raise
+ sleep 0.1 while t.alive?
+ assert_nothing_raised(RuntimeError, bug8669) { str.clear }
+ assert_raise(RuntimeError) { t.join }
+ }
+ end
+
+ def test_sysread_unlocktmp_ensure
+ bug8669 = '[ruby-core:56121] [Bug #8669]'
+
+ str = ""
+ IO.pipe {|r, w|
+ t = Thread.new { r.sysread(4096, str) }
+ sleep 0.1 until t.stop?
+ t.raise
+ sleep 0.1 while t.alive?
+ assert_nothing_raised(RuntimeError, bug8669) { str.clear }
+ assert_raise(RuntimeError) { t.join }
+ }
+ end
+
+ def test_exception_at_close
+ bug10153 = '[ruby-core:64463] [Bug #10153] exception in close at the end of block'
+ assert_raise(Errno::EBADF, bug10153) do
+ IO.pipe do |r, w|
+ assert_nothing_raised {IO.open(w.fileno) {}}
+ end
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_io_m17n.rb b/jni/ruby/test/ruby/test_io_m17n.rb
new file mode 100644
index 0000000..734b017
--- /dev/null
+++ b/jni/ruby/test/ruby/test_io_m17n.rb
@@ -0,0 +1,2566 @@
+# coding: US-ASCII
+require 'test/unit'
+require 'tmpdir'
+require 'timeout'
+
+class TestIO_M17N < Test::Unit::TestCase
+ ENCS = [
+ Encoding::ASCII_8BIT,
+ Encoding::EUC_JP,
+ Encoding::Shift_JIS,
+ Encoding::UTF_8
+ ]
+
+ def with_tmpdir
+ Dir.mktmpdir {|dir|
+ Dir.chdir(dir) {
+ yield dir
+ }
+ }
+ end
+
+ def pipe(*args, wp, rp)
+ re, we = nil, nil
+ r, w = IO.pipe(*args)
+ rt = Thread.new do
+ begin
+ rp.call(r)
+ rescue Exception
+ r.close
+ re = $!
+ end
+ end
+ wt = Thread.new do
+ begin
+ wp.call(w)
+ rescue Exception
+ w.close
+ we = $!
+ end
+ end
+ flunk("timeout") unless wt.join(10) && rt.join(10)
+ ensure
+ w.close unless !w || w.closed?
+ r.close unless !r || r.closed?
+ (wt.kill; wt.join) if wt
+ (rt.kill; rt.join) if rt
+ raise we if we
+ raise re if re
+ end
+
+ def with_pipe(*args)
+ r, w = IO.pipe(*args)
+ begin
+ yield r, w
+ ensure
+ r.close if !r.closed?
+ w.close if !w.closed?
+ end
+ end
+
+ def generate_file(path, content)
+ open(path, "wb") {|f| f.write content }
+ end
+
+ def encdump(str)
+ "#{str.dump}.force_encoding(#{str.encoding.name.dump})"
+ end
+
+ def assert_str_equal(expected, actual, message=nil)
+ full_message = build_message(message, <<EOT)
+#{encdump expected} expected but not equal to
+#{encdump actual}.
+EOT
+ assert_equal(expected, actual, full_message)
+ end
+
+ def test_open_r
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r") {|f|
+ assert_equal(Encoding.default_external, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_rb
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "rb") {|f|
+ assert_equal(Encoding.find("ASCII-8BIT"), f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_enc
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r:euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_ascii8bit
+ with_tmpdir {
+ generate_file('tmp', "")
+ EnvUtil.with_default_external(Encoding::ASCII_8BIT) do
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ open("tmp", "r") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ open("tmp", "r:ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ open("tmp", "r:ascii-8bit:utf-16") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ end
+ EnvUtil.with_default_internal(nil) do
+ open("tmp", "r") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ open("tmp", "r:ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ open("tmp", "r:ascii-8bit:utf-16") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ end
+ end
+ }
+ end
+
+ def test_open_r_enc_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", encoding: "euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_encname_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", encoding: Encoding::EUC_JP) {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_ext_enc_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", external_encoding: Encoding::EUC_JP) {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_ext_encname_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", external_encoding: "euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_enc_enc
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", external_encoding: Encoding::EUC_JP, internal_encoding: Encoding::UTF_8) {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_encname_encname
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r:euc-jp:utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_encname_encname_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", encoding: "euc-jp:utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_enc_enc_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", external_encoding: Encoding::EUC_JP, internal_encoding: Encoding::UTF_8) {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_r_externalencname_internalencname_in_opt
+ with_tmpdir {
+ generate_file('tmp', "")
+ open("tmp", "r", external_encoding: "euc-jp", internal_encoding: "utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w
+ with_tmpdir {
+ open("tmp", "w") {|f|
+ assert_equal(nil, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_wb
+ with_tmpdir {
+ open("tmp", "wb") {|f|
+ assert_equal(Encoding.find("ASCII-8BIT"), f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc
+ with_tmpdir {
+ open("tmp", "w:euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_in_opt
+ with_tmpdir {
+ open("tmp", "w", encoding: "euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_in_opt2
+ with_tmpdir {
+ open("tmp", "w", external_encoding: "euc-jp") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_enc
+ with_tmpdir {
+ open("tmp", "w:euc-jp:utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_enc_in_opt
+ with_tmpdir {
+ open("tmp", "w", encoding: "euc-jp:utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_enc_in_opt2
+ with_tmpdir {
+ open("tmp", "w", external_encoding: "euc-jp", internal_encoding: "utf-8") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_open_w_enc_enc_perm
+ with_tmpdir {
+ open("tmp", "w:euc-jp:utf-8", 0600) {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ }
+ }
+ end
+
+ def test_ignored_encoding_option
+ enc = "\u{30a8 30f3 30b3 30fc 30c7 30a3 30f3 30b0}"
+ pattern = /#{enc}/
+ assert_warning(pattern) {
+ open(IO::NULL, external_encoding: "us-ascii", encoding: enc) {}
+ }
+ assert_warning(pattern) {
+ open(IO::NULL, internal_encoding: "us-ascii", encoding: enc) {}
+ }
+ end
+
+ def test_io_new_enc
+ with_tmpdir {
+ generate_file("tmp", "\xa1")
+ fd = IO.sysopen("tmp")
+ f = IO.new(fd, "r:sjis")
+ begin
+ assert_equal(Encoding::Windows_31J, f.read.encoding)
+ ensure
+ f.close
+ end
+ }
+ end
+
+ def test_s_pipe_invalid
+ pipe("utf-8", "euc-jp", { :invalid=>:replace },
+ proc do |w|
+ w << "\x80"
+ w.close
+ end,
+ proc do |r|
+ assert_equal("?", r.read)
+ end)
+ end
+
+ def test_s_pipe_undef
+ pipe("utf-8:euc-jp", { :undef=>:replace },
+ proc do |w|
+ w << "\ufffd"
+ w.close
+ end,
+ proc do |r|
+ assert_equal("?", r.read)
+ end)
+ end
+
+ def test_s_pipe_undef_replace_string
+ pipe("utf-8:euc-jp", { :undef=>:replace, :replace=>"X" },
+ proc do |w|
+ w << "\ufffd"
+ w.close
+ end,
+ proc do |r|
+ assert_equal("X", r.read)
+ end)
+ end
+
+ def test_dup
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ w << "\u3042"
+ w.close
+ end,
+ proc do |r|
+ r2 = r.dup
+ begin
+ assert_equal("\xA4\xA2".force_encoding("euc-jp"), r2.read)
+ ensure
+ r2.close
+ end
+ end)
+ end
+
+ def test_dup_undef
+ pipe("utf-8:euc-jp", { :undef=>:replace },
+ proc do |w|
+ w << "\uFFFD"
+ w.close
+ end,
+ proc do |r|
+ r2 = r.dup
+ begin
+ assert_equal("?", r2.read)
+ ensure
+ r2.close
+ end
+ end)
+ end
+
+ def test_stdin
+ assert_equal(Encoding.default_external, STDIN.external_encoding)
+ assert_equal(nil, STDIN.internal_encoding)
+ end
+
+ def test_stdout
+ assert_equal(nil, STDOUT.external_encoding)
+ assert_equal(nil, STDOUT.internal_encoding)
+ end
+
+ def test_stderr
+ assert_equal(nil, STDERR.external_encoding)
+ assert_equal(nil, STDERR.internal_encoding)
+ end
+
+ def test_terminator_conversion
+ with_tmpdir {
+ generate_file('tmp', "before \u00FF after")
+ s = open("tmp", "r:utf-8:iso-8859-1") {|f|
+ f.gets("\xFF".force_encoding("iso-8859-1"))
+ }
+ assert_equal(Encoding.find("iso-8859-1"), s.encoding)
+ assert_str_equal("before \xFF".force_encoding("iso-8859-1"), s, '[ruby-core:14288]')
+ }
+ end
+
+ def test_terminator_conversion2
+ with_tmpdir {
+ generate_file('tmp', "before \xA1\xA2\xA2\xA3 after")
+ s = open("tmp", "r:euc-jp:utf-8") {|f|
+ f.gets("\xA2\xA2".force_encoding("euc-jp").encode("utf-8"))
+ }
+ assert_equal(Encoding.find("utf-8"), s.encoding)
+ assert_str_equal("before \xA1\xA2\xA2\xA3 after".force_encoding("euc-jp").encode("utf-8"), s, '[ruby-core:14319]')
+ }
+ end
+
+ def test_terminator_stateful_conversion
+ with_tmpdir {
+ src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp")
+ generate_file('tmp', src)
+ s = open("tmp", "r:iso-2022-jp:euc-jp") {|f|
+ f.gets("0".force_encoding("euc-jp"))
+ }
+ assert_equal(Encoding.find("euc-jp"), s.encoding)
+ assert_str_equal(src.encode("euc-jp"), s)
+ }
+ end
+
+ def test_nonascii_terminator
+ with_tmpdir {
+ generate_file('tmp', "before \xA2\xA2 after")
+ open("tmp", "r:euc-jp") {|f|
+ assert_raise(ArgumentError) {
+ f.gets("\xA2\xA2".force_encoding("utf-8"))
+ }
+ }
+ }
+ end
+
+ def test_pipe_terminator_conversion
+ rs = "\xA2\xA2".encode("utf-8", "euc-jp")
+ pipe("euc-jp:utf-8",
+ proc do |w|
+ w.write "before \xa2\xa2 after"
+ w.close
+ end,
+ proc do |r|
+ timeout(1) {
+ assert_equal("before \xa2\xa2".encode("utf-8", "euc-jp"),
+ r.gets(rs))
+ }
+ end)
+ end
+
+ def test_pipe_conversion
+ pipe("euc-jp:utf-8",
+ proc do |w|
+ w.write "\xa1\xa1"
+ end,
+ proc do |r|
+ assert_equal("\xa1\xa1".encode("utf-8", "euc-jp"), r.getc)
+ end)
+ end
+
+ def test_pipe_convert_partial_read
+ pipe("euc-jp:utf-8",
+ proc do |w|
+ w.write "\xa1"
+ sleep 0.1
+ w.write "\xa1"
+ end,
+ proc do |r|
+ assert_equal("\xa1\xa1".encode("utf-8", "euc-jp"), r.getc)
+ end)
+ end
+
+ def test_getc_invalid
+ pipe("euc-jp:utf-8",
+ proc do |w|
+ w << "\xa1xyz"
+ w.close
+ end,
+ proc do |r|
+ err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc }
+ assert_equal("\xA1".force_encoding("ascii-8bit"), err.error_bytes)
+ assert_equal("xyz", r.read(10))
+ end)
+ end
+
+ def test_getc_stateful_conversion
+ with_tmpdir {
+ src = "\e$B\x23\x30\x23\x31\e(B".force_encoding("iso-2022-jp")
+ generate_file('tmp', src)
+ open("tmp", "r:iso-2022-jp:euc-jp") {|f|
+ assert_equal("\xa3\xb0".force_encoding("euc-jp"), f.getc)
+ assert_equal("\xa3\xb1".force_encoding("euc-jp"), f.getc)
+ }
+ }
+ end
+
+ def test_getc_newlineconv
+ with_tmpdir {
+ src = "\u3042"
+ generate_file('tmp', src)
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ open("tmp", "rt") {|f|
+ s = f.getc
+ assert_equal(true, s.valid_encoding?)
+ assert_equal("\u3042", s)
+ }
+ end
+ }
+ end
+
+ def test_getc_newlineconv_invalid
+ with_tmpdir {
+ src = "\xE3\x81"
+ generate_file('tmp', src)
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ open("tmp", "rt") {|f|
+ s = f.getc
+ assert_equal(false, s.valid_encoding?)
+ assert_equal("\xE3".force_encoding("UTF-8"), s)
+ s = f.getc
+ assert_equal(false, s.valid_encoding?)
+ assert_equal("\x81".force_encoding("UTF-8"), s)
+ }
+ end
+ }
+ end
+
+ def test_ungetc_int
+ with_tmpdir {
+ generate_file('tmp', "A")
+ s = open("tmp", "r:GB18030") {|f|
+ f.ungetc(0x8431A439)
+ f.read
+ }
+ assert_equal(Encoding::GB18030, s.encoding)
+ assert_str_equal(0x8431A439.chr("GB18030")+"A", s)
+ }
+ end
+
+ def test_ungetc_str
+ with_tmpdir {
+ generate_file('tmp', "A")
+ s = open("tmp", "r:GB18030") {|f|
+ f.ungetc(0x8431A439.chr("GB18030"))
+ f.read
+ }
+ assert_equal(Encoding::GB18030, s.encoding)
+ assert_str_equal(0x8431A439.chr("GB18030")+"A", s)
+ }
+ end
+
+ def test_ungetc_stateful_conversion
+ with_tmpdir {
+ src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp")
+ generate_file('tmp', src)
+ s = open("tmp", "r:iso-2022-jp:euc-jp") {|f|
+ f.ungetc("0".force_encoding("euc-jp"))
+ f.read
+ }
+ assert_equal(Encoding.find("euc-jp"), s.encoding)
+ assert_str_equal("0" + src.encode("euc-jp"), s)
+ }
+ end
+
+ def test_ungetc_stateful_conversion2
+ with_tmpdir {
+ src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp")
+ former = "before \e$B\x23\x30\e(B".force_encoding("iso-2022-jp")
+ rs = "\e$B\x23\x30\e(B".force_encoding("iso-2022-jp")
+ latter = "\e$B\x23\x31\e(B after".force_encoding("iso-2022-jp")
+ generate_file('tmp', src)
+ s = open("tmp", "r:iso-2022-jp:euc-jp") {|f|
+ assert_equal(former.encode("euc-jp", "iso-2022-jp"),
+ f.gets(rs.encode("euc-jp", "iso-2022-jp")))
+ f.ungetc("0")
+ f.read
+ }
+ assert_equal(Encoding.find("euc-jp"), s.encoding)
+ assert_str_equal("0" + latter.encode("euc-jp"), s)
+ }
+ end
+
+ def test_open_ascii
+ with_tmpdir {
+ src = "abc\n"
+ generate_file('tmp', "abc\n")
+ ENCS.each {|enc|
+ s = open('tmp', "r:#{enc}") {|f| f.gets }
+ assert_equal(enc, s.encoding)
+ assert_str_equal(src, s)
+ }
+ }
+ end
+
+ def test_open_nonascii
+ with_tmpdir {
+ src = "\xc2\xa1\n"
+ generate_file('tmp', src)
+ ENCS.each {|enc|
+ content = src.dup.force_encoding(enc)
+ s = open('tmp', "r:#{enc}") {|f| f.gets }
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ }
+ end
+
+ def test_read_encoding
+ with_tmpdir {
+ src = "\xc2\xa1\n".force_encoding("ASCII-8BIT")
+ generate_file('tmp', "\xc2\xa1\n")
+ ENCS.each {|enc|
+ content = src.dup.force_encoding(enc)
+ open('tmp', "r:#{enc}") {|f|
+ s = f.getc
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content[0], s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.readchar
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content[0], s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.gets
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.readline
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ lines = f.readlines
+ assert_equal(1, lines.length)
+ s = lines[0]
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ f.each_line {|s|
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.read
+ assert_equal(enc, s.encoding)
+ assert_str_equal(content, s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.read(1)
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_str_equal(src[0], s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.readpartial(1)
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_str_equal(src[0], s)
+ }
+ open('tmp', "r:#{enc}") {|f|
+ s = f.sysread(1)
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_str_equal(src[0], s)
+ }
+ }
+ }
+ end
+
+ def test_write_noenc
+ src = "\xc2\xa1\n".force_encoding("ascii-8bit")
+ with_tmpdir {
+ open('tmp', "w") {|f|
+ ENCS.each {|enc|
+ f.write src.dup.force_encoding(enc)
+ }
+ }
+ open('tmp', 'r:ascii-8bit') {|f|
+ assert_equal(src*ENCS.length, f.read)
+ }
+ }
+ end
+
+ def test_write_conversion
+ utf8 = "\u6666"
+ eucjp = "\xb3\xa2".force_encoding("EUC-JP")
+ with_tmpdir {
+ open('tmp', "w:EUC-JP") {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ f.print utf8
+ }
+ assert_equal(eucjp, File.read('tmp').force_encoding("EUC-JP"))
+ open('tmp', 'r:EUC-JP:UTF-8') {|f|
+ assert_equal(Encoding::EUC_JP, f.external_encoding)
+ assert_equal(Encoding::UTF_8, f.internal_encoding)
+ assert_equal(utf8, f.read)
+ }
+ }
+ end
+
+ def test_pipe
+ utf8 = "\u6666"
+ eucjp = "\xb3\xa2".force_encoding("EUC-JP")
+
+ pipe(proc do |w|
+ w << utf8
+ w.close
+ end, proc do |r|
+ assert_equal(Encoding.default_external, r.external_encoding)
+ assert_equal(nil, r.internal_encoding)
+ s = r.read
+ assert_equal(Encoding.default_external, s.encoding)
+ assert_str_equal(utf8.dup.force_encoding(Encoding.default_external), s)
+ end)
+
+ pipe("EUC-JP",
+ proc do |w|
+ w << eucjp
+ w.close
+ end,
+ proc do |r|
+ assert_equal(Encoding::EUC_JP, r.external_encoding)
+ assert_equal(nil, r.internal_encoding)
+ assert_equal(eucjp, r.read)
+ end)
+
+ pipe("UTF-8",
+ proc do |w|
+ w << "a" * 1023 + "\u3042" + "a" * 1022
+ w.close
+ end,
+ proc do |r|
+ assert_equal(true, r.read.valid_encoding?)
+ end)
+
+ pipe("UTF-8:EUC-JP",
+ proc do |w|
+ w << utf8
+ w.close
+ end,
+ proc do |r|
+ assert_equal(Encoding::UTF_8, r.external_encoding)
+ assert_equal(Encoding::EUC_JP, r.internal_encoding)
+ assert_equal(eucjp, r.read)
+ end)
+
+ assert_raise_with_message(ArgumentError, /invalid name encoding/) do
+ with_pipe("UTF-8", "UTF-8".encode("UTF-32BE")) {}
+ end
+ assert_raise_with_message(ArgumentError, /invalid name encoding/) do
+ with_pipe("UTF-8".encode("UTF-32BE")) {}
+ end
+
+ ENCS.each {|enc|
+ pipe(enc,
+ proc do |w|
+ w << "\xc2\xa1"
+ w.close
+ end,
+ proc do |r|
+ s = r.getc
+ assert_equal(enc, s.encoding)
+ end)
+ }
+
+ ENCS.each {|enc|
+ next if enc == Encoding::ASCII_8BIT
+ next if enc == Encoding::UTF_8
+ pipe("#{enc}:UTF-8",
+ proc do |w|
+ w << "\xc2\xa1"
+ w.close
+ end,
+ proc do |r|
+ s = r.read
+ assert_equal(Encoding::UTF_8, s.encoding)
+ assert_equal(s.encode("UTF-8"), s)
+ end)
+ }
+
+ end
+
+ def test_marshal
+ data = 56225
+ pipe("EUC-JP",
+ proc do |w|
+ Marshal.dump(data, w)
+ w.close
+ end,
+ proc do |r|
+ result = nil
+ assert_nothing_raised("[ruby-dev:33264]") { result = Marshal.load(r) }
+ assert_equal(data, result)
+ end)
+ end
+
+ def test_gets_nil
+ pipe("UTF-8:EUC-JP",
+ proc do |w|
+ w << "\u{3042}"
+ w.close
+ end,
+ proc do |r|
+ result = r.gets(nil)
+ assert_equal("\u{3042}".encode("euc-jp"), result)
+ end)
+ end
+
+ def test_gets_limit
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.gets(1)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.gets(2)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4".force_encoding("euc-jp"), r.gets(3)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4".force_encoding("euc-jp"), r.gets(4)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6".force_encoding("euc-jp"), r.gets(5)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6".force_encoding("euc-jp"), r.gets(6)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(7)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(8)) })
+ pipe("euc-jp",
+ proc {|w| w << "\xa4\xa2\xa4\xa4\xa4\xa6\n\xa4\xa8\xa4\xaa"; w.close },
+ proc {|r| assert_equal("\xa4\xa2\xa4\xa4\xa4\xa6\n".force_encoding("euc-jp"), r.gets(9)) })
+ end
+
+ def test_gets_invalid
+ before = "\u{3042}\u{3044}"
+ invalid = "\x80".force_encoding("utf-8")
+ after = "\u{3046}\u{3048}"
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ w << before + invalid + after
+ w.close
+ end,
+ proc do |r|
+ err = assert_raise(Encoding::InvalidByteSequenceError) { r.gets }
+ assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes)
+ assert_equal(after.encode("euc-jp"), r.gets)
+ end)
+ end
+
+ def test_getc_invalid2
+ before1 = "\u{3042}"
+ before2 = "\u{3044}"
+ invalid = "\x80".force_encoding("utf-8")
+ after1 = "\u{3046}"
+ after2 = "\u{3048}"
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ w << before1 + before2 + invalid + after1 + after2
+ w.close
+ end,
+ proc do |r|
+ assert_equal(before1.encode("euc-jp"), r.getc)
+ assert_equal(before2.encode("euc-jp"), r.getc)
+ err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc }
+ assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes)
+ assert_equal(after1.encode("euc-jp"), r.getc)
+ assert_equal(after2.encode("euc-jp"), r.getc)
+ end)
+ end
+
+ def test_getc_invalid3
+ before1 = "\x42\x30".force_encoding("utf-16le")
+ before2 = "\x44\x30".force_encoding("utf-16le")
+ invalid = "\x00\xd8".force_encoding("utf-16le")
+ after1 = "\x46\x30".force_encoding("utf-16le")
+ after2 = "\x48\x30".force_encoding("utf-16le")
+ pipe("utf-16le:euc-jp", { :binmode => true },
+ proc do |w|
+ w << before1 + before2 + invalid + after1 + after2
+ w.close
+ end,
+ proc do |r|
+ assert_equal(before1.encode("euc-jp"), r.getc)
+ assert_equal(before2.encode("euc-jp"), r.getc)
+ err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc }
+ assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes)
+ assert_equal(after1.encode("euc-jp"), r.getc)
+ assert_equal(after2.encode("euc-jp"), r.getc)
+ end)
+ end
+
+ def test_read_all
+ str = "\u3042\u3044"
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ w << str
+ w.close
+ end,
+ proc do |r|
+ assert_equal(str.encode("euc-jp"), r.read)
+ end)
+ end
+
+ def test_read_all_invalid
+ before = "\u{3042}\u{3044}"
+ invalid = "\x80".force_encoding("utf-8")
+ after = "\u{3046}\u{3048}"
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ w << before + invalid + after
+ w.close
+ end,
+ proc do |r|
+ err = assert_raise(Encoding::InvalidByteSequenceError) { r.read }
+ assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes)
+ assert_equal(after.encode("euc-jp"), r.read)
+ end)
+ end
+
+ def test_file_foreach
+ with_tmpdir {
+ generate_file('tst', 'a' * 8191 + "\xa1\xa1")
+ assert_nothing_raised {
+ File.foreach('tst', :encoding=>"euc-jp") {|line| line.inspect }
+ }
+ }
+ end
+
+ def test_set_encoding
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ s = "\u3042".force_encoding("ascii-8bit")
+ s << "\x82\xa0".force_encoding("ascii-8bit")
+ w << s
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ r.set_encoding("shift_jis:euc-jp")
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ end)
+ end
+
+ def test_set_encoding2
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ s = "\u3042".force_encoding("ascii-8bit")
+ s << "\x82\xa0".force_encoding("ascii-8bit")
+ w << s
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ r.set_encoding("shift_jis", "euc-jp")
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ end)
+ end
+
+ def test_set_encoding_nil
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ s = "\u3042".force_encoding("ascii-8bit")
+ s << "\x82\xa0".force_encoding("ascii-8bit")
+ w << s
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ r.set_encoding(nil)
+ assert_equal("\x82\xa0".force_encoding(Encoding.default_external), r.read)
+ end)
+ end
+
+ def test_set_encoding_enc
+ pipe("utf-8:euc-jp",
+ proc do |w|
+ s = "\u3042".force_encoding("ascii-8bit")
+ s << "\x82\xa0".force_encoding("ascii-8bit")
+ w << s
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), r.getc)
+ r.set_encoding(Encoding::Shift_JIS)
+ assert_equal("\x82\xa0".force_encoding(Encoding::Shift_JIS), r.getc)
+ end)
+ end
+
+ def test_set_encoding_invalid
+ pipe(proc do |w|
+ w << "\x80"
+ w.close
+ end,
+ proc do |r|
+ r.set_encoding("utf-8:euc-jp", :invalid=>:replace)
+ assert_equal("?", r.read)
+ end)
+ end
+
+ def test_set_encoding_identical
+ #bug5568 = '[ruby-core:40727]'
+ bug6324 = '[ruby-core:44455]'
+ open(__FILE__, "r") do |f|
+ assert_warning('', bug6324) {
+ f.set_encoding("eucjp:euc-jp")
+ }
+ assert_warning('', bug6324) {
+ f.set_encoding("eucjp", "euc-jp")
+ }
+ assert_warning('', bug6324) {
+ f.set_encoding(Encoding::EUC_JP, "euc-jp")
+ }
+ assert_warning('', bug6324) {
+ f.set_encoding("eucjp", Encoding::EUC_JP)
+ }
+ assert_warning('', bug6324) {
+ f.set_encoding(Encoding::EUC_JP, Encoding::EUC_JP)
+ }
+ nonstr = Object.new
+ def nonstr.to_str; "eucjp"; end
+ assert_warning('', bug6324) {
+ f.set_encoding(nonstr, nonstr)
+ }
+ end
+ end
+
+ def test_set_encoding_undef
+ pipe(proc do |w|
+ w << "\ufffd"
+ w.close
+ end,
+ proc do |r|
+ r.set_encoding("utf-8", "euc-jp", :undef=>:replace)
+ assert_equal("?", r.read)
+ end)
+ end
+
+ def test_set_encoding_undef_replace
+ pipe(proc do |w|
+ w << "\ufffd"
+ w.close
+ end,
+ proc do |r|
+ r.set_encoding("utf-8", "euc-jp", :undef=>:replace, :replace=>"ZZZ")
+ assert_equal("ZZZ", r.read)
+ end)
+ pipe(proc do |w|
+ w << "\ufffd"
+ w.close
+ end,
+ proc do |r|
+ r.set_encoding("utf-8:euc-jp", :undef=>:replace, :replace=>"ZZZ")
+ assert_equal("ZZZ", r.read)
+ end)
+ end
+
+ def test_set_encoding_binmode
+ assert_raise(ArgumentError) {
+ open(__FILE__, "rt") {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_raise(ArgumentError) {
+ open(__FILE__, "r") {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_nothing_raised {
+ open(__FILE__, "rb") {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_nothing_raised {
+ open(__FILE__, "r") {|f|
+ f.binmode
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_nothing_raised {
+ open(__FILE__, "rt") {|f|
+ f.binmode
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_nothing_raised {
+ open(__FILE__, "r", binmode: true) {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_raise(ArgumentError) {
+ open(__FILE__, "rb", binmode: true) {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_raise(ArgumentError) {
+ open(__FILE__, "rb", binmode: false) {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ end
+
+ def test_set_encoding_unsupported
+ bug5567 = '[ruby-core:40726]'
+ IO.pipe do |r, w|
+ assert_nothing_raised(bug5567) do
+ assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx")}
+ assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx", "us-ascii")}
+ assert_warning(/Unsupported/, bug5567) {r.set_encoding("us-ascii", "fffffffffffxx")}
+ end
+ end
+ end
+
+ def test_textmode_twice
+ assert_raise(ArgumentError) {
+ open(__FILE__, "rt", textmode: true) {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ assert_raise(ArgumentError) {
+ open(__FILE__, "rt", textmode: false) {|f|
+ f.set_encoding("iso-2022-jp")
+ }
+ }
+ end
+
+ def test_write_conversion_fixenc
+ pipe(proc do |w|
+ w.set_encoding("iso-2022-jp:utf-8")
+ w << "\u3042"
+ w << "\u3044"
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"),
+ r.read.force_encoding("ascii-8bit"))
+ end)
+ end
+
+ def test_write_conversion_anyenc_stateful
+ pipe(proc do |w|
+ w.set_encoding("iso-2022-jp")
+ w << "\u3042"
+ w << "\x82\xa2".force_encoding("sjis")
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"),
+ r.read.force_encoding("ascii-8bit"))
+ end)
+ end
+
+ def test_write_conversion_anyenc_stateless
+ pipe(proc do |w|
+ w.set_encoding("euc-jp")
+ w << "\u3042"
+ w << "\x82\xa2".force_encoding("sjis")
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\xa4\xa2\xa4\xa4".force_encoding("ascii-8bit"),
+ r.read.force_encoding("ascii-8bit"))
+ end)
+ end
+
+ def test_write_conversion_anyenc_stateful_nosync
+ pipe(proc do |w|
+ w.sync = false
+ w.set_encoding("iso-2022-jp")
+ w << "\u3042"
+ w << "\x82\xa2".force_encoding("sjis")
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\e$B$\"$$\e(B".force_encoding("ascii-8bit"),
+ r.read.force_encoding("ascii-8bit"))
+ end)
+ end
+
+ def test_read_stateful
+ pipe("euc-jp:iso-2022-jp",
+ proc do |w|
+ w << "\xA4\xA2"
+ w.close
+ end,
+ proc do |r|
+ assert_equal("\e$B$\"\e(B".force_encoding("iso-2022-jp"), r.read)
+ end)
+ end
+
+ def test_stdin_external_encoding_with_reopen
+ skip "passing non-stdio fds is not supported" if /mswin|mingw/ =~ RUBY_PLATFORM
+ with_tmpdir {
+ open("tst", "w+") {|f|
+ pid = spawn(EnvUtil.rubybin, '-e', <<-'End', 10=>f)
+ io = IO.new(10, "r+")
+ STDIN.reopen(io)
+ STDIN.external_encoding
+ STDIN.write "\u3042"
+ STDIN.flush
+ End
+ Process.wait pid
+ f.rewind
+ result = f.read.force_encoding("ascii-8bit")
+ assert_equal("\u3042".force_encoding("ascii-8bit"), result)
+ }
+ }
+ end
+
+ def test_popen_r_enc
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ end
+
+ def test_popen_r_enc_in_opt
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r", encoding: "ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ end
+
+ def test_popen_r_enc_in_opt2
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 255'", "r", external_encoding: "ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ end
+
+ def test_popen_r_enc_enc
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r:shift_jis:euc-jp") {|f|
+ assert_equal(Encoding::Shift_JIS, f.external_encoding)
+ assert_equal(Encoding::EUC_JP, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\x8e\xa1".force_encoding("euc-jp"), s)
+ }
+ end
+
+ def test_popen_r_enc_enc_in_opt
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r", encoding: "shift_jis:euc-jp") {|f|
+ assert_equal(Encoding::Shift_JIS, f.external_encoding)
+ assert_equal(Encoding::EUC_JP, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\x8e\xa1".force_encoding("euc-jp"), s)
+ }
+ end
+
+ def test_popen_r_enc_enc_in_opt2
+ IO.popen("#{EnvUtil.rubybin} -e 'putc 0xa1'", "r", external_encoding: "shift_jis", internal_encoding: "euc-jp") {|f|
+ assert_equal(Encoding::Shift_JIS, f.external_encoding)
+ assert_equal(Encoding::EUC_JP, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\x8e\xa1".force_encoding("euc-jp"), s)
+ }
+ end
+
+ def test_popenv_r_enc_enc_in_opt2
+ IO.popen([EnvUtil.rubybin, "-e", "putc 0xa1"], "r", external_encoding: "shift_jis", internal_encoding: "euc-jp") {|f|
+ assert_equal(Encoding::Shift_JIS, f.external_encoding)
+ assert_equal(Encoding::EUC_JP, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\x8e\xa1".force_encoding("euc-jp"), s)
+ }
+ end
+
+ def test_open_pipe_r_enc
+ open("|#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ end
+
+ def test_open_pipe_r_enc2
+ open("|#{EnvUtil.rubybin} -e 'putc \"\\u3042\"'", "r:UTF-8") {|f|
+ assert_equal(Encoding::UTF_8, f.external_encoding)
+ assert_equal(nil, f.internal_encoding)
+ s = f.read
+ assert_equal(Encoding::UTF_8, s.encoding)
+ assert_equal("\u3042", s)
+ }
+ end
+
+ def test_s_foreach_enc
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :mode => "r:ascii-8bit") {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_enc_in_opt
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :encoding => "ascii-8bit") {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_enc_in_opt2
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :external_encoding => "ascii-8bit") {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_enc_enc
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :mode => "r:utf-8:euc-jp") {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_enc_enc_in_opt
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :mode => "r", :encoding => "utf-8:euc-jp") {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_enc_enc_in_opt2
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :mode => "r", :external_encoding => "utf-8", :internal_encoding => "euc-jp") {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :open_args => ["r:ascii-8bit"]) {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc_in_opt
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :open_args => ["r", encoding: "ascii-8bit"]) {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc_in_opt2
+ with_tmpdir {
+ generate_file("t", "\xff")
+ IO.foreach("t", :open_args => ["r", external_encoding: "ascii-8bit"]) {|s|
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ assert_equal("\xff".force_encoding("ascii-8bit"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc_enc
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :open_args => ["r:utf-8:euc-jp"]) {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc_enc_in_opt
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :open_args => ["r", encoding: "utf-8:euc-jp"]) {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_s_foreach_open_args_enc_enc_in_opt2
+ with_tmpdir {
+ generate_file("t", "\u3042")
+ IO.foreach("t", :open_args => ["r", external_encoding: "utf-8", internal_encoding: "euc-jp"]) {|s|
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ assert_equal("\xa4\xa2".force_encoding("euc-jp"), s)
+ }
+ }
+ end
+
+ def test_both_textmode_binmode
+ bug5918 = '[ruby-core:42199]'
+ assert_raise(ArgumentError, bug5918) { open("not-exist", "r", :textmode=>true, :binmode=>true) }
+ assert_raise(ArgumentError, bug5918) { open("not-exist", "rt", :binmode=>true) }
+ assert_raise(ArgumentError, bug5918) { open("not-exist", "rt", :binmode=>false) }
+ assert_raise(ArgumentError, bug5918) { open("not-exist", "rb", :textmode=>true) }
+ assert_raise(ArgumentError, bug5918) { open("not-exist", "rb", :textmode=>false) }
+ end
+
+ def test_textmode_decode_universal_newline_read
+ with_tmpdir {
+ generate_file("t.crlf", "a\r\nb\r\nc\r\n")
+ assert_equal("a\nb\nc\n", File.read("t.crlf", mode:"rt:euc-jp:utf-8"))
+ assert_equal("a\nb\nc\n", File.read("t.crlf", mode:"rt"))
+ open("t.crlf", "rt:euc-jp:utf-8") {|f| assert_equal("a\nb\nc\n", f.read) }
+ open("t.crlf", "rt") {|f| assert_equal("a\nb\nc\n", f.read) }
+ open("t.crlf", "r", :textmode=>true) {|f| assert_equal("a\nb\nc\n", f.read) }
+ open("t.crlf", "r", textmode: true, universal_newline: false) {|f|
+ assert_equal("a\r\nb\r\nc\r\n", f.read)
+ }
+
+ generate_file("t.cr", "a\rb\rc\r")
+ assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt:euc-jp:utf-8"))
+ assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt"))
+
+ generate_file("t.lf", "a\nb\nc\n")
+ assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt:euc-jp:utf-8"))
+ assert_equal("a\nb\nc\n", File.read("t.cr", mode:"rt"))
+ }
+ end
+
+ def test_textmode_decode_universal_newline_getc
+ with_tmpdir {
+ generate_file("t.crlf", "a\r\nb\r\nc\r\n")
+ open("t.crlf", "rt") {|f|
+ assert_equal("a", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("b", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("c", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal(nil, f.getc)
+ }
+
+ generate_file("t.cr", "a\rb\rc\r")
+ open("t.cr", "rt") {|f|
+ assert_equal("a", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("b", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("c", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal(nil, f.getc)
+ }
+
+ generate_file("t.lf", "a\nb\nc\n")
+ open("t.lf", "rt") {|f|
+ assert_equal("a", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("b", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("c", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal(nil, f.getc)
+ }
+ }
+ end
+
+ def test_textmode_decode_universal_newline_gets
+ with_tmpdir {
+ generate_file("t.crlf", "a\r\nb\r\nc\r\n")
+ open("t.crlf", "rt") {|f|
+ assert_equal("a\n", f.gets)
+ assert_equal("b\n", f.gets)
+ assert_equal("c\n", f.gets)
+ assert_equal(nil, f.gets)
+ }
+
+ generate_file("t.cr", "a\rb\rc\r")
+ open("t.cr", "rt") {|f|
+ assert_equal("a\n", f.gets)
+ assert_equal("b\n", f.gets)
+ assert_equal("c\n", f.gets)
+ assert_equal(nil, f.gets)
+ }
+
+ generate_file("t.lf", "a\nb\nc\n")
+ open("t.lf", "rt") {|f|
+ assert_equal("a\n", f.gets)
+ assert_equal("b\n", f.gets)
+ assert_equal("c\n", f.gets)
+ assert_equal(nil, f.gets)
+ }
+ }
+ end
+
+ def test_textmode_decode_universal_newline_utf16
+ with_tmpdir {
+ generate_file("t.utf16be.crlf", "\0a\0\r\0\n\0b\0\r\0\n\0c\0\r\0\n")
+ assert_equal("a\nb\nc\n", File.read("t.utf16be.crlf", mode:"rt:utf-16be:utf-8"))
+
+ generate_file("t.utf16le.crlf", "a\0\r\0\n\0b\0\r\0\n\0c\0\r\0\n\0")
+ assert_equal("a\nb\nc\n", File.read("t.utf16le.crlf", mode:"rt:utf-16le:utf-8"))
+
+ generate_file("t.utf16be.cr", "\0a\0\r\0b\0\r\0c\0\r")
+ assert_equal("a\nb\nc\n", File.read("t.utf16be.cr", mode:"rt:utf-16be:utf-8"))
+
+ generate_file("t.utf16le.cr", "a\0\r\0b\0\r\0c\0\r\0")
+ assert_equal("a\nb\nc\n", File.read("t.utf16le.cr", mode:"rt:utf-16le:utf-8"))
+
+ generate_file("t.utf16be.lf", "\0a\0\n\0b\0\n\0c\0\n")
+ assert_equal("a\nb\nc\n", File.read("t.utf16be.lf", mode:"rt:utf-16be:utf-8"))
+
+ generate_file("t.utf16le.lf", "a\0\n\0b\0\n\0c\0\n\0")
+ assert_equal("a\nb\nc\n", File.read("t.utf16le.lf", mode:"rt:utf-16le:utf-8"))
+ }
+ end
+
+ SYSTEM_NEWLINE = []
+ def system_newline
+ return SYSTEM_NEWLINE.first if !SYSTEM_NEWLINE.empty?
+ with_tmpdir {
+ open("newline", "wt") {|f|
+ f.print "\n"
+ }
+ open("newline", "rb") {|f|
+ SYSTEM_NEWLINE << f.read
+ }
+ }
+ SYSTEM_NEWLINE.first
+ end
+
+ def test_textmode_encode_newline
+ with_tmpdir {
+ open("t.txt", "wt") {|f|
+ f.puts "abc"
+ f.puts "def"
+ }
+ content = File.read("t.txt", :mode=>"rb")
+ nl = system_newline
+ assert_equal("abc#{nl}def#{nl}", content)
+ }
+ end
+
+ def test_textmode_encode_newline_enc
+ with_tmpdir {
+ open("t.txt", "wt:euc-jp") {|f|
+ f.puts "abc\u3042"
+ f.puts "def\u3044"
+ }
+ content = File.read("t.txt", :mode=>"rb:ascii-8bit")
+ nl = system_newline
+ assert_equal("abc\xA4\xA2#{nl}def\xA4\xA4#{nl}", content)
+ }
+ end
+
+ def test_read_newline_conversion_with_encoding_conversion
+ with_tmpdir {
+ generate_file("t.utf8.crlf", "a\r\nb\r\n")
+ open("t.utf8.crlf", "rb:utf-8:utf-16be") {|f|
+ content = f.read
+ assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"), content)
+ }
+ open("t.utf8.crlf", "rt:utf-8:utf-16be") {|f|
+ content = f.read
+ assert_equal("\0a\0\n\0b\0\n".force_encoding("UTF-16BE"), content)
+ }
+ open("t.utf8.crlf", "r:utf-8:utf-16be") {|f|
+ content = f.read
+ if system_newline == "\n"
+ assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"), content)
+ else
+ assert_equal("\0a\0\n\0b\0\n".force_encoding("UTF-16BE"), content)
+ end
+ }
+ }
+ end
+
+ def test_read_newline_conversion_without_encoding_conversion
+ with_tmpdir {
+ generate_file("t.utf16.crlf", "\0a\0\r\0\n\0b\0\r\0\n")
+ open("t.utf16.crlf", "rb:utf-16be") {|f|
+ content = f.read
+ assert_equal("\0a\0\r\0\n\0b\0\r\0\n".force_encoding("UTF-16BE"),
+ content)
+ }
+ }
+ end
+
+ def test_read_newline_conversion_error
+ with_tmpdir {
+ generate_file("empty.txt", "")
+ # ascii incompatible encoding without conversion needs binmode.
+ assert_raise(ArgumentError) {
+ open("empty.txt", "rt:utf-16be") {|f| }
+ }
+ assert_raise(ArgumentError) {
+ open("empty.txt", "r:utf-16be") {|f| }
+ }
+ }
+ end
+
+ def test_read_mode
+ with_tmpdir {
+ generate_file("t", "a\rb\r\nc\n\xc2\xa2")
+ generate_file("ie", "a\rb\r\nc\n\e$B\x42\x22\e(B")
+ generate_file("iu", "a\rb\r\nc\n\e$B\x21\x71\e(B")
+ generate_file("be", "\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35")
+ generate_file("bu", "\0a\0\r\0b\0\r\0\n\0c\0\n\0\xa2")
+ # "\xc2\xa2" is valid as EUC-JP and UTF-8
+ # EUC-JP UTF-8 Unicode
+ # 0xC2A2 0xE894B5 U+8535
+ # 0xA1F1 0xC2A2 U+00A2
+
+ open("t","rt") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding(Encoding.default_external), f.read) }
+ open("t","rb") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding(Encoding::ASCII_8BIT), f.read) }
+
+ open("t","rt:euc-jp") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) }
+ open("t","rb:euc-jp") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) }
+ open("t","rt:utf-8") {|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) }
+ open("t","rb:utf-8") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) }
+ assert_raise(ArgumentError) { open("t", "rt:iso-2022-jp") {|f| } }
+ open("t","rb:iso-2022-jp") {|f| assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("ISO-2022-JP"), f.read) }
+
+ open("t","rt:euc-jp:utf-8") {|f| assert_equal("a\nb\nc\n\u8535", f.read) }
+ open("t","rt:utf-8:euc-jp") {|f| assert_equal("a\nb\nc\n\xa1\xf1".force_encoding("EUC-JP"), f.read) }
+ open("t","rb:euc-jp:utf-8") {|f| assert_equal("a\rb\r\nc\n\u8535", f.read) }
+ open("t","rb:utf-8:euc-jp") {|f| assert_equal("a\rb\r\nc\n\xa1\xf1".force_encoding("EUC-JP"), f.read) }
+
+ open("t","rt:euc-jp:iso-2022-jp"){|f| assert_equal("a\nb\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"), f.read) }
+ open("t","rt:utf-8:iso-2022-jp"){|f| assert_equal("a\nb\nc\n\e$B\x21\x71\e(B".force_encoding("ISO-2022-JP"), f.read) }
+ open("t","rt:euc-jp:utf-16be"){|f| assert_equal("\0a\0\n\0b\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"), f.read) }
+ open("t","rt:utf-8:utf-16be"){|f| assert_equal("\0a\0\n\0b\0\n\0c\0\n\0\xa2".force_encoding("UTF-16BE"), f.read) }
+ open("t","rb:euc-jp:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)}
+ open("t","rb:utf-8:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x21\x71\e(B".force_encoding("ISO-2022-JP"),f.read)}
+ open("t","rb:euc-jp:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)}
+ open("t","rb:utf-8:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\0\xa2".force_encoding("UTF-16BE"),f.read)}
+
+ open("ie","rt:iso-2022-jp:euc-jp"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) }
+ open("iu","rt:iso-2022-jp:utf-8"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) }
+ open("be","rt:utf-16be:euc-jp"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("EUC-JP"), f.read) }
+ open("bu","rt:utf-16be:utf-8"){|f| assert_equal("a\nb\nc\n\xc2\xa2".force_encoding("UTF-8"), f.read) }
+ open("ie","rb:iso-2022-jp:euc-jp"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"),f.read)}
+ open("iu","rb:iso-2022-jp:utf-8"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"),f.read)}
+ open("be","rb:utf-16be:euc-jp"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("EUC-JP"),f.read)}
+ open("bu","rb:utf-16be:utf-8"){|f|assert_equal("a\rb\r\nc\n\xc2\xa2".force_encoding("UTF-8"),f.read)}
+
+ open("ie","rt:iso-2022-jp:utf-16be"){|f|assert_equal("\0a\0\n\0b\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)}
+ open("be","rt:utf-16be:iso-2022-jp"){|f|assert_equal("a\nb\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)}
+ open("ie","rb:iso-2022-jp:utf-16be"){|f|assert_equal("\0a\0\r\0b\0\r\0\n\0c\0\n\x85\x35".force_encoding("UTF-16BE"),f.read)}
+ open("be","rb:utf-16be:iso-2022-jp"){|f|assert_equal("a\rb\r\nc\n\e$B\x42\x22\e(B".force_encoding("ISO-2022-JP"),f.read)}
+ }
+ end
+
+ def assert_write(expected, mode, *args)
+ with_tmpdir {
+ open("t", mode) {|f|
+ args.each {|arg| f.print arg }
+ }
+ content = File.read("t", :mode=>"rb:ascii-8bit")
+ assert_equal(expected.dup.force_encoding("ascii-8bit"),
+ content.force_encoding("ascii-8bit"))
+ }
+ end
+
+ def test_write_mode
+ # "\xc2\xa2" is valid as EUC-JP and UTF-8
+ # EUC-JP UTF-8 Unicode
+ # 0xC2A2 0xE894B5 U+8535
+ # 0xA1F1 0xC2A2 U+00A2
+ a = "a\rb\r\nc\n"
+ e = "\xc2\xa2".force_encoding("euc-jp")
+ u8 = "\xc2\xa2".force_encoding("utf-8")
+ u16 = "\x85\x35\0\r\x00\xa2\0\r\0\n\0\n".force_encoding("utf-16be")
+ i = "\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n".force_encoding("iso-2022-jp")
+ n = system_newline
+ n.encode("utf-16be").force_encoding("ascii-8bit")
+
+ assert_write("a\rb\r#{n}c#{n}", "wt", a)
+ assert_write("\xc2\xa2", "wt", e)
+ assert_write("\xc2\xa2", "wt", u8)
+
+ assert_write("a\rb\r\nc\n", "wb", a)
+ assert_write("\xc2\xa2", "wb", e)
+ assert_write("\xc2\xa2", "wb", u8)
+
+ #assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wt", u16) should raise
+ #assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wt", i) should raise
+ assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb", u16)
+ assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb", i)
+
+ t_write_mode_enc
+ t_write_mode_enc(":utf-8")
+ end
+
+ def t_write_mode_enc(enc="")
+ # "\xc2\xa2" is valid as EUC-JP and UTF-8
+ # EUC-JP UTF-8 Unicode
+ # 0xC2A2 0xE894B5 U+8535
+ # 0xA1F1 0xC2A2 U+00A2
+ a = "a\rb\r\nc\n"
+ e = "\xc2\xa2".force_encoding("euc-jp")
+ u8 = "\xc2\xa2".force_encoding("utf-8")
+ u16 = "\x85\x35\0\r\x00\xa2\0\r\0\n\0\n".force_encoding("utf-16be")
+ i = "\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n".force_encoding("iso-2022-jp")
+ n = system_newline
+ un = n.encode("utf-16be").force_encoding("ascii-8bit")
+
+ assert_write("a\rb\r#{n}c#{n}", "wt:euc-jp#{enc}", a)
+ assert_write("\xc2\xa2", "wt:euc-jp#{enc}", e)
+ assert_write("\xa1\xf1", "wt:euc-jp#{enc}", u8)
+
+ assert_write("a\rb\r\nc\n", "wb:euc-jp#{enc}", a)
+ assert_write("\xc2\xa2", "wb:euc-jp#{enc}", e)
+ assert_write("\xa1\xf1", "wb:euc-jp#{enc}", u8)
+
+ assert_write("\xc2\xa2\r\xa1\xf1\r#{n}#{n}", "wt:euc-jp#{enc}", u16)
+ assert_write("\xc2\xa2\r\xa1\xf1\r#{n}#{n}", "wt:euc-jp#{enc}", i)
+ assert_write("\xc2\xa2\r\xa1\xf1\r\n\n", "wb:euc-jp#{enc}", u16)
+ assert_write("\xc2\xa2\r\xa1\xf1\r\n\n", "wb:euc-jp#{enc}", i)
+
+ assert_write("\0a\0\r\0b\0\r#{un}\0c#{un}", "wt:utf-16be#{enc}", a)
+ assert_write("\x85\x35", "wt:utf-16be#{enc}", e)
+ assert_write("\x00\xa2", "wt:utf-16be#{enc}", u8)
+ assert_write("a\rb\r#{n}c#{n}", "wt:iso-2022-jp#{enc}", a)
+ assert_write("\e$B\x42\x22\e(B", "wt:iso-2022-jp#{enc}", e)
+ assert_write("\e$B\x21\x71\e(B", "wt:iso-2022-jp#{enc}", u8)
+
+ assert_write("\0a\0\r\0b\0\r\0\n\0c\0\n", "wb:utf-16be#{enc}", a)
+ assert_write("\x85\x35", "wb:utf-16be#{enc}", e)
+ assert_write("\x00\xa2", "wb:utf-16be#{enc}", u8)
+ assert_write("a\rb\r\nc\n", "wb:iso-2022-jp#{enc}", a)
+ assert_write("\e$B\x42\x22\e(B", "wb:iso-2022-jp#{enc}", e)
+ assert_write("\e$B\x21\x71\e(B", "wb:iso-2022-jp#{enc}", u8)
+
+ assert_write("\x85\x35\0\r\x00\xa2\0\r#{un}#{un}", "wt:utf-16be#{enc}", u16)
+ assert_write("\x85\x35\0\r\x00\xa2\0\r#{un}#{un}", "wt:utf-16be#{enc}", i)
+ assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb:utf-16be#{enc}", u16)
+ assert_write("\x85\x35\0\r\x00\xa2\0\r\0\n\0\n", "wb:utf-16be#{enc}", i)
+ assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r#{n}#{n}", "wt:iso-2022-jp#{enc}", u16)
+ assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r#{n}#{n}", "wt:iso-2022-jp#{enc}", i)
+ assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb:iso-2022-jp#{enc}", u16)
+ assert_write("\e$B\x42\x22\e(B\r\e$B\x21\x71\e(B\r\n\n", "wb:iso-2022-jp#{enc}", i)
+ end
+
+ def test_write_mode_fail
+ return if system_newline == "\n"
+ with_tmpdir {
+ open("t", "wt") {|f|
+ assert_raise(ArgumentError) { f.print "\0\r\0\r\0\n\0\n".force_encoding("utf-16be") }
+ }
+ }
+ end
+
+ def test_write_ascii_incompat
+ with_tmpdir {
+ open("t.utf8", "wb:utf-8:utf-16be") {|f| }
+ open("t.utf8", "wt:utf-8:utf-16be") {|f| }
+ open("t.utf8", "w:utf-8:utf-16be") {|f| }
+ open("t.utf16", "wb:utf-16be") {|f| }
+ open("t.utf16", "wt:utf-16be") {|f| }
+ open("t.utf16", "w:utf-16be") {|f| }
+ }
+ end
+
+ def test_binmode_write_ascii_incompat_internal
+ with_tmpdir {
+ open("t.utf8.lf", "wb:utf-8:utf-16be") {|f|
+ f.print "\0a\0\n\0b\0\n".force_encoding("UTF-16BE")
+ }
+ content = File.read("t.utf8.lf", :mode=>"rb:ascii-8bit")
+ assert_equal("a\nb\n", content)
+
+ open("t.utf8.lf", "wb:utf-16be") {|f|
+ f.print "\0a\0\n\0b\0\n".force_encoding("UTF-16BE")
+ }
+ content = File.read("t.utf8.lf", :mode=>"rb:ascii-8bit")
+ assert_equal("\0a\0\n\0b\0\n", content)
+ }
+ end
+
+ def test_binary
+ with_tmpdir {
+ src = "a\nb\rc\r\nd\n"
+ generate_file("t.txt", src)
+ open("t.txt", "rb") {|f|
+ assert_equal(src, f.read)
+ }
+ open("t.txt", "r", :binmode=>true) {|f|
+ assert_equal(src, f.read)
+ }
+ if system_newline == "\n"
+ open("t.txt", "r") {|f|
+ assert_equal(src, f.read)
+ }
+ end
+ }
+ end
+
+ def test_binmode
+ with_tmpdir {
+ src = "a\r\nb\r\nc\r\n"
+ generate_file("t.txt", src)
+ open("t.txt", "rt") {|f|
+ assert_equal("a", f.getc)
+ assert_equal("\n", f.getc)
+ f.binmode
+ assert_equal("b", f.getc)
+ assert_equal("\r", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("c", f.getc)
+ assert_equal("\r", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal(nil, f.getc)
+ }
+ }
+ end
+
+ def test_binmode2
+ with_tmpdir {
+ src = "a\r\nb\r\nc\r\n"
+ generate_file("t.txt", src)
+ open("t.txt", "rt:euc-jp:utf-8") {|f|
+ assert_equal("a", f.getc)
+ assert_equal("\n", f.getc)
+ f.binmode
+ assert_equal("b", f.getc)
+ assert_equal("\r", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal("c", f.getc)
+ assert_equal("\r", f.getc)
+ assert_equal("\n", f.getc)
+ assert_equal(nil, f.getc)
+ }
+ }
+ end
+
+ def test_binmode3
+ with_tmpdir {
+ src = "\u3042\r\n"
+ generate_file("t.txt", src)
+ srcbin = src.dup.force_encoding("ascii-8bit")
+ open("t.txt", "rt:utf-8:euc-jp") {|f|
+ f.binmode
+ result = f.read
+ assert_str_equal(srcbin, result)
+ assert_equal(Encoding::ASCII_8BIT, result.encoding)
+ }
+ }
+ end
+
+ def test_invalid_r
+ with_tmpdir {
+ generate_file("t.txt", "a\x80b")
+ open("t.txt", "r:utf-8:euc-jp", :invalid => :replace) {|f|
+ assert_equal("a?b", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :invalid => :replace, :replace => "") {|f|
+ assert_equal("ab", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :undef => :replace) {|f|
+ assert_raise(Encoding::InvalidByteSequenceError) { f.read }
+ assert_equal("b", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :undef => :replace, :replace => "") {|f|
+ assert_raise(Encoding::InvalidByteSequenceError) { f.read }
+ assert_equal("b", f.read)
+ }
+ }
+ end
+
+ def test_undef_r
+ with_tmpdir {
+ generate_file("t.txt", "a\uFFFDb")
+ open("t.txt", "r:utf-8:euc-jp", :undef => :replace) {|f|
+ assert_equal("a?b", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :undef => :replace, :replace => "") {|f|
+ assert_equal("ab", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :invalid => :replace) {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.read }
+ assert_equal("b", f.read)
+ }
+ open("t.txt", "r:utf-8:euc-jp", :invalid => :replace, :replace => "") {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.read }
+ assert_equal("b", f.read)
+ }
+ }
+ end
+
+ def test_invalid_w
+ with_tmpdir {
+ invalid_utf8 = "a\x80b".force_encoding("utf-8")
+ open("t.txt", "w:euc-jp", :invalid => :replace) {|f|
+ assert_nothing_raised { f.write invalid_utf8 }
+ }
+ assert_equal("a?b", File.read("t.txt"))
+
+ open("t.txt", "w:euc-jp", :invalid => :replace, :replace => "") {|f|
+ assert_nothing_raised { f.write invalid_utf8 }
+ }
+ assert_equal("ab", File.read("t.txt"))
+
+ open("t.txt", "w:euc-jp", :undef => :replace) {|f|
+ assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 }
+ }
+ open("t.txt", "w:euc-jp", :undef => :replace, :replace => "") {|f|
+ assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 }
+ }
+ }
+ end
+
+ def test_undef_w_stateless
+ with_tmpdir {
+ generate_file("t.txt", "a\uFFFDb")
+ open("t.txt", "w:euc-jp:utf-8", :undef => :replace) {|f|
+ assert_nothing_raised { f.write "a\uFFFDb" }
+ }
+ assert_equal("a?b", File.read("t.txt"))
+ open("t.txt", "w:euc-jp:utf-8", :undef => :replace, :replace => "") {|f|
+ assert_nothing_raised { f.write "a\uFFFDb" }
+ }
+ assert_equal("ab", File.read("t.txt"))
+ open("t.txt", "w:euc-jp:utf-8", :invalid => :replace) {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" }
+ }
+ open("t.txt", "w:euc-jp:utf-8", :invalid => :replace, :replace => "") {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" }
+ }
+ }
+ end
+
+ def test_undef_w_stateful
+ with_tmpdir {
+ generate_file("t.txt", "a\uFFFDb")
+ open("t.txt", "w:iso-2022-jp:utf-8", :undef => :replace) {|f|
+ assert_nothing_raised { f.write "a\uFFFDb" }
+ }
+ assert_equal("a?b", File.read("t.txt"))
+ open("t.txt", "w:iso-2022-jp:utf-8", :undef => :replace, :replace => "") {|f|
+ assert_nothing_raised { f.write "a\uFFFDb" }
+ }
+ assert_equal("ab", File.read("t.txt"))
+ open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace) {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" }
+ }
+ open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace, :replace => "") {|f|
+ assert_raise(Encoding::UndefinedConversionError) { f.write "a\uFFFDb" }
+ }
+ }
+ end
+
+ def test_w_xml_attr
+ with_tmpdir {
+ open("raw.txt", "wb", xml: :attr) {|f| f.print '&<>"\''; f.puts "\u4E02\u3042" }
+ content = File.read("raw.txt", :mode=>"rb:ascii-8bit")
+ assert_equal("\"&amp;&lt;&gt;&quot;'\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("\"&amp;&lt;&gt;&quot;'&#x4E02;&#x3042;\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("\"&amp;&lt;&gt;&quot;'&#x4E02;\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("\"&#x4E02;\"".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("\"&#x4E02;\"".force_encoding("ascii-8bit"), content)
+ }
+ end
+
+ def test_strip_bom
+ with_tmpdir {
+ text = "\uFEFFa"
+ stripped = "a"
+ %w/UTF-8 UTF-16BE UTF-16LE UTF-32BE UTF-32LE/.each do |name|
+ path = '%s-bom.txt' % name
+ content = text.encode(name)
+ generate_file(path, content)
+ result = File.read(path, mode: 'rb:BOM|UTF-8')
+ assert_equal(content[1].force_encoding("ascii-8bit"),
+ result.force_encoding("ascii-8bit"))
+ result = File.read(path, mode: 'rb:BOM|UTF-8:UTF-8')
+ assert_equal(Encoding::UTF_8, result.encoding)
+ assert_equal(stripped, result)
+ end
+
+ bug3407 = '[ruby-core:30641]'
+ path = 'UTF-8-bom.txt'
+ result = File.read(path, encoding: 'BOM|UTF-8')
+ assert_equal("a", result.force_encoding("ascii-8bit"), bug3407)
+
+ bug8323 = '[ruby-core:54563] [Bug #8323]'
+ expected = "a\xff".force_encoding("utf-8")
+ open(path, 'ab') {|f| f.write("\xff")}
+ result = File.read(path, encoding: 'BOM|UTF-8')
+ assert_not_predicate(result, :valid_encoding?, bug8323)
+ assert_equal(expected, result, bug8323)
+ result = File.read(path, encoding: 'BOM|UTF-8:UTF-8')
+ assert_not_predicate(result, :valid_encoding?, bug8323)
+ assert_equal(expected, result, bug8323)
+
+ path = 'ascii.txt'
+ generate_file(path, stripped)
+ result = File.read(path, encoding: 'BOM|UTF-8')
+ assert_equal(stripped, result, bug8323)
+ result = File.read(path, encoding: 'BOM|UTF-8:UTF-8')
+ assert_equal(stripped, result, bug8323)
+ }
+ end
+
+ def test_cbuf
+ with_tmpdir {
+ fn = "tst"
+ open(fn, "w") {|f| f.print "foo" }
+ open(fn, "r+t") {|f|
+ f.ungetc(f.getc)
+ assert_raise(IOError, "[ruby-dev:40493]") { f.readpartial(2) }
+ assert_raise(IOError) { f.read(2) }
+ assert_raise(IOError) { f.each_byte {|c| } }
+ assert_raise(IOError) { f.getbyte }
+ assert_raise(IOError) { f.ungetbyte(0) }
+ assert_raise(IOError) { f.sysread(2) }
+ assert_raise(IOError) { IO.copy_stream(f, "tmpout") }
+ assert_raise(IOError) { f.sysseek(2) }
+ }
+ open(fn, "r+t") {|f|
+ f.ungetc(f.getc)
+ assert_equal("foo", f.read)
+ }
+ }
+ end
+
+ def test_text_mode_ungetc_eof
+ with_tmpdir {
+ open("ff", "w") {|f| }
+ open("ff", "rt") {|f|
+ f.ungetc "a"
+ assert_not_predicate(f, :eof?, "[ruby-dev:40506] (3)")
+ }
+ }
+ end
+
+ def test_cbuf_select
+ pipe("US-ASCII:UTF-8", { :universal_newline => true },
+ proc do |w|
+ w << "\r\n"
+ end,
+ proc do |r|
+ r.ungetc(r.getc)
+ assert_equal([[r],[],[]], IO.select([r], nil, nil, 1))
+ end)
+ end
+
+ def test_textmode_paragraphmode
+ pipe("US-ASCII:UTF-8", { :universal_newline => true },
+ proc do |w|
+ w << "a\n\n\nc".gsub(/\n/, "\r\n")
+ w.close
+ end,
+ proc do |r|
+ assert_equal("a\n\n", r.gets(""))
+ assert_equal("c", r.gets(""), "[ruby-core:23723] (18)")
+ end)
+ end
+
+ def test_textmode_paragraph_binaryread
+ pipe("US-ASCII:UTF-8", { :universal_newline => true },
+ proc do |w|
+ w << "a\n\n\ncdefgh".gsub(/\n/, "\r\n")
+ w.close
+ end,
+ proc do |r|
+ assert_equal("a\n\n", r.gets(""))
+ assert_equal("c", r.getc)
+ assert_equal("defgh", r.readpartial(10))
+ end)
+ end
+
+ def test_textmode_paragraph_nonasciicompat
+ bug3534 = ['[ruby-dev:41803]', '[Bug #3534]']
+ IO.pipe {|r, w|
+ [Encoding::UTF_32BE, Encoding::UTF_32LE,
+ Encoding::UTF_16BE, Encoding::UTF_16LE,
+ Encoding::UTF_8].each do |e|
+ r.set_encoding(Encoding::US_ASCII, e)
+ wthr = Thread.new{ w.print(bug3534[0], "\n\n\n\n", bug3534[1], "\n") }
+ assert_equal((bug3534[0]+"\n\n").encode(e), r.gets(""), bug3534[0])
+ assert_equal((bug3534[1]+"\n").encode(e), r.gets(), bug3534[1])
+ wthr.join
+ end
+ }
+ end
+
+ def test_binmode_paragraph_nonasciicompat
+ bug3534 = ['[ruby-dev:41803]', '[Bug #3534]']
+ IO.pipe {|r, w|
+ r.binmode
+ w.binmode
+ [Encoding::UTF_32BE, Encoding::UTF_32LE,
+ Encoding::UTF_16BE, Encoding::UTF_16LE,
+ Encoding::UTF_8].each do |e|
+ r.set_encoding(Encoding::US_ASCII, e)
+ wthr = Thread.new{ w.print(bug3534[0], "\n\n\n\n", bug3534[1], "\n") }
+ assert_equal((bug3534[0]+"\n\n").encode(e), r.gets(""), bug3534[0])
+ assert_equal((bug3534[1]+"\n").encode(e), r.gets(), bug3534[1])
+ wthr.join
+ end
+ }
+ end
+
+ def test_puts_widechar
+ bug = '[ruby-dev:42212]'
+ pipe(Encoding::ASCII_8BIT,
+ proc do |w|
+ w.binmode
+ w.puts(0x010a.chr(Encoding::UTF_32BE))
+ w.puts(0x010a.chr(Encoding::UTF_16BE))
+ w.puts(0x0a010000.chr(Encoding::UTF_32LE))
+ w.puts(0x0a01.chr(Encoding::UTF_16LE))
+ w.close
+ end,
+ proc do |r|
+ r.binmode
+ assert_equal("\x00\x00\x01\x0a\n", r.read(5), bug)
+ assert_equal("\x01\x0a\n", r.read(3), bug)
+ assert_equal("\x00\x00\x01\x0a\n", r.read(5), bug)
+ assert_equal("\x01\x0a\n", r.read(3), bug)
+ assert_equal("", r.read, bug)
+ r.close
+ end)
+ end
+
+ def test_getc_ascii_only
+ bug4557 = '[ruby-core:35630]'
+ c = with_tmpdir {
+ open("a", "wb") {|f| f.puts "a"}
+ open("a", "rt") {|f| f.getc}
+ }
+ assert_predicate(c, :ascii_only?, bug4557)
+ end
+
+ def test_getc_conversion
+ bug8516 = '[ruby-core:55444] [Bug #8516]'
+ c = with_tmpdir {
+ open("a", "wb") {|f| f.putc "\xe1"}
+ open("a", "r:iso-8859-1:utf-8") {|f| f.getc}
+ }
+ assert_not_predicate(c, :ascii_only?, bug8516)
+ assert_equal(1, c.size, bug8516)
+ end
+
+ def test_default_mode_on_dosish
+ with_tmpdir {
+ open("a", "w") {|f| f.write "\n"}
+ assert_equal("\r\n", IO.binread("a"))
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_default_mode_on_unix
+ with_tmpdir {
+ open("a", "w") {|f| f.write "\n"}
+ assert_equal("\n", IO.binread("a"))
+ }
+ end unless /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_text_mode
+ with_tmpdir {
+ open("a", "wb") {|f| f.write "\r\n"}
+ assert_equal("\n", open("a", "rt"){|f| f.read})
+ }
+ end
+
+ def test_binary_mode
+ with_tmpdir {
+ open("a", "wb") {|f| f.write "\r\n"}
+ assert_equal("\r\n", open("a", "rb"){|f| f.read})
+ }
+ end
+
+ def test_default_stdout_stderr_mode
+ with_pipe do |in_r, in_w|
+ with_pipe do |out_r, out_w|
+ pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w, err: out_w)
+ in_r.close
+ out_w.close
+ in_w.write <<-EOS
+ STDOUT.puts "abc"
+ STDOUT.flush
+ STDERR.puts "def"
+ STDERR.flush
+ EOS
+ in_w.close
+ Process.wait pid
+ assert_equal "abc\r\ndef\r\n", out_r.binmode.read
+ out_r.close
+ end
+ end
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_cr_decorator_on_stdout
+ with_pipe do |in_r, in_w|
+ with_pipe do |out_r, out_w|
+ pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w)
+ in_r.close
+ out_w.close
+ in_w.write <<-EOS
+ STDOUT.set_encoding('locale', nil, newline: :cr)
+ STDOUT.puts "abc"
+ STDOUT.flush
+ EOS
+ in_w.close
+ Process.wait pid
+ assert_equal "abc\r", out_r.binmode.read
+ out_r.close
+ end
+ end
+ end
+
+ def test_lf_decorator_on_stdout
+ with_pipe do |in_r, in_w|
+ with_pipe do |out_r, out_w|
+ pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w)
+ in_r.close
+ out_w.close
+ in_w.write <<-EOS
+ STDOUT.set_encoding('locale', nil, newline: :lf)
+ STDOUT.puts "abc"
+ STDOUT.flush
+ EOS
+ in_w.close
+ Process.wait pid
+ assert_equal "abc\n", out_r.binmode.read
+ out_r.close
+ end
+ end
+ end
+
+ def test_crlf_decorator_on_stdout
+ with_pipe do |in_r, in_w|
+ with_pipe do |out_r, out_w|
+ pid = Process.spawn({}, EnvUtil.rubybin, in: in_r, out: out_w)
+ in_r.close
+ out_w.close
+ in_w.write <<-EOS
+ STDOUT.set_encoding('locale', nil, newline: :crlf)
+ STDOUT.puts "abc"
+ STDOUT.flush
+ EOS
+ in_w.close
+ Process.wait pid
+ assert_equal "abc\r\n", out_r.binmode.read
+ out_r.close
+ end
+ end
+ end
+
+ def test_binmode_with_pipe
+ with_pipe do |r, w|
+ src = "a\r\nb\r\nc\r\n"
+ w.binmode.write src
+ w.close
+
+ assert_equal("a", r.getc)
+ assert_equal("\n", r.getc)
+ r.binmode
+ assert_equal("b", r.getc)
+ assert_equal("\r", r.getc)
+ assert_equal("\n", r.getc)
+ assert_equal("c", r.getc)
+ assert_equal("\r", r.getc)
+ assert_equal("\n", r.getc)
+ assert_equal(nil, r.getc)
+ r.close
+ end
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_stdin_binmode
+ with_pipe do |in_r, in_w|
+ with_pipe do |out_r, out_w|
+ pid = Process.spawn({}, EnvUtil.rubybin, '-e', <<-'End', in: in_r, out: out_w)
+ STDOUT.binmode
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDIN.binmode
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ STDOUT.write STDIN.getc
+ End
+ in_r.close
+ out_w.close
+ src = "a\r\nb\r\nc\r\n"
+ in_w.binmode.write src
+ in_w.close
+ Process.wait pid
+ assert_equal "a\nb\r\nc\r\n", out_r.binmode.read
+ out_r.close
+ end
+ end
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_with_length
+ with_tmpdir {
+ str = "a\nb"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ assert_equal(str, f.read(3))
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_with_length_binmode
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ # read with length should be binary mode
+ assert_equal("a\r\n", f.read(3)) # binary
+ assert_equal("b\nc\n\n", f.read) # text
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_gets_and_read_with_binmode
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n\n\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ assert_equal("a\n", f.gets) # text
+ assert_equal("b\r\n", f.read(3)) # binary
+ assert_equal("c\r\n", f.read(3)) # binary
+ assert_equal("\n\n", f.read) # text
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_getc_and_read_with_binmode
+ with_tmpdir {
+ str = "a\r\nb\r\nc\n\n\r\n\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ assert_equal("a", f.getc) # text
+ assert_equal("\n", f.getc) # text
+ assert_equal("b\r\n", f.read(3)) # binary
+ assert_equal("c\n\n\n\n", f.read) # text
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_with_binmode_and_gets
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n\r\n"
+ open("tmp", "wb") { |f| f.write str }
+ open("tmp", "r") do |f|
+ assert_equal("a", f.getc) # text
+ assert_equal("\n", f.getc) # text
+ assert_equal("b\r\n", f.read(3)) # binary
+ assert_equal("c\n", f.gets) # text
+ assert_equal("\n", f.gets) # text
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_with_binmode_and_getc
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n\r\n"
+ open("tmp", "wb") { |f| f.write str }
+ open("tmp", "r") do |f|
+ assert_equal("a", f.getc) # text
+ assert_equal("\n", f.getc) # text
+ assert_equal("b\r\n", f.read(3)) # binary
+ assert_equal("c", f.getc) # text
+ assert_equal("\n", f.getc) # text
+ assert_equal("\n", f.getc) # text
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_write_with_binmode
+ with_tmpdir {
+ str = "a\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r+") do |f|
+ assert_equal("a\r\n", f.read(3)) # binary
+ f.write("b\n\n"); # text
+ f.rewind
+ assert_equal("a\nb\n\n", f.read) # text
+ f.rewind
+ assert_equal("a\r\nb\r\n\r\n", f.binmode.read) # binary
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_seek_with_setting_binmode
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n\r\n\n\n\n\n\n\n\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ assert_equal("a\n", f.gets) # text
+ assert_equal("b\r\n", f.read(3)) # binary
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_error_nonascii
+ bug6071 = '[ruby-dev:45279]'
+ paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
+ encs = with_tmpdir {
+ paths.map {|path|
+ open(path) rescue $!.message.encoding
+ }
+ }
+ assert_equal(paths.map(&:encoding), encs, bug6071)
+ end
+
+ def test_inspect_nonascii
+ bug6072 = '[ruby-dev:45280]'
+ paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
+ encs = with_tmpdir {
+ paths.map {|path|
+ open(path, "wb") {|f| f.inspect.encoding}
+ }
+ }
+ assert_equal(paths.map(&:encoding), encs, bug6072)
+ end
+
+ def test_pos_dont_move_cursor_position
+ bug6179 = '[ruby-core:43497]'
+ with_tmpdir {
+ str = "line one\r\nline two\r\nline three\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ assert_equal("line one\n", f.readline)
+ assert_equal(10, f.pos, bug6179)
+ assert_equal("line two\n", f.readline, bug6179)
+ assert_equal(20, f.pos, bug6179)
+ assert_equal("line three\n", f.readline, bug6179)
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_pos_with_buffer_end_cr
+ bug6401 = '[ruby-core:44874]'
+ with_tmpdir {
+ # Read buffer size is 8191. This generates '\r' at 8191.
+ lines = ["X" * 8187, "X"]
+ generate_file("tmp", lines.join("\r\n") + "\r\n")
+
+ open("tmp", "r") do |f|
+ lines.each do |line|
+ f.pos
+ assert_equal(line, f.readline.chomp, bug6401)
+ end
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_crlf_and_eof
+ bug6271 = '[ruby-core:44189]'
+ with_tmpdir {
+ str = "a\r\nb\r\nc\r\n"
+ generate_file("tmp", str)
+ open("tmp", "r") do |f|
+ i = 0
+ until f.eof?
+ assert_equal(str[i], f.read(1), bug6271)
+ i += 1
+ end
+ assert_equal(str.size, i, bug6271)
+ end
+ }
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_read_with_buf_broken_ascii_only
+ a, b = IO.pipe
+ a.binmode
+ b.binmode
+ b.write("\xE2\x9C\x93")
+ b.close
+
+ buf = "".force_encoding("binary")
+ assert buf.ascii_only?, "should have been ascii_only?"
+ a.read(1, buf)
+ assert !buf.ascii_only?, "should not have been ascii_only?"
+ ensure
+ a.close rescue nil
+ b.close rescue nil
+ end
+end
diff --git a/jni/ruby/test/ruby/test_iseq.rb b/jni/ruby/test/ruby/test_iseq.rb
new file mode 100644
index 0000000..686646d
--- /dev/null
+++ b/jni/ruby/test/ruby/test_iseq.rb
@@ -0,0 +1,144 @@
+require 'test/unit'
+
+class TestISeq < Test::Unit::TestCase
+ ISeq = RubyVM::InstructionSequence
+
+ def test_no_linenum
+ bug5894 = '[ruby-dev:45130]'
+ assert_normal_exit('p RubyVM::InstructionSequence.compile("1", "mac", "", 0).to_a', bug5894)
+ end
+
+ def lines src
+ body = RubyVM::InstructionSequence.new(src).to_a[13]
+ body.find_all{|e| e.kind_of? Fixnum}
+ end
+
+ def test_to_a_lines
+ src = <<-EOS
+ p __LINE__ # 1
+ p __LINE__ # 2
+ # 3
+ p __LINE__ # 4
+ EOS
+ assert_equal [1, 2, 4], lines(src)
+
+ src = <<-EOS
+ # 1
+ p __LINE__ # 2
+ # 3
+ p __LINE__ # 4
+ # 5
+ EOS
+ assert_equal [2, 4], lines(src)
+
+ src = <<-EOS
+ 1 # should be optimized out
+ 2 # should be optimized out
+ p __LINE__ # 3
+ p __LINE__ # 4
+ 5 # should be optimized out
+ 6 # should be optimized out
+ p __LINE__ # 7
+ 8 # should be optimized out
+ 9
+ EOS
+ assert_equal [3, 4, 7, 9], lines(src)
+ end
+
+ def test_unsupport_type
+ ary = RubyVM::InstructionSequence.compile("p").to_a
+ ary[9] = :foobar
+ assert_raise_with_message(TypeError, /:foobar/) {RubyVM::InstructionSequence.load(ary)}
+ end if defined?(RubyVM::InstructionSequence.load)
+
+ def test_disasm_encoding
+ src = "\u{3042} = 1; \u{3042}; \u{3043}"
+ asm = RubyVM::InstructionSequence.compile(src).disasm
+ assert_equal(src.encoding, asm.encoding)
+ assert_predicate(asm, :valid_encoding?)
+ src.encode!(Encoding::Shift_JIS)
+ asm = RubyVM::InstructionSequence.compile(src).disasm
+ assert_equal(src.encoding, asm.encoding)
+ assert_predicate(asm, :valid_encoding?)
+ end
+
+ LINE_BEFORE_METHOD = __LINE__
+ def method_test_line_trace
+
+ a = 1
+
+ b = 2
+
+ end
+
+ def test_line_trace
+ iseq = ISeq.compile \
+ %q{ a = 1
+ b = 2
+ c = 3
+ # d = 4
+ e = 5
+ # f = 6
+ g = 7
+
+ }
+ assert_equal([1, 2, 3, 5, 7], iseq.line_trace_all)
+ iseq.line_trace_specify(1, true) # line 2
+ iseq.line_trace_specify(3, true) # line 5
+
+ result = []
+ TracePoint.new(:specified_line){|tp|
+ result << tp.lineno
+ }.enable{
+ iseq.eval
+ }
+ assert_equal([2, 5], result)
+
+ iseq = ISeq.of(self.class.instance_method(:method_test_line_trace))
+ assert_equal([LINE_BEFORE_METHOD + 3, LINE_BEFORE_METHOD + 5], iseq.line_trace_all)
+ end if false # TODO: now, it is only for C APIs.
+
+ LINE_OF_HERE = __LINE__
+ def test_location
+ iseq = ISeq.of(method(:test_location))
+
+ assert_equal(__FILE__, iseq.path)
+ assert_match(/#{__FILE__}/, iseq.absolute_path)
+ assert_equal("test_location", iseq.label)
+ assert_equal("test_location", iseq.base_label)
+ assert_equal(LINE_OF_HERE+1, iseq.first_lineno)
+
+ line = __LINE__
+ iseq = ISeq.of(Proc.new{})
+ assert_equal(__FILE__, iseq.path)
+ assert_match(/#{__FILE__}/, iseq.absolute_path)
+ assert_equal("test_location", iseq.base_label)
+ assert_equal("block in test_location", iseq.label)
+ assert_equal(line+1, iseq.first_lineno)
+ end
+
+ def test_label_fstring
+ c = Class.new{ def foobar() end }
+
+ a, b = eval("# encoding: us-ascii\n'foobar'.freeze"),
+ ISeq.of(c.instance_method(:foobar)).label
+ assert_same a, b
+ end
+
+ def test_disable_opt
+ src = "a['foo'] = a['bar']; 'a'.freeze"
+ _,_,_,_,_,_,_,_,_,_,_,_,_,body= RubyVM::InstructionSequence.compile(src, __FILE__, __FILE__, __LINE__, false).to_a
+ body.each{|insn|
+ next if Integer === insn
+ op = insn.first
+ assert(!op.to_s.match(/^opt_/), "#{op}")
+ }
+ end
+
+ def test_invalid_source
+ bug11159 = '[ruby-core:69219] [Bug #11159]'
+ assert_raise(TypeError, bug11159) {ISeq.compile(nil)}
+ assert_raise(TypeError, bug11159) {ISeq.compile(:foo)}
+ assert_raise(TypeError, bug11159) {ISeq.compile(1)}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_iterator.rb b/jni/ruby/test/ruby/test_iterator.rb
new file mode 100644
index 0000000..34652db
--- /dev/null
+++ b/jni/ruby/test/ruby/test_iterator.rb
@@ -0,0 +1,497 @@
+require 'test/unit'
+
+class Array
+ def iter_test1
+ collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]}
+ end
+ def iter_test2
+ ary = collect{|e| [e, yield(e)]}
+ ary.sort{|a,b|a[1]<=>b[1]}
+ end
+end
+
+class TestIterator < Test::Unit::TestCase
+ def ttt
+ assert(iterator?)
+ end
+
+ def test_iterator
+ assert(!iterator?)
+
+ ttt{}
+
+ # yield at top level !! here's not toplevel
+ assert(!defined?(yield))
+ end
+
+ def test_array
+ x = [1, 2, 3, 4]
+ y = []
+
+ # iterator over array
+ for i in x
+ y.push i
+ end
+ assert_equal(x, y)
+ end
+
+ def tt
+ 1.upto(10) {|i|
+ yield i
+ }
+ end
+
+ def tt2(dummy)
+ yield 1
+ end
+
+ def tt3(&block)
+ tt2(raise(ArgumentError,""),&block)
+ end
+
+ def test_nested_iterator
+ i = 0
+ tt{|j| break if j == 5}
+ assert_equal(0, i)
+
+ assert_raise(ArgumentError) do
+ tt3{}
+ end
+ end
+
+ def tt4 &block
+ tt2(raise(ArgumentError,""),&block)
+ end
+
+ def test_block_argument_without_paren
+ assert_raise(ArgumentError) do
+ tt4{}
+ end
+ end
+
+ # iterator break/redo/next
+ def test_break
+ done = true
+ loop{
+ break
+ done = false # should not reach here
+ }
+ assert(done)
+
+ done = false
+ bad = false
+ loop {
+ break if done
+ done = true
+ next
+ bad = true # should not reach here
+ }
+ assert(!bad)
+
+ done = false
+ bad = false
+ loop {
+ break if done
+ done = true
+ redo
+ bad = true # should not reach here
+ }
+ assert(!bad)
+
+ x = []
+ for i in 1 .. 7
+ x.push i
+ end
+ assert_equal(7, x.size)
+ assert_equal([1, 2, 3, 4, 5, 6, 7], x)
+ end
+
+ def test_append_method_to_built_in_class
+ x = [[1,2],[3,4],[5,6]]
+ assert_equal(x.iter_test1{|x|x}, x.iter_test2{|x|x})
+ end
+
+ class IterTest
+ def initialize(e); @body = e; end
+
+ def each0(&block); @body.each(&block); end
+ def each1(&block); @body.each {|*x| block.call(*x) } end
+ def each2(&block); @body.each {|*x| block.call(x) } end
+ def each3(&block); @body.each {|x| block.call(*x) } end
+ def each4(&block); @body.each {|x| block.call(x) } end
+ def each5; @body.each {|*x| yield(*x) } end
+ def each6; @body.each {|*x| yield(x) } end
+ def each7; @body.each {|x| yield(*x) } end
+ def each8; @body.each {|x| yield(x) } end
+
+ def f(a)
+ a
+ end
+ end
+
+ def test_itertest
+ assert_equal([1], IterTest.new(nil).method(:f).to_proc.call([1]))
+ m = /\w+/.match("abc")
+ assert_equal([m], IterTest.new(nil).method(:f).to_proc.call([m]))
+
+ IterTest.new([0]).each0 {|x| assert_equal(0, x)}
+ IterTest.new([1]).each1 {|x| assert_equal(1, x)}
+ IterTest.new([2]).each2 {|x| assert_equal([2], x)}
+ IterTest.new([4]).each4 {|x| assert_equal(4, x)}
+ IterTest.new([5]).each5 {|x| assert_equal(5, x)}
+ IterTest.new([6]).each6 {|x| assert_equal([6], x)}
+ IterTest.new([8]).each8 {|x| assert_equal(8, x)}
+
+ IterTest.new([[0]]).each0 {|x| assert_equal([0], x)}
+ IterTest.new([[1]]).each1 {|x| assert_equal([1], x)}
+ IterTest.new([[2]]).each2 {|x| assert_equal([[2]], x)}
+ IterTest.new([[3]]).each3 {|x| assert_equal(3, x)}
+ IterTest.new([[4]]).each4 {|x| assert_equal([4], x)}
+ IterTest.new([[5]]).each5 {|x| assert_equal([5], x)}
+ IterTest.new([[6]]).each6 {|x| assert_equal([[6]], x)}
+ IterTest.new([[7]]).each7 {|x| assert_equal(7, x)}
+ IterTest.new([[8]]).each8 {|x| assert_equal([8], x)}
+
+ IterTest.new([[0,0]]).each0 {|*x| assert_equal([[0,0]], x)}
+ IterTest.new([[8,8]]).each8 {|*x| assert_equal([[8,8]], x)}
+ end
+
+ def m(var)
+ var
+ end
+
+ def m1
+ m(block_given?)
+ end
+
+ def m2
+ m(block_given?,&proc{})
+ end
+
+ def test_block_given
+ assert(m1{p 'test'})
+ assert(m2{p 'test'})
+ assert(!m1())
+ assert(!m2())
+ end
+
+ def m3(var, &block)
+ m(yield(var), &block)
+ end
+
+ def m4(&block)
+ m(m1(), &block)
+ end
+
+ def test_block_passing
+ assert(!m4())
+ assert(!m4 {})
+ assert_equal(100, m3(10) {|x|x*x})
+ end
+
+ class C
+ include Enumerable
+ def initialize
+ @a = [1,2,3]
+ end
+ def each(&block)
+ @a.each(&block)
+ end
+ end
+
+ def test_collect
+ assert_equal([1,2,3], C.new.collect{|n| n})
+ end
+
+ def test_proc
+ assert_instance_of(Proc, lambda{})
+ assert_instance_of(Proc, Proc.new{})
+ lambda{|a|assert_equal(a, 1)}.call(1)
+ end
+
+ def test_block
+ assert_instance_of(NilClass, get_block)
+ assert_instance_of(Proc, get_block{})
+ end
+
+ def test_argument
+ assert_nothing_raised {lambda{||}.call}
+ assert_raise(ArgumentError) {lambda{||}.call(1)}
+ assert_nothing_raised {lambda{|a,|}.call(1)}
+ assert_raise(ArgumentError) {lambda{|a,|}.call()}
+ assert_raise(ArgumentError) {lambda{|a,|}.call(1,2)}
+ end
+
+ def get_block(&block)
+ block
+ end
+
+ def test_get_block
+ assert_instance_of(Proc, get_block{})
+ assert_nothing_raised {get_block{||}.call()}
+ assert_nothing_raised {get_block{||}.call(1)}
+ assert_nothing_raised {get_block{|a,|}.call(1)}
+ assert_nothing_raised {get_block{|a,|}.call()}
+ assert_nothing_raised {get_block{|a,|}.call(1,2)}
+
+ assert_nothing_raised {get_block(&lambda{||}).call()}
+ assert_raise(ArgumentError) {get_block(&lambda{||}).call(1)}
+ assert_nothing_raised {get_block(&lambda{|a,|}).call(1)}
+ assert_raise(ArgumentError) {get_block(&lambda{|a,|}).call(1,2)}
+
+ block = get_block{11}
+ assert_instance_of(Proc, block)
+ assert_instance_of(Proc, block.to_proc)
+ assert_equal(block.clone.call, 11)
+ assert_instance_of(Proc, get_block(&block))
+
+ lmd = lambda{44}
+ assert_instance_of(Proc, lmd)
+ assert_instance_of(Proc, lmd.to_proc)
+ assert_equal(lmd.clone.call, 44)
+ assert_instance_of(Proc, get_block(&lmd))
+
+ assert_equal(1, Proc.new{|a,| a}.call(1,2,3))
+ assert_nothing_raised {Proc.new{|a,|}.call(1,2)}
+ end
+
+ def return1_test
+ Proc.new {
+ return 55
+ }.call + 5
+ end
+
+ def test_return1
+ assert_equal(55, return1_test())
+ end
+
+ def return2_test
+ lambda {
+ return 55
+ }.call + 5
+ end
+
+ def test_return2
+ assert_equal(60, return2_test())
+ end
+
+ def proc_call(&b)
+ b.call
+ end
+ def proc_yield()
+ yield
+ end
+ def proc_return1
+ proc_call{return 42}+1
+ end
+
+ def test_proc_return1
+ assert_equal(42, proc_return1())
+ end
+
+ def proc_return2
+ proc_yield{return 42}+1
+ end
+
+ def test_proc_return2
+ assert_equal(42, proc_return2())
+ end
+
+ def test_ljump
+ assert_raise(LocalJumpError) {get_block{break}.call}
+
+ # cannot use assert_nothing_raised due to passing block.
+ begin
+ val = lambda{break 11}.call
+ rescue LocalJumpError
+ assert(false, "LocalJumpError occurred from break in lambda")
+ else
+ assert_equal(11, val)
+ end
+
+ block = get_block{11}
+ lmd = lambda{44}
+ assert_equal(0, block.arity)
+ assert_equal(0, lmd.arity)
+ assert_equal(0, lambda{||}.arity)
+ assert_equal(1, lambda{|a|}.arity)
+ assert_equal(1, lambda{|a,|}.arity)
+ assert_equal(2, lambda{|a,b|}.arity)
+ end
+
+ def marity_test(m)
+ mobj = method(m)
+ assert_equal(mobj.arity, mobj.to_proc.arity)
+ end
+
+ def test_marity
+ marity_test(:assert)
+ marity_test(:marity_test)
+ marity_test(:p)
+
+ lambda(&method(:assert)).call(true)
+ lambda(&get_block{|a,n| assert(a,n)}).call(true, "marity")
+ end
+
+ def foo
+ yield(:key, :value)
+ end
+ def bar(&blk)
+ blk.call(:key, :value)
+ end
+
+ def test_yield_vs_call
+ foo{|k,v| assert_equal([:key, :value], [k,v])}
+ bar{|k,v| assert_equal([:key, :value], [k,v])}
+ end
+
+ class H
+ def each
+ yield [:key, :value]
+ end
+ alias each_pair each
+ end
+
+ def test_assoc_yield
+ [{:key=>:value}, H.new].each {|h|
+ h.each{|a| assert_equal([:key, :value], a)}
+ h.each{|a,| assert_equal(:key, a)}
+ h.each{|*a| assert_equal([[:key, :value]], a)}
+ h.each{|k,v| assert_equal([:key, :value], [k,v])}
+ h.each_pair{|a| assert_equal([:key, :value], a)}
+ h.each_pair{|a,| assert_equal(:key, a)}
+ h.each_pair{|*a| assert_equal([[:key, :value]], a)}
+ h.each_pair{|k,v| assert_equal([:key, :value], [k,v])}
+ }
+ end
+
+ class ITER_TEST1
+ def a
+ block_given?
+ end
+ end
+
+ class ITER_TEST2 < ITER_TEST1
+ include Test::Unit::Assertions
+ def a
+ assert(super)
+ super
+ end
+ end
+
+ def test_iter_test2
+ assert(ITER_TEST2.new.a {})
+ end
+
+ class ITER_TEST3
+ def foo x
+ return yield if block_given?
+ x
+ end
+ end
+
+ class ITER_TEST4 < ITER_TEST3
+ include Test::Unit::Assertions
+ def foo x
+ assert_equal(super, yield)
+ assert_equal(x, super(x, &nil))
+ end
+ end
+
+ def test_iter4
+ ITER_TEST4.new.foo(44){55}
+ end
+
+ def test_break__nested_loop1
+ _test_break__nested_loop1 do
+ break
+ end
+ end
+
+ def _test_break__nested_loop1
+ while true
+ yield
+ end
+ assert(false, "must not reach here")
+ end
+
+ def test_break__nested_loop2
+ _test_break__nested_loop2 do
+ break
+ end
+ end
+
+ def _test_break__nested_loop2
+ until false
+ yield
+ end
+ assert(false, "must not reach here")
+ end
+
+ def test_break__nested_loop3
+ _test_break__nested_loop3 do
+ break
+ end
+ end
+
+ def _test_break__nested_loop3
+ loop do
+ yield
+ end
+ assert(false, "must not reach here")
+ end
+
+ def test_break_from_enum
+ result = ["a"].inject("ng") {|x,y| break "ok"}
+ assert_equal("ok", result)
+ end
+
+ def _test_return_trace_func(x)
+ set_trace_func(proc {})
+ [].fetch(2) {return x}
+ ensure
+ set_trace_func(nil)
+ end
+
+ def test_return_trace_func
+ ok = "returned gracefully"
+ result = "skipped"
+ result = _test_return_trace_func(ok)
+ ensure
+ assert_equal(ok, result)
+ return
+ end
+
+ class IterString < ::String
+ def ===(other)
+ super if !block_given?
+ end
+ end
+
+ # Check that the block passed to an iterator
+ # does not get propagated inappropriately
+ def test_block_given_within_iterator
+ assert_equal(["b"], ["a", "b", "c"].grep(IterString.new("b")) {|s| s})
+ end
+
+ def test_enumerator
+ [1,2,3].each.with_index {|x,i|
+ assert_equal(x, i+1)
+ }
+
+ e = [1,2,3].each
+ assert_equal(1, e.next)
+ assert_equal(2, e.next)
+ assert_equal(3, e.next)
+ assert_raise(StopIteration){e.next}
+ e.rewind
+ assert_equal(1, e.next)
+ e.rewind
+ a = []
+ loop{a.push e.next}
+ assert_equal([1,2,3], a)
+
+ assert_equal([[8, 1, 10], [6, 2, 11], [4, 3, 12]],
+ [8,6,4].zip((1..10),(10..100)).to_a)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_keyword.rb b/jni/ruby/test/ruby/test_keyword.rb
new file mode 100644
index 0000000..9c76e15
--- /dev/null
+++ b/jni/ruby/test/ruby/test_keyword.rb
@@ -0,0 +1,579 @@
+require 'test/unit'
+
+class TestKeywordArguments < Test::Unit::TestCase
+ def f1(str: "foo", num: 424242)
+ [str, num]
+ end
+
+ def test_f1
+ assert_equal(["foo", 424242], f1)
+ assert_equal(["bar", 424242], f1(str: "bar"))
+ assert_equal(["foo", 111111], f1(num: 111111))
+ assert_equal(["bar", 111111], f1(str: "bar", num: 111111))
+ assert_raise(ArgumentError) { f1(str: "bar", check: true) }
+ assert_raise(ArgumentError) { f1("string") }
+ end
+
+
+ def f2(x, str: "foo", num: 424242)
+ [x, str, num]
+ end
+
+ def test_f2
+ assert_equal([:xyz, "foo", 424242], f2(:xyz))
+ assert_equal([{"bar"=>42}, "foo", 424242], f2("bar"=>42))
+ end
+
+
+ def f3(str: "foo", num: 424242, **h)
+ [str, num, h]
+ end
+
+ def test_f3
+ assert_equal(["foo", 424242, {}], f3)
+ assert_equal(["bar", 424242, {}], f3(str: "bar"))
+ assert_equal(["foo", 111111, {}], f3(num: 111111))
+ assert_equal(["bar", 111111, {}], f3(str: "bar", num: 111111))
+ assert_equal(["bar", 424242, {:check=>true}], f3(str: "bar", check: true))
+ assert_raise(ArgumentError) { f3("string") }
+ end
+
+
+ define_method(:f4) {|str: "foo", num: 424242| [str, num] }
+
+ def test_f4
+ assert_equal(["foo", 424242], f4)
+ assert_equal(["bar", 424242], f4(str: "bar"))
+ assert_equal(["foo", 111111], f4(num: 111111))
+ assert_equal(["bar", 111111], f4(str: "bar", num: 111111))
+ assert_raise(ArgumentError) { f4(str: "bar", check: true) }
+ assert_raise(ArgumentError) { f4("string") }
+ end
+
+
+ define_method(:f5) {|str: "foo", num: 424242, **h| [str, num, h] }
+
+ def test_f5
+ assert_equal(["foo", 424242, {}], f5)
+ assert_equal(["bar", 424242, {}], f5(str: "bar"))
+ assert_equal(["foo", 111111, {}], f5(num: 111111))
+ assert_equal(["bar", 111111, {}], f5(str: "bar", num: 111111))
+ assert_equal(["bar", 424242, {:check=>true}], f5(str: "bar", check: true))
+ assert_raise(ArgumentError) { f5("string") }
+ end
+
+
+ def f6(str: "foo", num: 424242, **h, &blk)
+ [str, num, h, blk]
+ end
+
+ def test_f6 # [ruby-core:40518]
+ assert_equal(["foo", 424242, {}, nil], f6)
+ assert_equal(["bar", 424242, {}, nil], f6(str: "bar"))
+ assert_equal(["foo", 111111, {}, nil], f6(num: 111111))
+ assert_equal(["bar", 111111, {}, nil], f6(str: "bar", num: 111111))
+ assert_equal(["bar", 424242, {:check=>true}, nil], f6(str: "bar", check: true))
+ a = f6 {|x| x + 42 }
+ assert_equal(["foo", 424242, {}], a[0, 3])
+ assert_equal(43, a.last.call(1))
+ end
+
+ def f7(*r, str: "foo", num: 424242, **h)
+ [r, str, num, h]
+ end
+
+ def test_f7 # [ruby-core:41772]
+ assert_equal([[], "foo", 424242, {}], f7)
+ assert_equal([[], "bar", 424242, {}], f7(str: "bar"))
+ assert_equal([[], "foo", 111111, {}], f7(num: 111111))
+ assert_equal([[], "bar", 111111, {}], f7(str: "bar", num: 111111))
+ assert_equal([[1], "foo", 424242, {}], f7(1))
+ assert_equal([[1, 2], "foo", 424242, {}], f7(1, 2))
+ assert_equal([[1, 2, 3], "foo", 424242, {}], f7(1, 2, 3))
+ assert_equal([[1], "bar", 424242, {}], f7(1, str: "bar"))
+ assert_equal([[1, 2], "bar", 424242, {}], f7(1, 2, str: "bar"))
+ assert_equal([[1, 2, 3], "bar", 424242, {}], f7(1, 2, 3, str: "bar"))
+ end
+
+ define_method(:f8) { |opt = :ion, *rest, key: :word|
+ [opt, rest, key]
+ }
+
+ def test_f8
+ assert_equal([:ion, [], :word], f8)
+ assert_equal([1, [], :word], f8(1))
+ assert_equal([1, [2], :word], f8(1, 2))
+ end
+
+ def f9(r, o=42, *args, p, k: :key, **kw, &b)
+ [r, o, args, p, k, kw, b]
+ end
+
+ def test_f9
+ assert_equal([1, 42, [], 2, :key, {}, nil], f9(1, 2))
+ assert_equal([1, 2, [], 3, :key, {}, nil], f9(1, 2, 3))
+ assert_equal([1, 2, [3], 4, :key, {}, nil], f9(1, 2, 3, 4))
+ assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], f9(1, 2, 3, 4, 5, str: "bar"))
+ end
+
+ def f10(a: 1, **)
+ a
+ end
+
+ def test_f10
+ assert_equal(42, f10(a: 42))
+ assert_equal(1, f10(b: 42))
+ end
+
+ def test_method_parameters
+ assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters);
+ assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters);
+ assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f3).parameters);
+ assert_equal([[:key, :str], [:key, :num]], method(:f4).parameters);
+ assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f5).parameters);
+ assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], method(:f6).parameters);
+ assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], method(:f7).parameters);
+ assert_equal([[:opt, :opt], [:rest, :rest], [:key, :key]], method(:f8).parameters) # [Bug #7540] [ruby-core:50735]
+ assert_equal([[:req, :r], [:opt, :o], [:rest, :args], [:req, :p], [:key, :k],
+ [:keyrest, :kw], [:block, :b]], method(:f9).parameters)
+ end
+
+ def test_lambda
+ f = ->(str: "foo", num: 424242) { [str, num] }
+ assert_equal(["foo", 424242], f[])
+ assert_equal(["bar", 424242], f[str: "bar"])
+ assert_equal(["foo", 111111], f[num: 111111])
+ assert_equal(["bar", 111111], f[str: "bar", num: 111111])
+ end
+
+
+ def p1
+ Proc.new do |str: "foo", num: 424242|
+ [str, num]
+ end
+ end
+
+ def test_p1
+ assert_equal(["foo", 424242], p1[])
+ assert_equal(["bar", 424242], p1[str: "bar"])
+ assert_equal(["foo", 111111], p1[num: 111111])
+ assert_equal(["bar", 111111], p1[str: "bar", num: 111111])
+ assert_raise(ArgumentError) { p1[str: "bar", check: true] }
+ assert_equal(["foo", 424242], p1["string"] )
+ end
+
+
+ def p2
+ Proc.new do |x, str: "foo", num: 424242|
+ [x, str, num]
+ end
+ end
+
+ def test_p2
+ assert_equal([nil, "foo", 424242], p2[])
+ assert_equal([:xyz, "foo", 424242], p2[:xyz])
+ end
+
+
+ def p3
+ Proc.new do |str: "foo", num: 424242, **h|
+ [str, num, h]
+ end
+ end
+
+ def test_p3
+ assert_equal(["foo", 424242, {}], p3[])
+ assert_equal(["bar", 424242, {}], p3[str: "bar"])
+ assert_equal(["foo", 111111, {}], p3[num: 111111])
+ assert_equal(["bar", 111111, {}], p3[str: "bar", num: 111111])
+ assert_equal(["bar", 424242, {:check=>true}], p3[str: "bar", check: true])
+ assert_equal(["foo", 424242, {}], p3["string"])
+ end
+
+
+ def p4
+ Proc.new do |str: "foo", num: 424242, **h, &blk|
+ [str, num, h, blk]
+ end
+ end
+
+ def test_p4
+ assert_equal(["foo", 424242, {}, nil], p4[])
+ assert_equal(["bar", 424242, {}, nil], p4[str: "bar"])
+ assert_equal(["foo", 111111, {}, nil], p4[num: 111111])
+ assert_equal(["bar", 111111, {}, nil], p4[str: "bar", num: 111111])
+ assert_equal(["bar", 424242, {:check=>true}, nil], p4[str: "bar", check: true])
+ a = p4.call {|x| x + 42 }
+ assert_equal(["foo", 424242, {}], a[0, 3])
+ assert_equal(43, a.last.call(1))
+ end
+
+
+ def p5
+ Proc.new do |*r, str: "foo", num: 424242, **h|
+ [r, str, num, h]
+ end
+ end
+
+ def test_p5
+ assert_equal([[], "foo", 424242, {}], p5[])
+ assert_equal([[], "bar", 424242, {}], p5[str: "bar"])
+ assert_equal([[], "foo", 111111, {}], p5[num: 111111])
+ assert_equal([[], "bar", 111111, {}], p5[str: "bar", num: 111111])
+ assert_equal([[1], "foo", 424242, {}], p5[1])
+ assert_equal([[1, 2], "foo", 424242, {}], p5[1, 2])
+ assert_equal([[1, 2, 3], "foo", 424242, {}], p5[1, 2, 3])
+ assert_equal([[1], "bar", 424242, {}], p5[1, str: "bar"])
+ assert_equal([[1, 2], "bar", 424242, {}], p5[1, 2, str: "bar"])
+ assert_equal([[1, 2, 3], "bar", 424242, {}], p5[1, 2, 3, str: "bar"])
+ end
+
+
+ def p6
+ Proc.new do |o1, o2=42, *args, p, k: :key, **kw, &b|
+ [o1, o2, args, p, k, kw, b]
+ end
+ end
+
+ def test_p6
+ assert_equal([nil, 42, [], nil, :key, {}, nil], p6[])
+ assert_equal([1, 42, [], 2, :key, {}, nil], p6[1, 2])
+ assert_equal([1, 2, [], 3, :key, {}, nil], p6[1, 2, 3])
+ assert_equal([1, 2, [3], 4, :key, {}, nil], p6[1, 2, 3, 4])
+ assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], p6[1, 2, 3, 4, 5, str: "bar"])
+ end
+
+ def test_proc_parameters
+ assert_equal([[:key, :str], [:key, :num]], p1.parameters);
+ assert_equal([[:opt, :x], [:key, :str], [:key, :num]], p2.parameters);
+ assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], p3.parameters);
+ assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], p4.parameters);
+ assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], p5.parameters);
+ assert_equal([[:opt, :o1], [:opt, :o2], [:rest, :args], [:opt, :p], [:key, :k],
+ [:keyrest, :kw], [:block, :b]], p6.parameters)
+ end
+
+ def m1(*args)
+ yield(*args)
+ end
+
+ def test_block
+ blk = Proc.new {|str: "foo", num: 424242| [str, num] }
+ assert_equal(["foo", 424242], m1(&blk))
+ assert_equal(["bar", 424242], m1(str: "bar", &blk))
+ assert_equal(["foo", 111111], m1(num: 111111, &blk))
+ assert_equal(["bar", 111111], m1(str: "bar", num: 111111, &blk))
+ end
+
+ def rest_keyrest(*args, **opt)
+ return *args, opt
+ end
+
+ def test_rest_keyrest
+ bug7665 = '[ruby-core:51278]'
+ bug8463 = '[ruby-core:55203] [Bug #8463]'
+ expect = [*%w[foo bar], {zzz: 42}]
+ assert_equal(expect, rest_keyrest(*expect), bug7665)
+ pr = proc {|*args, **opt| next *args, opt}
+ assert_equal(expect, pr.call(*expect), bug7665)
+ assert_equal(expect, pr.call(expect), bug8463)
+ pr = proc {|a, *b, **opt| next a, *b, opt}
+ assert_equal(expect, pr.call(expect), bug8463)
+ pr = proc {|a, **opt| next a, opt}
+ assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463)
+ end
+
+ def test_bare_kwrest
+ # valid syntax, but its semantics is undefined
+ assert_valid_syntax("def bug7662(**) end")
+ assert_valid_syntax("def bug7662(*, **) end")
+ assert_valid_syntax("def bug7662(a, **) end")
+ end
+
+ def test_without_paren
+ bug7942 = '[ruby-core:52820] [Bug #7942]'
+ assert_valid_syntax("def bug7942 a: 1; end")
+ assert_valid_syntax("def bug7942 a: 1, **; end")
+
+ o = Object.new
+ eval("def o.bug7942 a: 1; a; end", nil, __FILE__, __LINE__)
+ assert_equal(1, o.bug7942(), bug7942)
+ assert_equal(42, o.bug7942(a: 42), bug7942)
+
+ o = Object.new
+ eval("def o.bug7942 a: 1, **; a; end", nil, __FILE__, __LINE__)
+ assert_equal(1, o.bug7942(), bug7942)
+ assert_equal(42, o.bug7942(a: 42), bug7942)
+ end
+
+ def test_required_keyword
+ feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
+ o = Object.new
+ assert_nothing_raised(SyntaxError, feature7701) do
+ eval("def o.foo(a:) a; end", nil, "xyzzy")
+ eval("def o.bar(a:,**b) [a, b]; end")
+ end
+ assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {o.foo}
+ assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {o.foo(a:0, b:1)}
+ begin
+ o.foo(a: 0, b: 1)
+ rescue => e
+ assert_equal('xyzzy', e.backtrace_locations[0].path)
+ end
+ assert_equal(42, o.foo(a: 42), feature7701)
+ assert_equal([[:keyreq, :a]], o.method(:foo).parameters, feature7701)
+
+ bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
+ assert_equal([42, {}], o.bar(a: 42), feature7701)
+ assert_equal([42, {c: feature7701}], o.bar(a: 42, c: feature7701), feature7701)
+ assert_equal([[:keyreq, :a], [:keyrest, :b]], o.method(:bar).parameters, feature7701)
+ assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar(c: bug8139)}
+ assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar}
+ end
+
+ def test_required_keyword_with_newline
+ bug9669 = '[ruby-core:61658] [Bug #9669]'
+ assert_nothing_raised(SyntaxError, bug9669) do
+ eval(<<-'end;', nil, __FILE__, __LINE__)
+ def bug9669.foo a:
+ return a
+ end
+ end;
+ end
+ assert_equal(42, bug9669.foo(a: 42))
+ o = nil
+ assert_nothing_raised(SyntaxError, bug9669) do
+ eval(<<-'end;', nil, __FILE__, __LINE__)
+ o = {
+ a:
+ 1
+ }
+ end;
+ end
+ assert_equal({a: 1}, o, bug9669)
+ end
+
+ def test_required_keyword_with_reserved
+ bug10279 = '[ruby-core:65211] [Bug #10279]'
+ h = nil
+ assert_nothing_raised(SyntaxError, bug10279) do
+ break eval(<<-'end;', nil, __FILE__, __LINE__)
+ h = {a: if true then 42 end}
+ end;
+ end
+ assert_equal({a: 42}, h, bug10279)
+ end
+
+ def test_block_required_keyword
+ feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
+ b = assert_nothing_raised(SyntaxError, feature7701) do
+ break eval("proc {|a:| a}", nil, 'xyzzy', __LINE__)
+ end
+ assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {b.call}
+ assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {b.call(a:0, b:1)}
+ begin
+ b.call(a: 0, b: 1)
+ rescue => e
+ assert_equal('xyzzy', e.backtrace_locations[0].path)
+ end
+
+ assert_equal(42, b.call(a: 42), feature7701)
+ assert_equal([[:keyreq, :a]], b.parameters, feature7701)
+
+ bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
+ b = assert_nothing_raised(SyntaxError, feature7701) do
+ break eval("proc {|a:, **bl| [a, bl]}", nil, __FILE__, __LINE__)
+ end
+ assert_equal([42, {}], b.call(a: 42), feature7701)
+ assert_equal([42, {c: feature7701}], b.call(a: 42, c: feature7701), feature7701)
+ assert_equal([[:keyreq, :a], [:keyrest, :bl]], b.parameters, feature7701)
+ assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call(c: bug8139)}
+ assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call}
+ end
+
+ def test_super_with_keyword
+ bug8236 = '[ruby-core:54094] [Bug #8236]'
+ base = Class.new do
+ def foo(*args)
+ args
+ end
+ end
+ a = Class.new(base) do
+ def foo(arg, bar: 'x')
+ super
+ end
+ end
+ b = Class.new(base) do
+ def foo(*args, bar: 'x')
+ super
+ end
+ end
+ assert_equal([42, {:bar=>"x"}], a.new.foo(42), bug8236)
+ assert_equal([42, {:bar=>"x"}], b.new.foo(42), bug8236)
+ end
+
+ def test_zsuper_only_named_kwrest
+ bug8416 = '[ruby-core:55033] [Bug #8416]'
+ base = Class.new do
+ def foo(**h)
+ h
+ end
+ end
+ a = Class.new(base) do
+ def foo(**h)
+ super
+ end
+ end
+ assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
+ end
+
+ def test_zsuper_only_anonymous_kwrest
+ bug8416 = '[ruby-core:55033] [Bug #8416]'
+ base = Class.new do
+ def foo(**h)
+ h
+ end
+ end
+ a = Class.new(base) do
+ def foo(**)
+ super
+ end
+ end
+ assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
+ end
+
+ def test_precedence_of_keyword_arguments
+ bug8040 = '[ruby-core:53199] [Bug #8040]'
+ a = Class.new do
+ def foo(x, **h)
+ [x, h]
+ end
+ end
+ assert_equal([{}, {}], a.new.foo({}))
+ assert_equal([{}, {:bar=>"x"}], a.new.foo({}, bar: "x"), bug8040)
+ end
+
+ def test_precedence_of_keyword_arguments_with_post_argument
+ bug8993 = '[ruby-core:57706] [Bug #8993]'
+ a = Class.new do
+ def foo(a, b, c=1, *d, e, f:2, **g)
+ [a, b, c, d, e, f, g]
+ end
+ end
+ assert_equal([1, 2, 1, [], {:f=>5}, 2, {}], a.new.foo(1, 2, f:5), bug8993)
+ end
+
+ def test_splat_keyword_nondestructive
+ bug9776 = '[ruby-core:62161] [Bug #9776]'
+
+ h = {a: 1}
+ assert_equal({a:1, b:2}, {**h, b:2})
+ assert_equal({a:1}, h, bug9776)
+
+ pr = proc {|**opt| next opt}
+ assert_equal({a: 1}, pr.call(**h))
+ assert_equal({a: 1, b: 2}, pr.call(**h, b: 2))
+ assert_equal({a: 1}, h, bug9776)
+ end
+
+ def test_splat_hash_conversion
+ bug9898 = '[ruby-core:62921] [Bug #9898]'
+
+ o = Object.new
+ def o.to_hash() { a: 1 } end
+ assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898)
+ o2 = Object.new
+ def o2.to_hash() { b: 2 } end
+ assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898)
+ end
+
+ def test_implicit_hash_conversion
+ bug10016 = '[ruby-core:63593] [Bug #10016]'
+
+ o = Object.new
+ def o.to_hash() { k: 9 } end
+ assert_equal([1, 42, [], o, :key, {}, nil], f9(1, o))
+ assert_equal([1, 9], m1(1, o) {|a, k: 0| break [a, k]}, bug10016)
+ assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016)
+ end
+
+ def test_gced_object_in_stack
+ bug8964 = '[ruby-dev:47729] [Bug #8964]'
+ assert_normal_exit %q{
+ def m(a: [])
+ end
+ GC.stress = true
+ tap { m }
+ GC.start
+ tap { m }
+ }, bug8964
+ assert_normal_exit %q{
+ prc = Proc.new {|a: []|}
+ GC.stress = true
+ tap { prc.call }
+ GC.start
+ tap { prc.call }
+ }, bug8964
+ end
+
+ def test_dynamic_symbol_keyword
+ bug10266 = '[ruby-dev:48564] [Bug #10266]'
+ assert_separately(['-', bug10266], <<-'end;') # do
+ bug = ARGV.shift
+ "hoge".to_sym
+ assert_nothing_raised(bug) {eval("def a(hoge:); end")}
+ end;
+ end
+
+ def test_unknown_keyword_with_block
+ bug10413 = '[ruby-core:65837] [Bug #10413]'
+ class << (o = Object.new)
+ def bar(k2: 'v2')
+ end
+
+ def foo
+ bar(k1: 1)
+ end
+ end
+ assert_raise_with_message(ArgumentError, /unknown keyword: k1/, bug10413) {
+ o.foo {raise "unreachable"}
+ }
+ end
+
+ def test_super_with_anon_restkeywords
+ bug10659 = '[ruby-core:67157] [Bug #10659]'
+
+ foo = Class.new do
+ def foo(**h)
+ h
+ end
+ end
+
+ class << (obj = foo.new)
+ def foo(bar: "bar", **)
+ super
+ end
+ end
+
+ assert_nothing_raised(TypeError, bug10659) {
+ assert_equal({:bar => "bar"}, obj.foo, bug10659)
+ }
+ end
+
+ def m(a) yield a end
+
+ def test_nonsymbol_key
+ result = m(["a" => 10]) { |a = nil, **b| [a, b] }
+ assert_equal([{"a" => 10}, {}], result)
+ end
+
+ def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw
+ [k1, k2, rest_kw]
+ end
+
+ def test_to_hash_call_during_setup_complex_parameters
+ sym = "sym_#{Time.now}".to_sym
+ h = method_for_test_to_hash_call_during_setup_complex_parameters k1: "foo", k2: "bar", sym => "baz"
+ assert_equal ["foo", "bar", {sym => "baz"}], h, '[Bug #11027]'
+ end
+end
diff --git a/jni/ruby/test/ruby/test_lambda.rb b/jni/ruby/test/ruby/test_lambda.rb
new file mode 100644
index 0000000..0f3382c
--- /dev/null
+++ b/jni/ruby/test/ruby/test_lambda.rb
@@ -0,0 +1,173 @@
+require 'test/unit'
+
+class TestLambdaParameters < Test::Unit::TestCase
+
+ def test_exact_parameter
+ assert_raise(ArgumentError){(1..3).each(&lambda{})}
+ end
+
+ def test_call_simple
+ assert_equal(1, lambda{|a| a}.call(1))
+ assert_equal([1,2], lambda{|a, b| [a,b]}.call(1,2))
+ assert_raise(ArgumentError) { lambda{|a|}.call(1,2) }
+ assert_raise(ArgumentError) { lambda{|a|}.call() }
+ assert_raise(ArgumentError) { lambda{}.call(1) }
+ assert_raise(ArgumentError) { lambda{|a, b|}.call(1,2,3) }
+
+ assert_equal(1, ->(a){ a }.call(1))
+ assert_equal([1,2], ->(a,b){ [a,b] }.call(1,2))
+ assert_raise(ArgumentError) { ->(a){ }.call(1,2) }
+ assert_raise(ArgumentError) { ->(a){ }.call() }
+ assert_raise(ArgumentError) { ->(){ }.call(1) }
+ assert_raise(ArgumentError) { ->(a,b){ }.call(1,2,3) }
+ end
+
+ def test_lambda_as_iterator
+ a = 0
+ 2.times(&->(_){ a += 1 })
+ assert_equal(2, a)
+ assert_raise(ArgumentError) {1.times(&->(){ a += 1 })}
+ bug9605 = '[ruby-core:61468] [Bug #9605]'
+ assert_nothing_raised(ArgumentError, bug9605) {1.times(&->(n){ a += 1 })}
+ assert_equal(3, a, bug9605)
+ assert_nothing_raised(ArgumentError, bug9605) {a = [[1, 2]].map(&->(x, y) {x+y})}
+ assert_equal([3], a, bug9605)
+ end
+
+ def test_call_rest_args
+ assert_equal([1,2], ->(*a){ a }.call(1,2))
+ assert_equal([1,2,[]], ->(a,b,*c){ [a,b,c] }.call(1,2))
+ assert_raise(ArgumentError){ ->(a,*b){ }.call() }
+ end
+
+ def test_call_opt_args
+ assert_equal([1,2,3,4], ->(a,b,c=3,d=4){ [a,b,c,d] }.call(1,2))
+ assert_equal([1,2,3,4], ->(a,b,c=0,d=4){ [a,b,c,d] }.call(1,2,3))
+ assert_raise(ArgumentError){ ->(a,b=1){ }.call() }
+ assert_raise(ArgumentError){ ->(a,b=1){ }.call(1,2,3) }
+ end
+
+ def test_call_rest_and_opt
+ assert_equal([1,2,3,[]], ->(a,b=2,c=3,*d){ [a,b,c,d] }.call(1))
+ assert_equal([1,2,3,[]], ->(a,b=0,c=3,*d){ [a,b,c,d] }.call(1,2))
+ assert_equal([1,2,3,[4,5,6]], ->(a,b=0,c=0,*d){ [a,b,c,d] }.call(1,2,3,4,5,6))
+ assert_raise(ArgumentError){ ->(a,b=1,*c){ }.call() }
+ end
+
+ def test_call_with_block
+ f = ->(a,b,c=3,*d,&e){ [a,b,c,d,e.call(d + [a,b,c])] }
+ assert_equal([1,2,3,[],6], f.call(1,2){|z| z.inject{|s,x| s+x} } )
+ assert_equal(nil, ->(&b){ b }.call)
+ foo { puts "bogus block " }
+ assert_equal(1, ->(&b){ b.call }.call { 1 })
+ b = nil
+ assert_equal(1, ->(&b){ b.call }.call { 1 })
+ assert_nil(b)
+ end
+
+ def test_call_block_from_lambda
+ bug9605 = '[ruby-core:61470] [Bug #9605]'
+ plus = ->(x,y) {x+y}
+ assert_raise(ArgumentError, bug9605) {proc(&plus).call [1,2]}
+ end
+
+ def yield_1(arg)
+ yield arg
+ end
+
+ tap do |;bug9605, expected, result|
+ bug9605 = '[ruby-core:65887] [Bug #9605] arity check should be relaxed'
+ expected = [1,2,3]
+
+ [
+ ["array", expected],
+ ["to_ary", Struct.new(:to_ary).new(expected)],
+ ].product \
+ [
+ ["proc", proc {|a, b, c| [a, b, c]}],
+ ["lambda", lambda {|a, b, c| [a, b, c]}],
+ ] do
+ |(vtype, val), (btype, block)|
+ define_method("test_yeild_relaxed(#{vtype},&#{btype})") do
+ result = assert_nothing_raised(ArgumentError, bug9605) {
+ break yield_1(val, &block)
+ }
+ assert_equal(expected, result, bug9605)
+ end
+ end
+ end
+
+ def foo
+ assert_equal(nil, ->(&b){ b }.call)
+ end
+
+ def test_in_basic_object
+ bug5966 = '[ruby-core:42349]'
+ called = false
+ BasicObject.new.instance_eval {->() {called = true}.()}
+ assert_equal(true, called, bug5966)
+ end
+
+ def test_location_on_error
+ bug6151 = '[ruby-core:43314]'
+ called = 0
+ line, f = __LINE__, lambda do
+ called += 1
+ true
+ end
+ e = assert_raise(ArgumentError) do
+ f.call(42)
+ end
+ assert_send([e.backtrace.first, :start_with?, "#{__FILE__}:#{line}:"], bug6151)
+ assert_equal(0, called)
+ e = assert_raise(ArgumentError) do
+ 42.times(&f)
+ end
+ assert_send([e.backtrace.first, :start_with?, "#{__FILE__}:#{line}:"], bug6151)
+ assert_equal(0, called)
+ end
+
+ def return_in_current(val)
+ 1.tap(&->(*) {return 0})
+ val
+ end
+
+ def yield_block
+ yield
+ end
+
+ def return_in_callee(val)
+ yield_block(&->(*) {return 0})
+ val
+ end
+
+ def test_return
+ feature8693 = '[ruby-core:56193] [Feature #8693]'
+ assert_equal(42, return_in_current(42), feature8693)
+ assert_equal(42, return_in_callee(42), feature8693)
+ end
+
+ def test_do_lambda_source_location
+ exp_lineno = __LINE__ + 3
+ lmd = ->(x,
+ y,
+ z) do
+ #
+ end
+ file, lineno = lmd.source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(exp_lineno, lineno, "must be at the beginning of the block")
+ end
+
+ def test_brace_lambda_source_location
+ exp_lineno = __LINE__ + 3
+ lmd = ->(x,
+ y,
+ z) {
+ #
+ }
+ file, lineno = lmd.source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(exp_lineno, lineno, "must be at the beginning of the block")
+ end
+end
diff --git a/jni/ruby/test/ruby/test_lazy_enumerator.rb b/jni/ruby/test/ruby/test_lazy_enumerator.rb
new file mode 100644
index 0000000..75f2458
--- /dev/null
+++ b/jni/ruby/test/ruby/test_lazy_enumerator.rb
@@ -0,0 +1,494 @@
+require 'test/unit'
+
+class TestLazyEnumerator < Test::Unit::TestCase
+ class Step
+ include Enumerable
+ attr_reader :current, :args
+
+ def initialize(enum)
+ @enum = enum
+ @current = nil
+ @args = nil
+ end
+
+ def each(*args)
+ @args = args
+ @enum.each {|i| @current = i; yield i}
+ end
+ end
+
+ def test_initialize
+ assert_equal([1, 2, 3], [1, 2, 3].lazy.to_a)
+ assert_equal([1, 2, 3], Enumerator::Lazy.new([1, 2, 3]){|y, v| y << v}.to_a)
+ assert_raise(ArgumentError) { Enumerator::Lazy.new([1, 2, 3]) }
+
+ a = [1, 2, 3].lazy
+ a.freeze
+ assert_raise(RuntimeError) {
+ a.__send__ :initialize, [4, 5], &->(y, *v) { y << yield(*v) }
+ }
+ end
+
+ def test_each_args
+ a = Step.new(1..3)
+ assert_equal(1, a.lazy.each(4).first)
+ assert_equal([4], a.args)
+ end
+
+ def test_each_line
+ name = lineno = nil
+ File.open(__FILE__) do |f|
+ f.each("").map do |paragraph|
+ paragraph[/\A\s*(.*)/, 1]
+ end.find do |line|
+ if name = line[/^class\s+(\S+)/, 1]
+ lineno = f.lineno
+ true
+ end
+ end
+ end
+ assert_equal(self.class.name, name)
+ assert_operator(lineno, :>, 2)
+
+ name = lineno = nil
+ File.open(__FILE__) do |f|
+ f.lazy.each("").map do |paragraph|
+ paragraph[/\A\s*(.*)/, 1]
+ end.find do |line|
+ if name = line[/^class\s+(\S+)/, 1]
+ lineno = f.lineno
+ true
+ end
+ end
+ end
+ assert_equal(self.class.name, name)
+ assert_equal(2, lineno)
+ end
+
+ def test_select
+ a = Step.new(1..6)
+ assert_equal(4, a.select {|x| x > 3}.first)
+ assert_equal(6, a.current)
+ assert_equal(4, a.lazy.select {|x| x > 3}.first)
+ assert_equal(4, a.current)
+
+ a = Step.new(['word', nil, 1])
+ assert_raise(TypeError) {a.select {|x| "x"+x}.first}
+ assert_equal(nil, a.current)
+ assert_equal("word", a.lazy.select {|x| "x"+x}.first)
+ assert_equal("word", a.current)
+ end
+
+ def test_select_multiple_values
+ e = Enumerator.new { |yielder|
+ for i in 1..5
+ yielder.yield(i, i.to_s)
+ end
+ }
+ assert_equal([[2, "2"], [4, "4"]],
+ e.select {|x| x[0] % 2 == 0})
+ assert_equal([[2, "2"], [4, "4"]],
+ e.lazy.select {|x| x[0] % 2 == 0}.force)
+ end
+
+ def test_map
+ a = Step.new(1..3)
+ assert_equal(2, a.map {|x| x * 2}.first)
+ assert_equal(3, a.current)
+ assert_equal(2, a.lazy.map {|x| x * 2}.first)
+ assert_equal(1, a.current)
+ end
+
+ def test_flat_map
+ a = Step.new(1..3)
+ assert_equal(2, a.flat_map {|x| [x * 2]}.first)
+ assert_equal(3, a.current)
+ assert_equal(2, a.lazy.flat_map {|x| [x * 2]}.first)
+ assert_equal(1, a.current)
+ end
+
+ def test_flat_map_nested
+ a = Step.new(1..3)
+ assert_equal([1, "a"],
+ a.flat_map {|x| ("a".."c").map {|y| [x, y]}}.first)
+ assert_equal(3, a.current)
+ assert_equal([1, "a"],
+ a.lazy.flat_map {|x| ("a".."c").lazy.map {|y| [x, y]}}.first)
+ assert_equal(1, a.current)
+ end
+
+ def test_flat_map_to_ary
+ to_ary = Class.new {
+ def initialize(value)
+ @value = value
+ end
+
+ def to_ary
+ [:to_ary, @value]
+ end
+ }
+ assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3],
+ [1, 2, 3].flat_map {|x| to_ary.new(x)})
+ assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3],
+ [1, 2, 3].lazy.flat_map {|x| to_ary.new(x)}.force)
+ end
+
+ def test_flat_map_non_array
+ assert_equal(["1", "2", "3"], [1, 2, 3].flat_map {|x| x.to_s})
+ assert_equal(["1", "2", "3"], [1, 2, 3].lazy.flat_map {|x| x.to_s}.force)
+ end
+
+ def test_flat_map_hash
+ assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].flat_map {|x| {x=>x.ord}})
+ assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].lazy.flat_map {|x| {x=>x.ord}}.force)
+ end
+
+ def test_reject
+ a = Step.new(1..6)
+ assert_equal(4, a.reject {|x| x < 4}.first)
+ assert_equal(6, a.current)
+ assert_equal(4, a.lazy.reject {|x| x < 4}.first)
+ assert_equal(4, a.current)
+
+ a = Step.new(['word', nil, 1])
+ assert_equal(nil, a.reject {|x| x}.first)
+ assert_equal(1, a.current)
+ assert_equal(nil, a.lazy.reject {|x| x}.first)
+ assert_equal(nil, a.current)
+ end
+
+ def test_reject_multiple_values
+ e = Enumerator.new { |yielder|
+ for i in 1..5
+ yielder.yield(i, i.to_s)
+ end
+ }
+ assert_equal([[2, "2"], [4, "4"]],
+ e.reject {|x| x[0] % 2 != 0})
+ assert_equal([[2, "2"], [4, "4"]],
+ e.lazy.reject {|x| x[0] % 2 != 0}.force)
+ end
+
+ def test_grep
+ a = Step.new('a'..'f')
+ assert_equal('c', a.grep(/c/).first)
+ assert_equal('f', a.current)
+ assert_equal('c', a.lazy.grep(/c/).first)
+ assert_equal('c', a.current)
+ assert_equal(%w[a e], a.grep(proc {|x| /[aeiou]/ =~ x}))
+ assert_equal(%w[a e], a.lazy.grep(proc {|x| /[aeiou]/ =~ x}).to_a)
+ end
+
+ def test_grep_with_block
+ a = Step.new('a'..'f')
+ assert_equal('C', a.grep(/c/) {|i| i.upcase}.first)
+ assert_equal('C', a.lazy.grep(/c/) {|i| i.upcase}.first)
+ end
+
+ def test_grep_multiple_values
+ e = Enumerator.new { |yielder|
+ 3.times { |i|
+ yielder.yield(i, i.to_s)
+ }
+ }
+ assert_equal([[2, "2"]], e.grep(proc {|x| x == [2, "2"]}))
+ assert_equal([[2, "2"]], e.lazy.grep(proc {|x| x == [2, "2"]}).force)
+ assert_equal(["22"],
+ e.lazy.grep(proc {|x| x == [2, "2"]}, &:join).force)
+ end
+
+ def test_zip
+ a = Step.new(1..3)
+ assert_equal([1, "a"], a.zip("a".."c").first)
+ assert_equal(3, a.current)
+ assert_equal([1, "a"], a.lazy.zip("a".."c").first)
+ assert_equal(1, a.current)
+ end
+
+ def test_zip_short_arg
+ a = Step.new(1..5)
+ assert_equal([5, nil], a.zip("a".."c").last)
+ assert_equal([5, nil], a.lazy.zip("a".."c").force.last)
+ end
+
+ def test_zip_without_arg
+ a = Step.new(1..3)
+ assert_equal([1], a.zip.first)
+ assert_equal(3, a.current)
+ assert_equal([1], a.lazy.zip.first)
+ assert_equal(1, a.current)
+ end
+
+ def test_zip_bad_arg
+ a = Step.new(1..3)
+ assert_raise(TypeError){ a.lazy.zip(42) }
+ end
+
+ def test_zip_with_block
+ # zip should be eager when a block is given
+ a = Step.new(1..3)
+ ary = []
+ assert_equal(nil, a.lazy.zip("a".."c") {|x, y| ary << [x, y]})
+ assert_equal(a.zip("a".."c"), ary)
+ assert_equal(3, a.current)
+ end
+
+ def test_take
+ a = Step.new(1..10)
+ assert_equal(1, a.take(5).first)
+ assert_equal(5, a.current)
+ assert_equal(1, a.lazy.take(5).first)
+ assert_equal(1, a.current)
+ assert_equal((1..5).to_a, a.lazy.take(5).force)
+ assert_equal(5, a.current)
+ a = Step.new(1..10)
+ assert_equal([], a.lazy.take(0).force)
+ assert_equal(nil, a.current)
+ end
+
+ def test_take_recycle
+ bug6428 = '[ruby-dev:45634]'
+ a = Step.new(1..10)
+ take5 = a.lazy.take(5)
+ assert_equal((1..5).to_a, take5.force, bug6428)
+ assert_equal((1..5).to_a, take5.force, bug6428)
+ end
+
+ def test_take_nested
+ bug7696 = '[ruby-core:51470]'
+ a = Step.new(1..10)
+ take5 = a.lazy.take(5)
+ assert_equal([*(1..5)]*5, take5.flat_map{take5}.force, bug7696)
+ end
+
+ def test_drop_while_nested
+ bug7696 = '[ruby-core:51470]'
+ a = Step.new(1..10)
+ drop5 = a.lazy.drop_while{|x| x < 6}
+ assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696)
+ end
+
+ def test_drop_nested
+ bug7696 = '[ruby-core:51470]'
+ a = Step.new(1..10)
+ drop5 = a.lazy.drop(5)
+ assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696)
+ end
+
+ def test_zip_nested
+ bug7696 = '[ruby-core:51470]'
+ enum = ('a'..'z').each
+ enum.next
+ zip = (1..3).lazy.zip(enum, enum)
+ assert_equal([[1, 'a', 'a'], [2, 'b', 'b'], [3, 'c', 'c']]*3, zip.flat_map{zip}.force, bug7696)
+ end
+
+ def test_zip_lazy_on_args
+ zip = Step.new(1..2).lazy.zip(42..Float::INFINITY)
+ assert_equal [[1, 42], [2, 43]], zip.force
+ end
+
+ def test_zip_efficient_on_array_args
+ ary = [42, :foo]
+ %i[to_enum enum_for lazy each].each do |forbid|
+ ary.define_singleton_method(forbid){ fail "#{forbid} was called"}
+ end
+ zip = Step.new(1..2).lazy.zip(ary)
+ assert_equal [[1, 42], [2, :foo]], zip.force
+ end
+
+ def test_zip_nonsingle
+ bug8735 = '[ruby-core:56383] [Bug #8735]'
+
+ obj = Object.new
+ def obj.each
+ yield
+ yield 1, 2
+ end
+
+ assert_equal(obj.to_enum.zip(obj.to_enum), obj.to_enum.lazy.zip(obj.to_enum).force, bug8735)
+ end
+
+ def test_take_rewound
+ bug7696 = '[ruby-core:51470]'
+ e=(1..42).lazy.take(2)
+ assert_equal 1, e.next, bug7696
+ assert_equal 2, e.next, bug7696
+ e.rewind
+ assert_equal 1, e.next, bug7696
+ assert_equal 2, e.next, bug7696
+ end
+
+ def test_take_while
+ a = Step.new(1..10)
+ assert_equal(1, a.take_while {|i| i < 5}.first)
+ assert_equal(5, a.current)
+ assert_equal(1, a.lazy.take_while {|i| i < 5}.first)
+ assert_equal(1, a.current)
+ assert_equal((1..4).to_a, a.lazy.take_while {|i| i < 5}.to_a)
+ end
+
+ def test_drop
+ a = Step.new(1..10)
+ assert_equal(6, a.drop(5).first)
+ assert_equal(10, a.current)
+ assert_equal(6, a.lazy.drop(5).first)
+ assert_equal(6, a.current)
+ assert_equal((6..10).to_a, a.lazy.drop(5).to_a)
+ end
+
+ def test_drop_while
+ a = Step.new(1..10)
+ assert_equal(5, a.drop_while {|i| i % 5 > 0}.first)
+ assert_equal(10, a.current)
+ assert_equal(5, a.lazy.drop_while {|i| i % 5 > 0}.first)
+ assert_equal(5, a.current)
+ assert_equal((5..10).to_a, a.lazy.drop_while {|i| i % 5 > 0}.to_a)
+ end
+
+ def test_drop_and_take
+ assert_equal([4, 5], (1..Float::INFINITY).lazy.drop(3).take(2).to_a)
+ end
+
+ def test_cycle
+ a = Step.new(1..3)
+ assert_equal("1", a.cycle(2).map(&:to_s).first)
+ assert_equal(3, a.current)
+ assert_equal("1", a.lazy.cycle(2).map(&:to_s).first)
+ assert_equal(1, a.current)
+ end
+
+ def test_cycle_with_block
+ # cycle should be eager when a block is given
+ a = Step.new(1..3)
+ ary = []
+ assert_equal(nil, a.lazy.cycle(2) {|i| ary << i})
+ assert_equal(a.cycle(2).to_a, ary)
+ assert_equal(3, a.current)
+ end
+
+ def test_cycle_chain
+ a = 1..3
+ assert_equal([1,2,3,1,2,3,1,2,3,1], a.lazy.cycle.take(10).force)
+ assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.cycle.select {|x| x == 2}.take(10).force)
+ assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.select {|x| x == 2}.cycle.take(10).force)
+ end
+
+ def test_force
+ assert_equal([1, 2, 3], (1..Float::INFINITY).lazy.take(3).force)
+ end
+
+ def test_inspect
+ assert_equal("#<Enumerator::Lazy: 1..10>", (1..10).lazy.inspect)
+ assert_equal('#<Enumerator::Lazy: #<Enumerator: "foo":each_char>>',
+ "foo".each_char.lazy.inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>",
+ (1..10).lazy.map {}.inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(0)>",
+ (1..10).lazy.take(0).inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(3)>",
+ (1..10).lazy.take(3).inspect)
+ assert_equal('#<Enumerator::Lazy: #<Enumerator::Lazy: "a".."c">:grep(/b/)>',
+ ("a".."c").lazy.grep(/b/).inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>",
+ (1..10).lazy.cycle(3).inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle>",
+ (1..10).lazy.cycle.inspect)
+ assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>",
+ (1..10).lazy.cycle(3).inspect)
+ l = (1..10).lazy.map {}.collect {}.flat_map {}.collect_concat {}.select {}.find_all {}.reject {}.grep(1).zip(?a..?c).take(10).take_while {}.drop(3).drop_while {}.cycle(3)
+ assert_equal(<<EOS.chomp, l.inspect)
+#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>:collect>:flat_map>:collect_concat>:select>:find_all>:reject>:grep(1)>:zip("a".."c")>:take(10)>:take_while>:drop(3)>:drop_while>:cycle(3)>
+EOS
+ end
+
+ def test_lazy_to_enum
+ lazy = [1, 2, 3].lazy
+ def lazy.foo(*args)
+ yield args
+ yield args
+ end
+ enum = lazy.to_enum(:foo, :hello, :world)
+ assert_equal Enumerator::Lazy, enum.class
+ assert_equal nil, enum.size
+ assert_equal [[:hello, :world], [:hello, :world]], enum.to_a
+
+ assert_equal [1, 2, 3], lazy.to_enum.to_a
+ end
+
+ def test_size
+ lazy = [1, 2, 3].lazy
+ assert_equal 3, lazy.size
+ assert_equal 42, Enumerator::Lazy.new([],->{42}){}.size
+ assert_equal 42, Enumerator::Lazy.new([],42){}.size
+ assert_equal 42, Enumerator::Lazy.new([],42){}.lazy.size
+ assert_equal 42, lazy.to_enum{ 42 }.size
+
+ %i[map collect].each do |m|
+ assert_equal 3, lazy.send(m){}.size
+ end
+ assert_equal 3, lazy.zip([4]).size
+ %i[flat_map collect_concat select find_all reject take_while drop_while].each do |m|
+ assert_equal nil, lazy.send(m){}.size
+ end
+ assert_equal nil, lazy.grep(//).size
+
+ assert_equal 2, lazy.take(2).size
+ assert_equal 3, lazy.take(4).size
+ assert_equal 4, loop.lazy.take(4).size
+ assert_equal nil, lazy.select{}.take(4).size
+
+ assert_equal 1, lazy.drop(2).size
+ assert_equal 0, lazy.drop(4).size
+ assert_equal Float::INFINITY, loop.lazy.drop(4).size
+ assert_equal nil, lazy.select{}.drop(4).size
+
+ assert_equal 0, lazy.cycle(0).size
+ assert_equal 6, lazy.cycle(2).size
+ assert_equal 3 << 80, 4.times.inject(lazy){|enum| enum.cycle(1 << 20)}.size
+ assert_equal Float::INFINITY, lazy.cycle.size
+ assert_equal Float::INFINITY, loop.lazy.cycle(4).size
+ assert_equal Float::INFINITY, loop.lazy.cycle.size
+ assert_equal nil, lazy.select{}.cycle(4).size
+ assert_equal nil, lazy.select{}.cycle.size
+ end
+
+ def test_map_zip
+ bug7507 = '[ruby-core:50545]'
+ assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip(){}"], "", bug7507)
+ assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip().to_a"], "", bug7507)
+ end
+
+ def test_require_block
+ %i[select reject drop_while take_while map flat_map].each do |method|
+ assert_raise(ArgumentError){ [].lazy.send(method) }
+ end
+ end
+
+ def test_laziness_conservation
+ bug7507 = '[ruby-core:51510]'
+ {
+ slice_before: //,
+ slice_after: //,
+ with_index: nil,
+ cycle: nil,
+ each_with_object: 42,
+ each_slice: 42,
+ each_entry: nil,
+ each_cons: 42,
+ }.each do |method, arg|
+ assert_equal Enumerator::Lazy, [].lazy.send(method, *arg).class, bug7507
+ end
+ assert_equal Enumerator::Lazy, [].lazy.chunk{}.class, bug7507
+ assert_equal Enumerator::Lazy, [].lazy.slice_when{}.class, bug7507
+ end
+
+ def test_no_warnings
+ le = (1..3).lazy
+ assert_warning("") {le.zip([4,5,6]).force}
+ assert_warning("") {le.zip(4..6).force}
+ assert_warning("") {le.take(1).force}
+ assert_warning("") {le.drop(1).force}
+ assert_warning("") {le.drop_while{false}.force}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_literal.rb b/jni/ruby/test/ruby/test_literal.rb
new file mode 100644
index 0000000..ed5f836
--- /dev/null
+++ b/jni/ruby/test/ruby/test_literal.rb
@@ -0,0 +1,461 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+
+class TestRubyLiteral < Test::Unit::TestCase
+
+ def test_special_const
+ assert_equal 'true', true.inspect
+ assert_instance_of TrueClass, true
+ assert_equal 'false', false.inspect
+ assert_instance_of FalseClass, false
+ assert_equal 'nil', nil.inspect
+ assert_instance_of NilClass, nil
+ assert_equal ':sym', :sym.inspect
+ assert_instance_of Symbol, :sym
+ assert_equal '1234', 1234.inspect
+ assert_instance_of Fixnum, 1234
+ assert_equal '1234', 1_2_3_4.inspect
+ assert_instance_of Fixnum, 1_2_3_4
+ assert_equal '18', 0x12.inspect
+ assert_instance_of Fixnum, 0x12
+ assert_raise(SyntaxError) { eval("0x") }
+ assert_equal '15', 0o17.inspect
+ assert_instance_of Fixnum, 0o17
+ assert_raise(SyntaxError) { eval("0o") }
+ assert_equal '5', 0b101.inspect
+ assert_instance_of Fixnum, 0b101
+ assert_raise(SyntaxError) { eval("0b") }
+ assert_equal '123456789012345678901234567890', 123456789012345678901234567890.inspect
+ assert_instance_of Bignum, 123456789012345678901234567890
+ assert_instance_of Float, 1.3
+ assert_equal '2', eval("0x00+2").inspect
+ end
+
+ def test_self
+ assert_equal self, self
+ assert_instance_of TestRubyLiteral, self
+ assert_respond_to self, :test_self
+ end
+
+ def test_string
+ assert_instance_of String, ?a
+ assert_equal "a", ?a
+ assert_instance_of String, ?A
+ assert_equal "A", ?A
+ assert_instance_of String, ?\n
+ assert_equal "\n", ?\n
+ assert_equal " ", ?\ # space
+ assert_equal '', ''
+ assert_equal 'string', 'string'
+ assert_equal 'string string', 'string string'
+ assert_equal ' ', ' '
+ assert_equal ' ', " "
+ assert_equal "\0", "\0"
+ assert_equal "\1", "\1"
+ assert_equal "3", "\x33"
+ assert_equal "\n", "\n"
+ bug2500 = '[ruby-core:27228]'
+ bug5262 = '[ruby-core:39222]'
+ %w[c C- M-].each do |pre|
+ ["u", %w[u{ }]].each do |open, close|
+ ["?", ['"', '"']].each do |qopen, qclose|
+ str = "#{qopen}\\#{pre}\\#{open}5555#{close}#{qclose}"
+ assert_raise(SyntaxError, "#{bug2500} eval(#{str})") {eval(str)}
+
+ str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}"
+ assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
+
+ str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("euc-jp")
+ assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
+
+ str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("iso-8859-13")
+ assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
+
+ str = "#{qopen}\\#{pre}\\#{open}\xe2\x7f#{close}#{qclose}".force_encoding("utf-8")
+ assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
+ end
+ end
+ end
+ bug6069 = '[ruby-dev:45278]'
+ assert_equal "\x13", "\c\x33"
+ assert_equal "\x13", "\C-\x33"
+ assert_equal "\xB3", "\M-\x33"
+ assert_equal "\u201c", eval(%["\\\u{201c}"]), bug5262
+ assert_equal "\u201c".encode("euc-jp"), eval(%["\\\u{201c}"].encode("euc-jp")), bug5262
+ assert_equal "\u201c".encode("iso-8859-13"), eval(%["\\\u{201c}"].encode("iso-8859-13")), bug5262
+ assert_equal "\\\u201c", eval(%['\\\u{201c}']), bug6069
+ assert_equal "\\\u201c".encode("euc-jp"), eval(%['\\\u{201c}'].encode("euc-jp")), bug6069
+ assert_equal "\\\u201c".encode("iso-8859-13"), eval(%['\\\u{201c}'].encode("iso-8859-13")), bug6069
+ assert_equal "\u201c", eval(%[?\\\u{201c}]), bug6069
+ assert_equal "\u201c".encode("euc-jp"), eval(%[?\\\u{201c}].encode("euc-jp")), bug6069
+ assert_equal "\u201c".encode("iso-8859-13"), eval(%[?\\\u{201c}].encode("iso-8859-13")), bug6069
+ end
+
+ def test_dstring
+ assert_equal '2', "#{1+1}"
+ assert_equal '16', "#{2 ** 4}"
+ s = "string"
+ assert_equal s, "#{s}"
+ a = 'Foo'
+ b = "#{a}" << 'Bar'
+ assert_equal('Foo', a, 'r3842')
+ assert_equal('FooBar', b, 'r3842')
+ end
+
+ def test_dsymbol
+ assert_equal :a3c, :"a#{1+2}c"
+ end
+
+ def test_xstring
+ assert_equal "foo\n", `echo foo`
+ s = 'foo'
+ assert_equal "foo\n", `echo #{s}`
+ end
+
+ def test_regexp
+ assert_instance_of Regexp, //
+ assert_match(//, 'a')
+ assert_match(//, '')
+ assert_instance_of Regexp, /a/
+ assert_match(/a/, 'a')
+ assert_no_match(/test/, 'tes')
+ re = /test/
+ assert_match re, 'test'
+ str = 'test'
+ assert_match re, str
+ assert_match(/test/, str)
+ assert_equal 0, (/test/ =~ 'test')
+ assert_equal 0, (re =~ 'test')
+ assert_equal 0, (/test/ =~ str)
+ assert_equal 0, (re =~ str)
+ assert_equal 0, ('test' =~ /test/)
+ assert_equal 0, ('test' =~ re)
+ assert_equal 0, (str =~ /test/)
+ assert_equal 0, (str =~ re)
+ end
+
+ def test_dregexp
+ assert_instance_of Regexp, /re#{'ge'}xp/
+ assert_equal(/regexp/, /re#{'ge'}xp/)
+ bug3903 = '[ruby-core:32682]'
+ assert_raise(SyntaxError, bug3903) {eval('/[#{"\x80"}]/')}
+ end
+
+ def test_array
+ assert_instance_of Array, []
+ assert_equal [], []
+ assert_equal 0, [].size
+ assert_instance_of Array, [0]
+ assert_equal [3], [3]
+ assert_equal 1, [3].size
+ a = [3]
+ assert_equal 3, a[0]
+ assert_instance_of Array, [1,2]
+ assert_equal [1,2], [1,2]
+ assert_instance_of Array, [1,2,3,4,5]
+ assert_equal [1,2,3,4,5], [1,2,3,4,5]
+ assert_equal 5, [1,2,3,4,5].size
+ a = [1,2]
+ assert_equal 1, a[0]
+ assert_equal 2, a[1]
+ a = [1 + 2, 3 + 4, 5 + 6]
+ assert_instance_of Array, a
+ assert_equal [3, 7, 11], a
+ assert_equal 7, a[1]
+ assert_equal 1, ([0][0] += 1)
+ assert_equal 1, ([2][0] -= 1)
+ a = [obj = Object.new]
+ assert_instance_of Array, a
+ assert_equal 1, a.size
+ assert_equal obj, a[0]
+ a = [1,2,3]
+ a[1] = 5
+ assert_equal 5, a[1]
+ end
+
+ def test_hash
+ assert_instance_of Hash, {}
+ assert_equal({}, {})
+ assert_instance_of Hash, {1 => 2}
+ assert_equal({1 => 2}, {1 => 2})
+ h = {1 => 2}
+ assert_equal 2, h[1]
+ h = {"string" => "literal", "goto" => "hell"}
+ assert_equal h, h
+ assert_equal 2, h.size
+ assert_equal h, h
+ assert_equal "literal", h["string"]
+ end
+
+ def test_big_array_and_hash_literal
+ assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).map{'x'}.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
+ assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).to_a.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
+ assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => x"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
+ assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => #{n}"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
+ end
+
+ def test_big_hash_literal
+ bug7466 = '[ruby-dev:46658]'
+ h = {
+ 0xFE042 => 0xE5CD,
+ 0xFE043 => 0xE5CD,
+ 0xFE045 => 0xEA94,
+ 0xFE046 => 0xE4E3,
+ 0xFE047 => 0xE4E2,
+ 0xFE048 => 0xEA96,
+ 0xFE049 => 0x3013,
+ 0xFE04A => 0xEB36,
+ 0xFE04B => 0xEB37,
+ 0xFE04C => 0xEB38,
+ 0xFE04D => 0xEB49,
+ 0xFE04E => 0xEB82,
+ 0xFE04F => 0xE4D2,
+ 0xFE050 => 0xEB35,
+ 0xFE051 => 0xEAB9,
+ 0xFE052 => 0xEABA,
+ 0xFE053 => 0xE4D4,
+ 0xFE054 => 0xE4CD,
+ 0xFE055 => 0xEABB,
+ 0xFE056 => 0xEABC,
+ 0xFE057 => 0xEB32,
+ 0xFE058 => 0xEB33,
+ 0xFE059 => 0xEB34,
+ 0xFE05A => 0xEB39,
+ 0xFE05B => 0xEB5A,
+ 0xFE190 => 0xE5A4,
+ 0xFE191 => 0xE5A5,
+ 0xFE192 => 0xEAD0,
+ 0xFE193 => 0xEAD1,
+ 0xFE194 => 0xEB47,
+ 0xFE195 => 0xE509,
+ 0xFE196 => 0xEAA0,
+ 0xFE197 => 0xE50B,
+ 0xFE198 => 0xEAA1,
+ 0xFE199 => 0xEAA2,
+ 0xFE19A => 0x3013,
+ 0xFE19B => 0xE4FC,
+ 0xFE19C => 0xE4FA,
+ 0xFE19D => 0xE4FC,
+ 0xFE19E => 0xE4FA,
+ 0xFE19F => 0xE501,
+ 0xFE1A0 => 0x3013,
+ 0xFE1A1 => 0xE5DD,
+ 0xFE1A2 => 0xEADB,
+ 0xFE1A3 => 0xEAE9,
+ 0xFE1A4 => 0xEB13,
+ 0xFE1A5 => 0xEB14,
+ 0xFE1A6 => 0xEB15,
+ 0xFE1A7 => 0xEB16,
+ 0xFE1A8 => 0xEB17,
+ 0xFE1A9 => 0xEB18,
+ 0xFE1AA => 0xEB19,
+ 0xFE1AB => 0xEB1A,
+ 0xFE1AC => 0xEB44,
+ 0xFE1AD => 0xEB45,
+ 0xFE1AE => 0xE4CB,
+ 0xFE1AF => 0xE5BF,
+ 0xFE1B0 => 0xE50E,
+ 0xFE1B1 => 0xE4EC,
+ 0xFE1B2 => 0xE4EF,
+ 0xFE1B3 => 0xE4F8,
+ 0xFE1B4 => 0x3013,
+ 0xFE1B5 => 0x3013,
+ 0xFE1B6 => 0xEB1C,
+ 0xFE1B9 => 0xEB7E,
+ 0xFE1D3 => 0xEB22,
+ 0xFE7DC => 0xE4D8,
+ 0xFE1D4 => 0xEB23,
+ 0xFE1D5 => 0xEB24,
+ 0xFE1D6 => 0xEB25,
+ 0xFE1CC => 0xEB1F,
+ 0xFE1CD => 0xEB20,
+ 0xFE1CE => 0xE4D9,
+ 0xFE1CF => 0xE48F,
+ 0xFE1C5 => 0xE5C7,
+ 0xFE1C6 => 0xEAEC,
+ 0xFE1CB => 0xEB1E,
+ 0xFE1DA => 0xE4DD,
+ 0xFE1E1 => 0xEB57,
+ 0xFE1E2 => 0xEB58,
+ 0xFE1E3 => 0xE492,
+ 0xFE1C9 => 0xEB1D,
+ 0xFE1D9 => 0xE4D3,
+ 0xFE1DC => 0xE5D4,
+ 0xFE1BA => 0xE4E0,
+ 0xFE1BB => 0xEB76,
+ 0xFE1C8 => 0xE4E0,
+ 0xFE1DD => 0xE5DB,
+ 0xFE1BC => 0xE4DC,
+ 0xFE1D8 => 0xE4DF,
+ 0xFE1BD => 0xE49A,
+ 0xFE1C7 => 0xEB1B,
+ 0xFE1C2 => 0xE5C2,
+ 0xFE1C0 => 0xE5C0,
+ 0xFE1B8 => 0xE4DB,
+ 0xFE1C3 => 0xE470,
+ 0xFE1BE => 0xE4D8,
+ 0xFE1C4 => 0xE4D9,
+ 0xFE1B7 => 0xE4E1,
+ 0xFE1BF => 0xE4DE,
+ 0xFE1C1 => 0xE5C1,
+ 0xFE1CA => 0x3013,
+ 0xFE1D0 => 0xE4E1,
+ 0xFE1D1 => 0xEB21,
+ 0xFE1D2 => 0xE4D7,
+ 0xFE1D7 => 0xE4DA,
+ 0xFE1DB => 0xE4EE,
+ 0xFE1DE => 0xEB3F,
+ 0xFE1DF => 0xEB46,
+ 0xFE1E0 => 0xEB48,
+ 0xFE336 => 0xE4FB,
+ 0xFE320 => 0xE472,
+ 0xFE321 => 0xEB67,
+ 0xFE322 => 0xEACA,
+ 0xFE323 => 0xEAC0,
+ 0xFE324 => 0xE5AE,
+ 0xFE325 => 0xEACB,
+ 0xFE326 => 0xEAC9,
+ 0xFE327 => 0xE5C4,
+ 0xFE328 => 0xEAC1,
+ 0xFE329 => 0xE4E7,
+ 0xFE32A => 0xE4E7,
+ 0xFE32B => 0xEACD,
+ 0xFE32C => 0xEACF,
+ 0xFE32D => 0xEACE,
+ 0xFE32E => 0xEAC7,
+ 0xFE32F => 0xEAC8,
+ 0xFE330 => 0xE471,
+ 0xFE331 => "[Bug #7466]",
+ }
+ k = h.keys
+ assert_equal([129, 0xFE331], [k.size, k.last], bug7466)
+
+ code = [
+ "h = {",
+ (1..128).map {|i| "#{i} => 0,"},
+ (129..140).map {|i| "#{i} => [],"},
+ "}",
+ ].join
+ assert_separately([], <<-"end;")
+ GC.stress = true
+ #{code}
+ GC.stress = false
+ assert_equal(140, h.size)
+ end;
+ end
+
+ def test_range
+ assert_instance_of Range, (1..2)
+ assert_equal(1..2, 1..2)
+ r = 1..2
+ assert_equal 1, r.begin
+ assert_equal 2, r.end
+ assert_equal false, r.exclude_end?
+ assert_instance_of Range, (1...3)
+ assert_equal(1...3, 1...3)
+ r = 1...3
+ assert_equal 1, r.begin
+ assert_equal 3, r.end
+ assert_equal true, r.exclude_end?
+ r = 1+2 .. 3+4
+ assert_instance_of Range, r
+ assert_equal 3, r.begin
+ assert_equal 7, r.end
+ assert_equal false, r.exclude_end?
+ r = 1+2 ... 3+4
+ assert_instance_of Range, r
+ assert_equal 3, r.begin
+ assert_equal 7, r.end
+ assert_equal true, r.exclude_end?
+ assert_instance_of Range, 'a'..'c'
+ r = 'a'..'c'
+ assert_equal 'a', r.begin
+ assert_equal 'c', r.end
+ end
+
+ def test__FILE__
+ assert_instance_of String, __FILE__
+ assert_equal __FILE__, __FILE__
+ assert_equal 'test_literal.rb', File.basename(__FILE__)
+ end
+
+ def test__LINE__
+ assert_instance_of Fixnum, __LINE__
+ assert_equal __LINE__, __LINE__
+ end
+
+ def test_integer
+ head = ['', '0x', '0o', '0b', '0d', '-', '+']
+ chars = ['0', '1', '_', '9', 'f']
+ head.each {|h|
+ 4.times {|len|
+ a = [h]
+ len.times { a = a.product(chars).map {|x| x.join('') } }
+ a.each {|s|
+ next if s.empty?
+ begin
+ r1 = Integer(s)
+ rescue ArgumentError
+ r1 = :err
+ end
+ begin
+ r2 = eval(s)
+ rescue NameError, SyntaxError
+ r2 = :err
+ end
+ assert_equal(r1, r2, "Integer(#{s.inspect}) != eval(#{s.inspect})")
+ }
+ }
+ }
+ bug2407 = '[ruby-dev:39798]'
+ head.each {|h|
+ if /^0/ =~ h
+ begin
+ eval("#{h}_")
+ rescue SyntaxError => e
+ assert_match(/numeric literal without digits\Z/, e.message, bug2407)
+ end
+ end
+ }
+ end
+
+ def test_float
+ head = ['', '-', '+']
+ chars = ['0', '1', '_', '9', 'f', '.']
+ head.each {|h|
+ 6.times {|len|
+ a = [h]
+ len.times { a = a.product(chars).map {|x| x.join('') } }
+ a.each {|s|
+ next if s.empty?
+ next if /\.\z/ =~ s
+ next if /\A[-+]?\./ =~ s
+ next if /\A[-+]?0/ =~ s
+ begin
+ r1 = Float(s)
+ rescue ArgumentError
+ r1 = :err
+ end
+ begin
+ r2 = eval(s)
+ rescue NameError, SyntaxError
+ r2 = :err
+ end
+ r2 = :err if Range === r2
+ assert_equal(r1, r2, "Float(#{s.inspect}) != eval(#{s.inspect})")
+ }
+ }
+ }
+ end
+
+ def test_symbol_list
+ assert_equal([:foo, :bar], %i[foo bar])
+ assert_equal([:"\"foo"], %i["foo])
+
+ x = 10
+ assert_equal([:foo, :b10], %I[foo b#{x}])
+ assert_equal([:"\"foo10"], %I["foo#{x}])
+
+ assert_ruby_status(["--disable-gems", "--dump=parsetree"], "%I[foo bar]")
+ end
+end
diff --git a/jni/ruby/test/ruby/test_m17n.rb b/jni/ruby/test/ruby/test_m17n.rb
new file mode 100644
index 0000000..980f9c8
--- /dev/null
+++ b/jni/ruby/test/ruby/test_m17n.rb
@@ -0,0 +1,1599 @@
+# coding: US-ASCII
+require 'test/unit'
+
+class TestM17N < Test::Unit::TestCase
+ def assert_encoding(encname, actual, message=nil)
+ assert_equal(Encoding.find(encname), actual, message)
+ end
+
+ module AESU
+ def ua(str) str.dup.force_encoding("US-ASCII") end
+ def a(str) str.dup.force_encoding("ASCII-8BIT") end
+ def e(str) str.dup.force_encoding("EUC-JP") end
+ def s(str) str.dup.force_encoding("Windows-31J") end
+ def u(str) str.dup.force_encoding("UTF-8") end
+ end
+ include AESU
+ extend AESU
+
+ def assert_strenc(bytes, enc, actual, message=nil)
+ assert_instance_of(String, actual, message)
+ enc = Encoding.find(enc) if String === enc
+ assert_equal(enc, actual.encoding, message)
+ assert_equal(a(bytes), a(actual), message)
+ end
+
+ def assert_regexp_generic_encoding(r)
+ assert_not_predicate(r, :fixed_encoding?)
+ %w[ASCII-8BIT EUC-JP Windows-31J UTF-8].each {|ename|
+ # "\xc2\xa1" is a valid sequence for ASCII-8BIT, EUC-JP, Windows-31J and UTF-8.
+ assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(ename) }
+ }
+ end
+
+ def assert_regexp_fixed_encoding(r)
+ assert_predicate(r, :fixed_encoding?)
+ %w[ASCII-8BIT EUC-JP Windows-31J UTF-8].each {|ename|
+ enc = Encoding.find(ename)
+ if enc == r.encoding
+ assert_nothing_raised { r =~ "\xc2\xa1".force_encoding(enc) }
+ else
+ assert_raise(Encoding::CompatibilityError) { r =~ "\xc2\xa1".force_encoding(enc) }
+ end
+ }
+ end
+
+ def assert_regexp_generic_ascii(r)
+ assert_encoding("US-ASCII", r.encoding)
+ assert_regexp_generic_encoding(r)
+ end
+
+ def assert_regexp_fixed_ascii8bit(r)
+ assert_encoding("ASCII-8BIT", r.encoding)
+ assert_regexp_fixed_encoding(r)
+ end
+
+ def assert_regexp_fixed_eucjp(r)
+ assert_encoding("EUC-JP", r.encoding)
+ assert_regexp_fixed_encoding(r)
+ end
+
+ def assert_regexp_fixed_sjis(r)
+ assert_encoding("Windows-31J", r.encoding)
+ assert_regexp_fixed_encoding(r)
+ end
+
+ def assert_regexp_fixed_utf8(r)
+ assert_encoding("UTF-8", r.encoding)
+ assert_regexp_fixed_encoding(r)
+ end
+
+ def assert_regexp_usascii_literal(r, enc, ex = nil)
+ code = "# -*- encoding: US-ASCII -*-\n#{r}.encoding"
+ if ex
+ assert_raise(ex) { eval(code) }
+ else
+ assert_equal(enc, eval(code))
+ end
+ end
+
+ def encdump(str)
+ d = str.dump
+ if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d
+ d
+ else
+ "#{d}.force_encoding(#{str.encoding.name.dump})"
+ end
+ end
+
+ def encdumpargs(args)
+ r = '('
+ args.each_with_index {|a, i|
+ r << ',' if 0 < i
+ if String === a
+ r << encdump(a)
+ else
+ r << a.inspect
+ end
+ }
+ r << ')'
+ r
+ end
+
+ def assert_str_enc_propagation(t, s1, s2)
+ if !s1.ascii_only?
+ assert_equal(s1.encoding, t.encoding)
+ elsif !s2.ascii_only?
+ assert_equal(s2.encoding, t.encoding)
+ else
+ assert_include([s1.encoding, s2.encoding], t.encoding)
+ end
+ end
+
+ def assert_same_result(expected_proc, actual_proc)
+ e = nil
+ begin
+ t = expected_proc.call
+ rescue
+ e = $!
+ end
+ if e
+ assert_raise(e.class) { actual_proc.call }
+ else
+ assert_equal(t, actual_proc.call)
+ end
+ end
+
+ def str_enc_compatible?(*strs)
+ encs = []
+ strs.each {|s|
+ encs << s.encoding if !s.ascii_only?
+ }
+ encs.uniq!
+ encs.length <= 1
+ end
+
+ # tests start
+
+ def test_string_ascii_literal
+ assert_encoding("ASCII-8BIT", eval(a(%{""})).encoding)
+ assert_encoding("ASCII-8BIT", eval(a(%{"a"})).encoding)
+ end
+
+ def test_string_eucjp_literal
+ assert_encoding("EUC-JP", eval(e(%{""})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"a"})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"\xa1\xa1"})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"\\xa1\\xa1"})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"\\x20"})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"\\n"})).encoding)
+ assert_encoding("EUC-JP", eval(e(%{"\\x80"})).encoding)
+ end
+
+ def test_utf8_literal
+ assert_equal(Encoding::UTF_8, "\u3042".encoding, "[ruby-dev:33406] \"\\u3042\".encoding")
+ assert_raise(SyntaxError) { eval(a('\u3052\x80')) }
+ end
+
+ def test_string_mixed_unicode
+ assert_raise(SyntaxError) { eval(a(%{"\xc2\xa1\\u{6666}"})) }
+ assert_raise(SyntaxError) { eval(e(%{"\xc2\xa1\\u{6666}"})) }
+ assert_raise(SyntaxError) { eval(s(%{"\xc2\xa1\\u{6666}"})) }
+ assert_nothing_raised { eval(u(%{"\xc2\xa1\\u{6666}"})) }
+ assert_raise(SyntaxError) { eval(a(%{"\\u{6666}\xc2\xa1"})) }
+ assert_raise(SyntaxError) { eval(e(%{"\\u{6666}\xc2\xa1"})) }
+ assert_raise(SyntaxError) { eval(s(%{"\\u{6666}\xc2\xa1"})) }
+ assert_nothing_raised { eval(u(%{"\\u{6666}\xc2\xa1"})) }
+ end
+
+ def test_string_inspect_invalid
+ assert_equal('"\xFE"', e("\xfe").inspect)
+ assert_equal('"\x8E"', e("\x8e").inspect)
+ assert_equal('"\x8F"', e("\x8f").inspect)
+ assert_equal('"\x8F\xA1"', e("\x8f\xa1").inspect)
+ assert_equal('"\xEF"', s("\xef").inspect)
+ assert_equal('"\xC2"', u("\xc2").inspect)
+ assert_equal('"\xE0\x80"', u("\xe0\x80").inspect)
+ assert_equal('"\xF0\x80\x80"', u("\xf0\x80\x80").inspect)
+ assert_equal('"\xF8\x80\x80\x80"', u("\xf8\x80\x80\x80").inspect)
+ assert_equal('"\xFC\x80\x80\x80\x80"', u("\xfc\x80\x80\x80\x80").inspect)
+
+ assert_equal('"\xFE "', e("\xfe ").inspect)
+ assert_equal('"\x8E "', e("\x8e ").inspect)
+ assert_equal('"\x8F "', e("\x8f ").inspect)
+ assert_equal('"\x8F\xA1 "', e("\x8f\xa1 ").inspect)
+ assert_equal('"\xEF "', s("\xef ").inspect)
+ assert_equal('"\xC2 "', u("\xc2 ").inspect)
+ assert_equal('"\xE0\x80 "', u("\xe0\x80 ").inspect)
+ assert_equal('"\xF0\x80\x80 "', u("\xf0\x80\x80 ").inspect)
+ assert_equal('"\xF8\x80\x80\x80 "', u("\xf8\x80\x80\x80 ").inspect)
+ assert_equal('"\xFC\x80\x80\x80\x80 "', u("\xfc\x80\x80\x80\x80 ").inspect)
+
+ assert_equal('"\x81."', s("\x81.").inspect)
+ assert_equal('"\xFC"', u("\xfc").inspect)
+ end
+
+ def test_string_inspect_encoding
+ EnvUtil.suppress_warning do
+ begin
+ orig_int = Encoding.default_internal
+ orig_ext = Encoding.default_external
+ Encoding.default_internal = nil
+ [Encoding::UTF_8, Encoding::EUC_JP, Encoding::Windows_31J, Encoding::GB18030].
+ each do |e|
+ Encoding.default_external = e
+ str = "\x81\x30\x81\x30".force_encoding('GB18030')
+ assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect)
+ str = e("\xa1\x8f\xa1\xa1")
+ expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP")
+ assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect)
+ str = s("\x81@")
+ assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect)
+ str = "\u3042\u{10FFFD}"
+ assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect)
+ end
+ Encoding.default_external = Encoding::UTF_8
+ [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE,
+ Encoding::UTF8_SOFTBANK].each do |e|
+ str = "abc".encode(e)
+ assert_equal('"abc"', str.inspect)
+ end
+ ensure
+ Encoding.default_internal = orig_int
+ Encoding.default_external = orig_ext
+ end
+ end
+ end
+
+ STR_WITHOUT_BOM = "\u3042".freeze
+ STR_WITH_BOM = "\uFEFF\u3042".freeze
+ bug8940 = '[ruby-core:59757] [Bug #8940]'
+ bug9415 = '[ruby-dev:47895] [Bug #9415]'
+ %w/UTF-16 UTF-32/.each do |enc|
+ %w/BE LE/.each do |endian|
+ bom = "\uFEFF".encode("#{enc}#{endian}").force_encoding(enc)
+
+ define_method("test_utf_16_32_inspect(#{enc}#{endian})") do
+ s = STR_WITHOUT_BOM.encode(enc + endian)
+ # When a UTF-16/32 string doesn't have a BOM,
+ # inspect as a dummy encoding string.
+ assert_equal(s.dup.force_encoding("ISO-2022-JP").inspect,
+ s.dup.force_encoding(enc).inspect)
+ assert_normal_exit("#{bom.b.dump}.force_encoding('#{enc}').inspect", bug8940)
+ end
+
+ define_method("test_utf_16_32_codepoints(#{enc}#{endian})") do
+ assert_equal([0xFEFF], bom.codepoints, bug9415)
+ end
+
+ define_method("test_utf_16_32_ord(#{enc}#{endian})") do
+ assert_equal(0xFEFF, bom.ord, bug9415)
+ end
+
+ define_method("test_utf_16_32_inspect(#{enc}#{endian}-BOM)") do
+ s = STR_WITH_BOM.encode(enc + endian)
+ # When a UTF-16/32 string has a BOM,
+ # inspect as a particular encoding string.
+ assert_equal(s.inspect,
+ s.dup.force_encoding(enc).inspect)
+ end
+ end
+ end
+
+ def test_utf_without_bom_asciionly
+ bug10598 = '[ruby-core:66835] [Bug #10598]'
+ encs = [Encoding::UTF_16, Encoding::UTF_32].find_all {|enc|
+ "abcd".force_encoding(enc).ascii_only?
+ }
+ assert_empty(encs, bug10598)
+ end
+
+ def test_object_utf16_32_inspect
+ EnvUtil.suppress_warning do
+ begin
+ orig_int = Encoding.default_internal
+ orig_ext = Encoding.default_external
+ Encoding.default_internal = nil
+ Encoding.default_external = Encoding::UTF_8
+ o = Object.new
+ [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e|
+ o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end"
+ assert_raise(Encoding::CompatibilityError) { [o].inspect }
+ end
+ ensure
+ Encoding.default_internal = orig_int
+ Encoding.default_external = orig_ext
+ end
+ end
+ end
+
+ def test_object_inspect_external
+ orig_v, $VERBOSE = $VERBOSE, false
+ orig_int, Encoding.default_internal = Encoding.default_internal, nil
+ orig_ext = Encoding.default_external
+ o = Object.new
+
+ Encoding.default_external = Encoding::UTF_16BE
+ def o.inspect
+ "abc"
+ end
+ assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect }
+
+ def o.inspect
+ "abc".encode(Encoding.default_external)
+ end
+ assert_raise(Encoding::CompatibilityError) { [o].inspect }
+
+ Encoding.default_external = Encoding::US_ASCII
+ def o.inspect
+ "\u3042"
+ end
+ assert_raise(Encoding::CompatibilityError) { [o].inspect }
+ ensure
+ Encoding.default_internal = orig_int
+ Encoding.default_external = orig_ext
+ $VERBOSE = orig_v
+ end
+
+ def test_str_dump
+ [
+ e("\xfe"),
+ e("\x8e"),
+ e("\x8f"),
+ e("\x8f\xa1"),
+ s("\xef"),
+ u("\xc2"),
+ u("\xe0\x80"),
+ u("\xf0\x80\x80"),
+ u("\xf8\x80\x80\x80"),
+ u("\xfc\x80\x80\x80\x80"),
+
+ e("\xfe "),
+ e("\x8e "),
+ e("\x8f "),
+ e("\x8f\xa1 "),
+ s("\xef "),
+ u("\xc2 "),
+ u("\xe0\x80 "),
+ u("\xf0\x80\x80 "),
+ u("\xf8\x80\x80\x80 "),
+ u("\xfc\x80\x80\x80\x80 "),
+
+
+ e("\xa1\x8f\xa1\xa1"),
+
+ s("\x81."),
+ s("\x81@"),
+
+ u("\xfc"),
+ "\u3042",
+ "ascii",
+
+ "\u3042".encode("UTF-16LE"),
+ "\u3042".encode("UTF-16BE"),
+ ].each do |str|
+ assert_equal(str, eval(str.dump), "[ruby-dev:33142]")
+ end
+ end
+
+ def test_validate_redundant_utf8
+ bits_0x10ffff = "11110100 10001111 10111111 10111111"
+ [
+ "0xxxxxxx",
+ "110XXXXx 10xxxxxx",
+ "1110XXXX 10Xxxxxx 10xxxxxx",
+ "11110XXX 10XXxxxx 10xxxxxx 10xxxxxx",
+ "111110XX 10XXXxxx 10xxxxxx 10xxxxxx 10xxxxxx",
+ "1111110X 10XXXXxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx",
+ "11111110 10XXXXXx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx",
+ "11111111 10XXXXXX 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx",
+ ].each {|pat0|
+ [
+ pat0.gsub(/x/, '1'),
+ pat0.gsub(/x/, '0')
+ ].each {|pat1|
+ [
+ pat1.sub(/X([^X]*)\z/, '1\1').gsub(/X/, "0"),
+ pat1.gsub(/X/, "1"),
+ ].each {|pat2|
+ s = [pat2.gsub(/ /, "")].pack("B*").force_encoding("utf-8")
+ if pat2 <= bits_0x10ffff
+ assert_predicate(s, :valid_encoding?, "#{pat2}")
+ else
+ assert_not_predicate(s, :valid_encoding?, "#{pat2}")
+ end
+ }
+ if / / =~ pat0
+ pat3 = pat1.gsub(/X/, "0")
+ s = [pat3.gsub(/ /, "")].pack("B*").force_encoding("utf-8")
+ assert_not_predicate(s, :valid_encoding?, "#{pat3}")
+ end
+ }
+ }
+ end
+
+ def test_validate_surrogate
+ # 1110XXXX 10Xxxxxx 10xxxxxx : 3 bytes UTF-8
+ pats = [
+ "11101101 10011111 10111111", # just before surrogate high
+ "11101101 1010xxxx 10xxxxxx", # surrogate high
+ "11101101 1011xxxx 10xxxxxx", # surrogate low
+ "11101110 10000000 10000000", # just after surrogate low
+ ]
+ pats.values_at(1,2).each {|pat0|
+ [
+ pat0.gsub(/x/, '0'),
+ pat0.gsub(/x/, '1'),
+ ].each {|pat1|
+ s = [pat1.gsub(/ /, "")].pack("B*").force_encoding("utf-8")
+ assert_not_predicate(s, :valid_encoding?, "#{pat1}")
+ }
+ }
+ pats.values_at(0,3).each {|pat|
+ s = [pat.gsub(/ /, "")].pack("B*").force_encoding("utf-8")
+ assert_predicate(s, :valid_encoding?, "#{pat}")
+ }
+ end
+
+ def test_regexp_too_short_multibyte_character
+ assert_raise(SyntaxError) { eval('/\xfe/e') }
+ assert_raise(SyntaxError) { eval('/\x8e/e') }
+ assert_raise(SyntaxError) { eval('/\x8f/e') }
+ assert_raise(SyntaxError) { eval('/\x8f\xa1/e') }
+ assert_raise(SyntaxError) { eval('/\xef/s') }
+ assert_raise(SyntaxError) { eval('/\xc2/u') }
+ assert_raise(SyntaxError) { eval('/\xe0\x80/u') }
+ assert_raise(SyntaxError) { eval('/\xf0\x80\x80/u') }
+ assert_raise(SyntaxError) { eval('/\xf8\x80\x80\x80/u') }
+ assert_raise(SyntaxError) { eval('/\xfc\x80\x80\x80\x80/u') }
+
+ # raw 8bit
+ assert_raise(SyntaxError) { eval("/\xfe/e") }
+ assert_raise(SyntaxError) { eval("/\xc2/u") }
+
+ # invalid suffix
+ assert_raise(SyntaxError) { eval('/\xc2\xff/u') }
+ assert_raise(SyntaxError) { eval('/\xc2 /u') }
+ assert_raise(SyntaxError) { eval('/\xc2\x20/u') }
+ end
+
+ def test_regexp_generic
+ assert_regexp_generic_ascii(/a/)
+ assert_regexp_generic_ascii(Regexp.new(a("a")))
+ assert_regexp_generic_ascii(Regexp.new(e("a")))
+ assert_regexp_generic_ascii(Regexp.new(s("a")))
+ assert_regexp_generic_ascii(Regexp.new(u("a")))
+
+ [/a/, Regexp.new(a("a"))].each {|r|
+ assert_equal(0, r =~ a("a"))
+ assert_equal(0, r =~ e("a"))
+ assert_equal(0, r =~ s("a"))
+ assert_equal(0, r =~ u("a"))
+ assert_equal(nil, r =~ a("\xc2\xa1"))
+ assert_equal(nil, r =~ e("\xc2\xa1"))
+ assert_equal(nil, r =~ s("\xc2\xa1"))
+ assert_equal(nil, r =~ u("\xc2\xa1"))
+ }
+ end
+
+ def test_regexp_ascii_none
+ r = /a/n
+
+ assert_warning(%r{regexp match /.../n against to}) {
+ assert_regexp_generic_ascii(r)
+ }
+
+ assert_equal(0, r =~ a("a"))
+ assert_equal(0, r =~ e("a"))
+ assert_equal(0, r =~ s("a"))
+ assert_equal(0, r =~ u("a"))
+ assert_equal(nil, r =~ a("\xc2\xa1"))
+ assert_warning(%r{regexp match /.../n against to EUC-JP string}) {
+ assert_equal(nil, r =~ e("\xc2\xa1"))
+ }
+ assert_warning(%r{regexp match /.../n against to Windows-31J string}) {
+ assert_equal(nil, r =~ s("\xc2\xa1"))
+ }
+ assert_warning(%r{regexp match /.../n against to UTF-8 string}) {
+ assert_equal(nil, r =~ u("\xc2\xa1"))
+ }
+
+ assert_nothing_raised { eval(e("/\\x80/n")) }
+ end
+
+ def test_regexp_ascii
+ assert_regexp_fixed_ascii8bit(/\xc2\xa1/n)
+ assert_regexp_fixed_ascii8bit(eval(a(%{/\xc2\xa1/})))
+ assert_regexp_fixed_ascii8bit(eval(a(%{/\xc2\xa1/n})))
+ assert_regexp_fixed_ascii8bit(eval(a(%q{/\xc2\xa1/})))
+
+ s = '\xc2\xa1'
+ assert_regexp_fixed_ascii8bit(/#{s}/)
+
+ assert_raise(SyntaxError) { eval("/\xa1\xa1/n".force_encoding("euc-jp")) }
+
+ [/\xc2\xa1/n, eval(a(%{/\xc2\xa1/})), eval(a(%{/\xc2\xa1/n}))].each {|r|
+ assert_equal(nil, r =~ a("a"))
+ assert_equal(nil, r =~ e("a"))
+ assert_equal(nil, r =~ s("a"))
+ assert_equal(nil, r =~ u("a"))
+ assert_equal(0, r =~ a("\xc2\xa1"))
+ assert_raise(Encoding::CompatibilityError) { r =~ e("\xc2\xa1") }
+ assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") }
+ assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") }
+ }
+ end
+
+ def test_regexp_euc
+ assert_regexp_fixed_eucjp(/a/e)
+ assert_regexp_fixed_eucjp(/\xc2\xa1/e)
+ assert_regexp_fixed_eucjp(eval(e(%{/\xc2\xa1/})))
+ assert_regexp_fixed_eucjp(eval(e(%q{/\xc2\xa1/})))
+
+ [/a/e].each {|r|
+ assert_equal(0, r =~ a("a"))
+ assert_equal(0, r =~ e("a"))
+ assert_equal(0, r =~ s("a"))
+ assert_equal(0, r =~ u("a"))
+ assert_raise(Encoding::CompatibilityError) { r =~ a("\xc2\xa1") }
+ assert_equal(nil, r =~ e("\xc2\xa1"))
+ assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") }
+ assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") }
+ }
+
+ [/\xc2\xa1/e, eval(e(%{/\xc2\xa1/})), eval(e(%q{/\xc2\xa1/}))].each {|r|
+ assert_equal(nil, r =~ a("a"))
+ assert_equal(nil, r =~ e("a"))
+ assert_equal(nil, r =~ s("a"))
+ assert_equal(nil, r =~ u("a"))
+ assert_raise(Encoding::CompatibilityError) { r =~ a("\xc2\xa1") }
+ assert_equal(0, r =~ e("\xc2\xa1"))
+ assert_raise(Encoding::CompatibilityError) { r =~ s("\xc2\xa1") }
+ assert_raise(Encoding::CompatibilityError) { r =~ u("\xc2\xa1") }
+ }
+ end
+
+ def test_regexp_sjis
+ assert_regexp_fixed_sjis(/a/s)
+ assert_regexp_fixed_sjis(/\xc2\xa1/s)
+ assert_regexp_fixed_sjis(eval(s(%{/\xc2\xa1/})))
+ assert_regexp_fixed_sjis(eval(s(%q{/\xc2\xa1/})))
+ end
+
+ def test_regexp_windows_31j
+ begin
+ Regexp.new("\xa1".force_encoding("windows-31j")) =~ "\xa1\xa1".force_encoding("euc-jp")
+ rescue Encoding::CompatibilityError
+ err = $!
+ end
+ assert_match(/windows-31j/i, err.message)
+ end
+
+ def test_regexp_embed
+ r = eval(e("/\xc2\xa1/"))
+ assert_raise(RegexpError) { eval(s("/\xc2\xa1\#{r}/s")) }
+ assert_raise(RegexpError) { eval(s("/\#{r}\xc2\xa1/s")) }
+
+ r = /\xc2\xa1/e
+ assert_raise(RegexpError) { eval(s("/\xc2\xa1\#{r}/s")) }
+ assert_raise(RegexpError) { eval(s("/\#{r}\xc2\xa1/s")) }
+
+ r = eval(e("/\xc2\xa1/"))
+ assert_raise(RegexpError) { /\xc2\xa1#{r}/s }
+
+ r = /\xc2\xa1/e
+ assert_raise(RegexpError) { /\xc2\xa1#{r}/s }
+
+ r1 = Regexp.new('foo'.force_encoding("ascii-8bit"))
+ r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::US_ASCII, r2.encoding)
+
+ r1 = Regexp.new('foo'.force_encoding("us-ascii"))
+ r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::US_ASCII, r2.encoding)
+
+ r1 = Regexp.new('foo'.force_encoding("ascii-8bit"))
+ r2 = eval('/bar#{r1}/'.force_encoding('us-ascii'))
+ assert_equal(Encoding::US_ASCII, r2.encoding)
+
+ r1 = Regexp.new('foo'.force_encoding("us-ascii"))
+ r2 = eval('/bar#{r1}/'.force_encoding('us-ascii'))
+ assert_equal(Encoding::US_ASCII, r2.encoding)
+
+ r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit"))
+ r2 = eval('/bar#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::ASCII_8BIT, r2.encoding)
+
+ r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit"))
+ r2 = eval('/bar#{r1}/'.force_encoding('us-ascii'))
+ assert_equal(Encoding::ASCII_8BIT, r2.encoding)
+
+ r1 = Regexp.new('foo'.force_encoding("ascii-8bit"))
+ r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::ASCII_8BIT, r2.encoding)
+
+ r1 = Regexp.new('foo'.force_encoding("us-ascii"))
+ r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::ASCII_8BIT, r2.encoding)
+
+ r1 = Regexp.new('\xa1'.force_encoding("ascii-8bit"))
+ r2 = eval('/\xa1#{r1}/'.force_encoding('ascii-8bit'))
+ assert_equal(Encoding::ASCII_8BIT, r2.encoding)
+ end
+
+ def test_regexp_named_class
+ assert_match(/[[:space:]]/u, "\u{00a0}")
+ assert_match(/[[:space:]]/, "\u{00a0}")
+ end
+
+ def test_regexp_property
+ s = '\p{Hiragana}'.force_encoding("euc-jp")
+ assert_equal(Encoding::EUC_JP, s.encoding)
+ r = nil
+ assert_nothing_raised {
+ r = Regexp.new(s)
+ }
+ assert_predicate(r, :fixed_encoding?)
+ assert_match(r, "\xa4\xa2".force_encoding("euc-jp"))
+
+ r = eval('/\p{Hiragana}/'.force_encoding("euc-jp"))
+ assert_predicate(r, :fixed_encoding?)
+ assert_match(r, "\xa4\xa2".force_encoding("euc-jp"))
+
+ r = /\p{Hiragana}/e
+ assert_predicate(r, :fixed_encoding?)
+ assert_match(r, "\xa4\xa2".force_encoding("euc-jp"))
+
+ r = /\p{AsciI}/e
+ assert_predicate(r, :fixed_encoding?)
+ assert_match(r, "a".force_encoding("euc-jp"))
+
+ r = /\p{hiraganA}/e
+ assert_predicate(r, :fixed_encoding?)
+ assert_match(r, "\xa4\xa2".force_encoding("euc-jp"))
+
+ r = eval('/\u{3042}\p{Hiragana}/'.force_encoding("euc-jp"))
+ assert_predicate(r, :fixed_encoding?)
+ assert_equal(Encoding::UTF_8, r.encoding)
+
+ r = eval('/\p{Hiragana}\u{3042}/'.force_encoding("euc-jp"))
+ assert_predicate(r, :fixed_encoding?)
+ assert_equal(Encoding::UTF_8, r.encoding)
+ end
+
+ def test_regexp_embed_preprocess
+ r1 = /\xa4\xa2/e
+ r2 = /#{r1}/
+ assert_include(r2.source, r1.source)
+ end
+
+ def test_begin_end_offset
+ str = e("\244\242\244\244\244\246\244\250\244\252a")
+ assert(/(a)/ =~ str)
+ assert_equal("a", $&)
+ assert_equal(5, $~.begin(0))
+ assert_equal(6, $~.end(0))
+ assert_equal([5,6], $~.offset(0))
+ assert_equal(5, $~.begin(1))
+ assert_equal(6, $~.end(1))
+ assert_equal([5,6], $~.offset(1))
+ end
+
+ def test_begin_end_offset_sjis
+ str = s("\x81@@")
+ assert(/@/ =~ str)
+ assert_equal(s("\x81@"), $`)
+ assert_equal("@", $&)
+ assert_equal("", $')
+ assert_equal([1,2], $~.offset(0))
+ end
+
+ def test_quote
+ assert_regexp_generic_ascii(/#{Regexp.quote(a("a"))}#{Regexp.quote(e("e"))}/)
+
+ assert_encoding("US-ASCII", Regexp.quote(a("")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(e("")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(s("")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(u("")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(a("a")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(e("a")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(s("a")).encoding)
+ assert_encoding("US-ASCII", Regexp.quote(u("a")).encoding)
+
+ assert_encoding("ASCII-8BIT", Regexp.quote(a("\xc2\xa1")).encoding)
+ assert_encoding("EUC-JP", Regexp.quote(e("\xc2\xa1")).encoding)
+ assert_encoding("Windows-31J", Regexp.quote(s("\xc2\xa1")).encoding)
+ assert_encoding("UTF-8", Regexp.quote(u("\xc2\xa1")).encoding)
+ end
+
+ def test_union_0
+ r = Regexp.union
+ assert_regexp_generic_ascii(r)
+ assert_not_match(r, a(""))
+ assert_not_match(r, e(""))
+ assert_not_match(r, s(""))
+ assert_not_match(r, u(""))
+ end
+
+ def test_union_1_asciionly_string
+ assert_regexp_generic_ascii(Regexp.union(a("")))
+ assert_regexp_generic_ascii(Regexp.union(e("")))
+ assert_regexp_generic_ascii(Regexp.union(s("")))
+ assert_regexp_generic_ascii(Regexp.union(u("")))
+ assert_regexp_generic_ascii(Regexp.union(a("a")))
+ assert_regexp_generic_ascii(Regexp.union(e("a")))
+ assert_regexp_generic_ascii(Regexp.union(s("a")))
+ assert_regexp_generic_ascii(Regexp.union(u("a")))
+ assert_regexp_generic_ascii(Regexp.union(a("\t")))
+ assert_regexp_generic_ascii(Regexp.union(e("\t")))
+ assert_regexp_generic_ascii(Regexp.union(s("\t")))
+ assert_regexp_generic_ascii(Regexp.union(u("\t")))
+ end
+
+ def test_union_1_nonascii_string
+ assert_regexp_fixed_ascii8bit(Regexp.union(a("\xc2\xa1")))
+ assert_regexp_fixed_eucjp(Regexp.union(e("\xc2\xa1")))
+ assert_regexp_fixed_sjis(Regexp.union(s("\xc2\xa1")))
+ assert_regexp_fixed_utf8(Regexp.union(u("\xc2\xa1")))
+ end
+
+ def test_union_1_regexp
+ assert_regexp_generic_ascii(Regexp.union(//))
+ assert_warning(%r{regexp match /.../n against to}) {
+ assert_regexp_generic_ascii(Regexp.union(//n))
+ }
+ assert_regexp_fixed_eucjp(Regexp.union(//e))
+ assert_regexp_fixed_sjis(Regexp.union(//s))
+ assert_regexp_fixed_utf8(Regexp.union(//u))
+ end
+
+ def test_union_2
+ ary = [
+ a(""), e(""), s(""), u(""),
+ a("\xc2\xa1"), e("\xc2\xa1"), s("\xc2\xa1"), u("\xc2\xa1")
+ ]
+ ary.each {|s1|
+ ary.each {|s2|
+ if s1.empty?
+ if s2.empty?
+ assert_regexp_generic_ascii(Regexp.union(s1, s2))
+ else
+ r = Regexp.union(s1, s2)
+ assert_regexp_fixed_encoding(r)
+ assert_equal(s2.encoding, r.encoding)
+ end
+ else
+ if s2.empty?
+ r = Regexp.union(s1, s2)
+ assert_regexp_fixed_encoding(r)
+ assert_equal(s1.encoding, r.encoding)
+ else
+ if s1.encoding == s2.encoding
+ r = Regexp.union(s1, s2)
+ assert_regexp_fixed_encoding(r)
+ assert_equal(s1.encoding, r.encoding)
+ else
+ assert_raise(ArgumentError) { Regexp.union(s1, s2) }
+ end
+ end
+ end
+ }
+ }
+ end
+
+ def test_dynamic_ascii_regexp
+ assert_warning(%r{regexp match /.../n against to}) {
+ assert_regexp_generic_ascii(/#{ }/n)
+ }
+ assert_regexp_fixed_ascii8bit(/#{ }\xc2\xa1/n)
+ assert_regexp_fixed_ascii8bit(/\xc2\xa1#{ }/n)
+ assert_nothing_raised { s1, s2 = a('\xc2'), a('\xa1'); /#{s1}#{s2}/ }
+ end
+
+ def test_dynamic_eucjp_regexp
+ assert_regexp_fixed_eucjp(/#{ }/e)
+ assert_regexp_fixed_eucjp(/#{ }\xc2\xa1/e)
+ assert_regexp_fixed_eucjp(/\xc2\xa1#{ }/e)
+ assert_raise(SyntaxError) { eval('/\xc2#{ }/e') }
+ assert_raise(SyntaxError) { eval('/#{ }\xc2/e') }
+ assert_raise(SyntaxError) { eval('/\xc2#{ }\xa1/e') }
+ assert_raise(ArgumentError) { s1, s2 = e('\xc2'), e('\xa1'); /#{s1}#{s2}/ }
+ end
+
+ def test_dynamic_sjis_regexp
+ assert_regexp_fixed_sjis(/#{ }/s)
+ assert_regexp_fixed_sjis(/#{ }\xc2\xa1/s)
+ assert_regexp_fixed_sjis(/\xc2\xa1#{ }/s)
+ assert_raise(SyntaxError) { eval('/\x81#{ }/s') }
+ assert_raise(SyntaxError) { eval('/#{ }\x81/s') }
+ assert_raise(SyntaxError) { eval('/\x81#{ }\xa1/s') }
+ assert_raise(ArgumentError) { s1, s2 = s('\x81'), s('\xa1'); /#{s1}#{s2}/ }
+ end
+
+ def test_dynamic_utf8_regexp
+ assert_regexp_fixed_utf8(/#{ }/u)
+ assert_regexp_fixed_utf8(/#{ }\xc2\xa1/u)
+ assert_regexp_fixed_utf8(/\xc2\xa1#{ }/u)
+ assert_raise(SyntaxError) { eval('/\xc2#{ }/u') }
+ assert_raise(SyntaxError) { eval('/#{ }\xc2/u') }
+ assert_raise(SyntaxError) { eval('/\xc2#{ }\xa1/u') }
+ assert_raise(ArgumentError) { s1, s2 = u('\xc2'), u('\xa1'); /#{s1}#{s2}/ }
+ end
+
+ def test_regexp_unicode
+ assert_nothing_raised { eval '/\u{0}/u' }
+ assert_nothing_raised { eval '/\u{D7FF}/u' }
+ assert_raise(SyntaxError) { eval '/\u{D800}/u' }
+ assert_raise(SyntaxError) { eval '/\u{DFFF}/u' }
+ assert_nothing_raised { eval '/\u{E000}/u' }
+ assert_nothing_raised { eval '/\u{10FFFF}/u' }
+ assert_raise(SyntaxError) { eval '/\u{110000}/u' }
+ end
+
+ def test_regexp_mixed_unicode
+ assert_raise(SyntaxError) { eval(a(%{/\xc2\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\xc2\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\xc2\xa1\\u{6666}/})) }
+ assert_nothing_raised { eval(u(%{/\xc2\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(a(%{/\\u{6666}\xc2\xa1/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\u{6666}\xc2\xa1/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\u{6666}\xc2\xa1/})) }
+ assert_nothing_raised { eval(u(%{/\\u{6666}\xc2\xa1/})) }
+
+ assert_raise(SyntaxError) { eval(a(%{/\\xc2\\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\xc2\\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\xc2\\xa1\\u{6666}/})) }
+ assert_nothing_raised { eval(u(%{/\\xc2\\xa1\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(a(%{/\\u{6666}\\xc2\\xa1/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\u{6666}\\xc2\\xa1/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\u{6666}\\xc2\\xa1/})) }
+ assert_nothing_raised { eval(u(%{/\\u{6666}\\xc2\\xa1/})) }
+
+ assert_raise(SyntaxError) { eval(a(%{/\xc2\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\xc2\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\xc2\xa1#{ }\\u{6666}/})) }
+ assert_nothing_raised { eval(u(%{/\xc2\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(a(%{/\\u{6666}#{ }\xc2\xa1/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\u{6666}#{ }\xc2\xa1/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\u{6666}#{ }\xc2\xa1/})) }
+ assert_nothing_raised { eval(u(%{/\\u{6666}#{ }\xc2\xa1/})) }
+
+ assert_raise(SyntaxError) { eval(a(%{/\\xc2\\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\xc2\\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\xc2\\xa1#{ }\\u{6666}/})) }
+ assert_nothing_raised { eval(u(%{/\\xc2\\xa1#{ }\\u{6666}/})) }
+ assert_raise(SyntaxError) { eval(a(%{/\\u{6666}#{ }\\xc2\\xa1/})) }
+ assert_raise(SyntaxError) { eval(e(%{/\\u{6666}#{ }\\xc2\\xa1/})) }
+ assert_raise(SyntaxError) { eval(s(%{/\\u{6666}#{ }\\xc2\\xa1/})) }
+ assert_nothing_raised { eval(u(%{/\\u{6666}#{ }\\xc2\\xa1/})) }
+ end
+
+ def test_str_allocate
+ s = String.allocate
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+ end
+
+ def test_str_String
+ s = String(10)
+ assert_equal(Encoding::US_ASCII, s.encoding)
+ end
+
+ def test_sprintf_c
+ assert_strenc("\x80", 'ASCII-8BIT', a("%c") % 128)
+ #assert_raise(ArgumentError) { a("%c") % 0xc2a1 }
+ assert_strenc("\xc2\xa1", 'EUC-JP', e("%c") % 0xc2a1)
+ assert_raise(ArgumentError) { e("%c") % 0xc2 }
+ assert_strenc("\xc2", 'Windows-31J', s("%c") % 0xc2)
+ #assert_raise(ArgumentError) { s("%c") % 0xc2a1 }
+ assert_strenc("\u{c2a1}", 'UTF-8', u("%c") % 0xc2a1)
+ assert_strenc("\u{c2}", 'UTF-8', u("%c") % 0xc2)
+ assert_raise(Encoding::CompatibilityError) {
+ "%s%s" % [s("\xc2\xa1"), e("\xc2\xa1")]
+ }
+ end
+
+ def test_sprintf_p
+ Encoding.list.each do |e|
+ format = "%p".force_encoding(e)
+ ['', 'a', "\xC2\xA1", "\x00"].each do |s|
+ s.force_encoding(e)
+ enc = (''.force_encoding(e) + s.inspect).encoding
+ assert_strenc(s.inspect, enc, format % s)
+ end
+ s = "\xC2\xA1".force_encoding(e)
+ enc = ('' + s.inspect).encoding
+ assert_strenc('%10s' % s.inspect, enc, "%10p" % s)
+ end
+ end
+
+ def test_sprintf_s
+ assert_strenc('', 'ASCII-8BIT', a("%s") % a(""))
+ assert_strenc('', 'EUC-JP', e("%s") % e(""))
+ assert_strenc('', 'Windows-31J', s("%s") % s(""))
+ assert_strenc('', 'UTF-8', u("%s") % u(""))
+
+ assert_strenc('a', 'ASCII-8BIT', a("%s") % a("a"))
+ assert_strenc('a', 'EUC-JP', e("%s") % e("a"))
+ assert_strenc('a', 'Windows-31J', s("%s") % s("a"))
+ assert_strenc('a', 'UTF-8', u("%s") % u("a"))
+
+ assert_strenc("\xC2\xA1", 'ASCII-8BIT', a("%s") % a("\xc2\xa1"))
+ assert_strenc("\xC2\xA1", 'EUC-JP', e("%s") % e("\xc2\xa1"))
+ #assert_strenc("\xC2\xA1", 'Windows-31J', s("%s") % s("\xc2\xa1"))
+ assert_strenc("\xC2\xA1", 'UTF-8', u("%s") % u("\xc2\xa1"))
+
+ assert_strenc(" \xC2\xA1", 'ASCII-8BIT', "%10s" % a("\xc2\xa1"))
+ assert_strenc(" \xA1\xA1", 'EUC-JP', "%10s" % e("\xa1\xa1"))
+ #assert_strenc(" \xC2\xA1", 'Windows-31J', "%10s" % s("\xc2\xa1"))
+ assert_strenc(" \xC2\xA1", 'UTF-8', "%10s" % u("\xc2\xa1"))
+
+ assert_strenc("\x00", 'ASCII-8BIT', a("%s") % a("\x00"))
+ assert_strenc("\x00", 'EUC-JP', e("%s") % e("\x00"))
+ assert_strenc("\x00", 'Windows-31J', s("%s") % s("\x00"))
+ assert_strenc("\x00", 'UTF-8', u("%s") % u("\x00"))
+ assert_equal("EUC-JP", (e("\xc2\xa1 %s") % "foo").encoding.name)
+ end
+
+ def test_str_lt
+ assert_operator(a("a"), :<, a("\xa1"))
+ assert_operator(a("a"), :<, s("\xa1"))
+ assert_operator(s("a"), :<, a("\xa1"))
+ end
+
+ def test_str_multiply
+ str = "\u3042"
+ assert_equal(true, (str * 0).ascii_only?, "[ruby-dev:33895]")
+ assert_equal(false, (str * 1).ascii_only?)
+ assert_equal(false, (str * 2).ascii_only?)
+ end
+
+ def test_str_aref
+ assert_equal(a("\xc2"), a("\xc2\xa1")[0])
+ assert_equal(a("\xa1"), a("\xc2\xa1")[1])
+ assert_equal(nil, a("\xc2\xa1")[2])
+ assert_equal(e("\xc2\xa1"), e("\xc2\xa1")[0])
+ assert_equal(nil, e("\xc2\xa1")[1])
+ assert_equal(s("\xc2"), s("\xc2\xa1")[0])
+ assert_equal(s("\xa1"), s("\xc2\xa1")[1])
+ assert_equal(nil, s("\xc2\xa1")[2])
+ assert_equal(u("\xc2\xa1"), u("\xc2\xa1")[0])
+ assert_equal(nil, u("\xc2\xa1")[1])
+
+ str = "\u3042"
+ assert_equal(true, str[0, 0].ascii_only?, "[ruby-dev:33895]")
+ assert_equal(false, str[0, 1].ascii_only?)
+ assert_equal(false, str[0..-1].ascii_only?)
+ end
+
+ def test_utf8str_aref
+ s = "abcdefghijklmnopqrstuvwxyz\u{3042 3044 3046 3048 304A}"
+ assert_equal("a", s[0])
+ assert_equal("h", s[7])
+ assert_equal("i", s[8])
+ assert_equal("j", s[9])
+ assert_equal("\u{3044}", s[27])
+ assert_equal("\u{3046}", s[28])
+ assert_equal("\u{3048}", s[29])
+ s = "abcdefghijklmnopqrstuvw\u{3042 3044 3046 3048 304A}"
+ assert_equal("\u{3044}", s[24])
+ end
+
+ def test_str_aref_len
+ assert_equal(a("\xa1"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1])
+ assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2])
+
+ assert_equal(e("\xc2\xa2"), e("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1])
+ assert_equal(e("\xc2\xa2\xc2\xa3"), e("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2])
+
+ assert_equal(s("\xa1"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1])
+ assert_equal(s("\xa1\xc2"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2])
+
+ assert_equal(u("\xc2\xa2"), u("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1])
+ assert_equal(u("\xc2\xa2\xc2\xa3"), u("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2])
+ end
+
+ def test_str_aref_substr
+ assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")])
+ assert_raise(Encoding::CompatibilityError) { a("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")] }
+
+ assert_equal(nil, e("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")])
+ assert_raise(Encoding::CompatibilityError) { e("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")] }
+
+ assert_equal(s("\xa1\xc2"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")])
+ assert_raise(Encoding::CompatibilityError) { s("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")] }
+
+ assert_equal(nil, u("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")])
+ assert_raise(Encoding::CompatibilityError) { u("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")] }
+ assert_nil(e("\xa1\xa2\xa3\xa4")[e("\xa2\xa3")])
+
+ bug2379 = '[ruby-core:26787]'
+ assert_equal("\u{439}", "\u{439}"[0, 30], bug2379)
+ assert_equal("\u{439}", "a\u{439}"[1, 30], bug2379)
+ assert_equal("\u{439}", "a\u{439}bcdefghijklmnop"[1, 1][0, 1], bug2379)
+ end
+
+ def test_str_aref_force_encoding
+ bug5836 = '[ruby-core:41896]'
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ s = "abc".force_encoding(enc)
+ assert_equal("", s[3, 1], bug5836)
+ end
+ end
+
+ def test_aset
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s["\xb0\xa3"] = "foo"}
+
+ a = ua("a")
+ a[/a/] = u("")
+ assert_equal Encoding::US_ASCII, a.encoding
+ end
+
+ def test_str_center
+ assert_encoding("EUC-JP", "a".center(5, e("\xa1\xa2")).encoding)
+ assert_encoding("EUC-JP", e("\xa3\xb0").center(10).encoding)
+ end
+
+ def test_squeeze
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb1\xa3\xb3\xa3\xb4")
+ assert_equal(e("\xa3\xb0\xa3\xb1\xa3\xb3\xa3\xb4"), s.squeeze)
+ end
+
+ def test_tr
+ s = s("\x81\x41")
+ assert_equal(s.tr("A", "B"), s)
+ assert_equal(s.tr_s("A", "B"), s)
+
+ assert_nothing_raised {
+ "a".force_encoding("ASCII-8BIT").tr(a("a"), a("a"))
+ }
+
+ assert_equal(e("\xA1\xA1"), a("a").tr(a("a"), e("\xA1\xA1")))
+
+ assert_equal("X\u3042\u3044X", "A\u3042\u3044\u3046".tr("^\u3042\u3044", "X"))
+ assert_equal("\u3042\u3046" * 100, ("\u3042\u3044" * 100).tr("\u3044", "\u3046"))
+ assert_equal("Y", "\u3042".tr("^X", "Y"))
+ end
+
+ def test_tr_s
+ assert_equal("\xA1\xA1".force_encoding("EUC-JP"),
+ "a".force_encoding("ASCII-8BIT").tr("a".force_encoding("ASCII-8BIT"), "\xA1\xA1".force_encoding("EUC-JP")))
+ end
+
+ def test_count
+ assert_equal(0, e("\xa1\xa2").count("z"))
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s.count(a("\xa3\xb0"))}
+ end
+
+ def test_count_sjis_trailing_byte
+ bug10078 = '[ruby-dev:48442] [Bug #10078]'
+ assert_equal(0, s("\x98\x61").count("a"), bug10078)
+ end
+
+ def test_delete
+ assert_equal(1, e("\xa1\xa2").delete("z").length)
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s.delete(a("\xa3\xb2"))}
+
+ a = "\u3042\u3044\u3046\u3042\u3044\u3046"
+ a.delete!("\u3042\u3044", "^\u3044")
+ assert_equal("\u3044\u3046\u3044\u3046", a)
+ end
+
+ def test_include?
+ assert_equal(false, e("\xa1\xa2\xa3\xa4").include?(e("\xa3")))
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_equal(false, s.include?(e("\xb0\xa3")))
+ end
+
+ def test_index
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_nil(s.index(e("\xb3\xa3")))
+ assert_nil(e("\xa1\xa2\xa3\xa4").index(e("\xa3")))
+ assert_nil(e("\xa1\xa2\xa3\xa4").rindex(e("\xa3")))
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s.rindex(a("\xb1\xa3"))}
+ end
+
+ def test_next
+ s1 = e("\xa1\xa1")
+ s2 = s1.dup
+ (94*94+94).times { s2.next! }
+ assert_not_equal(s1, s2)
+ end
+
+ def test_sub
+ s = "abc".sub(/b/, "\xa1\xa1".force_encoding("euc-jp"))
+ assert_encoding("EUC-JP", s.encoding)
+ assert_equal(Encoding::EUC_JP, "\xa4\xa2".force_encoding("euc-jp").sub(/./, '\&').encoding)
+ assert_equal(Encoding::EUC_JP, "\xa4\xa2".force_encoding("euc-jp").gsub(/./, '\&').encoding)
+ end
+
+ def test_sub2
+ s = "\x80".force_encoding("ASCII-8BIT")
+ r = Regexp.new("\x80".force_encoding("ASCII-8BIT"))
+ s2 = s.sub(r, "")
+ assert_empty(s2)
+ assert_predicate(s2, :ascii_only?)
+ end
+
+ def test_sub3
+ repl = "\x81".force_encoding("sjis")
+ assert_equal(false, repl.valid_encoding?)
+ s = "a@".sub(/a/, repl)
+ assert_predicate(s, :valid_encoding?)
+ end
+
+ def test_insert
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_equal(e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4a"), s.insert(-1, "a"))
+ end
+
+ def test_scan
+ assert_equal(["a"], e("\xa1\xa2a\xa3\xa4").scan(/a/))
+ end
+
+ def test_dup_scan
+ s1 = e("\xa4\xa2")*100
+ s2 = s1.dup.force_encoding("ascii-8bit")
+ s2.scan(/\A./n) {|f|
+ assert_equal(Encoding::ASCII_8BIT, f.encoding)
+ }
+ end
+
+ def test_dup_aref
+ s1 = e("\xa4\xa2")*100
+ s2 = s1.dup.force_encoding("ascii-8bit")
+ assert_equal(Encoding::ASCII_8BIT, s2[10..-1].encoding)
+ end
+
+ def test_upto
+ s1 = e("\xa1\xa2")
+ s2 = s("\xa1\xa2")
+ assert_raise(Encoding::CompatibilityError){s1.upto(s2) {|x| break }}
+ end
+
+ def test_casecmp
+ s1 = s("\x81\x41")
+ s2 = s("\x81\x61")
+ assert_not_equal(0, s1.casecmp(s2))
+ end
+
+ def test_reverse
+ bug11387 = '[ruby-dev:49189] [Bug #11387]'
+ s1 = u("abcdefghij\xf0")
+ s2 = s1.reverse
+ assert_not_predicate(s1, :valid_encoding?, bug11387)
+ assert_equal(u("\xf0jihgfedcba"), s2)
+ assert_not_predicate(s2, :valid_encoding?, bug11387)
+ end
+
+ def test_reverse_bang
+ s = u("abcdefghij\xf0")
+ s.reverse!
+ assert_equal(u("\xf0jihgfedcba"), s)
+ end
+
+ def test_plus
+ assert_raise(Encoding::CompatibilityError){u("\xe3\x81\x82") + a("\xa1")}
+ end
+
+ def test_chomp
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s.chomp(s("\xa3\xb4"))}
+ end
+
+ def test_gsub
+ s = 'abc'
+ s.ascii_only?
+ s.gsub!(/b/, "\x80")
+ assert_equal(false, s.ascii_only?, "[ruby-core:14566] reported by Sam Ruby")
+
+ s = "abc".force_encoding(Encoding::ASCII_8BIT)
+ assert_equal(Encoding::ASCII_8BIT, s.encoding)
+
+ assert_raise(Encoding::CompatibilityError) {
+ "abc".gsub(/[ac]/) {
+ $& == "a" ? "\xc2\xa1".force_encoding("euc-jp") :
+ "\xc2\xa1".force_encoding("utf-8")
+ }
+ }
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_equal(e("\xa3\xb0z\xa3\xb2\xa3\xb3\xa3\xb4"), s.gsub(/\xa3\xb1/e, "z"))
+
+ assert_equal(Encoding::ASCII_8BIT, (a("").gsub(//) { e("") }.encoding))
+ assert_equal(Encoding::ASCII_8BIT, (a("a").gsub(/a/) { e("") }.encoding))
+ end
+
+ def test_end_with
+ s1 = s("\x81\x40")
+ s2 = "@"
+ assert_equal(false, s1.end_with?(s2), "#{encdump s1}.end_with?(#{encdump s2})")
+ each_encoding("\u3042\u3044", "\u3044") do |_s1, _s2|
+ assert_equal(true, _s1.end_with?(_s2), "#{encdump _s1}.end_with?(#{encdump _s2})")
+ end
+ each_encoding("\u3042a\u3044", "a\u3044") do |_s1, _s2|
+ assert_equal(true, _s1.end_with?(_s2), "#{encdump _s1}.end_with?(#{encdump _s2})")
+ end
+ end
+
+ def test_each_line
+ s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
+ assert_raise(Encoding::CompatibilityError){s.each_line(a("\xa3\xb1")) {|l| }}
+ s = e("\xa4\xa2\nfoo")
+
+ actual = []
+ s.each_line {|line| actual << line }
+ expected = [e("\xa4\xa2\n"), e("foo")]
+ assert_equal(expected, actual)
+ end
+
+ def test_each_char
+ a = [e("\xa4\xa2"), "b", e("\xa4\xa4"), "c"]
+ s = "\xa4\xa2b\xa4\xa4c".force_encoding("euc-jp")
+ assert_equal(a, s.each_char.to_a, "[ruby-dev:33211] #{encdump s}.each_char.to_a")
+ end
+
+ def test_str_concat
+ assert_equal(1, "".concat(0xA2).size)
+ assert_equal(Encoding::ASCII_8BIT, "".force_encoding("US-ASCII").concat(0xA2).encoding)
+ assert_equal("A\x84\x31\xA4\x39".force_encoding("GB18030"),
+ "A".force_encoding("GB18030") << 0x8431A439)
+ end
+
+ def test_regexp_match
+ assert_equal([0,0], //.match("\xa1\xa1".force_encoding("euc-jp"),-1).offset(0))
+ assert_equal(0, // =~ :a)
+ end
+
+ def test_split
+ assert_equal(e("\xa1\xa2\xa1\xa3").split(//),
+ [e("\xa1\xa2"), e("\xa1\xa3")],
+ '[ruby-dev:32452]')
+
+ each_encoding("abc,def", ",", "abc", "def") do |str, sep, *expected|
+ assert_equal(expected, str.split(sep, -1))
+ end
+ each_encoding("abc\0def", "\0", "abc", "def") do |str, sep, *expected|
+ assert_equal(expected, str.split(sep, -1))
+ end
+ end
+
+ def test_nonascii_method_name
+ eval(e("def \xc2\xa1() @nonascii_method_name = :e end"))
+ eval(u("def \xc2\xa1() @nonascii_method_name = :u end"))
+ eval(e("\xc2\xa1()"))
+ assert_equal(:e, @nonascii_method_name)
+ eval(u("\xc2\xa1()"))
+ assert_equal(:u, @nonascii_method_name)
+ me = method(e("\xc2\xa1"))
+ mu = method(u("\xc2\xa1"))
+ assert_not_equal(me.name, mu.name)
+ assert_not_equal(me.inspect, mu.inspect)
+ assert_equal(e("\xc2\xa1"), me.name.to_s)
+ assert_equal(u("\xc2\xa1"), mu.name.to_s)
+ end
+
+ def test_symbol
+ s1 = "\xc2\xa1".force_encoding("euc-jp").intern
+ s2 = "\xc2\xa1".force_encoding("utf-8").intern
+ assert_not_equal(s1, s2)
+ end
+
+ def test_symbol_op
+ ops = %w"
+ .. ... + - * / % ** +@ -@ | ^ & ! <=> > >= < <= ==
+ === != =~ !~ ~ ! [] []= << >> :: `
+ "
+ ops.each do |op|
+ assert_equal(Encoding::US_ASCII, op.intern.encoding, "[ruby-dev:33449]")
+ end
+ end
+
+ def test_chr
+ 0.upto(255) {|b|
+ assert_equal([b].pack("C"), b.chr)
+ }
+ assert_equal("\x84\x31\xA4\x39".force_encoding("GB18030"), 0x8431A439.chr("GB18030"))
+ e = assert_raise(RangeError) {
+ 2206368128.chr(Encoding::UTF_8)
+ }
+ assert_not_match(/-\d+ out of char range/, e.message)
+
+ assert_raise(RangeError){ 0x80.chr("US-ASCII") }
+ assert_raise(RangeError){ 0x80.chr("SHIFT_JIS") }
+ assert_raise(RangeError){ 0xE0.chr("SHIFT_JIS") }
+ assert_raise(RangeError){ 0x100.chr("SHIFT_JIS") }
+ assert_raise(RangeError){ 0xA0.chr("EUC-JP") }
+ assert_raise(RangeError){ 0x100.chr("EUC-JP") }
+ assert_raise(RangeError){ 0xA1A0.chr("EUC-JP") }
+ end
+
+ def test_marshal
+ s1 = "\xa1\xa1".force_encoding("euc-jp")
+ s2 = Marshal.load(Marshal.dump(s1))
+ assert_equal(s1, s2)
+ end
+
+ def test_env
+ locale_encoding = Encoding.find("locale")
+ ENV.each {|k, v|
+ assert_equal(locale_encoding, k.encoding, k)
+ assert_equal(locale_encoding, v.encoding, v)
+ }
+ end
+
+ def test_empty_string
+ assert_equal(Encoding::US_ASCII, "".encoding)
+ end
+
+ def test_nil_to_s
+ assert_equal(Encoding::US_ASCII, nil.to_s.encoding)
+ end
+
+ def test_nil_inspect
+ assert_equal(Encoding::US_ASCII, nil.inspect.encoding)
+ end
+
+ def test_true_to_s
+ assert_equal(Encoding::US_ASCII, true.to_s.encoding)
+ end
+
+ def test_false_to_s
+ assert_equal(Encoding::US_ASCII, false.to_s.encoding)
+ end
+
+ def test_fixnum_to_s
+ assert_equal(Encoding::US_ASCII, 1.to_s.encoding)
+ end
+
+ def test_float_to_s
+ assert_equal(Encoding::US_ASCII, 1.0.to_s.encoding)
+ end
+
+ def test_bignum_to_s
+ assert_equal(Encoding::US_ASCII, (1 << 129).to_s.encoding)
+ end
+
+ def test_array_to_s
+ assert_equal(Encoding::US_ASCII, [].to_s.encoding)
+ assert_equal(Encoding::US_ASCII, [nil].to_s.encoding)
+ assert_equal(Encoding::US_ASCII, [1].to_s.encoding)
+ assert_equal("".inspect.encoding, [""].to_s.encoding)
+ assert_equal("a".inspect.encoding, ["a"].to_s.encoding)
+ assert_equal(Encoding::US_ASCII, [nil,1,"","a","\x20",[]].to_s.encoding)
+ end
+
+ def test_hash_to_s
+ assert_equal(Encoding::US_ASCII, {}.to_s.encoding)
+ assert_equal(Encoding::US_ASCII, {1=>nil,"foo"=>""}.to_s.encoding)
+ end
+
+ def test_encoding_find
+ assert_raise(TypeError) {Encoding.find(nil)}
+ assert_raise(TypeError) {Encoding.find(0)}
+ assert_raise(TypeError) {Encoding.find([])}
+ assert_raise(TypeError) {Encoding.find({})}
+ end
+
+ def test_encoding_to_s
+ assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.to_s.encoding)
+ assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.inspect.encoding)
+ end
+
+ def test_regexp_source
+ s = "\xa4\xa2".force_encoding("euc-jp")
+ r = Regexp.new(s)
+ t = r.source
+ assert_equal(s, t, "[ruby-dev:33377] Regexp.new(#{encdump s}).source")
+ end
+
+ def test_magic_comment
+ assert_equal(Encoding::US_ASCII, eval("__ENCODING__".force_encoding("US-ASCII")))
+ assert_equal(Encoding::ASCII_8BIT, eval("__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::US_ASCII, eval("# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::ASCII_8BIT, eval("# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII")))
+ end
+
+ def test_magic_comment_vim
+ assert_equal(Encoding::US_ASCII, eval("# vim: filetype=ruby, fileencoding: US-ASCII, ts=3, sw=3\n__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::ASCII_8BIT, eval("# vim: filetype=ruby, fileencoding: ASCII-8BIT, ts=3, sw=3\n__ENCODING__".force_encoding("US-ASCII")))
+ end
+
+ def test_magic_comment_at_various_positions
+ # after shebang
+ assert_equal(Encoding::US_ASCII, eval("#!/usr/bin/ruby\n# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::ASCII_8BIT, eval("#!/usr/bin/ruby\n# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII")))
+ # wrong position
+ assert_equal(Encoding::ASCII_8BIT, eval("\n# -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::US_ASCII, eval("\n# -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII")))
+
+ # leading expressions
+ assert_equal(Encoding::ASCII_8BIT, eval("v=1 # -*- encoding: US-ASCII -*-\n__ENCODING__".force_encoding("ASCII-8BIT")))
+ assert_equal(Encoding::US_ASCII, eval("v=1 # -*- encoding: ASCII-8BIT -*-\n__ENCODING__".force_encoding("US-ASCII")))
+ end
+
+ def test_regexp_usascii
+ assert_regexp_usascii_literal('//', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/#{ }/', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/#{"a"}/', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/#{%q"\x80"}/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/#{"\x80"}/', nil, SyntaxError)
+
+ assert_regexp_usascii_literal('/a/', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/a#{ }/', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/a#{"a"}/', Encoding::US_ASCII)
+ assert_regexp_usascii_literal('/a#{%q"\x80"}/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/a#{"\x80"}/', nil, SyntaxError)
+
+ assert_regexp_usascii_literal('/\x80/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/\x80#{ }/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/\x80#{"a"}/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/\x80#{%q"\x80"}/', Encoding::ASCII_8BIT)
+ assert_regexp_usascii_literal('/\x80#{"\x80"}/', nil, SyntaxError)
+
+ assert_regexp_usascii_literal('/\u1234/', Encoding::UTF_8)
+ assert_regexp_usascii_literal('/\u1234#{ }/', Encoding::UTF_8)
+ assert_regexp_usascii_literal('/\u1234#{"a"}/', Encoding::UTF_8)
+ assert_regexp_usascii_literal('/\u1234#{%q"\x80"}/', nil, SyntaxError)
+ assert_regexp_usascii_literal('/\u1234#{"\x80"}/', nil, SyntaxError)
+ assert_regexp_usascii_literal('/\u1234\x80/', nil, SyntaxError)
+ assert_regexp_usascii_literal('/\u1234#{ }\x80/', nil, RegexpError)
+ end
+
+ def test_gbk
+ assert_equal("", "\x81\x40".force_encoding("GBK").chop)
+ end
+
+ def test_euc_tw
+ assert_equal("a", "a\x8e\xa2\xa1\xa1".force_encoding("euc-tw").chop)
+ end
+
+ def test_valid_encoding
+ s = "\xa1".force_encoding("euc-jp")
+ assert_equal(false, s.valid_encoding?)
+ assert_equal(true, (s+s).valid_encoding?, "[ruby-dev:33826]")
+ assert_equal(true, (s*2).valid_encoding?, "[ruby-dev:33826]")
+ assert_equal(true, ("%s%s" % [s, s]).valid_encoding?)
+ assert_equal(true, (s.dup << s).valid_encoding?)
+ assert_equal(true, "".center(2, s).valid_encoding?)
+
+ s = "\xa1\xa1\x8f".force_encoding("euc-jp")
+ assert_equal(false, s.valid_encoding?)
+ assert_equal(true, s.reverse.valid_encoding?)
+
+ bug4018 = '[ruby-core:33027]'
+ s = "\xa1\xa1".force_encoding("euc-jp")
+ assert_equal(true, s.valid_encoding?)
+ s << "\x8f".force_encoding("euc-jp")
+ assert_equal(false, s.valid_encoding?, bug4018)
+ s = "aa".force_encoding("utf-16be")
+ assert_equal(true, s.valid_encoding?)
+ s << "\xff".force_encoding("utf-16be")
+ assert_equal(false, s.valid_encoding?, bug4018)
+
+ bug6190 = '[ruby-core:43557]'
+ s = "\xe9"
+ s = s.encode("utf-8", "utf-8")
+ assert_equal(false, s.valid_encoding?, bug6190)
+ s = "\xe9"
+ s.encode!("utf-8", "utf-8")
+ assert_equal(false, s.valid_encoding?, bug6190)
+ end
+
+ def test_getbyte
+ assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(2))
+ assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(-4))
+ assert_nil(u("\xE3\x81\x82\xE3\x81\x84").getbyte(100))
+ end
+
+ def test_setbyte
+ s = u("\xE3\x81\x82\xE3\x81\x84")
+ s.setbyte(2, 0x84)
+ assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s)
+
+ s = u("\xE3\x81\x82\xE3\x81\x84")
+ assert_raise(IndexError) { s.setbyte(100, 0) }
+
+ s = u("\xE3\x81\x82\xE3\x81\x84")
+ s.setbyte(-4, 0x84)
+ assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s)
+ end
+
+ def test_compatible
+ assert_nil Encoding.compatible?("",0)
+ assert_equal(Encoding::UTF_8, Encoding.compatible?(u(""), ua("abc")))
+ assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::UTF_8))
+ assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::US_ASCII))
+ assert_equal(Encoding::ASCII_8BIT,
+ Encoding.compatible?(Encoding::ASCII_8BIT, Encoding::US_ASCII))
+ assert_nil Encoding.compatible?(Encoding::UTF_8, Encoding::ASCII_8BIT)
+ end
+
+ def test_force_encoding
+ assert_equal(u("\x80"), "".center(1, u("\x80")),
+ "moved from btest/knownbug, [ruby-dev:33807]")
+ a = "".force_encoding("ascii-8bit") << 0xC3 << 0xB6
+ assert_equal(1, a.force_encoding("utf-8").size, '[ruby-core:22437]')
+ b = "".force_encoding("ascii-8bit") << 0xC3.chr << 0xB6.chr
+ assert_equal(1, b.force_encoding("utf-8").size, '[ruby-core:22437]')
+
+ assert_raise(TypeError){ ''.force_encoding(nil) }
+ end
+
+ def test_combchar_codepoint
+ assert_equal([0x30BB, 0x309A], "\u30BB\u309A".codepoints.to_a)
+ assert_equal([0x30BB, 0x309A], "\u30BB\u309A".codepoints.to_a)
+ end
+
+ def each_encoding(*strings)
+ Encoding.list.each do |enc|
+ next if enc.dummy?
+ strs = strings.map {|s| s.encode(enc)} rescue next
+ yield(*strs)
+ end
+ end
+
+ def test_str_b
+ s = "\u3042"
+ assert_equal(a("\xE3\x81\x82"), s.b)
+ assert_equal(Encoding::ASCII_8BIT, s.b.encoding)
+ s.taint
+ assert_equal(true, s.b.tainted?)
+ s = "abc".b
+ assert_equal(true, s.b.ascii_only?)
+ end
+
+ def test_scrub
+ str = "\u3042\u3044"
+ assert_not_same(str, str.scrub)
+ str.force_encoding(Encoding::ISO_2022_JP) # dummy encoding
+ assert_not_same(str, str.scrub)
+ assert_nothing_raised(ArgumentError) {str.scrub(nil)}
+
+ assert_equal("\uFFFD\uFFFD\uFFFD", u("\x80\x80\x80").scrub)
+ assert_equal("\uFFFDA", u("\xF4\x80\x80A").scrub)
+
+ # examples in Unicode 6.1.0 D93b
+ assert_equal("\x41\uFFFD\uFFFD\x41\uFFFD\x41",
+ u("\x41\xC0\xAF\x41\xF4\x80\x80\x41").scrub)
+ assert_equal("\x41\uFFFD\uFFFD\uFFFD\x41",
+ u("\x41\xE0\x9F\x80\x41").scrub)
+ assert_equal("\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064",
+ u("\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64").scrub)
+ assert_equal("abcdefghijklmnopqrstuvwxyz\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064",
+ u("abcdefghijklmnopqrstuvwxyz\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64").scrub)
+
+ assert_equal("\u3042\u3013", u("\xE3\x81\x82\xE3\x81").scrub("\u3013"))
+ assert_raise(Encoding::CompatibilityError){ u("\xE3\x81\x82\xE3\x81").scrub(e("\xA4\xA2")) }
+ assert_raise(TypeError){ u("\xE3\x81\x82\xE3\x81").scrub(1) }
+ assert_raise(ArgumentError){ u("\xE3\x81\x82\xE3\x81\x82\xE3\x81").scrub(u("\x81")) }
+ assert_equal(e("\xA4\xA2\xA2\xAE"), e("\xA4\xA2\xA4").scrub(e("\xA2\xAE")))
+
+ assert_equal("\u3042<e381>", u("\xE3\x81\x82\xE3\x81").scrub{|x|'<'+x.unpack('H*')[0]+'>'})
+ assert_raise(Encoding::CompatibilityError){ u("\xE3\x81\x82\xE3\x81").scrub{e("\xA4\xA2")} }
+ assert_raise(TypeError){ u("\xE3\x81\x82\xE3\x81").scrub{1} }
+ assert_raise(ArgumentError){ u("\xE3\x81\x82\xE3\x81\x82\xE3\x81").scrub{u("\x81")} }
+ assert_equal(e("\xA4\xA2\xA2\xAE"), e("\xA4\xA2\xA4").scrub{e("\xA2\xAE")})
+
+ assert_equal(u("\x81"), u("a\x81").scrub {|c| break c})
+ assert_raise(ArgumentError) {u("a\x81").scrub {|c| c}}
+
+ assert_equal("\uFFFD\u3042".encode("UTF-16BE"),
+ "\xD8\x00\x30\x42".force_encoding(Encoding::UTF_16BE).
+ scrub)
+ assert_equal("\uFFFD\u3042".encode("UTF-16LE"),
+ "\x00\xD8\x42\x30".force_encoding(Encoding::UTF_16LE).
+ scrub)
+ assert_equal("\uFFFD".encode("UTF-32BE"),
+ "\xff".force_encoding(Encoding::UTF_32BE).
+ scrub)
+ assert_equal("\uFFFD".encode("UTF-32LE"),
+ "\xff".force_encoding(Encoding::UTF_32LE).
+ scrub)
+ end
+
+ def test_scrub_bang
+ str = "\u3042\u3044"
+ assert_same(str, str.scrub!)
+ str.force_encoding(Encoding::ISO_2022_JP) # dummy encoding
+ assert_same(str, str.scrub!)
+ assert_nothing_raised(ArgumentError) {str.scrub!(nil)}
+
+ str = u("\x80\x80\x80")
+ str.scrub!
+ assert_same(str, str.scrub!)
+ assert_equal("\uFFFD\uFFFD\uFFFD", str)
+ end
+
+ def test_escaped_metachar
+ bug10670 = '[ruby-core:67193] [Bug #10670]'
+
+ escape_plain = /\A[\x5B]*\z/.freeze
+
+ assert_match(escape_plain, 0x5b.chr(::Encoding::UTF_8), bug10670)
+ assert_match(escape_plain, 0x5b.chr, bug10670)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_m17n_comb.rb b/jni/ruby/test/ruby/test_m17n_comb.rb
new file mode 100644
index 0000000..3a37ed4
--- /dev/null
+++ b/jni/ruby/test/ruby/test_m17n_comb.rb
@@ -0,0 +1,1638 @@
+require 'test/unit'
+require 'etc'
+require_relative 'allpairs'
+
+class TestM17NComb < Test::Unit::TestCase
+ def assert_encoding(encname, actual, message=nil)
+ assert_equal(Encoding.find(encname), actual, message)
+ end
+
+ module AESU
+ def a(str) str.dup.force_encoding(Encoding::US_ASCII) end
+ def b(str) str.b end
+ def e(str) str.dup.force_encoding(Encoding::EUC_JP) end
+ def s(str) str.dup.force_encoding(Encoding::SJIS) end
+ def u(str) str.dup.force_encoding(Encoding::UTF_8) end
+ end
+ include AESU
+ extend AESU
+
+ def assert_strenc(bytes, enc, actual, message=nil)
+ assert_instance_of(String, actual, message)
+ enc = Encoding.find(enc) if String === enc
+ assert_equal(enc, actual.encoding, message)
+ assert_equal(b(bytes), b(actual), message)
+ end
+
+ STRINGS = [
+ b(""), e(""), s(""), u(""),
+ b("a"), e("a"), s("a"), u("a"),
+ b("."), e("."), s("."), u("."),
+
+ # single character
+ b("\x80"), b("\xff"),
+ e("\xa1\xa1"), e("\xfe\xfe"),
+ e("\x8e\xa1"), e("\x8e\xfe"),
+ e("\x8f\xa1\xa1"), e("\x8f\xfe\xfe"),
+ s("\x81\x40"), s("\xfc\xfc"),
+ s("\xa1"), s("\xdf"),
+ u("\xc2\x80"), u("\xf4\x8f\xbf\xbf"),
+
+ # same byte sequence
+ b("\xc2\xa1"), e("\xc2\xa1"), s("\xc2\xa1"), u("\xc2\xa1"),
+
+ s("\x81A"), # mutibyte character which contains "A"
+ s("\x81a"), # mutibyte character which contains "a"
+
+ # invalid
+ e("\xa1"), e("\x80"),
+ s("\x81"), s("\x80"),
+ u("\xc2"), u("\x80"),
+
+ # for transitivity test
+ u("\xe0\xa0\xa1"), e("\xe0\xa0\xa1"), s("\xe0\xa0\xa1"), # [ruby-dev:32693]
+ e("\xa1\xa1"), b("\xa1\xa1"), s("\xa1\xa1"), # [ruby-dev:36484]
+ ]
+
+ WSTRINGS = [
+ "aa".force_encoding("utf-16be"),
+ "aaaa".force_encoding("utf-32be"),
+ "aaa".force_encoding("utf-32be"),
+ ]
+
+ def combination(*args, &b)
+ AllPairs.each(*args, &b)
+ #AllPairs.exhaustive_each(*args, &b)
+ end
+
+ def encdump(str)
+ d = str.dump
+ if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d
+ d
+ else
+ "#{d}.force_encoding(#{str.encoding.name.dump})"
+ end
+ end
+
+ def encdumpargs(args)
+ r = '('
+ args.each_with_index {|a, i|
+ r << ',' if 0 < i
+ if String === a
+ r << encdump(a)
+ else
+ r << a.inspect
+ end
+ }
+ r << ')'
+ r
+ end
+
+ def encdumpcall(recv, meth, *args, &block)
+ desc = ''
+ if String === recv
+ desc << encdump(recv)
+ else
+ desc << recv.inspect
+ end
+ desc << '.' << meth.to_s
+ if !args.empty?
+ desc << '('
+ args.each_with_index {|a, i|
+ desc << ',' if 0 < i
+ if String === a
+ desc << encdump(a)
+ else
+ desc << a.inspect
+ end
+ }
+ desc << ')'
+ end
+ if block
+ desc << ' {}'
+ end
+ desc
+ end
+
+ def assert_enccall(recv, meth, *args, &block)
+ desc = encdumpcall(recv, meth, *args, &block)
+ result = nil
+ assert_nothing_raised(desc) {
+ result = recv.send(meth, *args, &block)
+ }
+ result
+ end
+ alias enccall assert_enccall
+
+ def assert_str_enc_propagation(t, s1, s2)
+ if !s1.ascii_only?
+ assert_equal(s1.encoding, t.encoding)
+ elsif !s2.ascii_only?
+ assert_equal(s2.encoding, t.encoding)
+ else
+ assert_include([s1.encoding, s2.encoding], t.encoding)
+ end
+ end
+
+ def assert_same_result(expected_proc, actual_proc)
+ e = nil
+ begin
+ t = expected_proc.call
+ rescue
+ e = $!
+ end
+ if e
+ assert_raise(e.class) { actual_proc.call }
+ else
+ assert_equal(t, actual_proc.call)
+ end
+ end
+
+ def each_slice_call
+ combination(STRINGS, -2..2) {|s, nth|
+ yield s, nth
+ }
+ combination(STRINGS, -2..2, 0..2) {|s, nth, len|
+ yield s, nth, len
+ }
+ combination(STRINGS, STRINGS) {|s, substr|
+ yield s, substr
+ }
+ combination(STRINGS, -2..2, 0..2) {|s, first, last|
+ yield s, first..last
+ yield s, first...last
+ }
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s2.valid_encoding?
+ next
+ end
+ yield s1, Regexp.new(Regexp.escape(s2))
+ }
+ combination(STRINGS, STRINGS, 0..2) {|s1, s2, nth|
+ if !s2.valid_encoding?
+ next
+ end
+ yield s1, Regexp.new(Regexp.escape(s2)), nth
+ }
+ end
+
+ ASCII_INCOMPATIBLE_ENCODINGS = %w[
+ UTF-16BE
+ UTF-16LE
+ UTF-32BE
+ UTF-32LE
+ ]
+ def str_enc_compatible?(*strs)
+ encs = []
+ ascii_incompatible_encodings = {}
+ has_ascii_compatible = false
+ strs.each {|s|
+ encs << s.encoding if !s.ascii_only?
+ if /\A#{Regexp.union ASCII_INCOMPATIBLE_ENCODINGS}\z/o =~ s.encoding.name
+ ascii_incompatible_encodings[s.encoding] = true
+ else
+ has_ascii_compatible = true
+ end
+ }
+ if ascii_incompatible_encodings.empty?
+ encs.uniq!
+ encs.length <= 1
+ else
+ !has_ascii_compatible && ascii_incompatible_encodings.size == 1
+ end
+ end
+
+ # tests start
+
+ def test_str_new
+ STRINGS.each {|s|
+ t = String.new(s)
+ assert_strenc(b(s), s.encoding, t)
+ }
+ end
+
+ def test_str_plus
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if s1.encoding != s2.encoding && !s1.ascii_only? && !s2.ascii_only?
+ assert_raise(Encoding::CompatibilityError) { s1 + s2 }
+ else
+ t = enccall(s1, :+, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_equal(b(s1) + b(s2), b(t))
+ assert_str_enc_propagation(t, s1, s2)
+ end
+ }
+ end
+
+ def test_str_times
+ STRINGS.each {|s|
+ [0,1,2].each {|n|
+ t = s * n
+ assert_predicate(t, :valid_encoding?) if s.valid_encoding?
+ assert_strenc(b(s) * n, s.encoding, t)
+ }
+ }
+ end
+
+ def test_sprintf_s
+ STRINGS.each {|s|
+ assert_strenc(b(s), s.encoding, "%s".force_encoding(s.encoding) % s)
+ if !s.empty? # xxx
+ t = enccall(b("%s"), :%, s)
+ assert_strenc(b(s), (b('')+s).encoding, t)
+ end
+ }
+ end
+
+ def test_str_eq_reflexive
+ STRINGS.each {|s|
+ assert_equal(s, s, "#{encdump s} == #{encdump s}")
+ }
+ end
+
+ def test_str_eq_symmetric
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if s1 == s2
+ assert_equal(s2, s1, "#{encdump s2} == #{encdump s1}")
+ else
+ assert_not_equal(s2, s1, "!(#{encdump s2} == #{encdump s1})")
+ end
+ }
+ end
+
+ def test_str_eq_transitive
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ if s1 == s2 && s2 == s3
+ assert_equal(s1, s3, "transitive: #{encdump s1} == #{encdump s2} == #{encdump s3}")
+ end
+ }
+ end
+
+ def test_str_eq
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc_eq = "#{encdump s1} == #{encdump s2}"
+ if b(s1) == b(s2) and
+ (s1.ascii_only? && s2.ascii_only? or
+ s1.encoding == s2.encoding) then
+ assert_operator(s1, :==, s2, desc_eq)
+ assert_not_operator(s1, :!=, s2)
+ assert_equal(0, s1 <=> s2)
+ assert_operator(s1, :eql?, s2, desc_eq)
+ else
+ assert_not_operator(s1, :==, s2, "!(#{desc_eq})")
+ assert_operator(s1, :!=, s2)
+ assert_not_equal(0, s1 <=> s2)
+ assert_not_operator(s1, :eql?, s2)
+ end
+ }
+ end
+
+ def test_str_concat
+ combination(STRINGS, STRINGS) {|s1, s2|
+ s = s1.dup
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ s << s2
+ assert_predicate(s, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_equal(b(s), b(s1) + b(s2))
+ assert_str_enc_propagation(s, s1, s2)
+ else
+ assert_raise(Encoding::CompatibilityError) { s << s2 }
+ end
+ }
+ end
+
+ def test_str_aref
+ STRINGS.each {|s|
+ t = ''.force_encoding(s.encoding)
+ 0.upto(s.length-1) {|i|
+ u = s[i]
+ assert_predicate(u, :valid_encoding?) if s.valid_encoding?
+ t << u
+ }
+ assert_equal(t, s)
+ }
+ end
+
+ def test_str_aref_len
+ STRINGS.each {|s|
+ t = ''.force_encoding(s.encoding)
+ 0.upto(s.length-1) {|i|
+ u = s[i,1]
+ assert_predicate(u, :valid_encoding?) if s.valid_encoding?
+ t << u
+ }
+ assert_equal(t, s)
+ }
+
+ STRINGS.each {|s|
+ t = ''.force_encoding(s.encoding)
+ 0.step(s.length-1, 2) {|i|
+ u = s[i,2]
+ assert_predicate(u, :valid_encoding?) if s.valid_encoding?
+ t << u
+ }
+ assert_equal(t, s)
+ }
+ end
+
+ def test_str_aref_substr
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ t = enccall(s1, :[], s2)
+ if t != nil
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_equal(s2, t)
+ assert_match(/#{Regexp.escape(b(s2))}/, b(s1))
+ if s1.valid_encoding?
+ assert_match(/#{Regexp.escape(s2)}/, s1)
+ end
+ end
+ else
+ assert_raise(Encoding::CompatibilityError) { s1[s2] }
+ end
+ }
+ end
+
+ def test_str_aref_range2
+ combination(STRINGS, -2..2, -2..2) {|s, first, last|
+ desc = "#{encdump s}[#{first}..#{last}]"
+ t = s[first..last]
+ if first < 0
+ first += s.length
+ if first < 0
+ assert_nil(t, desc)
+ next
+ end
+ end
+ if s.length < first
+ assert_nil(t, desc)
+ next
+ end
+ assert_predicate(t, :valid_encoding?) if s.valid_encoding?
+ if last < 0
+ last += s.length
+ end
+ t2 = ''
+ first.upto(last) {|i|
+ c = s[i]
+ t2 << c if c
+ }
+ assert_equal(t2, t, desc)
+ }
+ end
+
+ def test_str_aref_range3
+ combination(STRINGS, -2..2, -2..2) {|s, first, last|
+ desc = "#{encdump s}[#{first}..#{last}]"
+ t = s[first...last]
+ if first < 0
+ first += s.length
+ if first < 0
+ assert_nil(t, desc)
+ next
+ end
+ end
+ if s.length < first
+ assert_nil(t, desc)
+ next
+ end
+ if last < 0
+ last += s.length
+ end
+ assert_predicate(t, :valid_encoding?) if s.valid_encoding?
+ t2 = ''
+ first.upto(last-1) {|i|
+ c = s[i]
+ t2 << c if c
+ }
+ assert_equal(t2, t, desc)
+ }
+ end
+
+ def test_str_assign
+ combination(STRINGS, STRINGS) {|s1, s2|
+ (-2).upto(2) {|i|
+ t = s1.dup
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ if i < -s1.length || s1.length < i
+ assert_raise(IndexError) { t[i] = s2 }
+ else
+ t[i] = s2
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s2)])
+ if s1.valid_encoding? && s2.valid_encoding?
+ if i == s1.length && s2.empty?
+ assert_nil(t[i])
+ elsif i < 0
+ assert_equal(s2, t[i-s2.length+1,s2.length],
+ "t = #{encdump(s1)}; t[#{i}] = #{encdump(s2)}; t[#{i-s2.length+1},#{s2.length}]")
+ else
+ assert_equal(s2, t[i,s2.length],
+ "t = #{encdump(s1)}; t[#{i}] = #{encdump(s2)}; t[#{i},#{s2.length}]")
+ end
+ end
+ end
+ else
+ assert_raise(Encoding::CompatibilityError) { t[i] = s2 }
+ end
+ }
+ }
+ end
+
+ def test_str_assign_len
+ combination(STRINGS, -2..2, 0..2, STRINGS) {|s1, i, len, s2|
+ t = s1.dup
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ if i < -s1.length || s1.length < i
+ assert_raise(IndexError) { t[i,len] = s2 }
+ else
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ t[i,len] = s2
+ assert_send([b(t), :index, b(s2)])
+ if s1.valid_encoding? && s2.valid_encoding?
+ if i == s1.length && s2.empty?
+ assert_nil(t[i])
+ elsif i < 0
+ if -i < len
+ len = -i
+ end
+ assert_equal(s2, t[i-s2.length+len,s2.length],
+ "t = #{encdump(s1)}; t[#{i},#{len}] = #{encdump(s2)}; t[#{i-s2.length+len},#{s2.length}]")
+ else
+ assert_equal(s2, t[i,s2.length],
+ "t = #{encdump(s1)}; t[#{i},#{len}] = #{encdump(s2)}; t[#{i},#{s2.length}]")
+ end
+ end
+ end
+ else
+ assert_raise(Encoding::CompatibilityError) { t[i,len] = s2 }
+ end
+ }
+ end
+
+ def test_str_assign_substr
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ t = s1.dup
+ encs = [
+ !s1.ascii_only? ? s1.encoding : nil,
+ !s2.ascii_only? ? s2.encoding : nil,
+ !s3.ascii_only? ? s3.encoding : nil].uniq.compact
+ if 1 < encs.length
+ assert_raise(Encoding::CompatibilityError, IndexError) { t[s2] = s3 }
+ else
+ if encs.empty?
+ encs = [
+ s1.encoding,
+ s2.encoding,
+ s3.encoding].uniq.reject {|e| e == Encoding.find("ASCII-8BIT") }
+ if encs.empty?
+ encs = [Encoding.find("ASCII-8BIT")]
+ end
+ end
+ if !t[s2]
+ else
+ enccall(t, :[]=, s2, s3)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? && s3.valid_encoding?
+ end
+ end
+ }
+ end
+
+ def test_str_assign_range2
+ combination(STRINGS, -2..2, -2..2, STRINGS) {|s1, first, last, s2|
+ t = s1.dup
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ if first < -s1.length || s1.length < first
+ assert_raise(RangeError) { t[first..last] = s2 }
+ else
+ enccall(t, :[]=, first..last, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s2)])
+ if s1.valid_encoding? && s2.valid_encoding?
+ if first < 0
+ assert_equal(s2, t[s1.length+first, s2.length])
+ else
+ assert_equal(s2, t[first, s2.length])
+ end
+ end
+ end
+ else
+ assert_raise(Encoding::CompatibilityError, RangeError,
+ "t=#{encdump(s1)};t[#{first}..#{last}]=#{encdump(s2)}") {
+ t[first..last] = s2
+ }
+ end
+ }
+ end
+
+ def test_str_assign_range3
+ combination(STRINGS, -2..2, -2..2, STRINGS) {|s1, first, last, s2|
+ t = s1.dup
+ if s1.ascii_only? || s2.ascii_only? || s1.encoding == s2.encoding
+ if first < -s1.length || s1.length < first
+ assert_raise(RangeError) { t[first...last] = s2 }
+ else
+ enccall(t, :[]=, first...last, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s2)])
+ if s1.valid_encoding? && s2.valid_encoding?
+ if first < 0
+ assert_equal(s2, t[s1.length+first, s2.length])
+ else
+ assert_equal(s2, t[first, s2.length])
+ end
+ end
+ end
+ else
+ assert_raise(Encoding::CompatibilityError, RangeError,
+ "t=#{encdump(s1)};t[#{first}...#{last}]=#{encdump(s2)}") {
+ t[first...last] = s2
+ }
+ end
+ }
+ end
+
+ def test_str_cmp
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = "#{encdump s1} <=> #{encdump s2}"
+ r = s1 <=> s2
+ if s1 == s2
+ assert_equal(0, r, desc)
+ else
+ assert_not_equal(0, r, desc)
+ end
+ }
+ end
+
+ def test_str_capitalize
+ STRINGS.each {|s|
+ begin
+ t1 = s.capitalize
+ rescue ArgumentError
+ assert_not_predicate(s, :valid_encoding?)
+ next
+ end
+ assert_predicate(t1, :valid_encoding?) if s.valid_encoding?
+ assert_operator(t1, :casecmp, s)
+ t2 = s.dup
+ t2.capitalize!
+ assert_equal(t1, t2)
+ r = s.downcase
+ r = enccall(r, :sub, /\A[a-z]/) {|ch| b(ch).upcase }
+ assert_equal(r, t1)
+ }
+ end
+
+ def test_str_casecmp
+ combination(STRINGS, STRINGS) {|s1, s2|
+ #puts "#{encdump(s1)}.casecmp(#{encdump(s2)})"
+ next unless s1.valid_encoding? && s2.valid_encoding? && Encoding.compatible?(s1, s2)
+ r = s1.casecmp(s2)
+ assert_equal(s1.upcase <=> s2.upcase, r)
+ }
+ end
+
+ def test_str_center
+ combination(STRINGS, [0,1,2,3,10]) {|s1, width|
+ t = s1.center(width)
+ assert_send([b(t), :index, b(s1)])
+ }
+ combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2|
+ if s2.empty?
+ assert_raise(ArgumentError) { s1.center(width, s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.center(width, s2) }
+ next
+ end
+ t = enccall(s1, :center, width, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s1)])
+ assert_str_enc_propagation(t, s1, s2) if (t != s1)
+ }
+ end
+
+ def test_str_ljust
+ combination(STRINGS, [0,1,2,3,10]) {|s1, width|
+ t = s1.ljust(width)
+ assert_send([b(t), :index, b(s1)])
+ }
+ combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2|
+ if s2.empty?
+ assert_raise(ArgumentError) { s1.ljust(width, s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.ljust(width, s2) }
+ next
+ end
+ t = enccall(s1, :ljust, width, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s1)])
+ assert_str_enc_propagation(t, s1, s2) if (t != s1)
+ }
+ end
+
+ def test_str_rjust
+ combination(STRINGS, [0,1,2,3,10]) {|s1, width|
+ t = s1.rjust(width)
+ assert_send([b(t), :index, b(s1)])
+ }
+ combination(STRINGS, [0,1,2,3,10], STRINGS) {|s1, width, s2|
+ if s2.empty?
+ assert_raise(ArgumentError) { s1.rjust(width, s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.rjust(width, s2) }
+ next
+ end
+ t = enccall(s1, :rjust, width, s2)
+ assert_predicate(t, :valid_encoding?) if s1.valid_encoding? && s2.valid_encoding?
+ assert_send([b(t), :index, b(s1)])
+ assert_str_enc_propagation(t, s1, s2) if (t != s1)
+ }
+ end
+
+ def test_str_chomp
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s1.ascii_only? && !s2.ascii_only? && !Encoding.compatible?(s1,s2)
+ if s1.bytesize > s2.bytesize
+ assert_raise(Encoding::CompatibilityError, "#{encdump(s1)}.chomp(#{encdump(s2)})") do
+ s1.chomp(s2)
+ end
+ end
+ next
+ end
+ t = enccall(s1, :chomp, s2)
+ assert_predicate(t, :valid_encoding?, "#{encdump(s1)}.chomp(#{encdump(s2)})") if s1.valid_encoding? && s2.valid_encoding?
+ assert_equal(s1.encoding, t.encoding)
+ t2 = s1.dup
+ t2.chomp!(s2)
+ assert_equal(t, t2)
+ }
+ end
+
+ def test_str_smart_chomp
+ bug10893 = '[ruby-core:68258] [Bug #10893]'
+ encodings = Encoding.list.select {|enc| !enc.dummy?}
+ combination(encodings, encodings) do |e1, e2|
+ expected = "abc".encode(e1)
+ combination(["abc\n", "abc\r\n"], ["", "\n"]) do |str, rs|
+ assert_equal(expected, str.encode(e1).chomp(rs.encode(e2)), bug10893)
+ end
+ end
+ end
+
+ def test_str_chop
+ STRINGS.each {|s|
+ s = s.dup
+ desc = "#{encdump s}.chop"
+ t = nil
+ assert_nothing_raised(desc) { t = s.chop }
+ assert_predicate(t, :valid_encoding?) if s.valid_encoding?
+ assert_send([b(s), :index, b(t)])
+ t2 = s.dup
+ t2.chop!
+ assert_equal(t, t2)
+ }
+ end
+
+ def test_str_clear
+ STRINGS.each {|s|
+ t = s.dup
+ t.clear
+ assert_predicate(t, :valid_encoding?)
+ assert_empty(t)
+ }
+ end
+
+ def test_str_clone
+ STRINGS.each {|s|
+ t = s.clone
+ assert_equal(s, t)
+ assert_equal(s.encoding, t.encoding)
+ assert_equal(b(s), b(t))
+ }
+ end
+
+ def test_str_dup
+ STRINGS.each {|s|
+ t = s.dup
+ assert_equal(s, t)
+ assert_equal(s.encoding, t.encoding)
+ assert_equal(b(s), b(t))
+ }
+ end
+
+ def test_str_count
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = proc {encdumpcall(s1, :count, s2)}
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.count(s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError, desc) { s1.count(s2) }
+ next
+ end
+ n = enccall(s1, :count, s2)
+ n0 = b(s1).count(b(s2))
+ assert_operator(n, :<=, n0)
+ }
+ end
+
+ # glibc 2.16 or later denies salt contained other than [0-9A-Za-z./] #7312
+ # we use this check to test strict and non-strict behavior separately #11045
+ strict_crypt = if defined? Etc::CS_GNU_LIBC_VERSION
+ glibcver = Etc.confstr(Etc::CS_GNU_LIBC_VERSION).scan(/\d+/).map(&:to_i)
+ (glibcver <=> [2, 16]) >= 0
+ end
+
+ def test_str_crypt
+ combination(STRINGS, STRINGS) {|str, salt|
+ # skip input other than [0-9A-Za-z./] to confirm strict behavior
+ next unless salt.ascii_only? && /\A[0-9a-zA-Z.\/]+\z/ =~ salt
+
+ confirm_crypt_result(str, salt)
+ }
+ end
+
+ if !strict_crypt
+ def test_str_crypt_nonstrict
+ combination(STRINGS, STRINGS) {|str, salt|
+ # only test input other than [0-9A-Za-z./] to confirm non-strict behavior
+ next if salt.ascii_only? && /\A[0-9a-zA-Z.\/]+\z/ =~ salt
+
+ confirm_crypt_result(str, salt)
+ }
+ end
+ end
+
+ private def confirm_crypt_result(str, salt)
+ if b(salt).length < 2
+ assert_raise(ArgumentError) { str.crypt(salt) }
+ return
+ end
+ t = str.crypt(salt)
+ assert_equal(b(str).crypt(b(salt)), t, "#{encdump(str)}.crypt(#{encdump(salt)})")
+ assert_encoding('ASCII-8BIT', t.encoding)
+ end
+
+ def test_str_delete
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if s1.empty?
+ assert_equal(s1, s1.delete(s2))
+ next
+ end
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.delete(s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.delete(s2) }
+ next
+ end
+ t = enccall(s1, :delete, s2)
+ assert_predicate(t, :valid_encoding?)
+ assert_equal(t.encoding, s1.encoding)
+ assert_operator(t.length, :<=, s1.length)
+ t2 = s1.dup
+ t2.delete!(s2)
+ assert_equal(t, t2)
+ }
+ end
+
+ def test_str_downcase
+ STRINGS.each {|s|
+ if !s.valid_encoding?
+ assert_raise(ArgumentError) { s.downcase }
+ next
+ end
+ t = s.downcase
+ assert_predicate(t, :valid_encoding?)
+ assert_equal(t.encoding, s.encoding)
+ assert_operator(t, :casecmp, s)
+ t2 = s.dup
+ t2.downcase!
+ assert_equal(t, t2)
+ }
+ end
+
+ def test_str_dump
+ STRINGS.each {|s|
+ t = s.dump
+ assert_predicate(t, :valid_encoding?)
+ assert_predicate(t, :ascii_only?)
+ u = eval(t)
+ assert_equal(b(s), b(u))
+ }
+ end
+
+ def test_str_each_line
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.each_line(s2) {} }
+ next
+ end
+ lines = []
+ enccall(s1, :each_line, s2) {|line|
+ assert_equal(s1.encoding, line.encoding)
+ lines << line
+ }
+ next if lines.size == 0
+ s2 = lines.join('')
+ assert_equal(s1.encoding, s2.encoding)
+ assert_equal(s1, s2)
+ }
+ end
+
+ def test_str_each_byte
+ STRINGS.each {|s|
+ bytes = []
+ s.each_byte {|b|
+ bytes << b
+ }
+ b(s).split(//).each_with_index {|ch, i|
+ assert_equal(ch.ord, bytes[i])
+ }
+ }
+ end
+
+ def test_str_empty?
+ STRINGS.each {|s|
+ if s.length == 0
+ assert_empty(s)
+ else
+ assert_not_empty(s)
+ end
+ }
+ end
+
+ def test_str_hex
+ STRINGS.each {|s|
+ t = s.hex
+ t2 = b(s)[/\A[0-9a-fA-Fx]*/].hex
+ assert_equal(t2, t)
+ }
+ end
+
+ def test_str_include?
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.include?(s2) }
+ assert_raise(Encoding::CompatibilityError) { s1.index(s2) }
+ assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) }
+ next
+ end
+ t = enccall(s1, :include?, s2)
+ if t
+ assert_include(b(s1), b(s2))
+ assert_send([s1, :index, s2])
+ assert_send([s1, :rindex, s2])
+ else
+ assert_not_send([s1, :index, s2])
+ assert_not_send([s1, :rindex, s2], "!#{encdump(s1)}.rindex(#{encdump(s2)})")
+ end
+ if s2.empty?
+ assert_equal(true, t)
+ next
+ end
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_equal(false, t, "#{encdump s1}.include?(#{encdump s2})")
+ next
+ end
+ if t && s1.valid_encoding? && s2.valid_encoding?
+ assert_match(/#{Regexp.escape(s2)}/, s1)
+ else
+ assert_no_match(/#{Regexp.escape(s2)}/, s1)
+ end
+ }
+ end
+
+ def test_str_index
+ combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos|
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.index(s2) }
+ next
+ end
+ t = enccall(s1, :index, s2, pos)
+ if s2.empty?
+ if pos < 0 && pos+s1.length < 0
+ assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})");
+ elsif pos < 0
+ assert_equal(s1.length+pos, t, "#{encdump s1}.index(#{encdump s2}, #{pos})");
+ elsif s1.length < pos
+ assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})");
+ else
+ assert_equal(pos, t, "#{encdump s1}.index(#{encdump s2}, #{pos})");
+ end
+ next
+ end
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_equal(nil, t, "#{encdump s1}.index(#{encdump s2}, #{pos})");
+ next
+ end
+ if t
+ re = /#{Regexp.escape(s2)}/
+ assert(re.match(s1, pos))
+ assert_equal($`.length, t, "#{encdump s1}.index(#{encdump s2}, #{pos})")
+ else
+ assert_no_match(/#{Regexp.escape(s2)}/, s1[pos..-1])
+ end
+ }
+ end
+
+ def test_str_rindex
+ combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos|
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) }
+ next
+ end
+ t = enccall(s1, :rindex, s2, pos)
+ if s2.empty?
+ if pos < 0 && pos+s1.length < 0
+ assert_equal(nil, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ elsif pos < 0
+ assert_equal(s1.length+pos, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ elsif s1.length < pos
+ assert_equal(s1.length, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ else
+ assert_equal(pos, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ end
+ next
+ end
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_equal(nil, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ next
+ end
+ if t
+ #puts "#{encdump s1}.rindex(#{encdump s2}, #{pos}) => #{t}"
+ assert_send([b(s1), :index, b(s2)])
+ pos2 = pos
+ pos2 += s1.length if pos < 0
+ re = /\A(.{0,#{pos2}})#{Regexp.escape(s2)}/m
+ m = enccall(re, :match, s1)
+ assert(m, "#{re.inspect}.match(#{encdump(s1)})")
+ assert_equal(m[1].length, t, "#{encdump s1}.rindex(#{encdump s2}, #{pos})")
+ else
+ re = /#{Regexp.escape(s2)}/
+ n = re =~ s1
+ if n
+ if pos < 0
+ assert_operator(n, :>, s1.length+pos)
+ else
+ assert_operator(n, :>, pos)
+ end
+ end
+ end
+ }
+ end
+
+ def test_str_insert
+ combination(STRINGS, 0..2, STRINGS) {|s1, nth, s2|
+ t1 = s1.dup
+ t2 = s1.dup
+ begin
+ t1[nth, 0] = s2
+ rescue Encoding::CompatibilityError, IndexError => e1
+ end
+ begin
+ t2.insert(nth, s2)
+ rescue Encoding::CompatibilityError, IndexError => e2
+ end
+ assert_equal(t1, t2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t")
+ assert_equal(e1.class, e2.class, "begin #{encdump s1}.insert(#{nth},#{encdump s2}); rescue ArgumentError, IndexError => e; e end")
+ }
+ combination(STRINGS, -2..-1, STRINGS) {|s1, nth, s2|
+ next if s1.length + nth < 0
+ next unless s1.valid_encoding?
+ next unless s2.valid_encoding?
+ t1 = s1.dup
+ begin
+ t1.insert(nth, s2)
+ slen = s2.length
+ assert_equal(t1[nth-slen+1,slen], s2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t")
+ rescue Encoding::CompatibilityError, IndexError
+ end
+ }
+ end
+
+ def test_str_intern
+ STRINGS.each {|s|
+ if /\0/ =~ b(s)
+ assert_raise(ArgumentError) { s.intern }
+ elsif s.valid_encoding?
+ sym = s.intern
+ assert_equal(s, sym.to_s, "#{encdump s}.intern.to_s")
+ assert_equal(sym, s.to_sym)
+ else
+ assert_raise(EncodingError) { s.intern }
+ end
+ }
+ end
+
+ def test_str_length
+ STRINGS.each {|s|
+ assert_operator(s.length, :<=, s.bytesize)
+ }
+ end
+
+ def test_str_oct
+ STRINGS.each {|s|
+ t = s.oct
+ t2 = b(s)[/\A[0-9a-fA-FxX]*/].oct
+ assert_equal(t2, t)
+ }
+ end
+
+ def test_str_replace
+ combination(STRINGS, STRINGS) {|s1, s2|
+ t = s1.dup
+ t.replace s2
+ assert_equal(s2, t)
+ assert_equal(s2.encoding, t.encoding)
+ }
+ end
+
+ def test_str_reverse
+ STRINGS.each {|s|
+ t = s.reverse
+ assert_equal(s.bytesize, t.bytesize)
+ if !s.valid_encoding?
+ assert_operator(t.length, :<=, s.length)
+ next
+ end
+ assert_equal(s, t.reverse)
+ }
+ end
+
+ def test_str_scan
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = proc {"#{s1.dump}.scan(#{s2.dump})"}
+ if !s2.valid_encoding?
+ assert_raise(RegexpError, desc) { s1.scan(s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ if s1.valid_encoding?
+ assert_raise(Encoding::CompatibilityError, desc) { s1.scan(s2) }
+ else
+ assert_raise_with_message(ArgumentError, /invalid byte sequence/, desc) { s1.scan(s2) }
+ end
+ next
+ end
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError, desc) { s1.scan(s2) }
+ next
+ end
+ r = enccall(s1, :scan, s2)
+ r.each {|t|
+ assert_equal(s2, t, desc)
+ }
+ }
+ end
+
+ def test_str_slice
+ each_slice_call {|obj, *args|
+ assert_same_result(lambda { obj[*args] }, lambda { obj.slice(*args) })
+ }
+ end
+
+ def test_str_slice!
+ each_slice_call {|s, *args|
+ desc_slice = "#{encdump s}.slice#{encdumpargs args}"
+ desc_slice_bang = "#{encdump s}.slice!#{encdumpargs args}"
+ t = s.dup
+ begin
+ r = t.slice!(*args)
+ rescue
+ e = $!
+ end
+ if e
+ assert_raise(e.class, desc_slice) { s.slice(*args) }
+ next
+ end
+ if !r
+ assert_nil(s.slice(*args), desc_slice)
+ next
+ end
+ assert_equal(s.slice(*args), r, desc_slice_bang)
+ assert_equal(s.bytesize, r.bytesize + t.bytesize)
+ if args.length == 1 && String === args[0]
+ assert_equal(args[0].encoding, r.encoding,
+ "#{encdump s}.slice!#{encdumpargs args}.encoding")
+ else
+ assert_equal(s.encoding, r.encoding,
+ "#{encdump s}.slice!#{encdumpargs args}.encoding")
+ end
+ if [s, *args].all? {|o| !(String === o) || o.valid_encoding? }
+ assert_predicate(r, :valid_encoding?)
+ assert_predicate(t, :valid_encoding?)
+ assert_equal(s.length, r.length + t.length)
+ end
+ }
+ end
+
+ def test_str_split
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s2.valid_encoding?
+ assert_raise(ArgumentError, RegexpError) { s1.split(s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.split(s2) }
+ next
+ end
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError) { s1.split(s2) }
+ next
+ end
+ t = enccall(s1, :split, s2)
+ t.each {|r|
+ assert_include(b(s1), b(r))
+ assert_equal(s1.encoding, r.encoding)
+ }
+ assert_include(b(s1), t.map {|u| b(u) }.join(b(s2)))
+ if s1.valid_encoding? && s2.valid_encoding?
+ t.each {|r|
+ assert_predicate(r, :valid_encoding?)
+ }
+ end
+ }
+ end
+
+ def test_str_squeeze
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if !s1.valid_encoding? || !s2.valid_encoding?
+ assert_raise(ArgumentError, Encoding::CompatibilityError, "#{encdump s1}.squeeze(#{encdump s2})") { s1.squeeze(s2) }
+ next
+ end
+ if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
+ assert_raise(Encoding::CompatibilityError) { s1.squeeze(s2) }
+ next
+ end
+ t = enccall(s1, :squeeze, s2)
+ assert_operator(t.length, :<=, s1.length)
+ t2 = s1.dup
+ t2.squeeze!(s2)
+ assert_equal(t, t2)
+ }
+ end
+
+ def test_str_strip
+ STRINGS.each {|s|
+ if !s.valid_encoding?
+ assert_raise(ArgumentError, "#{encdump s}.strip") { s.strip }
+ next
+ end
+ t = s.strip
+ l = s.lstrip
+ r = s.rstrip
+ assert_operator(l.length, :<=, s.length)
+ assert_operator(r.length, :<=, s.length)
+ assert_operator(t.length, :<=, l.length)
+ assert_operator(t.length, :<=, r.length)
+ t2 = s.dup
+ t2.strip!
+ assert_equal(t, t2)
+ l2 = s.dup
+ l2.lstrip!
+ assert_equal(l, l2)
+ r2 = s.dup
+ r2.rstrip!
+ assert_equal(r, r2)
+ }
+ end
+
+ def test_str_sum
+ STRINGS.each {|s|
+ assert_equal(b(s).sum, s.sum)
+ }
+ end
+
+ def test_str_swapcase
+ STRINGS.each {|s|
+ if !s.valid_encoding?
+ assert_raise(ArgumentError, "#{encdump s}.swapcase") { s.swapcase }
+ next
+ end
+ t1 = s.swapcase
+ assert_predicate(t1, :valid_encoding?) if s.valid_encoding?
+ assert_operator(t1, :casecmp, s)
+ t2 = s.dup
+ t2.swapcase!
+ assert_equal(t1, t2)
+ t3 = t1.swapcase
+ assert_equal(s, t3);
+ }
+ end
+
+
+ def test_str_to_f
+ STRINGS.each {|s|
+ assert_nothing_raised { s.to_f }
+ }
+ end
+
+ def test_str_to_i
+ STRINGS.each {|s|
+ assert_nothing_raised { s.to_i }
+ 2.upto(36) {|radix|
+ assert_nothing_raised { s.to_i(radix) }
+ }
+ }
+ end
+
+ def test_str_to_s
+ STRINGS.each {|s|
+ assert_same(s, s.to_s)
+ assert_same(s, s.to_str)
+ }
+ end
+
+ def test_tr
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ desc = "#{encdump s1}.tr(#{encdump s2}, #{encdump s3})"
+ if s1.empty?
+ assert_equal(s1, s1.tr(s2, s3), desc)
+ next
+ end
+ if !str_enc_compatible?(s1, s2, s3)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) }
+ next
+ end
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError, desc) { s1.tr(s2, s3) }
+ next
+ end
+ if s2.empty?
+ t = enccall(s1, :tr, s2, s3)
+ assert_equal(s1, t, desc)
+ next
+ end
+ if !s2.valid_encoding? || !s3.valid_encoding?
+ assert_raise(ArgumentError, desc) { s1.tr(s2, s3) }
+ next
+ end
+ t = enccall(s1, :tr, s2, s3)
+ assert_operator(s1.length, :>=, t.length, desc)
+ }
+ end
+
+ def test_tr_sjis
+ expected = "\x83}\x83~\x83\x80\x83\x81\x83\x82".force_encoding(Encoding::SJIS)
+ source = "\xCF\xD0\xD1\xD2\xD3".force_encoding(Encoding::SJIS)
+ from = "\xCF-\xD3".force_encoding(Encoding::SJIS)
+ to = "\x83}-\x83\x82".force_encoding(Encoding::SJIS)
+ assert_equal(expected, source.tr(from, to))
+
+ expected = "\x84}\x84~\x84\x80\x84\x81\x84\x82".force_encoding(Encoding::SJIS)
+ source = "\x84M\x84N\x84O\x84P\x84Q".force_encoding(Encoding::SJIS)
+ from = "\x84@-\x84`".force_encoding(Encoding::SJIS)
+ to = "\x84p-\x84\x91".force_encoding(Encoding::SJIS)
+ assert_equal(expected, source.tr(from, to))
+ end
+
+ def test_tr_s
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ desc = "#{encdump s1}.tr_s(#{encdump s2}, #{encdump s3})"
+ if s1.empty?
+ assert_equal(s1, s1.tr_s(s2, s3), desc)
+ next
+ end
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.tr_s(s2, s3) }
+ next
+ end
+ if !str_enc_compatible?(s1, s2, s3)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) }
+ next
+ end
+ if s2.empty?
+ t = enccall(s1, :tr_s, s2, s3)
+ assert_equal(s1, t, desc)
+ next
+ end
+ if !s2.valid_encoding? || !s3.valid_encoding?
+ assert_raise(ArgumentError, desc) { s1.tr_s(s2, s3) }
+ next
+ end
+
+ t = enccall(s1, :tr_s, s2, s3)
+ assert_operator(s1.length, :>=, t.length, desc)
+ }
+ end
+
+ def test_str_upcase
+ STRINGS.each {|s|
+ desc = "#{encdump s}.upcase"
+ if !s.valid_encoding?
+ assert_raise(ArgumentError, desc) { s.upcase }
+ next
+ end
+ t1 = s.upcase
+ assert_predicate(t1, :valid_encoding?)
+ assert_operator(t1, :casecmp, s)
+ t2 = s.dup
+ t2.upcase!
+ assert_equal(t1, t2)
+ }
+ end
+
+ def test_str_succ
+ STRINGS.each {|s0|
+ next if s0.empty?
+ s = s0.dup
+ n = 300
+ h = {}
+ n.times {|i|
+ if h[s]
+ assert(false, "#{encdump s} cycle with succ #{i-h[s]} times")
+ end
+ h[s] = i
+ assert_operator(s.length, :<=, s0.length + Math.log2(i+1) + 1, "#{encdump s0} succ #{i} times => #{encdump s}")
+ #puts encdump(s)
+ t = s.succ
+ if s.valid_encoding?
+ assert_predicate(t, :valid_encoding?, "#{encdump s}.succ.valid_encoding?")
+ end
+ s = t
+ }
+ }
+
+ Encoding.list.each do |enc|
+ next if enc.dummy?
+ {"A"=>"B", "A1"=>"A2", "A9"=>"B0", "9"=>"10", "Z"=>"AA"}.each do |orig, expected|
+ s = orig.encode(enc)
+ assert_strenc(expected.encode(enc), enc, s.succ, proc {"#{orig.dump}.encode(#{enc}).succ"})
+ end
+ end
+ end
+
+ def test_str_succ2
+ assert_equal(a("\x01\x00"), a("\x7f").succ)
+ assert_equal(b("\x01\x00"), b("\xff").succ)
+ end
+
+ def test_str_hash
+ combination(STRINGS, STRINGS) {|s1, s2|
+ if s1.eql?(s2)
+ assert_equal(s1.hash, s2.hash, "#{encdump s1}.hash == #{encdump s2}.dump")
+ end
+ }
+ end
+
+ def test_marshal
+ STRINGS.each {|s|
+ m = Marshal.dump(s)
+ t = Marshal.load(m)
+ assert_equal(s, t)
+ }
+ end
+
+ def test_str_sub
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ if !s2.valid_encoding?
+ assert_raise(RegexpError) { Regexp.new(Regexp.escape(s2)) }
+ next
+ end
+ r2 = Regexp.new(Regexp.escape(s2))
+ [
+ [
+ "#{encdump s1}.sub(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { s1.sub(r2, s3) },
+ false
+ ],
+ [
+ "#{encdump s1}.sub(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { s1.sub(r2) { s3 } },
+ false
+ ],
+ [
+ "#{encdump s1}.gsub(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { s1.gsub(r2, s3) },
+ true
+ ],
+ [
+ "#{encdump s1}.gsub(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { s1.gsub(r2) { s3 } },
+ true
+ ]
+ ].each {|desc, doit, g|
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError, desc) { doit.call }
+ next
+ end
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { doit.call }
+ next
+ end
+ if !enccall(s1, :include?, s2)
+ assert_equal(s1, doit.call)
+ next
+ end
+ if !str_enc_compatible?(g ? s1.gsub(r2, '') : s1.sub(r2, ''), s3)
+ assert_raise(Encoding::CompatibilityError, desc) { doit.call }
+ next
+ end
+ t = nil
+ assert_nothing_raised(desc) {
+ t = doit.call
+ }
+ if s2 == s3
+ assert_equal(s1, t, desc)
+ else
+ assert_not_equal(s1, t, desc)
+ end
+ }
+ }
+ end
+
+ def test_str_sub!
+ combination(STRINGS, STRINGS, STRINGS) {|s1, s2, s3|
+ if !s2.valid_encoding?
+ assert_raise(RegexpError) { Regexp.new(Regexp.escape(s2)) }
+ next
+ end
+ r2 = Regexp.new(Regexp.escape(s2))
+ [
+ [
+ "t=#{encdump s1}.dup;t.sub!(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { t=s1.dup; [t, t.sub!(r2, s3)] },
+ false
+ ],
+ [
+ "t=#{encdump s1}.dup;t.sub!(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { t=s1.dup; [t, t.sub!(r2) { s3 }] },
+ false
+ ],
+ [
+ "t=#{encdump s1}.dup;t.gsub!(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { t=s1.dup; [t, t.gsub!(r2, s3)] },
+ true
+ ],
+ [
+ "t=#{encdump s1}.dup;t.gsub!(Regexp.new(#{encdump s2}), #{encdump s3})",
+ lambda { t=s1.dup; [t, t.gsub!(r2) { s3 }] },
+ true
+ ]
+ ].each {|desc, doit, g|
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError, desc) { doit.call }
+ next
+ end
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { doit.call }
+ next
+ end
+ if !enccall(s1, :include?, s2)
+ assert_equal([s1, nil], doit.call)
+ next
+ end
+ if !str_enc_compatible?(g ? s1.gsub(r2, '') : s1.sub(r2, ''), s3)
+ assert_raise(Encoding::CompatibilityError, desc) { doit.call }
+ next
+ end
+ t = ret = nil
+ assert_nothing_raised(desc) {
+ t, ret = doit.call
+ }
+ assert(ret)
+ if s2 == s3
+ assert_equal(s1, t, desc)
+ else
+ assert_not_equal(s1, t, desc)
+ end
+ }
+ }
+ end
+
+ def test_str_bytes
+ STRINGS.each {|s1|
+ ary = []
+ s1.bytes.each {|b|
+ ary << b
+ }
+ assert_equal(s1.unpack("C*"), ary)
+ }
+ end
+
+ def test_str_bytesize
+ STRINGS.each {|s1|
+ assert_equal(s1.unpack("C*").length, s1.bytesize)
+ }
+ end
+
+ def test_str_chars
+ STRINGS.each {|s1|
+ ary = []
+ s1.chars.each {|c|
+ ary << c
+ }
+ expected = []
+ s1.length.times {|i|
+ expected << s1[i]
+ }
+ assert_equal(expected, ary)
+ }
+ end
+
+ def test_str_chr
+ STRINGS.each {|s1|
+ if s1.empty?
+ assert_equal("", s1.chr)
+ next
+ end
+ assert_equal(s1[0], s1.chr)
+ }
+ end
+
+ def test_str_end_with?
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = "#{encdump s1}.end_with?(#{encdump s2})"
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.end_with?(s2) }
+ next
+ end
+ if s1.length < s2.length
+ assert_equal(false, enccall(s1, :end_with?, s2), desc)
+ next
+ end
+ if s1[s1.length-s2.length, s2.length] == s2
+ assert_equal(true, enccall(s1, :end_with?, s2), desc)
+ next
+ end
+ assert_equal(false, enccall(s1, :end_with?, s2), desc)
+ }
+ end
+
+ def test_str_start_with?
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = "#{encdump s1}.start_with?(#{encdump s2})"
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.start_with?(s2) }
+ next
+ end
+ s1 = s1.dup.force_encoding("ASCII-8BIT")
+ s2 = s2.dup.force_encoding("ASCII-8BIT")
+ if s1.length < s2.length
+ assert_equal(false, enccall(s1, :start_with?, s2), desc)
+ next
+ end
+ if s1[0, s2.length] == s2
+ assert_equal(true, enccall(s1, :start_with?, s2), desc)
+ next
+ end
+ assert_equal(false, enccall(s1, :start_with?, s2), desc)
+ }
+ end
+
+ def test_str_ord
+ STRINGS.each {|s1|
+ if s1.empty?
+ assert_raise(ArgumentError) { s1.ord }
+ next
+ end
+ if !s1.valid_encoding?
+ assert_raise(ArgumentError) { s1.ord }
+ next
+ end
+ assert_equal(s1[0].ord, s1.ord)
+ }
+ end
+
+ def test_str_partition
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = "#{encdump s1}.partition(#{encdump s2})"
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.partition(s2) }
+ next
+ end
+ i = enccall(s1, :index, s2)
+ if !i
+ assert_equal([s1, "", ""], s1.partition(s2), desc)
+ next
+ end
+ assert_equal([s1[0,i], s2, s1[(i+s2.length)..-1]], s1.partition(s2), desc)
+ }
+ end
+
+ def test_str_rpartition
+ combination(STRINGS, STRINGS) {|s1, s2|
+ desc = "#{encdump s1}.rpartition(#{encdump s2})"
+ if !str_enc_compatible?(s1, s2)
+ assert_raise(Encoding::CompatibilityError, desc) { s1.rpartition(s2) }
+ next
+ end
+ i = enccall(s1, :rindex, s2)
+ if !i
+ assert_equal(["", "", s1], s1.rpartition(s2), desc)
+ next
+ end
+ assert_equal([s1[0,i], s2, s1[(i+s2.length)..-1]], s1.rpartition(s2), desc)
+ }
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_marshal.rb b/jni/ruby/test/ruby/test_marshal.rb
new file mode 100644
index 0000000..3d5d6c9
--- /dev/null
+++ b/jni/ruby/test/ruby/test_marshal.rb
@@ -0,0 +1,650 @@
+require 'test/unit'
+require 'tempfile'
+require_relative 'marshaltestlib'
+
+class TestMarshal < Test::Unit::TestCase
+ include MarshalTestLib
+
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def encode(o)
+ Marshal.dump(o)
+ end
+
+ def decode(s)
+ Marshal.load(s)
+ end
+
+ def fact(n)
+ return 1 if n == 0
+ f = 1
+ while n>0
+ f *= n
+ n -= 1
+ end
+ return f
+ end
+
+ def test_marshal
+ a = [1, 2, 3, [4,5,"foo"], {1=>"bar"}, 2.5, fact(30)]
+ assert_equal a, Marshal.load(Marshal.dump(a))
+
+ [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z|
+ obj = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f))
+ assert_equal obj, Marshal.load(Marshal.dump(obj))
+ }
+
+ bug3659 = '[ruby-dev:41936]'
+ [1.0, 10.0, 100.0, 110.0].each {|x|
+ assert_equal(x, Marshal.load(Marshal.dump(x)), bug3659)
+ }
+ end
+
+ StrClone = String.clone
+ def test_marshal_cloned_class
+ assert_instance_of(StrClone, Marshal.load(Marshal.dump(StrClone.new("abc"))))
+ end
+
+ def test_inconsistent_struct
+ TestMarshal.const_set :StructOrNot, Struct.new(:a)
+ s = Marshal.dump(StructOrNot.new(1))
+ TestMarshal.instance_eval { remove_const :StructOrNot }
+ TestMarshal.const_set :StructOrNot, Class.new
+ assert_raise(TypeError, "[ruby-dev:31709]") { Marshal.load(s) }
+ end
+
+ def test_struct_invalid_members
+ TestMarshal.const_set :StructInvalidMembers, Struct.new(:a)
+ assert_raise(TypeError, "[ruby-dev:31759]") {
+ Marshal.load("\004\bIc&TestMarshal::StructInvalidMembers\006:\020__members__\"\bfoo")
+ TestMarshal::StructInvalidMembers.members
+ }
+ end
+
+ class C
+ def initialize(str)
+ @str = str
+ end
+ attr_reader :str
+ def _dump(limit)
+ @str
+ end
+ def self._load(s)
+ new(s)
+ end
+ end
+
+ def test_too_long_string
+ data = Marshal.dump(C.new("a".force_encoding("ascii-8bit")))
+ data[-2, 1] = "\003\377\377\377"
+ assert_raise_with_message(ArgumentError, "marshal data too short", "[ruby-dev:32054]") {
+ Marshal.load(data)
+ }
+ end
+
+
+ def test_userdef_encoding
+ s1 = "\xa4\xa4".force_encoding("euc-jp")
+ o1 = C.new(s1)
+ m = Marshal.dump(o1)
+ o2 = Marshal.load(m)
+ s2 = o2.str
+ assert_equal(s1, s2)
+ end
+
+ def test_pipe
+ o1 = C.new("a" * 10000)
+
+ IO.pipe do |r, w|
+ th = Thread.new {Marshal.dump(o1, w)}
+ o2 = Marshal.load(r)
+ th.join
+ assert_equal(o1.str, o2.str)
+ end
+
+ IO.pipe do |r, w|
+ th = Thread.new {Marshal.dump(o1, w, 2)}
+ o2 = Marshal.load(r)
+ th.join
+ assert_equal(o1.str, o2.str)
+ end
+
+ assert_raise(TypeError) { Marshal.dump("foo", Object.new) }
+ assert_raise(TypeError) { Marshal.load(Object.new) }
+ end
+
+ def test_limit
+ assert_equal([[[]]], Marshal.load(Marshal.dump([[[]]], 3)))
+ assert_raise(ArgumentError) { Marshal.dump([[[]]], 2) }
+ assert_nothing_raised(ArgumentError, '[ruby-core:24100]') { Marshal.dump("\u3042", 1) }
+ end
+
+ def test_userdef_invalid
+ o = C.new(nil)
+ assert_raise(TypeError) { Marshal.dump(o) }
+ end
+
+ def test_class
+ o = class << Object.new; self; end
+ assert_raise(TypeError) { Marshal.dump(o) }
+ assert_equal(Object, Marshal.load(Marshal.dump(Object)))
+ assert_equal(Enumerable, Marshal.load(Marshal.dump(Enumerable)))
+ end
+
+ class C2
+ def initialize(ary)
+ @ary = ary
+ end
+ def _dump(s)
+ @ary.clear
+ "foo"
+ end
+ end
+
+ def test_modify_array_during_dump
+ a = []
+ o = C2.new(a)
+ a << o << nil
+ assert_raise(RuntimeError) { Marshal.dump(a) }
+ end
+
+ def test_change_class_name
+ eval("class C3; def _dump(s); 'foo'; end; end")
+ m = Marshal.dump(C3.new)
+ assert_raise(TypeError) { Marshal.load(m) }
+ eval("C3 = nil")
+ assert_raise(TypeError) { Marshal.load(m) }
+ end
+
+ def test_change_struct
+ eval("C3 = Struct.new(:foo, :bar)")
+ m = Marshal.dump(C3.new("FOO", "BAR"))
+ eval("C3 = Struct.new(:foo)")
+ assert_raise(TypeError) { Marshal.load(m) }
+ eval("C3 = Struct.new(:foo, :baz)")
+ assert_raise(TypeError) { Marshal.load(m) }
+ end
+
+ class C4
+ def initialize(gc)
+ @gc = gc
+ end
+ def _dump(s)
+ GC.start if @gc
+ "foo"
+ end
+ end
+
+ def test_gc
+ assert_nothing_raised do
+ Marshal.dump((0..1000).map {|x| C4.new(x % 50 == 25) })
+ end
+ end
+
+ def test_taint
+ x = Object.new
+ x.taint
+ s = Marshal.dump(x)
+ assert_equal(true, s.tainted?)
+ y = Marshal.load(s)
+ assert_equal(true, y.tainted?)
+ end
+
+ def test_taint_each_object
+ x = Object.new
+ obj = [[x]]
+
+ # clean object causes crean stream
+ assert_equal(false, obj.tainted?)
+ assert_equal(false, obj.first.tainted?)
+ assert_equal(false, obj.first.first.tainted?)
+ s = Marshal.dump(obj)
+ assert_equal(false, s.tainted?)
+
+ # tainted object causes tainted stream
+ x.taint
+ assert_equal(false, obj.tainted?)
+ assert_equal(false, obj.first.tainted?)
+ assert_equal(true, obj.first.first.tainted?)
+ t = Marshal.dump(obj)
+ assert_equal(true, t.tainted?)
+
+ # clean stream causes clean objects
+ assert_equal(false, s.tainted?)
+ y = Marshal.load(s)
+ assert_equal(false, y.tainted?)
+ assert_equal(false, y.first.tainted?)
+ assert_equal(false, y.first.first.tainted?)
+
+ # tainted stream causes tainted objects
+ assert_equal(true, t.tainted?)
+ y = Marshal.load(t)
+ assert_equal(true, y.tainted?)
+ assert_equal(true, y.first.tainted?)
+ assert_equal(true, y.first.first.tainted?)
+
+ # same tests by different senario
+ s.taint
+ assert_equal(true, s.tainted?)
+ y = Marshal.load(s)
+ assert_equal(true, y.tainted?)
+ assert_equal(true, y.first.tainted?)
+ assert_equal(true, y.first.first.tainted?)
+ end
+
+ def test_symbol2
+ [:ruby, :"\u{7d05}\u{7389}"].each do |sym|
+ assert_equal(sym, Marshal.load(Marshal.dump(sym)), '[ruby-core:24788]')
+ end
+ bug2548 = '[ruby-core:27375]'
+ ary = [:$1, nil]
+ assert_equal(ary, Marshal.load(Marshal.dump(ary)), bug2548)
+ end
+
+ def test_symlink
+ assert_include(Marshal.dump([:a, :a]), ';')
+ end
+
+ def test_symlink_in_ivar
+ bug10991 = '[ruby-core:68587] [Bug #10991]'
+ sym = Marshal.load("\x04\x08" +
+ "I" ":\x0bKernel" +
+ ("\x06" +
+ ("I" ":\x07@a" +
+ ("\x06" ":\x07@b" "e;\x0""o:\x0bObject""\x0")) +
+ "0"))
+ assert_equal(:Kernel, sym, bug10991)
+ end
+
+ ClassUTF8 = eval("class R\u{e9}sum\u{e9}; self; end")
+
+ iso_8859_1 = Encoding::ISO_8859_1
+
+ structISO8859_1 = Struct.new("r\xe9sum\xe9".force_encoding(iso_8859_1).intern)
+ const_set("R\xe9sum\xe9".force_encoding(iso_8859_1), structISO8859_1)
+ structISO8859_1.name
+ StructISO8859_1 = structISO8859_1
+ classISO8859_1 = Class.new do
+ attr_accessor "r\xe9sum\xe9".force_encoding(iso_8859_1)
+ eval("def initialize(x) @r\xe9sum\xe9 = x; end".force_encoding(iso_8859_1))
+ end
+ const_set("R\xe9sum\xe92".force_encoding(iso_8859_1), classISO8859_1)
+ classISO8859_1.name
+ ClassISO8859_1 = classISO8859_1
+
+ def test_class_nonascii
+ a = ClassUTF8.new
+ assert_instance_of(ClassUTF8, Marshal.load(Marshal.dump(a)), '[ruby-core:24790]')
+
+ bug1932 = '[ruby-core:24882]'
+
+ a = StructISO8859_1.new(10)
+ assert_nothing_raised(bug1932) do
+ assert_equal(a, Marshal.load(Marshal.dump(a)), bug1932)
+ end
+ a.__send__("#{StructISO8859_1.members[0]}=", a)
+ assert_nothing_raised(bug1932) do
+ assert_equal(a, Marshal.load(Marshal.dump(a)), bug1932)
+ end
+
+ a = ClassISO8859_1.new(10)
+ assert_nothing_raised(bug1932) do
+ b = Marshal.load(Marshal.dump(a))
+ assert_equal(ClassISO8859_1, b.class, bug1932)
+ assert_equal(a.instance_variables, b.instance_variables, bug1932)
+ a.instance_variables.each do |i|
+ assert_equal(a.instance_variable_get(i), b.instance_variable_get(i), bug1932)
+ end
+ end
+ a.__send__(a.methods(true).grep(/=\z/)[0], a)
+ assert_nothing_raised(bug1932) do
+ b = Marshal.load(Marshal.dump(a))
+ assert_equal(ClassISO8859_1, b.class, bug1932)
+ assert_equal(a.instance_variables, b.instance_variables, bug1932)
+ assert_equal(b, b.instance_variable_get(a.instance_variables[0]), bug1932)
+ end
+ end
+
+ def test_regexp2
+ assert_equal(/\\u/, Marshal.load("\004\b/\b\\\\u\000"))
+ assert_equal(/u/, Marshal.load("\004\b/\a\\u\000"))
+ assert_equal(/u/, Marshal.load("\004\bI/\a\\u\000\006:\016@encoding\"\vEUC-JP"))
+
+ bug2109 = '[ruby-core:25625]'
+ a = "\x82\xa0".force_encoding(Encoding::Windows_31J)
+ b = "\x82\xa2".force_encoding(Encoding::Windows_31J)
+ c = [/#{a}/, /#{b}/]
+ assert_equal(c, Marshal.load(Marshal.dump(c)), bug2109)
+
+ assert_nothing_raised(ArgumentError, '[ruby-dev:40386]') do
+ re = Tempfile.create("marshal_regexp") do |f|
+ f.binmode.write("\x04\bI/\x00\x00\x06:\rencoding\"\rUS-ASCII")
+ f.rewind
+ re2 = Marshal.load(f)
+ re2
+ end
+ assert_equal(//, re)
+ end
+ end
+
+ class DumpTest
+ def marshal_dump
+ @@block.call(:marshal_dump)
+ end
+
+ def dump_each(&block)
+ @@block = block
+ Marshal.dump(self)
+ end
+ end
+
+ class LoadTest
+ def marshal_dump
+ nil
+ end
+ def marshal_load(obj)
+ @@block.call(:marshal_load)
+ end
+ def self.load_each(m, &block)
+ @@block = block
+ Marshal.load(m)
+ end
+ end
+
+ def test_context_switch
+ o = DumpTest.new
+ e = o.enum_for(:dump_each)
+ assert_equal(:marshal_dump, e.next)
+ GC.start
+ assert(true, '[ruby-dev:39425]')
+ assert_raise(StopIteration) {e.next}
+
+ o = LoadTest.new
+ m = Marshal.dump(o)
+ e = LoadTest.enum_for(:load_each, m)
+ assert_equal(:marshal_load, e.next)
+ GC.start
+ assert(true, '[ruby-dev:39425]')
+ assert_raise(StopIteration) {e.next}
+ end
+
+ def test_dump_buffer
+ bug2390 = '[ruby-dev:39744]'
+ w = ""
+ def w.write(str)
+ self << str.to_s
+ end
+ Marshal.dump(Object.new, w)
+ assert_not_empty(w, bug2390)
+ end
+
+ class C5
+ def marshal_dump
+ "foo"
+ end
+ def marshal_load(foo)
+ @foo = foo
+ end
+ def initialize(x)
+ @x = x
+ end
+ end
+ def test_marshal_dump
+ c = C5.new("bar")
+ s = Marshal.dump(c)
+ d = Marshal.load(s)
+ assert_equal("foo", d.instance_variable_get(:@foo))
+ assert_equal(false, d.instance_variable_defined?(:@x))
+ end
+
+ class C6
+ def initialize
+ @stdin = STDIN
+ end
+ attr_reader :stdin
+ def marshal_dump
+ 1
+ end
+ def marshal_load(x)
+ @stdin = STDIN
+ end
+ end
+ def test_marshal_dump_extra_iv
+ o = C6.new
+ m = nil
+ assert_nothing_raised("[ruby-dev:21475] [ruby-dev:39845]") {
+ m = Marshal.dump(o)
+ }
+ o2 = Marshal.load(m)
+ assert_equal(STDIN, o2.stdin)
+ end
+
+ def test_marshal_string_encoding
+ o1 = ["foo".force_encoding("EUC-JP")] + [ "bar" ] * 2
+ m = Marshal.dump(o1)
+ o2 = Marshal.load(m)
+ assert_equal(o1, o2, "[ruby-dev:40388]")
+ end
+
+ def test_marshal_regexp_encoding
+ o1 = [Regexp.new("r1".force_encoding("EUC-JP"))] + ["r2"] * 2
+ m = Marshal.dump(o1)
+ o2 = Marshal.load(m)
+ assert_equal(o1, o2, "[ruby-dev:40416]")
+ end
+
+ def test_marshal_encoding_encoding
+ o1 = [Encoding.find("EUC-JP")] + ["r2"] * 2
+ m = Marshal.dump(o1)
+ o2 = Marshal.load(m)
+ assert_equal(o1, o2)
+ end
+
+ def test_marshal_symbol_ascii8bit
+ bug6209 = '[ruby-core:43762]'
+ o1 = "\xff".force_encoding("ASCII-8BIT").intern
+ m = Marshal.dump(o1)
+ o2 = nil
+ assert_nothing_raised(EncodingError, bug6209) {o2 = Marshal.load(m)}
+ assert_equal(o1, o2, bug6209)
+ end
+
+ class PrivateClass
+ def initialize(foo)
+ @foo = foo
+ end
+ attr_reader :foo
+ end
+ private_constant :PrivateClass
+
+ def test_marshal_private_class
+ o1 = PrivateClass.new("test")
+ o2 = Marshal.load(Marshal.dump(o1))
+ assert_equal(o1.class, o2.class)
+ assert_equal(o1.foo, o2.foo)
+ end
+
+ def test_marshal_complex
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x05")}
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x06i\x00")}
+ assert_equal(Complex(1, 2), Marshal.load("\x04\bU:\fComplex[\ai\x06i\a"))
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\bi\x00i\x00i\x00")}
+ end
+
+ def test_marshal_rational
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\x05")}
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\x06i\x00")}
+ assert_equal(Rational(1, 2), Marshal.load("\x04\bU:\rRational[\ai\x06i\a"))
+ assert_raise(ArgumentError){Marshal.load("\x04\bU:\rRational[\bi\x00i\x00i\x00")}
+ end
+
+ def test_marshal_flonum_reference
+ bug7348 = '[ruby-core:49323]'
+ e = []
+ ary = [ [2.0, e], [e] ]
+ assert_equal(ary, Marshal.load(Marshal.dump(ary)), bug7348)
+ end
+
+ class TestClass
+ end
+
+ module TestModule
+ end
+
+ def test_marshal_load_should_not_taint_classes
+ bug7325 = '[ruby-core:49198]'
+ for c in [TestClass, TestModule]
+ assert_not_predicate(c, :tainted?)
+ c2 = Marshal.load(Marshal.dump(c).taint)
+ assert_same(c, c2)
+ assert_not_predicate(c, :tainted?, bug7325)
+ end
+ end
+
+ class Bug7627 < Struct.new(:bar)
+ attr_accessor :foo
+
+ def marshal_dump; 'dump'; end # fake dump data
+ def marshal_load(*); end # do nothing
+ end
+
+ def test_marshal_dump_struct_ivar
+ bug7627 = '[ruby-core:51163]'
+ obj = Bug7627.new
+ obj.foo = '[Bug #7627]'
+
+ dump = Marshal.dump(obj)
+ loaded = Marshal.load(dump)
+
+ assert_equal(obj, loaded, bug7627)
+ assert_nil(loaded.foo, bug7627)
+ end
+
+ class LoadData
+ attr_reader :data
+ def initialize(data)
+ @data = data
+ end
+ alias marshal_dump data
+ alias marshal_load initialize
+ end
+
+ class Bug8276 < LoadData
+ def initialize(*)
+ super
+ freeze
+ end
+ alias marshal_load initialize
+ end
+
+ class FrozenData < LoadData
+ def marshal_load(data)
+ super
+ data.instance_variables.each do |iv|
+ instance_variable_set(iv, data.instance_variable_get(iv))
+ end
+ freeze
+ end
+ end
+
+ def test_marshal_dump_excess_encoding
+ bug8276 = '[ruby-core:54334] [Bug #8276]'
+ t = Bug8276.new(bug8276)
+ s = Marshal.dump(t)
+ assert_nothing_raised(RuntimeError, bug8276) {s = Marshal.load(s)}
+ assert_equal(t.data, s.data, bug8276)
+ end
+
+ def test_marshal_dump_ivar
+ s = "data with ivar"
+ s.instance_variable_set(:@t, 42)
+ t = Bug8276.new(s)
+ s = Marshal.dump(t)
+ assert_raise(RuntimeError) {Marshal.load(s)}
+ end
+
+ def test_marshal_load_ivar
+ s = "data with ivar"
+ s.instance_variable_set(:@t, 42)
+ hook = ->(v) {
+ if LoadData === v
+ assert_send([v, :instance_variable_defined?, :@t], v.class.name)
+ assert_equal(42, v.instance_variable_get(:@t), v.class.name)
+ end
+ v
+ }
+ [LoadData, FrozenData].each do |klass|
+ t = klass.new(s)
+ d = Marshal.dump(t)
+ v = assert_nothing_raised(RuntimeError) {break Marshal.load(d, hook)}
+ assert_send([v, :instance_variable_defined?, :@t], klass.name)
+ assert_equal(42, v.instance_variable_get(:@t), klass.name)
+ end
+ end
+
+ def test_class_ivar
+ assert_raise(TypeError) {Marshal.load("\x04\x08Ic\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_not_operator(TestClass, :instance_variable_defined?, :@bug)
+ end
+
+ def test_module_ivar
+ assert_raise(TypeError) {Marshal.load("\x04\x08Im\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_not_operator(TestModule, :instance_variable_defined?, :@bug)
+ end
+
+ class TestForRespondToFalse
+ def respond_to?(a)
+ false
+ end
+ end
+
+ def test_marshal_respond_to_arity
+ assert_nothing_raised(ArgumentError, '[Bug #7722]') do
+ Marshal.dump(TestForRespondToFalse.new)
+ end
+ end
+
+ def test_packed_string
+ packed = ["foo"].pack("p")
+ bare = "".force_encoding(Encoding::ASCII_8BIT) << packed
+ assert_equal(Marshal.dump(bare), Marshal.dump(packed))
+ end
+
+ def test_untainted_numeric
+ bug8945 = '[ruby-core:57346] [Bug #8945] Numerics never be tainted'
+ b = 1 << 32
+ b *= b until Bignum === b
+ tainted = [0, 1.0, 1.72723e-77, b].select do |x|
+ Marshal.load(Marshal.dump(x).taint).tainted?
+ end
+ assert_empty(tainted.map {|x| [x, x.class]}, bug8945)
+ end
+
+ class Bug9523
+ attr_reader :cc
+ def marshal_dump
+ callcc {|c| @cc = c }
+ nil
+ end
+ def marshal_load(v)
+ end
+ end
+
+ def test_continuation
+ require "continuation"
+ c = Bug9523.new
+ assert_raise_with_message(RuntimeError, /Marshal\.dump reentered at marshal_dump/) do
+ Marshal.dump(c)
+ c.cc.call
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_math.rb b/jni/ruby/test/ruby/test_math.rb
new file mode 100644
index 0000000..c4d0ff9
--- /dev/null
+++ b/jni/ruby/test/ruby/test_math.rb
@@ -0,0 +1,292 @@
+require 'test/unit'
+
+class TestMath < Test::Unit::TestCase
+ def assert_infinity(a, *rest)
+ rest = ["not infinity: #{a.inspect}"] if rest.empty?
+ assert_predicate(a, :infinite?, *rest)
+ end
+
+ def assert_nan(a, *rest)
+ rest = ["not nan: #{a.inspect}"] if rest.empty?
+ assert_predicate(a, :nan?, *rest)
+ end
+
+ def assert_float(a, b)
+ err = [Float::EPSILON * 4, [a.abs, b.abs].max * Float::EPSILON * 256].max
+ assert_in_delta(a, b, err)
+ end
+ alias check assert_float
+
+ def test_atan2
+ check(+0.0, Math.atan2(+0.0, +0.0))
+ check(-0.0, Math.atan2(-0.0, +0.0))
+ check(+Math::PI, Math.atan2(+0.0, -0.0))
+ check(-Math::PI, Math.atan2(-0.0, -0.0))
+
+ inf = Float::INFINITY
+ expected = 3.0 * Math::PI / 4.0
+ assert_nothing_raised { check(+expected, Math.atan2(+inf, -inf)) }
+ assert_nothing_raised { check(-expected, Math.atan2(-inf, -inf)) }
+ expected = Math::PI / 4.0
+ assert_nothing_raised { check(+expected, Math.atan2(+inf, +inf)) }
+ assert_nothing_raised { check(-expected, Math.atan2(-inf, +inf)) }
+
+ check(0, Math.atan2(0, 1))
+ check(Math::PI / 4, Math.atan2(1, 1))
+ check(Math::PI / 2, Math.atan2(1, 0))
+ end
+
+ def test_cos
+ check(1.0, Math.cos(0 * Math::PI / 4))
+ check(1.0 / Math.sqrt(2), Math.cos(1 * Math::PI / 4))
+ check(0.0, Math.cos(2 * Math::PI / 4))
+ check(-1.0, Math.cos(4 * Math::PI / 4))
+ check(0.0, Math.cos(6 * Math::PI / 4))
+ end
+
+ def test_sin
+ check(0.0, Math.sin(0 * Math::PI / 4))
+ check(1.0 / Math.sqrt(2), Math.sin(1 * Math::PI / 4))
+ check(1.0, Math.sin(2 * Math::PI / 4))
+ check(0.0, Math.sin(4 * Math::PI / 4))
+ check(-1.0, Math.sin(6 * Math::PI / 4))
+ end
+
+ def test_tan
+ check(0.0, Math.tan(0 * Math::PI / 4))
+ check(1.0, Math.tan(1 * Math::PI / 4))
+ assert_operator(Math.tan(2 * Math::PI / 4).abs, :>, 1024)
+ check(0.0, Math.tan(4 * Math::PI / 4))
+ assert_operator(Math.tan(6 * Math::PI / 4).abs, :>, 1024)
+ end
+
+ def test_acos
+ check(0 * Math::PI / 4, Math.acos( 1.0))
+ check(1 * Math::PI / 4, Math.acos( 1.0 / Math.sqrt(2)))
+ check(2 * Math::PI / 4, Math.acos( 0.0))
+ check(4 * Math::PI / 4, Math.acos(-1.0))
+ assert_raise(Math::DomainError) { Math.acos(+1.0 + Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.acos(-1.0 - Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.acos(2.0) }
+ end
+
+ def test_asin
+ check( 0 * Math::PI / 4, Math.asin( 0.0))
+ check( 1 * Math::PI / 4, Math.asin( 1.0 / Math.sqrt(2)))
+ check( 2 * Math::PI / 4, Math.asin( 1.0))
+ check(-2 * Math::PI / 4, Math.asin(-1.0))
+ assert_raise(Math::DomainError) { Math.asin(+1.0 + Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.asin(-1.0 - Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.asin(2.0) }
+ end
+
+ def test_atan
+ check( 0 * Math::PI / 4, Math.atan( 0.0))
+ check( 1 * Math::PI / 4, Math.atan( 1.0))
+ check( 2 * Math::PI / 4, Math.atan(1.0 / 0.0))
+ check(-1 * Math::PI / 4, Math.atan(-1.0))
+ end
+
+ def test_cosh
+ check(1, Math.cosh(0))
+ check((Math::E ** 1 + Math::E ** -1) / 2, Math.cosh(1))
+ check((Math::E ** 2 + Math::E ** -2) / 2, Math.cosh(2))
+ end
+
+ def test_sinh
+ check(0, Math.sinh(0))
+ check((Math::E ** 1 - Math::E ** -1) / 2, Math.sinh(1))
+ check((Math::E ** 2 - Math::E ** -2) / 2, Math.sinh(2))
+ end
+
+ def test_tanh
+ check(Math.sinh(0) / Math.cosh(0), Math.tanh(0))
+ check(Math.sinh(1) / Math.cosh(1), Math.tanh(1))
+ check(Math.sinh(2) / Math.cosh(2), Math.tanh(2))
+ end
+
+ def test_acosh
+ check(0, Math.acosh(1))
+ check(1, Math.acosh((Math::E ** 1 + Math::E ** -1) / 2))
+ check(2, Math.acosh((Math::E ** 2 + Math::E ** -2) / 2))
+ assert_raise(Math::DomainError) { Math.acosh(1.0 - Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.acosh(0) }
+ end
+
+ def test_asinh
+ check(0, Math.asinh(0))
+ check(1, Math.asinh((Math::E ** 1 - Math::E ** -1) / 2))
+ check(2, Math.asinh((Math::E ** 2 - Math::E ** -2) / 2))
+ end
+
+ def test_atanh
+ check(0, Math.atanh(Math.sinh(0) / Math.cosh(0)))
+ check(1, Math.atanh(Math.sinh(1) / Math.cosh(1)))
+ check(2, Math.atanh(Math.sinh(2) / Math.cosh(2)))
+ assert_nothing_raised { assert_infinity(Math.atanh(1)) }
+ assert_nothing_raised { assert_infinity(-Math.atanh(-1)) }
+ assert_raise(Math::DomainError) { Math.atanh(+1.0 + Float::EPSILON) }
+ assert_raise(Math::DomainError) { Math.atanh(-1.0 - Float::EPSILON) }
+ end
+
+ def test_exp
+ check(1, Math.exp(0))
+ check(Math.sqrt(Math::E), Math.exp(0.5))
+ check(Math::E, Math.exp(1))
+ check(Math::E ** 2, Math.exp(2))
+ end
+
+ def test_log
+ check(0, Math.log(1))
+ check(1, Math.log(Math::E))
+ check(0, Math.log(1, 10))
+ check(1, Math.log(10, 10))
+ check(2, Math.log(100, 10))
+ check(Math.log(2.0 ** 64), Math.log(1 << 64))
+ assert_equal(1.0/0, Math.log(1.0/0))
+ assert_nothing_raised { assert_infinity(-Math.log(+0.0)) }
+ assert_nothing_raised { assert_infinity(-Math.log(-0.0)) }
+ assert_raise(Math::DomainError) { Math.log(-1.0) }
+ assert_raise(TypeError) { Math.log(1,nil) }
+ assert_raise(Math::DomainError, '[ruby-core:62309] [ruby-Bug #9797]') { Math.log(1.0, -1.0) }
+ assert_nothing_raised { assert_nan(Math.log(0.0, 0.0)) }
+ end
+
+ def test_log2
+ check(0, Math.log2(1))
+ check(1, Math.log2(2))
+ check(2, Math.log2(4))
+ check(Math.log2(2.0 ** 64), Math.log2(1 << 64))
+ assert_equal(1.0/0, Math.log2(1.0/0))
+ assert_nothing_raised { assert_infinity(-Math.log2(+0.0)) }
+ assert_nothing_raised { assert_infinity(-Math.log2(-0.0)) }
+ assert_raise(Math::DomainError) { Math.log2(-1.0) }
+ end
+
+ def test_log10
+ check(0, Math.log10(1))
+ check(1, Math.log10(10))
+ check(2, Math.log10(100))
+ check(Math.log10(2.0 ** 64), Math.log10(1 << 64))
+ assert_equal(1.0/0, Math.log10(1.0/0))
+ assert_nothing_raised { assert_infinity(-Math.log10(+0.0)) }
+ assert_nothing_raised { assert_infinity(-Math.log10(-0.0)) }
+ assert_raise(Math::DomainError) { Math.log10(-1.0) }
+ end
+
+ def test_sqrt
+ check(0, Math.sqrt(0))
+ check(1, Math.sqrt(1))
+ check(2, Math.sqrt(4))
+ assert_equal(1.0/0, Math.sqrt(1.0/0))
+ assert_equal("0.0", Math.sqrt(-0.0).to_s) # insure it is +0.0, not -0.0
+ assert_raise(Math::DomainError) { Math.sqrt(-1.0) }
+ end
+
+ def test_frexp
+ check(0.0, Math.frexp(0.0).first)
+ assert_equal(0, Math.frexp(0).last)
+ check(0.5, Math.frexp(0.5).first)
+ assert_equal(0, Math.frexp(0.5).last)
+ check(0.5, Math.frexp(1.0).first)
+ assert_equal(1, Math.frexp(1.0).last)
+ check(0.5, Math.frexp(2.0).first)
+ assert_equal(2, Math.frexp(2.0).last)
+ check(0.75, Math.frexp(3.0).first)
+ assert_equal(2, Math.frexp(3.0).last)
+ end
+
+ def test_ldexp
+ check(0.0, Math.ldexp(0.0, 0.0))
+ check(0.5, Math.ldexp(0.5, 0.0))
+ check(1.0, Math.ldexp(0.5, 1.0))
+ check(2.0, Math.ldexp(0.5, 2.0))
+ check(3.0, Math.ldexp(0.75, 2.0))
+ end
+
+ def test_hypot
+ check(5, Math.hypot(3, 4))
+ end
+
+ def test_erf
+ check(0, Math.erf(0))
+ check(1, Math.erf(1.0 / 0.0))
+ end
+
+ def test_erfc
+ check(1, Math.erfc(0))
+ check(0, Math.erfc(1.0 / 0.0))
+ end
+
+ def test_gamma
+ sqrt_pi = Math.sqrt(Math::PI)
+ check(4 * sqrt_pi / 3, Math.gamma(-1.5))
+ check(-2 * sqrt_pi, Math.gamma(-0.5))
+ check(sqrt_pi, Math.gamma(0.5))
+ check(1, Math.gamma(1))
+ check(sqrt_pi / 2, Math.gamma(1.5))
+ check(1, Math.gamma(2))
+ check(3 * sqrt_pi / 4, Math.gamma(2.5))
+ check(2, Math.gamma(3))
+ check(15 * sqrt_pi / 8, Math.gamma(3.5))
+ check(6, Math.gamma(4))
+
+ # no SEGV [ruby-core:25257]
+ 31.upto(65) do |i|
+ i = 1 << i
+ assert_infinity(Math.gamma(i), "Math.gamma(#{i}) should be INF")
+ assert_infinity(Math.gamma(i-1), "Math.gamma(#{i-1}) should be INF")
+ end
+
+ assert_raise(Math::DomainError) { Math.gamma(-Float::INFINITY) }
+ end
+
+ def test_lgamma
+ sqrt_pi = Math.sqrt(Math::PI)
+
+ g, s = Math.lgamma(-1.5)
+ check(Math.log(4 * sqrt_pi / 3), g)
+ assert_equal(s, 1)
+
+ g, s = Math.lgamma(-0.5)
+ check(Math.log(2 * sqrt_pi), g)
+ assert_equal(s, -1)
+
+ g, s = Math.lgamma(0.5)
+ check(Math.log(sqrt_pi), g)
+ assert_equal(s, 1)
+
+ assert_equal([0, 1], Math.lgamma(1))
+
+ g, s = Math.lgamma(1.5)
+ check(Math.log(sqrt_pi / 2), g)
+ assert_equal(s, 1)
+
+ assert_equal([0, 1], Math.lgamma(2))
+
+ g, s = Math.lgamma(2.5)
+ check(Math.log(3 * sqrt_pi / 4), g)
+ assert_equal(s, 1)
+
+ g, s = Math.lgamma(3)
+ check(Math.log(2), g)
+ assert_equal(s, 1)
+
+ g, s = Math.lgamma(3.5)
+ check(Math.log(15 * sqrt_pi / 8), g)
+ assert_equal(s, 1)
+
+ g, s = Math.lgamma(4)
+ check(Math.log(6), g)
+ assert_equal(s, 1)
+
+ assert_raise(Math::DomainError) { Math.lgamma(-Float::INFINITY) }
+ end
+
+ def test_cbrt
+ check(1, Math.cbrt(1))
+ check(-2, Math.cbrt(-8))
+ check(3, Math.cbrt(27))
+ check(-0.1, Math.cbrt(-0.001))
+ end
+end
diff --git a/jni/ruby/test/ruby/test_metaclass.rb b/jni/ruby/test/ruby/test_metaclass.rb
new file mode 100644
index 0000000..6386a02
--- /dev/null
+++ b/jni/ruby/test/ruby/test_metaclass.rb
@@ -0,0 +1,167 @@
+require 'test/unit'
+
+class TestMetaclass < Test::Unit::TestCase
+ class Foo; end
+ class Bar < Foo; end
+ class Baz; end
+
+ def setup
+ Object.class_eval do
+ def method_o; end
+ end
+ Module.class_eval do
+ def method_m; end
+ end
+ Class.class_eval do
+ def method_c; end
+ end
+ end
+ def teardown
+ Object.class_eval do
+ remove_method :method_o rescue nil
+ end
+ Module.class_eval do
+ remove_method :method_m rescue nil
+ end
+ Class.class_eval do
+ remove_method :method_c rescue nil
+ end
+ Object.class_eval do
+ class << self
+ remove_method :class_method_o rescue nil
+ end
+ end
+ Module.class_eval do
+ class << self
+ remove_method :class_method_m rescue nil
+ end
+ end
+ Class.class_eval do
+ class << self
+ remove_method :class_method_c rescue nil
+ end
+ end
+ Object.class_eval do
+ class << self
+ class << self
+ remove_method :metaclass_method_o rescue nil
+ end
+ end
+ end
+ Module.class_eval do
+ class << self
+ class << self
+ remove_method :metaclass_method_m rescue nil
+ end
+ end
+ end
+ Class.class_eval do
+ class << self
+ class << self
+ remove_method :metaclass_method_c rescue nil
+ end
+ end
+ end
+ end
+
+ def test_metaclass
+ class << Object
+ def class_method_o; end
+ end
+ class << Foo
+ def class_method_f; end
+ end
+ class << Baz
+ def class_method_b; end
+ end
+ assert_nothing_raised{ Bar.method_o }
+ assert_nothing_raised{ Bar.method_m }
+ assert_nothing_raised{ Bar.method_c }
+ assert_nothing_raised{ Bar.class_method_o }
+ assert_nothing_raised{ Bar.class_method_f }
+ assert_raise(NoMethodError){ Bar.class_method_b }
+
+ class << Module
+ def class_method_m; end
+ end
+ class << Class
+ def class_method_c; end
+ end
+ class << Object
+ class << self
+ def metaclass_method_o; end
+ end
+ end
+ class << Foo
+ class << self
+ def metaclass_method_f; end
+ end
+ end
+ class << Baz
+ class << self
+ def metaclass_method_b; end
+ end
+ end
+ metaclass_of_bar = class << Bar; self end
+ assert_nothing_raised{ metaclass_of_bar.method_o }
+ assert_nothing_raised{ metaclass_of_bar.method_m }
+ assert_nothing_raised{ metaclass_of_bar.method_c }
+ assert_nothing_raised{ metaclass_of_bar.class_method_o }
+ assert_raise(NoMethodError){ metaclass_of_bar.class_method_f }
+ assert_raise(NoMethodError){ metaclass_of_bar.class_method_b }
+ assert_nothing_raised{ metaclass_of_bar.class_method_m }
+ assert_nothing_raised{ metaclass_of_bar.class_method_c }
+ assert_nothing_raised{ metaclass_of_bar.metaclass_method_o }
+ assert_nothing_raised{ metaclass_of_bar.metaclass_method_f }
+ assert_raise(NoMethodError){ metaclass_of_bar.metaclass_method_b }
+
+ class << Module
+ class << self
+ def metaclass_method_m; end
+ end
+ end
+ class << Class
+ class << self
+ def metaclass_method_c; end
+ end
+ end
+ class << Object
+ class << self
+ class << self
+ def metametaclass_method_o; end
+ end
+ end
+ end
+ class << Foo
+ class << self
+ class << self
+ def metametaclass_method_f; end
+ end
+ end
+ end
+ class << Baz
+ class << self
+ class << self
+ def metametaclass_method_b; end
+ end
+ end
+ end
+ metametaclass_of_bar = class << metaclass_of_bar; self end
+ assert_nothing_raised{ metametaclass_of_bar.method_o }
+ assert_nothing_raised{ metametaclass_of_bar.method_m }
+ assert_nothing_raised{ metametaclass_of_bar.method_c }
+ assert_nothing_raised{ metametaclass_of_bar.class_method_o }
+ assert_raise(NoMethodError){ metametaclass_of_bar.class_method_f }
+ assert_raise(NoMethodError){ metametaclass_of_bar.class_method_b }
+ assert_nothing_raised{ metametaclass_of_bar.class_method_m }
+ assert_nothing_raised{ metametaclass_of_bar.class_method_c }
+ assert_nothing_raised{ metametaclass_of_bar.metaclass_method_o }
+ assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_f }
+ assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b }
+ assert_nothing_raised{ metametaclass_of_bar.metaclass_method_m }
+ assert_nothing_raised{ metametaclass_of_bar.metaclass_method_c }
+ assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_o }
+ assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_f }
+ assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_method.rb b/jni/ruby/test/ruby/test_method.rb
new file mode 100644
index 0000000..35ddc87
--- /dev/null
+++ b/jni/ruby/test/ruby/test_method.rb
@@ -0,0 +1,894 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+
+class TestMethod < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def m0() end
+ def m1(a) end
+ def m2(a, b) end
+ def mo1(a = nil, &b) end
+ def mo2(a, b = nil) end
+ def mo3(*a) end
+ def mo4(a, *b, &c) end
+ def mo5(a, *b, c) end
+ def mo6(a, *b, c, &d) end
+ def mo7(a, b = nil, *c, d, &e) end
+ def ma1((a), &b) nil && a end
+ def mk1(**) end
+ def mk2(**o) nil && o end
+ def mk3(a, **o) nil && o end
+ def mk4(a = nil, **o) nil && o end
+ def mk5(a, b = nil, **o) nil && o end
+ def mk6(a, b = nil, c, **o) nil && o end
+ def mk7(a, b = nil, *c, d, **o) nil && o end
+
+ class Base
+ def foo() :base end
+ end
+ class Derived < Base
+ def foo() :derived end
+ end
+ class T
+ def initialize; end
+ def initialize_copy(*) super end
+ def initialize_clone(*) super end
+ def initialize_dup(*) super end
+ def respond_to_missing?(*) super end
+ def normal_method; end
+ end
+ module M
+ def func; end
+ module_function :func
+ def meth; :meth end
+ end
+
+ def mv1() end
+ def mv2() end
+ private :mv2
+ def mv3() end
+ protected :mv3
+
+ class Visibility
+ def mv1() end
+ def mv2() end
+ private :mv2
+ def mv3() end
+ protected :mv3
+ end
+
+ def test_arity
+ assert_equal(0, method(:m0).arity)
+ assert_equal(1, method(:m1).arity)
+ assert_equal(2, method(:m2).arity)
+ assert_equal(-1, method(:mo1).arity)
+ assert_equal(-2, method(:mo2).arity)
+ assert_equal(-1, method(:mo3).arity)
+ assert_equal(-2, method(:mo4).arity)
+ assert_equal(-3, method(:mo5).arity)
+ assert_equal(-3, method(:mo6).arity)
+ assert_equal(-1, method(:mk1).arity)
+ assert_equal(-1, method(:mk2).arity)
+ assert_equal(-2, method(:mk3).arity)
+ assert_equal(-1, method(:mk4).arity)
+ assert_equal(-2, method(:mk5).arity)
+ assert_equal(-3, method(:mk6).arity)
+ assert_equal(-3, method(:mk7).arity)
+ end
+
+ def test_arity_special
+ assert_equal(-1, method(:__send__).arity)
+ end
+
+ def test_unbind
+ assert_equal(:derived, Derived.new.foo)
+ um = Derived.new.method(:foo).unbind
+ assert_instance_of(UnboundMethod, um)
+ Derived.class_eval do
+ def foo() :changed end
+ end
+ assert_equal(:changed, Derived.new.foo)
+ assert_equal(:derived, um.bind(Derived.new).call)
+ assert_raise(TypeError) do
+ um.bind(Base.new)
+ end
+ end
+
+ def test_callee
+ assert_equal(:test_callee, __method__)
+ assert_equal(:m, Class.new {def m; __method__; end}.new.m)
+ assert_equal(:m, Class.new {def m; tap{return __method__}; end}.new.m)
+ assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m)
+ assert_equal(:m, Class.new {define_method(:m) {tap{return __method__}}}.new.m)
+ assert_nil(eval("class TestCallee; __method__; end"))
+
+ assert_equal(:test_callee, __callee__)
+ [
+ ["method", Class.new {def m; __callee__; end},],
+ ["block", Class.new {def m; tap{return __callee__}; end},],
+ ["define_method", Class.new {define_method(:m) {__callee__}}],
+ ["define_method block", Class.new {define_method(:m) {tap{return __callee__}}}],
+ ].each do |mesg, c|
+ c.class_eval {alias m2 m}
+ o = c.new
+ assert_equal(:m, o.m, mesg)
+ assert_equal(:m2, o.m2, mesg)
+ end
+ assert_nil(eval("class TestCallee; __callee__; end"))
+ end
+
+ def test_method_in_define_method_block
+ bug4606 = '[ruby-core:35386]'
+ c = Class.new do
+ [:m1, :m2].each do |m|
+ define_method(m) do
+ __method__
+ end
+ end
+ end
+ assert_equal(:m1, c.new.m1, bug4606)
+ assert_equal(:m2, c.new.m2, bug4606)
+ end
+
+ def test_method_in_block_in_define_method_block
+ bug4606 = '[ruby-core:35386]'
+ c = Class.new do
+ [:m1, :m2].each do |m|
+ define_method(m) do
+ tap { return __method__ }
+ end
+ end
+ end
+ assert_equal(:m1, c.new.m1, bug4606)
+ assert_equal(:m2, c.new.m2, bug4606)
+ end
+
+ def test_body
+ o = Object.new
+ def o.foo; end
+ assert_nothing_raised { RubyVM::InstructionSequence.disasm(o.method(:foo)) }
+ assert_nothing_raised { RubyVM::InstructionSequence.disasm("x".method(:upcase)) }
+ assert_nothing_raised { RubyVM::InstructionSequence.disasm(method(:to_s).to_proc) }
+ end
+
+ def test_new
+ c1 = Class.new
+ c1.class_eval { def foo; :foo; end }
+ c2 = Class.new(c1)
+ c2.class_eval { private :foo }
+ o = c2.new
+ o.extend(Module.new)
+ assert_raise(NameError) { o.method(:bar) }
+ assert_raise(NameError) { o.public_method(:foo) }
+ assert_equal(:foo, o.method(:foo).call)
+ end
+
+ def test_eq
+ o = Object.new
+ class << o
+ def foo; end
+ alias bar foo
+ def baz; end
+ end
+ assert_not_equal(o.method(:foo), nil)
+ m = o.method(:foo)
+ def m.foo; end
+ assert_not_equal(o.method(:foo), m)
+ assert_equal(o.method(:foo), o.method(:foo))
+ assert_equal(o.method(:foo), o.method(:bar))
+ assert_not_equal(o.method(:foo), o.method(:baz))
+ end
+
+ def test_hash
+ o = Object.new
+ def o.foo; end
+ assert_kind_of(Integer, o.method(:foo).hash)
+ assert_equal(Array.instance_method(:map).hash, Array.instance_method(:collect).hash)
+ end
+
+ def test_owner
+ c = Class.new do
+ def foo; end
+ end
+ assert_equal(c, c.instance_method(:foo).owner)
+ c2 = Class.new(c)
+ assert_equal(c, c2.instance_method(:foo).owner)
+ end
+
+ def test_owner_missing
+ c = Class.new do
+ def respond_to_missing?(name, bool)
+ name == :foo
+ end
+ end
+ c2 = Class.new(c)
+ assert_equal(c, c.new.method(:foo).owner)
+ assert_equal(c2, c2.new.method(:foo).owner)
+ end
+
+ def test_receiver_name_owner
+ o = Object.new
+ def o.foo; end
+ m = o.method(:foo)
+ assert_equal(o, m.receiver)
+ assert_equal(:foo, m.name)
+ assert_equal(class << o; self; end, m.owner)
+ assert_equal(:foo, m.unbind.name)
+ assert_equal(class << o; self; end, m.unbind.owner)
+ class << o
+ alias bar foo
+ end
+ m = o.method(:bar)
+ assert_equal(:bar, m.name)
+ assert_equal(:foo, m.original_name)
+ end
+
+ def test_instance_method
+ c = Class.new
+ c.class_eval do
+ def foo; :foo; end
+ private :foo
+ end
+ o = c.new
+ o.method(:foo).unbind
+ assert_raise(NoMethodError) { o.foo }
+ c.instance_method(:foo).bind(o)
+ assert_equal(:foo, o.instance_eval { foo })
+ assert_raise(NameError) { c.public_instance_method(:foo) }
+ def o.bar; end
+ m = o.method(:bar).unbind
+ assert_raise(TypeError) { m.bind(Object.new) }
+
+ feature4254 = '[ruby-core:34267]'
+ m = M.instance_method(:meth)
+ assert_equal(:meth, m.bind(Object.new).call, feature4254)
+ end
+
+ def test_define_method
+ c = Class.new
+ c.class_eval { def foo; :foo; end }
+ o = c.new
+ def o.bar; :bar; end
+ assert_raise(TypeError) do
+ c.class_eval { define_method(:foo, :foo) }
+ end
+ assert_raise(ArgumentError) do
+ c.class_eval { define_method }
+ end
+ c2 = Class.new(c)
+ c2.class_eval { define_method(:baz, o.method(:foo)) }
+ assert_equal(:foo, c2.new.baz)
+ assert_raise(TypeError) do
+ Class.new.class_eval { define_method(:foo, o.method(:foo)) }
+ end
+ assert_raise(TypeError) do
+ Class.new.class_eval { define_method(:bar, o.method(:bar)) }
+ end
+ end
+
+ def test_define_singleton_method
+ o = Object.new
+ def o.foo(c)
+ c.class_eval { define_method(:foo) }
+ end
+ c = Class.new
+ o.foo(c) { :foo }
+ assert_equal(:foo, c.new.foo)
+
+ o = Object.new
+ o.instance_eval { define_singleton_method(:foo) { :foo } }
+ assert_equal(:foo, o.foo)
+
+ assert_raise(TypeError) do
+ Class.new.class_eval { define_method(:foo, Object.new) }
+ end
+
+ assert_raise(TypeError) do
+ Module.new.module_eval {define_method(:foo, Base.instance_method(:foo))}
+ end
+ end
+
+ def test_define_singleton_method_with_extended_method
+ bug8686 = "[ruby-core:56174]"
+
+ m = Module.new do
+ extend self
+
+ def a
+ "a"
+ end
+ end
+
+ assert_nothing_raised(bug8686) do
+ m.define_singleton_method(:a, m.method(:a))
+ end
+ end
+
+ def test_define_method_transplating
+ feature4254 = '[ruby-core:34267]'
+ m = Module.new {define_method(:meth, M.instance_method(:meth))}
+ assert_equal(:meth, Object.new.extend(m).meth, feature4254)
+ c = Class.new {define_method(:meth, M.instance_method(:meth))}
+ assert_equal(:meth, c.new.meth, feature4254)
+ end
+
+ def test_define_method_visibility
+ c = Class.new do
+ public
+ define_method(:foo) {:foo}
+ protected
+ define_method(:bar) {:bar}
+ private
+ define_method(:baz) {:baz}
+ end
+
+ assert_equal(true, c.public_method_defined?(:foo))
+ assert_equal(false, c.public_method_defined?(:bar))
+ assert_equal(false, c.public_method_defined?(:baz))
+
+ assert_equal(false, c.protected_method_defined?(:foo))
+ assert_equal(true, c.protected_method_defined?(:bar))
+ assert_equal(false, c.protected_method_defined?(:baz))
+
+ assert_equal(false, c.private_method_defined?(:foo))
+ assert_equal(false, c.private_method_defined?(:bar))
+ assert_equal(true, c.private_method_defined?(:baz))
+
+ m = Module.new do
+ module_function
+ define_method(:foo) {:foo}
+ end
+ assert_equal(true, m.respond_to?(:foo))
+ assert_equal(false, m.public_method_defined?(:foo))
+ assert_equal(false, m.protected_method_defined?(:foo))
+ assert_equal(true, m.private_method_defined?(:foo))
+ end
+
+ def test_define_method_in_private_scope
+ bug9005 = '[ruby-core:57747] [Bug #9005]'
+ c = Class.new
+ class << c
+ public :define_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|c|c.define_method(:x) {|x|throw x}}").call(c)
+ o = c.new
+ assert_throw(bug9005) {o.x(bug9005)}
+ end
+
+ def test_singleton_define_method_in_private_scope
+ bug9141 = '[ruby-core:58497] [Bug #9141]'
+ o = Object.new
+ class << o
+ public :define_singleton_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|o|o.define_singleton_method(:x) {|x|throw x}}").call(o)
+ assert_throw(bug9141) do
+ o.x(bug9141)
+ end
+ end
+
+ def test_super_in_proc_from_define_method
+ c1 = Class.new {
+ def m
+ :m1
+ end
+ }
+ c2 = Class.new(c1) { define_method(:m) { Proc.new { super() } } }
+ # c2.new.m.call should return :m1, but currently it raise NoMethodError.
+ # see [Bug #4881] and [Bug #3136]
+ assert_raise(NoMethodError) {
+ c2.new.m.call
+ }
+ end
+
+ def test_clone
+ o = Object.new
+ def o.foo; :foo; end
+ m = o.method(:foo)
+ def m.bar; :bar; end
+ assert_equal(:foo, m.clone.call)
+ assert_equal(:bar, m.clone.bar)
+ end
+
+ def test_inspect
+ o = Object.new
+ def o.foo; end
+ m = o.method(:foo)
+ assert_equal("#<Method: #{ o.inspect }.foo>", m.inspect)
+ m = o.method(:foo)
+ assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect)
+
+ c = Class.new
+ c.class_eval { def foo; end; }
+ m = c.new.method(:foo)
+ assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect)
+ m = c.instance_method(:foo)
+ assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect)
+
+ c2 = Class.new(c)
+ c2.class_eval { private :foo }
+ m2 = c2.new.method(:foo)
+ assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo>", m2.inspect)
+
+ bug7806 = '[ruby-core:52048] [Bug #7806]'
+ c3 = Class.new(c)
+ c3.class_eval { alias bar foo }
+ m3 = c3.new.method(:bar)
+ assert_equal("#<Method: #{c3.inspect}(#{c.inspect})#bar(foo)>", m3.inspect, bug7806)
+ end
+
+ def test_callee_top_level
+ assert_in_out_err([], "p __callee__", %w(nil), [])
+ end
+
+ def test_caller_top_level
+ assert_in_out_err([], "p caller", %w([]), [])
+ end
+
+ def test_caller_negative_level
+ assert_raise(ArgumentError) { caller(-1) }
+ end
+
+ def test_attrset_ivar
+ c = Class.new
+ c.class_eval { attr_accessor :foo }
+ o = c.new
+ o.method(:foo=).call(42)
+ assert_equal(42, o.foo)
+ assert_raise(ArgumentError) { o.method(:foo=).call(1, 2, 3) }
+ assert_raise(ArgumentError) { o.method(:foo).call(1) }
+ end
+
+ def test_default_accessibility
+ tmethods = T.public_instance_methods
+ assert_include tmethods, :normal_method, 'normal methods are public by default'
+ assert_not_include tmethods, :initialize, '#initialize is private'
+ assert_not_include tmethods, :initialize_copy, '#initialize_copy is private'
+ assert_not_include tmethods, :initialize_clone, '#initialize_clone is private'
+ assert_not_include tmethods, :initialize_dup, '#initialize_dup is private'
+ assert_not_include tmethods, :respond_to_missing?, '#respond_to_missing? is private'
+ mmethods = M.public_instance_methods
+ assert_not_include mmethods, :func, 'module methods are private by default'
+ assert_include mmethods, :meth, 'normal methods are public by default'
+ end
+
+ define_method(:pm0) {||}
+ define_method(:pm1) {|a|}
+ define_method(:pm2) {|a, b|}
+ define_method(:pmo1) {|a = nil, &b|}
+ define_method(:pmo2) {|a, b = nil|}
+ define_method(:pmo3) {|*a|}
+ define_method(:pmo4) {|a, *b, &c|}
+ define_method(:pmo5) {|a, *b, c|}
+ define_method(:pmo6) {|a, *b, c, &d|}
+ define_method(:pmo7) {|a, b = nil, *c, d, &e|}
+ define_method(:pma1) {|(a), &b| nil && a}
+ define_method(:pmk1) {|**|}
+ define_method(:pmk2) {|**o|}
+ define_method(:pmk3) {|a, **o|}
+ define_method(:pmk4) {|a = nil, **o|}
+ define_method(:pmk5) {|a, b = nil, **o|}
+ define_method(:pmk6) {|a, b = nil, c, **o|}
+ define_method(:pmk7) {|a, b = nil, *c, d, **o|}
+
+ def test_bound_parameters
+ assert_equal([], method(:m0).parameters)
+ assert_equal([[:req, :a]], method(:m1).parameters)
+ assert_equal([[:req, :a], [:req, :b]], method(:m2).parameters)
+ assert_equal([[:opt, :a], [:block, :b]], method(:mo1).parameters)
+ assert_equal([[:req, :a], [:opt, :b]], method(:mo2).parameters)
+ assert_equal([[:rest, :a]], method(:mo3).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:mo4).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters)
+ assert_equal([[:req], [:block, :b]], method(:ma1).parameters)
+ assert_equal([[:keyrest]], method(:mk1).parameters)
+ assert_equal([[:keyrest, :o]], method(:mk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], method(:mk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], method(:mk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:mk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:mk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters)
+ end
+
+ def test_unbound_parameters
+ assert_equal([], self.class.instance_method(:m0).parameters)
+ assert_equal([[:req, :a]], self.class.instance_method(:m1).parameters)
+ assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:m2).parameters)
+ assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:mo1).parameters)
+ assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:mo2).parameters)
+ assert_equal([[:rest, :a]], self.class.instance_method(:mo3).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:mo4).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters)
+ assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters)
+ assert_equal([[:keyrest]], self.class.instance_method(:mk1).parameters)
+ assert_equal([[:keyrest, :o]], self.class.instance_method(:mk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:mk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:mk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:mk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:mk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters)
+ end
+
+ def test_bmethod_bound_parameters
+ assert_equal([], method(:pm0).parameters)
+ assert_equal([[:req, :a]], method(:pm1).parameters)
+ assert_equal([[:req, :a], [:req, :b]], method(:pm2).parameters)
+ assert_equal([[:opt, :a], [:block, :b]], method(:pmo1).parameters)
+ assert_equal([[:req, :a], [:opt, :b]], method(:pmo2).parameters)
+ assert_equal([[:rest, :a]], method(:pmo3).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters)
+ assert_equal([[:req], [:block, :b]], method(:pma1).parameters)
+ assert_equal([[:keyrest]], method(:pmk1).parameters)
+ assert_equal([[:keyrest, :o]], method(:pmk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:pmk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:pmk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters)
+ end
+
+ def test_bmethod_unbound_parameters
+ assert_equal([], self.class.instance_method(:pm0).parameters)
+ assert_equal([[:req, :a]], self.class.instance_method(:pm1).parameters)
+ assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:pm2).parameters)
+ assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:pmo1).parameters)
+ assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:pmo2).parameters)
+ assert_equal([[:rest, :a]], self.class.instance_method(:pmo3).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:pmo4).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:pmo5).parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:pmo6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters)
+ assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters)
+ assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters)
+ assert_equal([[:keyrest]], self.class.instance_method(:pmk1).parameters)
+ assert_equal([[:keyrest, :o]], self.class.instance_method(:pmk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:pmk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:pmk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:pmk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:pmk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters)
+ end
+
+ def test_public_method_with_zsuper_method
+ c = Class.new
+ c.class_eval do
+ def foo
+ :ok
+ end
+ private :foo
+ end
+ d = Class.new(c)
+ d.class_eval do
+ public :foo
+ end
+ assert_equal(:ok, d.new.public_method(:foo).call)
+ end
+
+ def test_public_methods_with_extended
+ m = Module.new do def m1; end end
+ a = Class.new do def a; end end
+ bug = '[ruby-dev:41553]'
+ obj = a.new
+ assert_equal([:a], obj.public_methods(false), bug)
+ obj.extend(m)
+ assert_equal([:m1, :a], obj.public_methods(false), bug)
+ end
+
+ def test_visibility
+ assert_equal('method', defined?(mv1))
+ assert_equal('method', defined?(mv2))
+ assert_equal('method', defined?(mv3))
+
+ assert_equal('method', defined?(self.mv1))
+ assert_equal(nil, defined?(self.mv2))
+ assert_equal('method', defined?(self.mv3))
+
+ assert_equal(true, respond_to?(:mv1))
+ assert_equal(false, respond_to?(:mv2))
+ assert_equal(false, respond_to?(:mv3))
+
+ assert_equal(true, respond_to?(:mv1, true))
+ assert_equal(true, respond_to?(:mv2, true))
+ assert_equal(true, respond_to?(:mv3, true))
+
+ assert_nothing_raised { mv1 }
+ assert_nothing_raised { mv2 }
+ assert_nothing_raised { mv3 }
+
+ assert_nothing_raised { self.mv1 }
+ assert_raise(NoMethodError) { self.mv2 }
+ assert_nothing_raised { self.mv3 }
+
+ v = Visibility.new
+
+ assert_equal('method', defined?(v.mv1))
+ assert_equal(nil, defined?(v.mv2))
+ assert_equal(nil, defined?(v.mv3))
+
+ assert_equal(true, v.respond_to?(:mv1))
+ assert_equal(false, v.respond_to?(:mv2))
+ assert_equal(false, v.respond_to?(:mv3))
+
+ assert_equal(true, v.respond_to?(:mv1, true))
+ assert_equal(true, v.respond_to?(:mv2, true))
+ assert_equal(true, v.respond_to?(:mv3, true))
+
+ assert_nothing_raised { v.mv1 }
+ assert_raise(NoMethodError) { v.mv2 }
+ assert_raise(NoMethodError) { v.mv3 }
+
+ assert_nothing_raised { v.__send__(:mv1) }
+ assert_nothing_raised { v.__send__(:mv2) }
+ assert_nothing_raised { v.__send__(:mv3) }
+
+ assert_nothing_raised { v.instance_eval { mv1 } }
+ assert_nothing_raised { v.instance_eval { mv2 } }
+ assert_nothing_raised { v.instance_eval { mv3 } }
+ end
+
+ def test_bound_method_entry
+ bug6171 = '[ruby-core:43383]'
+ assert_ruby_status([], <<-EOC, bug6171)
+ class Bug6171
+ def initialize(target)
+ define_singleton_method(:reverse, target.method(:reverse).to_proc)
+ end
+ end
+ 100.times {p = Bug6171.new('test'); 1000.times {p.reverse}}
+ EOC
+ end
+
+ def test___dir__
+ assert_instance_of String, __dir__
+ assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
+ bug8436 = '[ruby-core:55123] [Bug #8436]'
+ assert_equal(__dir__, eval("__dir__", binding), bug8436)
+ bug8662 = '[ruby-core:56099] [Bug #8662]'
+ assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
+ assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)
+ end
+
+ def test_alias_owner
+ bug7613 = '[ruby-core:51105]'
+ bug7993 = '[Bug #7993]'
+ c = Class.new {
+ def foo
+ end
+ prepend Module.new
+ attr_reader :zot
+ }
+ x = c.new
+ class << x
+ alias bar foo
+ end
+ assert_equal(c, c.instance_method(:foo).owner)
+ assert_equal(c, x.method(:foo).owner)
+ assert_equal(x.singleton_class, x.method(:bar).owner)
+ assert_not_equal(x.method(:foo), x.method(:bar), bug7613)
+ assert_equal(c, x.method(:zot).owner, bug7993)
+ assert_equal(c, c.instance_method(:zot).owner, bug7993)
+ end
+
+ def test_included
+ m = Module.new {
+ def foo
+ end
+ }
+ c = Class.new {
+ def foo
+ end
+ include m
+ }
+ assert_equal(c, c.instance_method(:foo).owner)
+ end
+
+ def test_prepended
+ bug7836 = '[ruby-core:52160] [Bug #7836]'
+ bug7988 = '[ruby-core:53038] [Bug #7988]'
+ m = Module.new {
+ def foo
+ end
+ }
+ c = Class.new {
+ def foo
+ end
+ prepend m
+ }
+ assert_raise(NameError, bug7988) {Module.new{prepend m}.instance_method(:bar)}
+ true || c || bug7836
+ end
+
+ def test_gced_bmethod
+ assert_normal_exit %q{
+ require 'irb'
+ IRB::Irb.module_eval do
+ define_method(:eval_input) do
+ IRB::Irb.module_eval { alias_method :eval_input, :to_s }
+ GC.start
+ Kernel
+ end
+ end
+ IRB.start
+ }, '[Bug #7825]'
+ end
+
+ def test_unlinked_method_entry_in_method_object_bug
+ bug8100 = '[ruby-core:53640] [Bug #8100]'
+ begin
+ assert_normal_exit %q{
+ loop do
+ def x
+ "hello" * 1000
+ end
+ method(:x).call
+ end
+ }, bug8100, timeout: 2
+ rescue Timeout::Error => e
+ else
+ end
+ assert_raise(Timeout::Error, bug8100) {raise e if e}
+ end
+
+ def test_singleton_method
+ feature8391 = '[ruby-core:54914] [Feature #8391]'
+ c1 = Class.new
+ c1.class_eval { def foo; :foo; end }
+ o = c1.new
+ def o.bar; :bar; end
+ assert_nothing_raised(NameError) {o.method(:foo)}
+ assert_raise(NameError, feature8391) {o.singleton_method(:foo)}
+ m = assert_nothing_raised(NameError, feature8391) {break o.singleton_method(:bar)}
+ assert_equal(:bar, m.call, feature8391)
+ end
+
+ Feature9783 = '[ruby-core:62212] [Feature #9783]'
+
+ def assert_curry_three_args(m)
+ curried = m.curry
+ assert_equal(6, curried.(1).(2).(3), Feature9783)
+
+ curried = m.curry(3)
+ assert_equal(6, curried.(1).(2).(3), Feature9783)
+
+ assert_raise_with_message(ArgumentError, /wrong number/) {m.curry(2)}
+ end
+
+ def test_curry_method
+ c = Class.new {
+ def three_args(a,b,c) a + b + c end
+ }
+ assert_curry_three_args(c.new.method(:three_args))
+ end
+
+ def test_curry_from_proc
+ c = Class.new {
+ define_method(:three_args) {|a,b,c| a + b + c}
+ }
+ assert_curry_three_args(c.new.method(:three_args))
+ end
+
+ def assert_curry_var_args(m)
+ curried = m.curry(3)
+ assert_equal([1, 2, 3], curried.(1).(2).(3), Feature9783)
+
+ curried = m.curry(2)
+ assert_equal([1, 2], curried.(1).(2), Feature9783)
+
+ curried = m.curry(0)
+ assert_equal([1], curried.(1), Feature9783)
+ end
+
+ def test_curry_var_args
+ c = Class.new {
+ def var_args(*args) args end
+ }
+ assert_curry_var_args(c.new.method(:var_args))
+ end
+
+ def test_curry_from_proc_var_args
+ c = Class.new {
+ define_method(:var_args) {|*args| args}
+ }
+ assert_curry_var_args(c.new.method(:var_args))
+ end
+
+ Feature9781 = '[ruby-core:62202] [Feature #9781]'
+
+ def test_super_method
+ o = Derived.new
+ m = o.method(:foo).super_method
+ assert_equal(Base, m.owner, Feature9781)
+ assert_same(o, m.receiver, Feature9781)
+ assert_equal(:foo, m.name, Feature9781)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+ end
+
+ def test_super_method_unbound
+ m = Derived.instance_method(:foo)
+ m = m.super_method
+ assert_equal(Base.instance_method(:foo), m, Feature9781)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+ end
+
+ def test_super_method_module
+ m1 = Module.new {def foo; end}
+ c1 = Class.new(Derived) {include m1; def foo; end}
+ m = c1.instance_method(:foo)
+ assert_equal(c1, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(m1, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(Derived, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(Base, m.owner, Feature9781)
+ m2 = Module.new {def foo; end}
+ o = c1.new.extend(m2)
+ m = o.method(:foo)
+ assert_equal(m2, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(c1, m.owner, Feature9781)
+ assert_same(o, m.receiver, Feature9781)
+ end
+
+ def test_super_method_removed
+ c1 = Class.new {private def foo; end}
+ c2 = Class.new(c1) {public :foo}
+ c3 = Class.new(c2) {def foo; end}
+ c1.class_eval {undef foo}
+ m = c3.instance_method(:foo)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+ end
+
+ def rest_parameter(*rest)
+ rest
+ end
+
+ def test_splat_long_array
+ n = 10_000_000
+ assert_equal n , rest_parameter(*(1..n)).size, '[Feature #10440]'
+ end
+
+ def test_insecure_method
+ m = "\u{5371 967a}"
+ c = Class.new do
+ proc {$SAFE=3;def foo;end}.call
+ alias_method m, "foo"
+ eval "def bar; #{m}; end"
+ end
+ obj = c.new
+ assert_raise_with_message(SecurityError, /#{m}/) do
+ obj.bar
+ end
+ end
+
+ def test_to_proc_binding
+ bug11012 = '[ruby-core:68673] [Bug #11012]'
+ class << (obj = Object.new)
+ src = 1000.times.map {|i|"v#{i} = nil"}.join("\n")
+ eval("def foo()\n""#{src}\n""end")
+ end
+
+ b = obj.method(:foo).to_proc.binding
+ b.local_variables.each_with_index {|n, i|
+ b.local_variable_set(n, i)
+ }
+ assert_equal([998, 999], %w[v998 v999].map {|n| b.local_variable_get(n)}, bug11012)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb b/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb
new file mode 100644
index 0000000..982b57e
--- /dev/null
+++ b/jni/ruby/test/ruby/test_mixed_unicode_escapes.rb
@@ -0,0 +1,25 @@
+# -*- coding: cp932 -*-
+# This test is in a differnt file than TestUnicodeEscapes
+# So that we can have a different coding comment above
+
+require 'test/unit'
+
+class TestMixedUnicodeEscape < Test::Unit::TestCase
+ def test_basic
+ # Unicode escapes do work in an sjis encoded file, but only
+ # if they don't contain other multi-byte chars
+ assert_equal("A", "\u0041")
+ # 8-bit character escapes are okay.
+ assert_equal("B\xFF", "\u0042\xFF")
+
+ # sjis mb chars mixed with Unicode shound not work
+ assert_raise(SyntaxError) { eval %q("\u1234")}
+ assert_raise(SyntaxError) { eval %q("\u{1234}")}
+
+ # String interpolation turns into an expression and we get
+ # a different kind of error, but we still can't mix these
+ assert_raise(Encoding::CompatibilityError) { eval %q("\u{1234}#{nil}")}
+ assert_raise(Encoding::CompatibilityError) { eval %q("#{nil}\u1234")}
+
+ end
+end
diff --git a/jni/ruby/test/ruby/test_module.rb b/jni/ruby/test/ruby/test_module.rb
new file mode 100644
index 0000000..2f3e5c2
--- /dev/null
+++ b/jni/ruby/test/ruby/test_module.rb
@@ -0,0 +1,2032 @@
+require 'test/unit'
+require 'pp'
+
+$m0 = Module.nesting
+
+class TestModule < Test::Unit::TestCase
+ def _wrap_assertion
+ yield
+ end
+
+ def assert_method_defined?(klass, mid, message="")
+ message = build_message(message, "#{klass}\##{mid} expected to be defined.")
+ _wrap_assertion do
+ klass.method_defined?(mid) or
+ raise Test::Unit::AssertionFailedError, message, caller(3)
+ end
+ end
+
+ def assert_method_not_defined?(klass, mid, message="")
+ message = build_message(message, "#{klass}\##{mid} expected to not be defined.")
+ _wrap_assertion do
+ klass.method_defined?(mid) and
+ raise Test::Unit::AssertionFailedError, message, caller(3)
+ end
+ end
+
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_LT_0
+ assert_equal true, String < Object
+ assert_equal false, Object < String
+ assert_nil String < Array
+ assert_equal true, Array < Enumerable
+ assert_equal false, Enumerable < Array
+ assert_nil Proc < Comparable
+ assert_nil Comparable < Proc
+ end
+
+ def test_GT_0
+ assert_equal false, String > Object
+ assert_equal true, Object > String
+ assert_nil String > Array
+ assert_equal false, Array > Enumerable
+ assert_equal true, Enumerable > Array
+ assert_nil Comparable > Proc
+ assert_nil Proc > Comparable
+ end
+
+ def test_CMP_0
+ assert_equal(-1, (String <=> Object))
+ assert_equal 1, (Object <=> String)
+ assert_nil(Array <=> String)
+ end
+
+ ExpectedException = NoMethodError
+
+ # Support stuff
+
+ module Mixin
+ MIXIN = 1
+ def mixin
+ end
+ end
+
+ module User
+ USER = 2
+ include Mixin
+ def user
+ end
+ end
+
+ module Other
+ def other
+ end
+ end
+
+ class AClass
+ def AClass.cm1
+ "cm1"
+ end
+ def AClass.cm2
+ cm1 + "cm2" + cm3
+ end
+ def AClass.cm3
+ "cm3"
+ end
+
+ private_class_method :cm1, "cm3"
+
+ def aClass
+ :aClass
+ end
+
+ def aClass1
+ :aClass1
+ end
+
+ def aClass2
+ :aClass2
+ end
+
+ private :aClass1
+ protected :aClass2
+ end
+
+ class BClass < AClass
+ def bClass1
+ :bClass1
+ end
+
+ private
+
+ def bClass2
+ :bClass2
+ end
+
+ protected
+ def bClass3
+ :bClass3
+ end
+ end
+
+ class CClass < BClass
+ def self.cClass
+ end
+ end
+
+ MyClass = AClass.clone
+ class MyClass
+ public_class_method :cm1
+ end
+
+ # -----------------------------------------------------------
+
+ def test_CMP # '<=>'
+ assert_equal( 0, Mixin <=> Mixin)
+ assert_equal(-1, User <=> Mixin)
+ assert_equal( 1, Mixin <=> User)
+
+ assert_equal( 0, Object <=> Object)
+ assert_equal(-1, String <=> Object)
+ assert_equal( 1, Object <=> String)
+ end
+
+ def test_GE # '>='
+ assert_operator(Mixin, :>=, User)
+ assert_operator(Mixin, :>=, Mixin)
+ assert_not_operator(User, :>=, Mixin)
+
+ assert_operator(Object, :>=, String)
+ assert_operator(String, :>=, String)
+ assert_not_operator(String, :>=, Object)
+ end
+
+ def test_GT # '>'
+ assert_operator(Mixin, :>, User)
+ assert_not_operator(Mixin, :>, Mixin)
+ assert_not_operator(User, :>, Mixin)
+
+ assert_operator(Object, :>, String)
+ assert_not_operator(String, :>, String)
+ assert_not_operator(String, :>, Object)
+ end
+
+ def test_LE # '<='
+ assert_operator(User, :<=, Mixin)
+ assert_operator(Mixin, :<=, Mixin)
+ assert_not_operator(Mixin, :<=, User)
+
+ assert_operator(String, :<=, Object)
+ assert_operator(String, :<=, String)
+ assert_not_operator(Object, :<=, String)
+ end
+
+ def test_LT # '<'
+ assert_operator(User, :<, Mixin)
+ assert_not_operator(Mixin, :<, Mixin)
+ assert_not_operator(Mixin, :<, User)
+
+ assert_operator(String, :<, Object)
+ assert_not_operator(String, :<, String)
+ assert_not_operator(Object, :<, String)
+ end
+
+ def test_VERY_EQUAL # '==='
+ assert_operator(Object, :===, self)
+ assert_operator(Test::Unit::TestCase, :===, self)
+ assert_operator(TestModule, :===, self)
+ assert_not_operator(String, :===, self)
+ end
+
+ def test_ancestors
+ assert_equal([User, Mixin], User.ancestors)
+ assert_equal([Mixin], Mixin.ancestors)
+
+ ancestors = Object.ancestors
+ mixins = ancestors - [Object, Kernel, BasicObject]
+ mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String)
+ assert_equal([Object, Kernel, BasicObject], ancestors - mixins)
+ assert_equal([String, Comparable, Object, Kernel, BasicObject], String.ancestors - mixins)
+ end
+
+ CLASS_EVAL = 2
+ @@class_eval = 'b'
+
+ def test_class_eval
+ Other.class_eval("CLASS_EVAL = 1")
+ assert_equal(1, Other::CLASS_EVAL)
+ assert_include(Other.constants, :CLASS_EVAL)
+ assert_equal(2, Other.class_eval { CLASS_EVAL })
+
+ Other.class_eval("@@class_eval = 'a'")
+ assert_equal('a', Other.class_variable_get(:@@class_eval))
+ assert_equal('b', Other.class_eval { @@class_eval })
+
+ Other.class_eval do
+ module_function
+
+ def class_eval_test
+ "foo"
+ end
+ end
+ assert_equal("foo", Other.class_eval_test)
+
+ assert_equal([Other], Other.class_eval { |*args| args })
+ end
+
+ def test_const_defined?
+ assert_operator(Math, :const_defined?, :PI)
+ assert_operator(Math, :const_defined?, "PI")
+ assert_not_operator(Math, :const_defined?, :IP)
+ assert_not_operator(Math, :const_defined?, "IP")
+ end
+
+ def each_bad_constants(m, &b)
+ [
+ "#<Class:0x7b8b718b>",
+ ":Object",
+ "",
+ ":",
+ ["String::", "[Bug #7573]"],
+ "\u3042",
+ "Name?",
+ ].each do |name, msg|
+ expected = "wrong constant name %s" % quote(name)
+ msg = "#{msg}#{': ' if msg}wrong constant name #{name.dump}"
+ assert_raise_with_message(NameError, expected, "#{msg} to #{m}") do
+ yield name
+ end
+ end
+ end
+
+ def test_bad_constants_get
+ each_bad_constants("get") {|name|
+ Object.const_get name
+ }
+ end
+
+ def test_bad_constants_defined
+ each_bad_constants("defined?") {|name|
+ Object.const_defined? name
+ }
+ end
+
+ def test_leading_colons
+ assert_equal Object, AClass.const_get('::Object')
+ end
+
+ def test_const_get
+ assert_equal(Math::PI, Math.const_get("PI"))
+ assert_equal(Math::PI, Math.const_get(:PI))
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "PI"; end
+ def n.count; @count; end
+ assert_equal(Math::PI, Math.const_get(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_nested_get
+ assert_equal Other, Object.const_get([self.class, Other].join('::'))
+ assert_equal User::USER, self.class.const_get([User, 'USER'].join('::'))
+ end
+
+ def test_nested_get_symbol
+ const = [self.class, Other].join('::').to_sym
+ assert_raise(NameError) {Object.const_get(const)}
+
+ const = [User, 'USER'].join('::').to_sym
+ assert_raise(NameError) {self.class.const_get(const)}
+ end
+
+ def test_nested_get_const_missing
+ classes = []
+ klass = Class.new {
+ define_singleton_method(:const_missing) { |name|
+ classes << name
+ klass
+ }
+ }
+ klass.const_get("Foo::Bar::Baz")
+ assert_equal [:Foo, :Bar, :Baz], classes
+ end
+
+ def test_nested_get_bad_class
+ assert_raise(TypeError) do
+ self.class.const_get([User, 'USER', 'Foo'].join('::'))
+ end
+ end
+
+ def test_nested_defined
+ assert_send([Object, :const_defined?, [self.class.name, 'Other'].join('::')])
+ assert_send([self.class, :const_defined?, 'User::USER'])
+ assert_not_send([self.class, :const_defined?, 'User::Foo'])
+ end
+
+ def test_nested_defined_symbol
+ const = [self.class, Other].join('::').to_sym
+ assert_raise(NameError) {Object.const_defined?(const)}
+
+ const = [User, 'USER'].join('::').to_sym
+ assert_raise(NameError) {self.class.const_defined?(const)}
+ end
+
+ def test_nested_defined_bad_class
+ assert_raise(TypeError) do
+ self.class.const_defined?('User::USER::Foo')
+ end
+ end
+
+ def test_const_set
+ assert_not_operator(Other, :const_defined?, :KOALA)
+ Other.const_set(:KOALA, 99)
+ assert_operator(Other, :const_defined?, :KOALA)
+ assert_equal(99, Other::KOALA)
+ Other.const_set("WOMBAT", "Hi")
+ assert_equal("Hi", Other::WOMBAT)
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "HOGE"; end
+ def n.count; @count; end
+ def n.count=(v); @count=v; end
+ assert_not_operator(Other, :const_defined?, :HOGE)
+ Other.const_set(n, 999)
+ assert_equal(1, n.count)
+ n.count = 0
+ assert_equal(999, Other.const_get(n))
+ assert_equal(1, n.count)
+ n.count = 0
+ assert_equal(true, Other.const_defined?(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_constants
+ assert_equal([:MIXIN], Mixin.constants)
+ assert_equal([:MIXIN, :USER], User.constants.sort)
+ end
+
+ def test_self_initialize_copy
+ bug9535 = '[ruby-dev:47989] [Bug #9535]'
+ m = Module.new do
+ def foo
+ :ok
+ end
+ initialize_copy(self)
+ end
+ assert_equal(:ok, Object.new.extend(m).foo, bug9535)
+ end
+
+ def test_initialize_copy_empty
+ bug9813 = '[ruby-dev:48182] [Bug #9813]'
+ m = Module.new do
+ def x
+ end
+ const_set(:X, 1)
+ @x = 2
+ end
+ assert_equal([:x], m.instance_methods)
+ assert_equal([:@x], m.instance_variables)
+ assert_equal([:X], m.constants)
+ m.module_eval do
+ initialize_copy(Module.new)
+ end
+ assert_empty(m.instance_methods, bug9813)
+ assert_empty(m.instance_variables, bug9813)
+ assert_empty(m.constants, bug9813)
+ end
+
+ def test_dup
+ bug6454 = '[ruby-core:45132]'
+
+ a = Module.new
+ Other.const_set :BUG6454, a
+ b = a.dup
+ Other.const_set :BUG6454_dup, b
+
+ assert_equal "TestModule::Other::BUG6454_dup", b.inspect, bug6454
+ end
+
+ def test_dup_anonymous
+ bug6454 = '[ruby-core:45132]'
+
+ a = Module.new
+ original = a.inspect
+
+ b = a.dup
+
+ assert_not_equal original, b.inspect, bug6454
+ end
+
+ def test_public_include
+ assert_nothing_raised('#8846') do
+ Module.new.include(Module.new { def foo; end }).instance_methods == [:foo]
+ end
+ end
+
+ def test_include_toplevel
+ assert_separately([], <<-EOS)
+ Mod = Module.new {def foo; :include_foo end}
+ TOPLEVEL_BINDING.eval('include Mod')
+
+ assert_equal(:include_foo, TOPLEVEL_BINDING.eval('foo'))
+ assert_equal([Object, Mod], Object.ancestors.slice(0, 2))
+ EOS
+ end
+
+ def test_included_modules
+ assert_equal([], Mixin.included_modules)
+ assert_equal([Mixin], User.included_modules)
+
+ mixins = Object.included_modules - [Kernel]
+ mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String)
+ assert_equal([Kernel], Object.included_modules - mixins)
+ assert_equal([Comparable, Kernel], String.included_modules - mixins)
+ end
+
+ def test_instance_methods
+ assert_equal([:user], User.instance_methods(false))
+ assert_equal([:user, :mixin].sort, User.instance_methods(true).sort)
+ assert_equal([:mixin], Mixin.instance_methods)
+ assert_equal([:mixin], Mixin.instance_methods(true))
+ assert_equal([:cClass], (class << CClass; self; end).instance_methods(false))
+ assert_equal([], (class << BClass; self; end).instance_methods(false))
+ assert_equal([:cm2], (class << AClass; self; end).instance_methods(false))
+ # Ruby 1.8 feature change:
+ # #instance_methods includes protected methods.
+ #assert_equal([:aClass], AClass.instance_methods(false))
+ assert_equal([:aClass, :aClass2], AClass.instance_methods(false).sort)
+ assert_equal([:aClass, :aClass2],
+ (AClass.instance_methods(true) - Object.instance_methods(true)).sort)
+ end
+
+ def test_method_defined?
+ assert_method_not_defined?(User, :wombat)
+ assert_method_defined?(User, :user)
+ assert_method_defined?(User, :mixin)
+ assert_method_not_defined?(User, :wombat)
+ assert_method_defined?(User, :user)
+ assert_method_defined?(User, :mixin)
+ end
+
+ def module_exec_aux
+ Proc.new do
+ def dynamically_added_method_3; end
+ end
+ end
+ def module_exec_aux_2(&block)
+ User.module_exec(&block)
+ end
+
+ def test_module_exec
+ User.module_exec do
+ def dynamically_added_method_1; end
+ end
+ assert_method_defined?(User, :dynamically_added_method_1)
+
+ block = Proc.new do
+ def dynamically_added_method_2; end
+ end
+ User.module_exec(&block)
+ assert_method_defined?(User, :dynamically_added_method_2)
+
+ User.module_exec(&module_exec_aux)
+ assert_method_defined?(User, :dynamically_added_method_3)
+
+ module_exec_aux_2 do
+ def dynamically_added_method_4; end
+ end
+ assert_method_defined?(User, :dynamically_added_method_4)
+ end
+
+ def test_module_eval
+ User.module_eval("MODULE_EVAL = 1")
+ assert_equal(1, User::MODULE_EVAL)
+ assert_include(User.constants, :MODULE_EVAL)
+ User.instance_eval("remove_const(:MODULE_EVAL)")
+ assert_not_include(User.constants, :MODULE_EVAL)
+ end
+
+ def test_name
+ assert_equal("Fixnum", Fixnum.name)
+ assert_equal("TestModule::Mixin", Mixin.name)
+ assert_equal("TestModule::User", User.name)
+ end
+
+ def test_classpath
+ m = Module.new
+ n = Module.new
+ m.const_set(:N, n)
+ assert_nil(m.name)
+ assert_nil(n.name)
+ assert_equal([:N], m.constants)
+ m.module_eval("module O end")
+ assert_equal([:N, :O], m.constants)
+ m.module_eval("class C; end")
+ assert_equal([:N, :O, :C], m.constants)
+ assert_nil(m::N.name)
+ assert_match(/\A#<Module:.*>::O\z/, m::O.name)
+ assert_match(/\A#<Module:.*>::C\z/, m::C.name)
+ self.class.const_set(:M, m)
+ prefix = self.class.name + "::M::"
+ assert_equal(prefix+"N", m.const_get(:N).name)
+ assert_equal(prefix+"O", m.const_get(:O).name)
+ assert_equal(prefix+"C", m.const_get(:C).name)
+ end
+
+ def test_private_class_method
+ assert_raise(ExpectedException) { AClass.cm1 }
+ assert_raise(ExpectedException) { AClass.cm3 }
+ assert_equal("cm1cm2cm3", AClass.cm2)
+ end
+
+ def test_private_instance_methods
+ assert_equal([:aClass1], AClass.private_instance_methods(false))
+ assert_equal([:bClass2], BClass.private_instance_methods(false))
+ assert_equal([:aClass1, :bClass2],
+ (BClass.private_instance_methods(true) -
+ Object.private_instance_methods(true)).sort)
+ end
+
+ def test_protected_instance_methods
+ assert_equal([:aClass2], AClass.protected_instance_methods)
+ assert_equal([:bClass3], BClass.protected_instance_methods(false))
+ assert_equal([:bClass3, :aClass2].sort,
+ (BClass.protected_instance_methods(true) -
+ Object.protected_instance_methods(true)).sort)
+ end
+
+ def test_public_class_method
+ assert_equal("cm1", MyClass.cm1)
+ assert_equal("cm1cm2cm3", MyClass.cm2)
+ assert_raise(ExpectedException) { eval "MyClass.cm3" }
+ end
+
+ def test_public_instance_methods
+ assert_equal([:aClass], AClass.public_instance_methods(false))
+ assert_equal([:bClass1], BClass.public_instance_methods(false))
+ end
+
+ def test_s_constants
+ c1 = Module.constants
+ Object.module_eval "WALTER = 99"
+ c2 = Module.constants
+ assert_equal([:WALTER], c2 - c1)
+
+ assert_equal([], Module.constants(true))
+ assert_equal([], Module.constants(false))
+
+ src = <<-INPUT
+ ary = Module.constants
+ module M
+ WALTER = 99
+ end
+ class Module
+ include M
+ end
+ p Module.constants - ary, Module.constants(true), Module.constants(false)
+ INPUT
+ assert_in_out_err([], src, %w([:M] [:WALTER] []), [])
+
+ klass = Class.new do
+ const_set(:X, 123)
+ end
+ assert_equal(false, klass.class_eval { Module.constants }.include?(:X))
+ end
+
+ module M1
+ $m1 = Module.nesting
+ module M2
+ $m2 = Module.nesting
+ end
+ end
+
+ def test_s_nesting
+ assert_equal([], $m0)
+ assert_equal([TestModule::M1, TestModule], $m1)
+ assert_equal([TestModule::M1::M2,
+ TestModule::M1, TestModule], $m2)
+ end
+
+ def test_s_new
+ m = Module.new
+ assert_instance_of(Module, m)
+ end
+
+ def test_freeze
+ m = Module.new
+ m.freeze
+ assert_raise(RuntimeError) do
+ m.module_eval do
+ def foo; end
+ end
+ end
+ end
+
+ def test_attr_obsoleted_flag
+ c = Class.new
+ c.class_eval do
+ def initialize
+ @foo = :foo
+ @bar = :bar
+ end
+ attr :foo, true
+ attr :bar, false
+ end
+ o = c.new
+ assert_equal(true, o.respond_to?(:foo))
+ assert_equal(true, o.respond_to?(:foo=))
+ assert_equal(true, o.respond_to?(:bar))
+ assert_equal(false, o.respond_to?(:bar=))
+ end
+
+ def test_const_get_evaled
+ c1 = Class.new
+ c2 = Class.new(c1)
+
+ eval("c1::Foo = :foo")
+ assert_equal(:foo, c1::Foo)
+ assert_equal(:foo, c2::Foo)
+ assert_equal(:foo, c2.const_get(:Foo))
+ assert_raise(NameError) { c2.const_get(:Foo, false) }
+
+ eval("c1::Foo = :foo")
+ assert_raise(NameError) { c1::Bar }
+ assert_raise(NameError) { c2::Bar }
+ assert_raise(NameError) { c2.const_get(:Bar) }
+ assert_raise(NameError) { c2.const_get(:Bar, false) }
+ assert_raise(NameError) { c2.const_get("Bar", false) }
+ assert_raise(NameError) { c2.const_get("BaR11", false) }
+ assert_raise(NameError) { Object.const_get("BaR11", false) }
+
+ c1.instance_eval do
+ def const_missing(x)
+ x
+ end
+ end
+
+ assert_equal(:Bar, c1::Bar)
+ assert_equal(:Bar, c2::Bar)
+ assert_equal(:Bar, c2.const_get(:Bar))
+ assert_equal(:Bar, c2.const_get(:Bar, false))
+ assert_equal(:Bar, c2.const_get("Bar"))
+ assert_equal(:Bar, c2.const_get("Bar", false))
+
+ v = c2.const_get("Bar11", false)
+ assert_equal("Bar11".to_sym, v)
+
+ assert_raise(NameError) { c1.const_get(:foo) }
+ end
+
+ def test_const_set_invalid_name
+ c1 = Class.new
+ assert_raise_with_message(NameError, /foo/) { c1.const_set(:foo, :foo) }
+ assert_raise_with_message(NameError, /bar/) { c1.const_set("bar", :foo) }
+ assert_raise_with_message(TypeError, /1/) { c1.const_set(1, :foo) }
+ assert_nothing_raised(NameError) { c1.const_set("X\u{3042}", :foo) }
+ assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16be"), :foo) }
+ assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16le"), :foo) }
+ assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32be"), :foo) }
+ assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32le"), :foo) }
+ cx = EnvUtil.labeled_class("X\u{3042}")
+ EnvUtil.with_default_internal(Encoding::UTF_8) {
+ assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) }
+ }
+ end
+
+ def test_const_get_invalid_name
+ c1 = Class.new
+ assert_raise(NameError) { c1.const_get(:foo) }
+ bug5084 = '[ruby-dev:44200]'
+ assert_raise(TypeError, bug5084) { c1.const_get(1) }
+ bug7574 = '[ruby-dev:46749]'
+ assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) {
+ Object.const_get("String\0")
+ }
+ end
+
+ def test_const_defined_invalid_name
+ c1 = Class.new
+ assert_raise(NameError) { c1.const_defined?(:foo) }
+ bug5084 = '[ruby-dev:44200]'
+ assert_raise(TypeError, bug5084) { c1.const_defined?(1) }
+ bug7574 = '[ruby-dev:46749]'
+ assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) {
+ Object.const_defined?("String\0")
+ }
+ end
+
+ def test_const_get_no_inherited
+ bug3422 = '[ruby-core:30719]'
+ assert_in_out_err([], <<-INPUT, %w[1 NameError A], [], bug3422)
+ BasicObject::A = 1
+ puts [true, false].map {|inh|
+ begin
+ Object.const_get(:A, inh)
+ rescue NameError => e
+ [e.class, e.name]
+ end
+ }
+ INPUT
+ end
+
+ def test_const_get_inherited
+ bug3423 = '[ruby-core:30720]'
+ assert_in_out_err([], <<-INPUT, %w[NameError A NameError A], [], bug3423)
+ module Foo; A = 1; end
+ class Object; include Foo; end
+ class Bar; include Foo; end
+
+ puts [Object, Bar].map {|klass|
+ begin
+ klass.const_get(:A, false)
+ rescue NameError => e
+ [e.class, e.name]
+ end
+ }
+ INPUT
+ end
+
+ def test_const_in_module
+ bug3423 = '[ruby-core:37698]'
+ assert_in_out_err([], <<-INPUT, %w[ok], [], bug3423)
+ module LangModuleSpecInObject
+ module LangModuleTop
+ end
+ end
+ include LangModuleSpecInObject
+ module LangModuleTop
+ end
+ puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop
+ INPUT
+
+ bug5264 = '[ruby-core:39227]'
+ assert_in_out_err([], <<-'INPUT', [], [], bug5264)
+ class A
+ class X; end
+ end
+ class B < A
+ module X; end
+ end
+ INPUT
+ end
+
+ def test_class_variable_get
+ c = Class.new
+ c.class_eval('@@foo = :foo')
+ assert_equal(:foo, c.class_variable_get(:@@foo))
+ assert_raise(NameError) { c.class_variable_get(:@@bar) } # c.f. instance_variable_get
+ assert_raise(NameError) { c.class_variable_get(:'@@') }
+ assert_raise(NameError) { c.class_variable_get('@@') }
+ assert_raise(NameError) { c.class_variable_get(:foo) }
+ assert_raise(NameError) { c.class_variable_get("bar") }
+ assert_raise(TypeError) { c.class_variable_get(1) }
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end
+ def n.count; @count; end
+ assert_equal(:foo, c.class_variable_get(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_class_variable_set
+ c = Class.new
+ c.class_variable_set(:@@foo, :foo)
+ assert_equal(:foo, c.class_eval('@@foo'))
+ assert_raise(NameError) { c.class_variable_set(:'@@', 1) }
+ assert_raise(NameError) { c.class_variable_set('@@', 1) }
+ assert_raise(NameError) { c.class_variable_set(:foo, 1) }
+ assert_raise(NameError) { c.class_variable_set("bar", 1) }
+ assert_raise(TypeError) { c.class_variable_set(1, 1) }
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end
+ def n.count; @count; end
+ c.class_variable_set(n, :bar)
+ assert_equal(:bar, c.class_eval('@@foo'))
+ assert_equal(1, n.count)
+ end
+
+ def test_class_variable_defined
+ c = Class.new
+ c.class_eval('@@foo = :foo')
+ assert_equal(true, c.class_variable_defined?(:@@foo))
+ assert_equal(false, c.class_variable_defined?(:@@bar))
+ assert_raise(NameError) { c.class_variable_defined?(:'@@') }
+ assert_raise(NameError) { c.class_variable_defined?('@@') }
+ assert_raise(NameError) { c.class_variable_defined?(:foo) }
+ assert_raise(NameError) { c.class_variable_defined?("bar") }
+ assert_raise(TypeError) { c.class_variable_defined?(1) }
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end
+ def n.count; @count; end
+ assert_equal(true, c.class_variable_defined?(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_remove_class_variable
+ c = Class.new
+ c.class_eval('@@foo = :foo')
+ c.class_eval { remove_class_variable(:@@foo) }
+ assert_equal(false, c.class_variable_defined?(:@@foo))
+ end
+
+ def test_export_method
+ m = Module.new
+ assert_raise(NameError) do
+ m.instance_eval { public(:foo) }
+ end
+ end
+
+ def test_attr
+ assert_in_out_err([], <<-INPUT, %w(:ok nil), /warning: private attribute\?$/)
+ $VERBOSE = true
+ c = Class.new
+ c.instance_eval do
+ private
+ attr_reader :foo
+ end
+ o = c.new
+ o.foo rescue p(:ok)
+ p(o.instance_eval { foo })
+ INPUT
+
+ c = Class.new
+ assert_raise(NameError) do
+ c.instance_eval { attr_reader :"." }
+ end
+ end
+
+ def test_undef
+ c = Class.new
+ assert_raise(NameError) do
+ c.instance_eval { undef_method(:foo) }
+ end
+
+ m = Module.new
+ assert_raise(NameError) do
+ m.instance_eval { undef_method(:foo) }
+ end
+
+ o = Object.new
+ assert_raise(NameError) do
+ class << o; self; end.instance_eval { undef_method(:foo) }
+ end
+
+ %w(object_id __send__ initialize).each do |n|
+ assert_in_out_err([], <<-INPUT, [], %r"warning: undefining `#{n}' may cause serious problems$")
+ $VERBOSE = false
+ Class.new.instance_eval { undef_method(:#{n}) }
+ INPUT
+ end
+ end
+
+ def test_alias
+ m = Module.new
+ assert_raise(NameError) do
+ m.class_eval { alias foo bar }
+ end
+
+ assert_in_out_err([], <<-INPUT, %w(2), /discarding old foo$/)
+ $VERBOSE = true
+ c = Class.new
+ c.class_eval do
+ def foo; 1; end
+ def bar; 2; end
+ end
+ c.class_eval { alias foo bar }
+ p c.new.foo
+ INPUT
+ end
+
+ def test_mod_constants
+ m = Module.new
+ m.const_set(:Foo, :foo)
+ assert_equal([:Foo], m.constants(true))
+ assert_equal([:Foo], m.constants(false))
+ m.instance_eval { remove_const(:Foo) }
+ end
+
+ class Bug9413
+ class << self
+ Foo = :foo
+ end
+ end
+
+ def test_singleton_constants
+ bug9413 = '[ruby-core:59763] [Bug #9413]'
+ c = Bug9413.singleton_class
+ assert_include(c.constants(true), :Foo, bug9413)
+ assert_include(c.constants(false), :Foo, bug9413)
+ end
+
+ def test_frozen_module
+ m = Module.new
+ m.freeze
+ assert_raise(RuntimeError) do
+ m.instance_eval { undef_method(:foo) }
+ end
+ end
+
+ def test_frozen_class
+ c = Class.new
+ c.freeze
+ assert_raise(RuntimeError) do
+ c.instance_eval { undef_method(:foo) }
+ end
+ end
+
+ def test_frozen_singleton_class
+ klass = Class.new
+ o = klass.new
+ c = class << o; self; end
+ c.freeze
+ assert_raise_with_message(RuntimeError, /frozen/) do
+ c.instance_eval { undef_method(:foo) }
+ end
+ klass.class_eval do
+ def self.foo
+ end
+ end
+ end
+
+ def test_method_defined
+ c = Class.new
+ c.class_eval do
+ def foo; end
+ def bar; end
+ def baz; end
+ public :foo
+ protected :bar
+ private :baz
+ end
+
+ assert_equal(true, c.public_method_defined?(:foo))
+ assert_equal(false, c.public_method_defined?(:bar))
+ assert_equal(false, c.public_method_defined?(:baz))
+
+ assert_equal(false, c.protected_method_defined?(:foo))
+ assert_equal(true, c.protected_method_defined?(:bar))
+ assert_equal(false, c.protected_method_defined?(:baz))
+
+ assert_equal(false, c.private_method_defined?(:foo))
+ assert_equal(false, c.private_method_defined?(:bar))
+ assert_equal(true, c.private_method_defined?(:baz))
+ end
+
+ def test_top_public_private
+ assert_in_out_err([], <<-INPUT, %w([:foo] [:bar]), [])
+ private
+ def foo; :foo; end
+ public
+ def bar; :bar; end
+ p self.private_methods.grep(/^foo$|^bar$/)
+ p self.methods.grep(/^foo$|^bar$/)
+ INPUT
+ end
+
+ def test_append_features
+ t = nil
+ m = Module.new
+ m.module_eval do
+ def foo; :foo; end
+ end
+ class << m; self; end.class_eval do
+ define_method(:append_features) do |mod|
+ t = mod
+ super(mod)
+ end
+ end
+
+ m2 = Module.new
+ m2.module_eval { include(m) }
+ assert_equal(m2, t)
+
+ o = Object.new
+ o.extend(m2)
+ assert_equal(true, o.respond_to?(:foo))
+ end
+
+ def test_append_features_raise
+ m = Module.new
+ m.module_eval do
+ def foo; :foo; end
+ end
+ class << m; self; end.class_eval do
+ define_method(:append_features) {|mod| raise }
+ end
+
+ m2 = Module.new
+ assert_raise(RuntimeError) do
+ m2.module_eval { include(m) }
+ end
+
+ o = Object.new
+ o.extend(m2)
+ assert_equal(false, o.respond_to?(:foo))
+ end
+
+ def test_append_features_type_error
+ assert_raise(TypeError) do
+ Module.new.instance_eval { append_features(1) }
+ end
+ end
+
+ def test_included
+ m = Module.new
+ m.module_eval do
+ def foo; :foo; end
+ end
+ class << m; self; end.class_eval do
+ define_method(:included) {|mod| raise }
+ end
+
+ m2 = Module.new
+ assert_raise(RuntimeError) do
+ m2.module_eval { include(m) }
+ end
+
+ o = Object.new
+ o.extend(m2)
+ assert_equal(true, o.respond_to?(:foo))
+ end
+
+ def test_cyclic_include
+ m1 = Module.new
+ m2 = Module.new
+ m1.instance_eval { include(m2) }
+ assert_raise(ArgumentError) do
+ m2.instance_eval { include(m1) }
+ end
+ end
+
+ def test_include_p
+ m = Module.new
+ c1 = Class.new
+ c1.instance_eval { include(m) }
+ c2 = Class.new(c1)
+ assert_equal(true, c1.include?(m))
+ assert_equal(true, c2.include?(m))
+ assert_equal(false, m.include?(m))
+ end
+
+ def test_send
+ a = AClass.new
+ assert_equal(:aClass, a.__send__(:aClass))
+ assert_equal(:aClass1, a.__send__(:aClass1))
+ assert_equal(:aClass2, a.__send__(:aClass2))
+ b = BClass.new
+ assert_equal(:aClass, b.__send__(:aClass))
+ assert_equal(:aClass1, b.__send__(:aClass1))
+ assert_equal(:aClass2, b.__send__(:aClass2))
+ assert_equal(:bClass1, b.__send__(:bClass1))
+ assert_equal(:bClass2, b.__send__(:bClass2))
+ assert_equal(:bClass3, b.__send__(:bClass3))
+ end
+
+
+ def test_nonascii_name
+ c = eval("class ::C\u{df}; self; end")
+ assert_equal("C\u{df}", c.name, '[ruby-core:24600]')
+ c = eval("class C\u{df}; self; end")
+ assert_equal("TestModule::C\u{df}", c.name, '[ruby-core:24600]')
+ end
+
+ def test_method_added
+ memo = []
+ mod = Module.new do
+ mod = self
+ (class << self ; self ; end).class_eval do
+ define_method :method_added do |sym|
+ memo << sym
+ memo << mod.instance_methods(false)
+ memo << (mod.instance_method(sym) rescue nil)
+ end
+ end
+ def f
+ end
+ alias g f
+ attr_reader :a
+ attr_writer :a
+ end
+ assert_equal :f, memo.shift
+ assert_equal [:f], memo.shift, '[ruby-core:25536]'
+ assert_equal mod.instance_method(:f), memo.shift
+ assert_equal :g, memo.shift
+ assert_equal [:f, :g], memo.shift
+ assert_equal mod.instance_method(:f), memo.shift
+ assert_equal :a, memo.shift
+ assert_equal [:f, :g, :a], memo.shift
+ assert_equal mod.instance_method(:a), memo.shift
+ assert_equal :a=, memo.shift
+ assert_equal [:f, :g, :a, :a=], memo.shift
+ assert_equal mod.instance_method(:a=), memo.shift
+ end
+
+ def test_method_undefined
+ added = []
+ undefed = []
+ removed = []
+ mod = Module.new do
+ mod = self
+ def f
+ end
+ (class << self ; self ; end).class_eval do
+ define_method :method_added do |sym|
+ added << sym
+ end
+ define_method :method_undefined do |sym|
+ undefed << sym
+ end
+ define_method :method_removed do |sym|
+ removed << sym
+ end
+ end
+ end
+ assert_method_defined?(mod, :f)
+ mod.module_eval do
+ undef :f
+ end
+ assert_equal [], added
+ assert_equal [:f], undefed
+ assert_equal [], removed
+ end
+
+ def test_method_removed
+ added = []
+ undefed = []
+ removed = []
+ mod = Module.new do
+ mod = self
+ def f
+ end
+ (class << self ; self ; end).class_eval do
+ define_method :method_added do |sym|
+ added << sym
+ end
+ define_method :method_undefined do |sym|
+ undefed << sym
+ end
+ define_method :method_removed do |sym|
+ removed << sym
+ end
+ end
+ end
+ assert_method_defined?(mod, :f)
+ mod.module_eval do
+ remove_method :f
+ end
+ assert_equal [], added
+ assert_equal [], undefed
+ assert_equal [:f], removed
+ end
+
+ def test_method_redefinition
+ feature2155 = '[ruby-dev:39400]'
+
+ line = __LINE__+4
+ stderr = EnvUtil.verbose_warning do
+ Module.new do
+ def foo; end
+ def foo; end
+ end
+ end
+ assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
+ assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
+
+ assert_warning '' do
+ Module.new do
+ def foo; end
+ alias bar foo
+ def foo; end
+ end
+ end
+
+ assert_warning '' do
+ Module.new do
+ def foo; end
+ alias bar foo
+ alias bar foo
+ end
+ end
+
+ line = __LINE__+4
+ stderr = EnvUtil.verbose_warning do
+ Module.new do
+ define_method(:foo) do end
+ def foo; end
+ end
+ end
+ assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
+ assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
+
+ assert_warning '' do
+ Module.new do
+ define_method(:foo) do end
+ alias bar foo
+ alias bar foo
+ end
+ end
+
+ assert_warning('', '[ruby-dev:39397]') do
+ Module.new do
+ module_function
+ def foo; end
+ module_function :foo
+ end
+ end
+
+ assert_warning '' do
+ Module.new do
+ def foo; end
+ undef foo
+ end
+ end
+ end
+
+ def test_protected_singleton_method
+ klass = Class.new
+ x = klass.new
+ class << x
+ protected
+
+ def foo
+ end
+ end
+ assert_raise(NoMethodError) do
+ x.foo
+ end
+ klass.send(:define_method, :bar) do
+ x.foo
+ end
+ assert_nothing_raised do
+ x.bar
+ end
+ y = klass.new
+ assert_raise(NoMethodError) do
+ y.bar
+ end
+ end
+
+ def test_uninitialized_toplevel_constant
+ bug3123 = '[ruby-dev:40951]'
+ e = assert_raise(NameError) {eval("Bug3123", TOPLEVEL_BINDING)}
+ assert_not_match(/Object::/, e.message, bug3123)
+ end
+
+ def test_attr_inherited_visibility
+ bug3406 = '[ruby-core:30638]'
+ c = Class.new do
+ class << self
+ private
+ def attr_accessor(*); super; end
+ end
+ attr_accessor :x
+ end.new
+ assert_nothing_raised(bug3406) {c.x = 1}
+ assert_equal(1, c.x, bug3406)
+ end
+
+ def test_attr_writer_with_no_arguments
+ bug8540 = "[ruby-core:55543]"
+ c = Class.new do
+ attr_writer :foo
+ end
+ assert_raise(ArgumentError, bug8540) { c.new.send :foo= }
+ end
+
+ def test_private_constant
+ c = Class.new
+ c.const_set(:FOO, "foo")
+ assert_equal("foo", c::FOO)
+ c.private_constant(:FOO)
+ assert_raise(NameError) { c::FOO }
+ assert_equal("foo", c.class_eval("FOO"))
+ assert_equal("foo", c.const_get("FOO"))
+ $VERBOSE, verbose = nil, $VERBOSE
+ c.const_set(:FOO, "foo")
+ $VERBOSE = verbose
+ assert_raise(NameError) { c::FOO }
+ end
+
+ def test_private_constant2
+ c = Class.new
+ c.const_set(:FOO, "foo")
+ c.const_set(:BAR, "bar")
+ assert_equal("foo", c::FOO)
+ assert_equal("bar", c::BAR)
+ c.private_constant(:FOO, :BAR)
+ assert_raise(NameError) { c::FOO }
+ assert_raise(NameError) { c::BAR }
+ assert_equal("foo", c.class_eval("FOO"))
+ assert_equal("bar", c.class_eval("BAR"))
+ end
+
+ def test_private_constant_with_no_args
+ assert_in_out_err([], <<-RUBY, [], ["-:3: warning: private_constant with no argument is just ignored"])
+ $-w = true
+ class X
+ private_constant
+ end
+ RUBY
+ end
+
+ class PrivateClass
+ end
+ private_constant :PrivateClass
+
+ def test_define_module_under_private_constant
+ assert_raise(NameError) do
+ eval %q{class TestModule::PrivateClass; end}
+ end
+ assert_raise(NameError) do
+ eval %q{module TestModule::PrivateClass::TestModule; end}
+ end
+ eval %q{class PrivateClass; end}
+ eval %q{module PrivateClass::TestModule; end}
+ assert_instance_of(Module, PrivateClass::TestModule)
+ PrivateClass.class_eval { remove_const(:TestModule) }
+ end
+
+ def test_public_constant
+ c = Class.new
+ c.const_set(:FOO, "foo")
+ assert_equal("foo", c::FOO)
+ c.private_constant(:FOO)
+ assert_raise(NameError) { c::FOO }
+ assert_equal("foo", c.class_eval("FOO"))
+ c.public_constant(:FOO)
+ assert_equal("foo", c::FOO)
+ end
+
+ def test_constants_with_private_constant
+ assert_not_include(::TestModule.constants, :PrivateClass)
+ end
+
+ def test_toplevel_private_constant
+ src = <<-INPUT
+ class Object
+ private_constant :Object
+ end
+ p Object
+ begin
+ p ::Object
+ rescue
+ p :ok
+ end
+ INPUT
+ assert_in_out_err([], src, %w(Object :ok), [])
+ end
+
+ def test_private_constants_clear_inlinecache
+ bug5702 = '[ruby-dev:44929]'
+ src = <<-INPUT
+ class A
+ C = :Const
+ def self.get_C
+ A::C
+ end
+ # fill cache
+ A.get_C
+ private_constant :C, :D rescue nil
+ begin
+ A.get_C
+ rescue NameError
+ puts "A.get_C"
+ end
+ end
+ INPUT
+ assert_in_out_err([], src, %w(A.get_C), [], bug5702)
+ end
+
+ def test_constant_lookup_in_method_defined_by_class_eval
+ src = <<-INPUT
+ class A
+ B = 42
+ end
+
+ A.class_eval do
+ def self.f
+ B
+ end
+
+ def f
+ B
+ end
+ end
+
+ begin
+ A.f
+ rescue NameError
+ puts "A.f"
+ end
+ begin
+ A.new.f
+ rescue NameError
+ puts "A.new.f"
+ end
+ INPUT
+ assert_in_out_err([], src, %w(A.f A.new.f), [])
+ end
+
+ def test_constant_lookup_in_toplevel_class_eval
+ src = <<-INPUT
+ module X
+ A = 123
+ end
+ begin
+ X.class_eval { A }
+ rescue NameError => e
+ puts e
+ end
+ INPUT
+ assert_in_out_err([], src, ["uninitialized constant A"], [])
+ end
+
+ def test_constant_lookup_in_module_in_class_eval
+ src = <<-INPUT
+ class A
+ B = 42
+ end
+
+ A.class_eval do
+ module C
+ begin
+ B
+ rescue NameError
+ puts "NameError"
+ end
+ end
+ end
+ INPUT
+ assert_in_out_err([], src, ["NameError"], [])
+ end
+
+ module M0
+ def m1; [:M0] end
+ end
+ module M1
+ def m1; [:M1, *super] end
+ end
+ module M2
+ def m1; [:M2, *super] end
+ end
+ M3 = Module.new do
+ def m1; [:M3, *super] end
+ end
+ module M4
+ def m1; [:M4, *super] end
+ end
+ class C
+ def m1; end
+ end
+ class C0 < C
+ include M0
+ prepend M1
+ def m1; [:C0, *super] end
+ end
+ class C1 < C0
+ prepend M2, M3
+ include M4
+ def m1; [:C1, *super] end
+ end
+
+ def test_prepend
+ obj = C0.new
+ expected = [:M1,:C0,:M0]
+ assert_equal(expected, obj.m1)
+ obj = C1.new
+ expected = [:M2,:M3,:C1,:M4,:M1,:C0,:M0]
+ assert_equal(expected, obj.m1)
+ end
+
+ def test_public_prepend
+ assert_nothing_raised('#8846') do
+ Class.new.prepend(Module.new)
+ end
+ end
+
+ def test_prepend_inheritance
+ bug6654 = '[ruby-core:45914]'
+ a = labeled_module("a")
+ b = labeled_module("b") {include a}
+ c = labeled_class("c") {prepend b}
+ assert_operator(c, :<, b, bug6654)
+ assert_operator(c, :<, a, bug6654)
+ bug8357 = '[ruby-core:54736] [Bug #8357]'
+ b = labeled_module("b") {prepend a}
+ c = labeled_class("c") {include b}
+ assert_operator(c, :<, b, bug8357)
+ assert_operator(c, :<, a, bug8357)
+ bug8357 = '[ruby-core:54742] [Bug #8357]'
+ assert_kind_of(b, c.new, bug8357)
+ end
+
+ def test_prepend_instance_methods
+ bug6655 = '[ruby-core:45915]'
+ assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655)
+ end
+
+ def test_prepend_singleton_methods
+ o = Object.new
+ o.singleton_class.class_eval {prepend Module.new}
+ assert_equal([], o.singleton_methods)
+ end
+
+ def test_prepend_remove_method
+ c = Class.new do
+ prepend Module.new {def foo; end}
+ end
+ assert_raise(NameError) do
+ c.class_eval do
+ remove_method(:foo)
+ end
+ end
+ c.class_eval do
+ def foo; end
+ end
+ removed = nil
+ c.singleton_class.class_eval do
+ define_method(:method_removed) {|id| removed = id}
+ end
+ assert_nothing_raised(NoMethodError, NameError, '[Bug #7843]') do
+ c.class_eval do
+ remove_method(:foo)
+ end
+ end
+ assert_equal(:foo, removed)
+ end
+
+ def test_prepend_class_ancestors
+ bug6658 = '[ruby-core:45919]'
+ m = labeled_module("m")
+ c = labeled_class("c") {prepend m}
+ assert_equal([m, c], c.ancestors[0, 2], bug6658)
+
+ bug6662 = '[ruby-dev:45868]'
+ c2 = labeled_class("c2", c)
+ anc = c2.ancestors
+ assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662)
+ end
+
+ def test_prepend_module_ancestors
+ bug6659 = '[ruby-dev:45861]'
+ m0 = labeled_module("m0") {def x; [:m0, *super] end}
+ m1 = labeled_module("m1") {def x; [:m1, *super] end; prepend m0}
+ m2 = labeled_module("m2") {def x; [:m2, *super] end; prepend m1}
+ c0 = labeled_class("c0") {def x; [:c0] end}
+ c1 = labeled_class("c1") {def x; [:c1] end; prepend m2}
+ c2 = labeled_class("c2", c0) {def x; [:c2, *super] end; include m2}
+
+ assert_equal([m0, m1], m1.ancestors, bug6659)
+
+ bug6662 = '[ruby-dev:45868]'
+ assert_equal([m0, m1, m2], m2.ancestors, bug6662)
+ assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662)
+ assert_equal([:m0, :m1, :m2, :c1], c1.new.x)
+ assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662)
+ assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x)
+
+ m3 = labeled_module("m3") {include m1; prepend m1}
+ assert_equal([m3, m0, m1], m3.ancestors)
+ m3 = labeled_module("m3") {prepend m1; include m1}
+ assert_equal([m0, m1, m3], m3.ancestors)
+ m3 = labeled_module("m3") {prepend m1; prepend m1}
+ assert_equal([m0, m1, m3], m3.ancestors)
+ m3 = labeled_module("m3") {include m1; include m1}
+ assert_equal([m3, m0, m1], m3.ancestors)
+ end
+
+ def labeled_module(name, &block)
+ EnvUtil.labeled_module(name, &block)
+ end
+
+ def labeled_class(name, superclass = Object, &block)
+ EnvUtil.labeled_class(name, superclass, &block)
+ end
+
+ def test_prepend_instance_methods_false
+ bug6660 = '[ruby-dev:45863]'
+ assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
+ assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
+ end
+
+ def test_cyclic_prepend
+ bug7841 = '[ruby-core:52205] [Bug #7841]'
+ m1 = Module.new
+ m2 = Module.new
+ m1.instance_eval { prepend(m2) }
+ assert_raise(ArgumentError, bug7841) do
+ m2.instance_eval { prepend(m1) }
+ end
+ end
+
+ def test_prepend_optmethod
+ bug7983 = '[ruby-dev:47124] [Bug #7983]'
+ assert_separately [], %{
+ module M
+ def /(other)
+ to_f / other
+ end
+ end
+ Fixnum.send(:prepend, M)
+ assert_equal(0.5, 1 / 2, "#{bug7983}")
+ }
+ assert_equal(0, 1 / 2)
+ end
+
+ def test_prepend_visibility
+ bug8005 = '[ruby-core:53106] [Bug #8005]'
+ c = Class.new do
+ prepend Module.new {}
+ def foo() end
+ protected :foo
+ end
+ a = c.new
+ assert_respond_to a, [:foo, true], bug8005
+ assert_nothing_raised(NoMethodError, bug8005) {a.send :foo}
+ end
+
+ def test_prepend_visibility_inherited
+ bug8238 = '[ruby-core:54105] [Bug #8238]'
+ assert_separately [], <<-"end;", timeout: 20
+ class A
+ def foo() A; end
+ private :foo
+ end
+ class B < A
+ public :foo
+ prepend Module.new
+ end
+ assert_equal(A, B.new.foo, "#{bug8238}")
+ end;
+ end
+
+ def test_prepend_included_modules
+ bug8025 = '[ruby-core:53158] [Bug #8025]'
+ mixin = labeled_module("mixin")
+ c = labeled_module("c") {prepend mixin}
+ im = c.included_modules
+ assert_not_include(im, c, bug8025)
+ assert_include(im, mixin, bug8025)
+ c1 = labeled_class("c1") {prepend mixin}
+ c2 = labeled_class("c2", c1)
+ im = c2.included_modules
+ assert_not_include(im, c1, bug8025)
+ assert_not_include(im, c2, bug8025)
+ assert_include(im, mixin, bug8025)
+ end
+
+ def test_prepend_super_in_alias
+ bug7842 = '[Bug #7842]'
+
+ p = labeled_module("P") do
+ def m; "P"+super; end
+ end
+ a = labeled_class("A") do
+ def m; "A"; end
+ end
+ b = labeled_class("B", a) do
+ def m; "B"+super; end
+ alias m2 m
+ prepend p
+ alias m3 m
+ end
+ assert_equal("BA", b.new.m2, bug7842)
+ assert_equal("PBA", b.new.m3, bug7842)
+ end
+
+ def test_include_super_in_alias
+ bug9236 = '[Bug #9236]'
+
+ fun = labeled_module("Fun") do
+ def hello
+ orig_hello
+ end
+ end
+
+ m1 = labeled_module("M1") do
+ def hello
+ 'hello!'
+ end
+ end
+
+ m2 = labeled_module("M2") do
+ def hello
+ super
+ end
+ end
+
+ foo = labeled_class("Foo") do
+ include m1
+ include m2
+
+ alias orig_hello hello
+ include fun
+ end
+
+ assert_equal('hello!', foo.new.hello, bug9236)
+ end
+
+ def test_prepend_call_super
+ assert_separately([], <<-'end;') #do
+ bug10847 = '[ruby-core:68093] [Bug #10847]'
+ module M; end
+ Float.prepend M
+ assert_nothing_raised(SystemStackError, bug10847) do
+ 0.3.numerator
+ end
+ end;
+ end
+
+ def test_class_variables
+ m = Module.new
+ m.class_variable_set(:@@foo, 1)
+ m2 = Module.new
+ m2.send(:include, m)
+ m2.class_variable_set(:@@bar, 2)
+ assert_equal([:@@foo], m.class_variables)
+ assert_equal([:@@bar, :@@foo], m2.class_variables)
+ assert_equal([:@@bar, :@@foo], m2.class_variables(true))
+ assert_equal([:@@bar], m2.class_variables(false))
+ end
+
+ Bug6891 = '[ruby-core:47241]'
+
+ def test_extend_module_with_protected_method
+ list = []
+
+ x = Class.new {
+ @list = list
+
+ extend Module.new {
+ protected
+
+ def inherited(klass)
+ @list << "protected"
+ super(klass)
+ end
+ }
+
+ extend Module.new {
+ def inherited(klass)
+ @list << "public"
+ super(klass)
+ end
+ }
+ }
+
+ assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)}
+ assert_equal(['public', 'protected'], list)
+ end
+
+ def test_extend_module_with_protected_bmethod
+ list = []
+
+ x = Class.new {
+ extend Module.new {
+ protected
+
+ define_method(:inherited) do |klass|
+ list << "protected"
+ super(klass)
+ end
+ }
+
+ extend Module.new {
+ define_method(:inherited) do |klass|
+ list << "public"
+ super(klass)
+ end
+ }
+ }
+
+ assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)}
+ assert_equal(['public', 'protected'], list)
+ end
+
+ def test_invalid_attr
+ %W[
+ foo?
+ @foo
+ @@foo
+ $foo
+ \u3042$
+ ].each do |name|
+ assert_raise_with_message(NameError, /#{Regexp.quote(quote(name))}/) do
+ Module.new { attr_accessor name.to_sym }
+ end
+ end
+ end
+
+ private def quote(name)
+ encoding = Encoding.default_internal || Encoding.default_external
+ (name.encoding == encoding || name.ascii_only?) ? name : name.inspect
+ end
+
+ class AttrTest
+ class << self
+ attr_accessor :cattr
+ end
+ attr_accessor :iattr
+ def ivar
+ @ivar
+ end
+ end
+
+ def test_uninitialized_instance_variable
+ a = AttrTest.new
+ assert_warning(/instance variable @ivar not initialized/) do
+ assert_nil(a.ivar)
+ end
+ a.instance_variable_set(:@ivar, 42)
+ assert_warning '' do
+ assert_equal(42, a.ivar)
+ end
+
+ name = "@\u{5909 6570}"
+ assert_warning(/instance variable #{name} not initialized/) do
+ val = EnvUtil.with_default_external(Encoding::UTF_8) {
+ a.instance_eval(name)
+ }
+ assert_nil(val)
+ end
+ end
+
+ def test_uninitialized_attr
+ a = AttrTest.new
+ assert_warning '' do
+ assert_nil(a.iattr)
+ end
+ a.iattr = 42
+ assert_warning '' do
+ assert_equal(42, a.iattr)
+ end
+ end
+
+ def test_uninitialized_attr_class
+ assert_warning '' do
+ assert_nil(AttrTest.cattr)
+ end
+ AttrTest.cattr = 42
+ assert_warning '' do
+ assert_equal(42, AttrTest.cattr)
+ end
+ end
+
+ def test_uninitialized_attr_non_object
+ a = Class.new(Array) do
+ attr_accessor :iattr
+ end.new
+ assert_warning '' do
+ assert_nil(a.iattr)
+ end
+ a.iattr = 42
+ assert_warning '' do
+ assert_equal(42, a.iattr)
+ end
+ end
+
+ def test_remove_const
+ m = Module.new
+ assert_raise(NameError){ m.instance_eval { remove_const(:__FOO__) } }
+ end
+
+ def test_private_top_methods
+ assert_top_method_is_private(:include)
+ assert_top_method_is_private(:public)
+ assert_top_method_is_private(:private)
+ assert_top_method_is_private(:define_method)
+ end
+
+ module PrivateConstantReopen
+ PRIVATE_CONSTANT = true
+ private_constant :PRIVATE_CONSTANT
+ end
+
+ def test_private_constant_reopen
+ assert_raise(NameError) do
+ eval <<-EOS, TOPLEVEL_BINDING
+ module TestModule::PrivateConstantReopen::PRIVATE_CONSTANT
+ end
+ EOS
+ end
+ assert_raise(NameError) do
+ eval <<-EOS, TOPLEVEL_BINDING
+ class TestModule::PrivateConstantReopen::PRIVATE_CONSTANT
+ end
+ EOS
+ end
+ end
+
+ def test_singleton_class_ancestors
+ feature8035 = '[ruby-core:53171]'
+ obj = Object.new
+ assert_equal [obj.singleton_class, Object], obj.singleton_class.ancestors.first(2), feature8035
+
+ mod = Module.new
+ obj.extend mod
+ assert_equal [obj.singleton_class, mod, Object], obj.singleton_class.ancestors.first(3)
+
+ obj = Object.new
+ obj.singleton_class.send :prepend, mod
+ assert_equal [mod, obj.singleton_class, Object], obj.singleton_class.ancestors.first(3)
+ end
+
+ def test_visibility_by_public_class_method
+ bug8284 = '[ruby-core:54404] [Bug #8284]'
+ assert_raise(NoMethodError) {Object.define_method}
+ Module.new.public_class_method(:define_method)
+ assert_raise(NoMethodError, bug8284) {Object.define_method}
+ end
+
+ def test_include_module_with_constants_invalidates_method_cache
+ assert_in_out_err([], <<-RUBY, %w(123 456), [])
+ A = 123
+
+ class Foo
+ def self.a
+ A
+ end
+ end
+
+ module M
+ A = 456
+ end
+
+ puts Foo.a
+ Foo.send(:include, M)
+ puts Foo.a
+ RUBY
+ end
+
+ def test_return_value_of_define_method
+ retvals = []
+ Class.new.class_eval do
+ retvals << define_method(:foo){}
+ retvals << define_method(:bar, instance_method(:foo))
+ end
+ assert_equal :foo, retvals[0]
+ assert_equal :bar, retvals[1]
+ end
+
+ def test_return_value_of_define_singleton_method
+ retvals = []
+ Class.new do
+ retvals << define_singleton_method(:foo){}
+ retvals << define_singleton_method(:bar, method(:foo))
+ end
+ assert_equal :foo, retvals[0]
+ assert_equal :bar, retvals[1]
+ end
+
+ def test_prepend_gc
+ assert_separately [], %{
+ module Foo
+ end
+ class Object
+ prepend Foo
+ end
+ GC.start # make created T_ICLASS old (or remembered shady)
+ class Object # add methods into T_ICLASS (need WB if it is old)
+ def foo; end
+ attr_reader :bar
+ end
+ 1_000_000.times{''} # cause GC
+ }
+ end
+
+ def test_inspect_segfault
+ bug_10282 = '[ruby-core:65214] [Bug #10282]'
+ assert_separately [], <<-RUBY
+ module ShallowInspect
+ def shallow_inspect
+ "foo"
+ end
+ end
+
+ module InspectIsShallow
+ include ShallowInspect
+ alias_method :inspect, :shallow_inspect
+ end
+
+ class A
+ end
+
+ A.prepend InspectIsShallow
+
+ expect = "#<Method: A(Object)#inspect(shallow_inspect)>"
+ assert_equal expect, A.new.method(:inspect).inspect, "#{bug_10282}"
+ RUBY
+ end
+
+ private
+
+ def assert_top_method_is_private(method)
+ assert_separately [], %{
+ methods = singleton_class.private_instance_methods(false)
+ assert_include(methods, :#{method}, ":#{method} should be private")
+
+ assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") {
+ self.#{method}
+ }
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_not.rb b/jni/ruby/test/ruby/test_not.rb
new file mode 100644
index 0000000..486075b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_not.rb
@@ -0,0 +1,12 @@
+require 'test/unit'
+
+class TestIfunless < Test::Unit::TestCase
+ def test_not_with_grouped_expression
+ assert_equal(false, (not (true)))
+ assert_equal(true, (not (false)))
+ end
+
+ def test_not_with_empty_grouped_expression
+ assert_equal(true, (not ()))
+ end
+end
diff --git a/jni/ruby/test/ruby/test_notimp.rb b/jni/ruby/test/ruby/test_notimp.rb
new file mode 100644
index 0000000..9721723
--- /dev/null
+++ b/jni/ruby/test/ruby/test_notimp.rb
@@ -0,0 +1,84 @@
+require 'test/unit'
+require 'timeout'
+require 'tmpdir'
+
+class TestNotImplement < Test::Unit::TestCase
+ def test_respond_to_fork
+ assert_include(Process.methods, :fork)
+ if /linux/ =~ RUBY_PLATFORM
+ assert_equal(true, Process.respond_to?(:fork))
+ end
+ end
+
+ def test_respond_to_lchmod
+ assert_include(File.methods, :lchmod)
+ if /linux/ =~ RUBY_PLATFORM
+ assert_equal(false, File.respond_to?(:lchmod))
+ end
+ if /freebsd/ =~ RUBY_PLATFORM
+ assert_equal(true, File.respond_to?(:lchmod))
+ end
+ end
+
+ def test_call_fork
+ GC.start
+ pid = nil
+ ps =
+ case RUBY_PLATFORM
+ when /linux/ # assume Linux Distribution uses procps
+ proc {`ps -eLf #{pid}`}
+ when /freebsd/
+ proc {`ps -lH #{pid}`}
+ when /darwin/
+ proc {`ps -lM #{pid}`}
+ else
+ proc {`ps -l #{pid}`}
+ end
+ assert_nothing_raised(Timeout::Error, ps) do
+ Timeout.timeout(5) {
+ pid = fork {}
+ Process.wait pid
+ pid = nil
+ }
+ end
+ ensure
+ if pid
+ Process.kill(:KILL, pid)
+ Process.wait pid
+ end
+ end if Process.respond_to?(:fork)
+
+ def test_call_lchmod
+ if File.respond_to?(:lchmod)
+ Dir.mktmpdir {|d|
+ f = "#{d}/f"
+ g = "#{d}/g"
+ File.open(f, "w") {}
+ File.symlink f, g
+ newmode = 0444
+ File.lchmod newmode, "#{d}/g"
+ snew = File.lstat(g)
+ assert_equal(newmode, snew.mode & 0777)
+ }
+ end
+ end
+
+ def test_method_inspect_fork
+ m = Process.method(:fork)
+ if Process.respond_to?(:fork)
+ assert_not_match(/not-implemented/, m.inspect)
+ else
+ assert_match(/not-implemented/, m.inspect)
+ end
+ end
+
+ def test_method_inspect_lchmod
+ m = File.method(:lchmod)
+ if File.respond_to?(:lchmod)
+ assert_not_match(/not-implemented/, m.inspect)
+ else
+ assert_match(/not-implemented/, m.inspect)
+ end
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_numeric.rb b/jni/ruby/test/ruby/test_numeric.rb
new file mode 100644
index 0000000..4c94c69
--- /dev/null
+++ b/jni/ruby/test/ruby/test_numeric.rb
@@ -0,0 +1,366 @@
+require 'test/unit'
+
+class TestNumeric < Test::Unit::TestCase
+ class DummyNumeric < Numeric
+ end
+
+ def test_coerce
+ a, b = 1.coerce(2)
+ assert_equal(Fixnum, a.class)
+ assert_equal(Fixnum, b.class)
+
+ a, b = 1.coerce(2.0)
+ assert_equal(Float, a.class)
+ assert_equal(Float, b.class)
+
+ assert_raise(TypeError) { -Numeric.new }
+
+ assert_raise_with_message(TypeError, /can't be coerced into /) {1+:foo}
+ assert_raise_with_message(TypeError, /can't be coerced into /) {1&:foo}
+ assert_raise_with_message(TypeError, /can't be coerced into /) {1|:foo}
+ assert_raise_with_message(TypeError, /can't be coerced into /) {1^:foo}
+
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"}
+ end
+ EnvUtil.with_default_external(Encoding::US_ASCII) do
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"}
+ end
+
+ bug10711 = '[ruby-core:67405] [Bug #10711]'
+ exp = "1.2 can't be coerced into Fixnum"
+ assert_raise_with_message(TypeError, exp, bug10711) { 1 & 1.2 }
+ end
+
+ def test_dummynumeric
+ a = DummyNumeric.new
+
+ DummyNumeric.class_eval do
+ def coerce(x); nil; end
+ end
+ assert_raise(TypeError) { -a }
+ assert_nil(1 <=> a)
+ assert_raise(ArgumentError) { 1 <= a }
+
+ DummyNumeric.class_eval do
+ remove_method :coerce
+ def coerce(x); 1.coerce(x); end
+ end
+ assert_equal(2, 1 + a)
+ assert_equal(0, 1 <=> a)
+ assert_operator(1, :<=, a)
+
+ DummyNumeric.class_eval do
+ remove_method :coerce
+ def coerce(x); [x, 1]; end
+ end
+ assert_equal(-1, -a)
+
+ bug7688 = '[ruby-core:51389] [Bug #7688]'
+ DummyNumeric.class_eval do
+ remove_method :coerce
+ def coerce(x); raise StandardError; end
+ end
+ assert_raise_with_message(TypeError, /can't be coerced into /) { 1 + a }
+ warn = /will no more rescue exceptions of #coerce.+ in the next release/m
+ assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
+
+ DummyNumeric.class_eval do
+ remove_method :coerce
+ def coerce(x); :bad_return_value; end
+ end
+ assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 + a }
+ warn = /Bad return value for #coerce.+next release will raise an error/m
+ assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
+
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :coerce
+ end
+ end
+
+ def test_singleton_method
+ a = Numeric.new
+ assert_raise_with_message(TypeError, /foo/) { def a.foo; end }
+ assert_raise_with_message(TypeError, /\u3042/) { eval("def a.\u3042; end") }
+ end
+
+ def test_dup
+ a = Numeric.new
+ assert_raise(TypeError) { a.dup }
+
+ c = Module.new do
+ break eval("class C\u{3042} < Numeric; self; end")
+ end
+ assert_raise_with_message(TypeError, /C\u3042/) {c.new.dup}
+ end
+
+ def test_quo
+ assert_raise(TypeError) {DummyNumeric.new.quo(1)}
+ end
+
+ def test_quo_ruby_core_41575
+ x = DummyNumeric.new
+ rat = 84.quo(1)
+ DummyNumeric.class_eval do
+ define_method(:to_r) { rat }
+ end
+ assert_equal(2.quo(1), x.quo(42), '[ruby-core:41575]')
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :to_r
+ end
+ end
+
+ def test_divmod
+=begin
+ DummyNumeric.class_eval do
+ def /(x); 42.0; end
+ def %(x); :mod; end
+ end
+
+ assert_equal(42, DummyNumeric.new.div(1))
+ assert_equal(:mod, DummyNumeric.new.modulo(1))
+ assert_equal([42, :mod], DummyNumeric.new.divmod(1))
+=end
+
+ assert_kind_of(Integer, 11.divmod(3.5).first, '[ruby-dev:34006]')
+
+=begin
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :/, :%
+ end
+=end
+ end
+
+ def test_real_p
+ assert_predicate(Numeric.new, :real?)
+ end
+
+ def test_integer_p
+ assert_not_predicate(Numeric.new, :integer?)
+ end
+
+ def test_abs
+ a = DummyNumeric.new
+ DummyNumeric.class_eval do
+ def -@; :ok; end
+ def <(x); true; end
+ end
+
+ assert_equal(:ok, a.abs)
+
+ DummyNumeric.class_eval do
+ remove_method :<
+ def <(x); false; end
+ end
+
+ assert_equal(a, a.abs)
+
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :-@, :<
+ end
+ end
+
+ def test_zero_p
+ DummyNumeric.class_eval do
+ def ==(x); true; end
+ end
+
+ assert_predicate(DummyNumeric.new, :zero?)
+
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :==
+ end
+ end
+
+ def test_to_int
+ DummyNumeric.class_eval do
+ def to_i; :ok; end
+ end
+
+ assert_equal(:ok, DummyNumeric.new.to_int)
+
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :to_i
+ end
+ end
+
+ def test_cmp
+ a = Numeric.new
+ assert_equal(0, a <=> a)
+ assert_nil(a <=> :foo)
+ end
+
+ def test_floor_ceil_round_truncate
+ DummyNumeric.class_eval do
+ def to_f; 1.5; end
+ end
+
+ a = DummyNumeric.new
+ assert_equal(1, a.floor)
+ assert_equal(2, a.ceil)
+ assert_equal(2, a.round)
+ assert_equal(1, a.truncate)
+
+ DummyNumeric.class_eval do
+ remove_method :to_f
+ def to_f; 1.4; end
+ end
+
+ a = DummyNumeric.new
+ assert_equal(1, a.floor)
+ assert_equal(2, a.ceil)
+ assert_equal(1, a.round)
+ assert_equal(1, a.truncate)
+
+ DummyNumeric.class_eval do
+ remove_method :to_f
+ def to_f; -1.5; end
+ end
+
+ a = DummyNumeric.new
+ assert_equal(-2, a.floor)
+ assert_equal(-1, a.ceil)
+ assert_equal(-2, a.round)
+ assert_equal(-1, a.truncate)
+
+ ensure
+ DummyNumeric.class_eval do
+ remove_method :to_f
+ end
+ end
+
+ def assert_step(expected, (from, *args), inf: false)
+ enum = from.step(*args)
+ size = enum.size
+ xsize = expected.size
+
+ if inf
+ assert_send [size, :infinite?], "step size: +infinity"
+ assert_send [size, :>, 0], "step size: +infinity"
+
+ a = []
+ from.step(*args) { |x| a << x; break if a.size == xsize }
+ assert_equal expected, a, "step"
+
+ a = []
+ enum.each { |x| a << x; break if a.size == xsize }
+ assert_equal expected, a, "step enumerator"
+ else
+ assert_equal expected.size, size, "step size"
+
+ a = []
+ from.step(*args) { |x| a << x }
+ assert_equal expected, a, "step"
+
+ a = []
+ enum.each { |x| a << x }
+ assert_equal expected, a, "step enumerator"
+ end
+ end
+
+ def test_step
+ i, bignum = 32, 1 << 30
+ bignum <<= (i <<= 1) - 32 until bignum.is_a?(Bignum)
+ assert_raise(ArgumentError) { 1.step(10, 1, 0) { } }
+ assert_raise(ArgumentError) { 1.step(10, 1, 0).size }
+ assert_raise(ArgumentError) { 1.step(10, 0) { } }
+ assert_raise(ArgumentError) { 1.step(10, 0).size }
+ assert_raise(ArgumentError) { 1.step(10, "1") { } }
+ assert_raise(ArgumentError) { 1.step(10, "1").size }
+ assert_raise(TypeError) { 1.step(10, nil) { } }
+ assert_raise(TypeError) { 1.step(10, nil).size }
+ assert_nothing_raised { 1.step(by: 0, to: nil) }
+ assert_nothing_raised { 1.step(by: 0, to: nil).size }
+ assert_nothing_raised { 1.step(by: 0) }
+ assert_nothing_raised { 1.step(by: 0).size }
+ assert_nothing_raised { 1.step(by: nil) }
+ assert_nothing_raised { 1.step(by: nil).size }
+
+ bug9811 = '[ruby-dev:48177] [Bug #9811]'
+ assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} }
+ assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size }
+ assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11) {} }
+ assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11).size }
+ assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11) {} }
+ assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11).size }
+
+ assert_equal(bignum*2+1, (-bignum).step(bignum, 1).size)
+ assert_equal(bignum*2, (-bignum).step(bignum-1, 1).size)
+
+ assert_equal(10+1, (0.0).step(10.0, 1.0).size)
+
+ i, bigflo = 1, bignum.to_f
+ i <<= 1 until (bigflo - i).to_i < bignum
+ bigflo -= i >> 1
+ assert_equal(bigflo.to_i, (0.0).step(bigflo-1.0, 1.0).size)
+ assert_operator((0.0).step(bignum.to_f, 1.0).size, :>=, bignum) # may loose precision
+
+ assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10]
+ assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10]
+ assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10, by: nil]
+ assert_step [1, 3, 5, 7, 9], [1, 10, 2]
+ assert_step [1, 3, 5, 7, 9], [1, to: 10, by: 2]
+
+ assert_step [10, 8, 6, 4, 2], [10, 1, -2]
+ assert_step [10, 8, 6, 4, 2], [10, to: 1, by: -2]
+ assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, 10.0, 2.0]
+ assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, to: 10.0, by: 2.0]
+ assert_step [1], [1, 10, bignum]
+ assert_step [1], [1, to: 10, by: bignum]
+
+ assert_step [], [2, 1, 3]
+ assert_step [], [-2, -1, -3]
+ assert_step [3, 3, 3, 3], [3, by: 0], inf: true
+ assert_step [3, 3, 3, 3], [3, by: 0, to: 42], inf: true
+ assert_step [10], [10, 1, -bignum]
+
+ assert_step [], [1, 0, Float::INFINITY]
+ assert_step [], [0, 1, -Float::INFINITY]
+ assert_step [10], [10, to: 1, by: -bignum]
+
+ assert_step [10, 11, 12, 13], [10], inf: true
+ assert_step [10, 9, 8, 7], [10, by: -1], inf: true
+ assert_step [10, 9, 8, 7], [10, by: -1, to: nil], inf: true
+
+ assert_step [42, 42, 42, 42], [42, by: 0, to: -Float::INFINITY], inf: true
+ assert_step [42, 42, 42, 42], [42, by: 0, to: 42.5], inf: true
+ assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: 0.0], inf: true
+ assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: -0.0], inf: true
+ assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 44], inf: true
+ assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 0], inf: true
+ assert_step [42.0, 42.0, 42.0, 42.0], [42, by: -0.0, to: 44], inf: true
+
+ assert_step [bignum]*4, [bignum, by: 0], inf: true
+ assert_step [bignum]*4, [bignum, by: 0.0], inf: true
+ assert_step [bignum]*4, [bignum, by: 0, to: bignum+1], inf: true
+ assert_step [bignum]*4, [bignum, by: 0, to: 0], inf: true
+ end
+
+ def test_num2long
+ assert_raise(TypeError) { 1 & nil }
+ assert_raise(TypeError) { 1 & 1.0 }
+ assert_raise(TypeError) { 1 & 2147483648.0 }
+ assert_raise(TypeError) { 1 & 9223372036854777856.0 }
+ o = Object.new
+ def o.to_int; 1; end
+ assert_raise(TypeError) { assert_equal(1, 1 & o) }
+ end
+
+ def test_eql
+ assert_equal(1, 1.0)
+ assert_not_operator(1, :eql?, 1.0)
+ assert_not_operator(1, :eql?, 2)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_object.rb b/jni/ruby/test/ruby/test_object.rb
new file mode 100644
index 0000000..d5b4a1b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_object.rb
@@ -0,0 +1,861 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+
+class TestObject < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_itself
+ feature6373 = '[ruby-core:44704] [Feature #6373]'
+ object = Object.new
+ assert_same(object, object.itself, feature6373)
+ end
+
+ def test_dup
+ assert_raise(TypeError) { 1.dup }
+ assert_raise(TypeError) { true.dup }
+ assert_raise(TypeError) { nil.dup }
+
+ assert_raise(TypeError) do
+ Object.new.instance_eval { initialize_copy(1) }
+ end
+ end
+
+ def test_init_dupclone
+ cls = Class.new do
+ def initialize_clone(orig); throw :initialize_clone; end
+ def initialize_dup(orig); throw :initialize_dup; end
+ end
+
+ obj = cls.new
+ assert_throw(:initialize_clone) {obj.clone}
+ assert_throw(:initialize_dup) {obj.dup}
+ end
+
+ def test_instance_of
+ assert_raise(TypeError) { 1.instance_of?(1) }
+ end
+
+ def test_kind_of
+ assert_raise(TypeError) { 1.kind_of?(1) }
+ end
+
+ def test_taint_frozen_obj
+ o = Object.new
+ o.freeze
+ assert_raise(RuntimeError) { o.taint }
+
+ o = Object.new
+ o.taint
+ o.freeze
+ assert_raise(RuntimeError) { o.untaint }
+ end
+
+ def test_freeze_immediate
+ assert_equal(true, 1.frozen?)
+ 1.freeze
+ assert_equal(true, 1.frozen?)
+ assert_equal(true, 2.frozen?)
+ assert_equal(true, true.frozen?)
+ assert_equal(true, false.frozen?)
+ assert_equal(true, nil.frozen?)
+ end
+
+ def test_frozen_error_message
+ name = "C\u{30c6 30b9 30c8}"
+ klass = EnvUtil.labeled_class(name) {
+ attr_accessor :foo
+ }
+ obj = klass.new.freeze
+ assert_raise_with_message(RuntimeError, /#{name}/) {
+ obj.foo = 1
+ }
+ end
+
+ def test_nil_to_f
+ assert_equal(0.0, nil.to_f)
+ end
+
+ def test_not
+ assert_equal(false, Object.new.send(:!))
+ assert_equal(true, nil.send(:!))
+ end
+
+ def test_true_and
+ assert_equal(true, true & true)
+ assert_equal(true, true & 1)
+ assert_equal(false, true & false)
+ assert_equal(false, true & nil)
+ end
+
+ def test_true_or
+ assert_equal(true, true | true)
+ assert_equal(true, true | 1)
+ assert_equal(true, true | false)
+ assert_equal(true, true | nil)
+ end
+
+ def test_true_xor
+ assert_equal(false, true ^ true)
+ assert_equal(false, true ^ 1)
+ assert_equal(true, true ^ false)
+ assert_equal(true, true ^ nil)
+ end
+
+ def test_false_and
+ assert_equal(false, false & true)
+ assert_equal(false, false & 1)
+ assert_equal(false, false & false)
+ assert_equal(false, false & nil)
+ end
+
+ def test_false_or
+ assert_equal(true, false | true)
+ assert_equal(true, false | 1)
+ assert_equal(false, false | false)
+ assert_equal(false, false | nil)
+ end
+
+ def test_false_xor
+ assert_equal(true, false ^ true)
+ assert_equal(true, false ^ 1)
+ assert_equal(false, false ^ false)
+ assert_equal(false, false ^ nil)
+ end
+
+ def test_methods
+ o = Object.new
+ a1 = o.methods
+ a2 = o.methods(false)
+
+ def o.foo; end
+
+ assert_equal([:foo], o.methods(true) - a1)
+ assert_equal([:foo], o.methods(false) - a2)
+ end
+
+ def test_methods2
+ c0 = Class.new
+ c1 = Class.new(c0)
+ c1.module_eval do
+ public ; def foo; end
+ protected; def bar; end
+ private ; def baz; end
+ end
+ c2 = Class.new(c1)
+ c2.module_eval do
+ public ; def foo2; end
+ protected; def bar2; end
+ private ; def baz2; end
+ end
+
+ o0 = c0.new
+ o2 = c2.new
+
+ assert_equal([:baz, :baz2], (o2.private_methods - o0.private_methods).sort)
+ assert_equal([:baz2], (o2.private_methods(false) - o0.private_methods(false)).sort)
+
+ assert_equal([:bar, :bar2], (o2.protected_methods - o0.protected_methods).sort)
+ assert_equal([:bar2], (o2.protected_methods(false) - o0.protected_methods(false)).sort)
+
+ assert_equal([:foo, :foo2], (o2.public_methods - o0.public_methods).sort)
+ assert_equal([:foo2], (o2.public_methods(false) - o0.public_methods(false)).sort)
+ end
+
+ def test_methods_prepend
+ bug8044 = '[ruby-core:53207] [Bug #8044]'
+ o = Object.new
+ def o.foo; end
+ assert_equal([:foo], o.methods(false))
+ class << o; prepend Module.new; end
+ assert_equal([:foo], o.methods(false), bug8044)
+ end
+
+ def test_instance_variable_get
+ o = Object.new
+ o.instance_eval { @foo = :foo }
+ assert_equal(:foo, o.instance_variable_get(:@foo))
+ assert_equal(nil, o.instance_variable_get(:@bar))
+ assert_raise(NameError) { o.instance_variable_get('@') }
+ assert_raise(NameError) { o.instance_variable_get(:'@') }
+ assert_raise(NameError) { o.instance_variable_get(:foo) }
+ assert_raise(NameError) { o.instance_variable_get("bar") }
+ assert_raise(TypeError) { o.instance_variable_get(1) }
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
+ def n.count; @count; end
+ assert_equal(:foo, o.instance_variable_get(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_instance_variable_set
+ o = Object.new
+ o.instance_variable_set(:@foo, :foo)
+ assert_equal(:foo, o.instance_eval { @foo })
+ assert_raise(NameError) { o.instance_variable_set(:'@', 1) }
+ assert_raise(NameError) { o.instance_variable_set('@', 1) }
+ assert_raise(NameError) { o.instance_variable_set(:foo, 1) }
+ assert_raise(NameError) { o.instance_variable_set("bar", 1) }
+ assert_raise(TypeError) { o.instance_variable_set(1, 1) }
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
+ def n.count; @count; end
+ o.instance_variable_set(n, :bar)
+ assert_equal(:bar, o.instance_eval { @foo })
+ assert_equal(1, n.count)
+ end
+
+ def test_instance_variable_defined
+ o = Object.new
+ o.instance_eval { @foo = :foo }
+ assert_equal(true, o.instance_variable_defined?(:@foo))
+ assert_equal(false, o.instance_variable_defined?(:@bar))
+ assert_raise(NameError) { o.instance_variable_defined?(:'@') }
+ assert_raise(NameError) { o.instance_variable_defined?('@') }
+ assert_raise(NameError) { o.instance_variable_defined?(:foo) }
+ assert_raise(NameError) { o.instance_variable_defined?("bar") }
+ assert_raise(TypeError) { o.instance_variable_defined?(1) }
+
+ n = Object.new
+ def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
+ def n.count; @count; end
+ assert_equal(true, o.instance_variable_defined?(n))
+ assert_equal(1, n.count)
+ end
+
+ def test_remove_instance_variable
+ o = Object.new
+ o.instance_eval { @foo = :foo }
+ o.remove_instance_variable(:@foo)
+ assert_equal(false, o.instance_variable_defined?(:@foo))
+ end
+
+ def test_convert_type
+ o = Object.new
+ def o.to_s; 1; end
+ assert_raise(TypeError) { String(o) }
+ def o.to_s; "o"; end
+ assert_equal("o", String(o))
+ def o.respond_to?(*) false; end
+ assert_raise(TypeError) { String(o) }
+ end
+
+ def test_check_convert_type
+ o = Object.new
+ def o.to_a; 1; end
+ assert_raise(TypeError) { Array(o) }
+ def o.to_a; [1]; end
+ assert_equal([1], Array(o))
+ def o.respond_to?(*) false; end
+ assert_equal([o], Array(o))
+ end
+
+ def test_convert_hash
+ assert_equal({}, Hash(nil))
+ assert_equal({}, Hash([]))
+ assert_equal({key: :value}, Hash(key: :value))
+ assert_raise(TypeError) { Hash([1,2]) }
+ assert_raise(TypeError) { Hash(Object.new) }
+ o = Object.new
+ def o.to_hash; {a: 1, b: 2}; end
+ assert_equal({a: 1, b: 2}, Hash(o))
+ def o.to_hash; 9; end
+ assert_raise(TypeError) { Hash(o) }
+ end
+
+ def test_to_integer
+ o = Object.new
+ def o.to_i; nil; end
+ assert_raise(TypeError) { Integer(o) }
+ def o.to_i; 42; end
+ assert_equal(42, Integer(o))
+ def o.respond_to?(*) false; end
+ assert_raise(TypeError) { Integer(o) }
+ end
+
+ class MyInteger
+ def initialize(n); @num = n; end
+ def to_int; @num; end
+ def <=>(n); @num <=> n.to_int; end
+ def <=(n); @num <= n.to_int; end
+ def +(n); MyInteger.new(@num + n.to_int); end
+ end
+
+ def test_check_to_integer
+ o1 = MyInteger.new(1)
+ o9 = MyInteger.new(9)
+ n = 0
+ Range.new(o1, o9).step(2) {|x| n += x.to_int }
+ assert_equal(1+3+5+7+9, n)
+ end
+
+ def test_redefine_method_under_verbose
+ assert_in_out_err([], <<-INPUT, %w(2), /warning: method redefined; discarding old foo$/)
+ $VERBOSE = true
+ o = Object.new
+ def o.foo; 1; end
+ def o.foo; 2; end
+ p o.foo
+ INPUT
+ end
+
+ def test_redefine_method_which_may_case_serious_problem
+ assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `object_id' may cause serious problems$")
+ $VERBOSE = false
+ def (Object.new).object_id; end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `__send__' may cause serious problems$")
+ $VERBOSE = false
+ def (Object.new).__send__; end
+ INPUT
+
+ bug10421 = '[ruby-dev:48691] [Bug #10421]'
+ assert_in_out_err([], <<-INPUT, ["1"], [], bug10421)
+ $VERBOSE = false
+ class C < BasicObject
+ def object_id; 1; end
+ end
+ puts C.new.object_id
+ INPUT
+ end
+
+ def test_remove_method
+ c = Class.new
+ c.freeze
+ assert_raise(RuntimeError) do
+ c.instance_eval { remove_method(:foo) }
+ end
+
+ c = Class.new do
+ def meth1; "meth" end
+ end
+ d = Class.new(c) do
+ alias meth2 meth1
+ end
+ o1 = c.new
+ assert_respond_to(o1, :meth1)
+ assert_equal("meth", o1.meth1)
+ o2 = d.new
+ assert_respond_to(o2, :meth1)
+ assert_equal("meth", o2.meth1)
+ assert_respond_to(o2, :meth2)
+ assert_equal("meth", o2.meth2)
+ d.class_eval do
+ remove_method :meth2
+ end
+ bug2202 = '[ruby-core:26074]'
+ assert_raise(NoMethodError, bug2202) {o2.meth2}
+
+ %w(object_id __send__ initialize).each do |m|
+ assert_in_out_err([], <<-INPUT, %w(:ok), %r"warning: removing `#{m}' may cause serious problems$")
+ $VERBOSE = false
+ begin
+ Class.new.instance_eval { remove_method(:#{m}) }
+ rescue NameError
+ p :ok
+ end
+ INPUT
+ end
+
+ m = "\u{30e1 30bd 30c3 30c9}"
+ c = Class.new
+ assert_raise_with_message(NameError, /#{m}/) do
+ c.class_eval {remove_method m}
+ end
+ c = Class.new {
+ define_method(m) {}
+ remove_method(m)
+ }
+ assert_raise_with_message(NameError, /#{m}/) do
+ c.class_eval {remove_method m}
+ end
+ end
+
+ def test_method_missing
+ assert_raise(ArgumentError) do
+ 1.instance_eval { method_missing }
+ end
+
+ c = Class.new
+ c.class_eval do
+ protected
+ def foo; end
+ end
+ assert_raise(NoMethodError) do
+ c.new.foo
+ end
+
+ assert_raise(NoMethodError) do
+ 1.instance_eval { method_missing(:method_missing) }
+ end
+
+ c.class_eval do
+ undef_method(:method_missing)
+ end
+
+ assert_raise(ArgumentError) do
+ c.new.method_missing
+ end
+
+ bug2494 = '[ruby-core:27219]'
+ c = Class.new do
+ def method_missing(meth, *args)
+ super
+ end
+ end
+ b = c.new
+ foo rescue nil
+ assert_nothing_raised(bug2494) {[b].flatten}
+ end
+
+ def test_respond_to_missing_string
+ c = Class.new do
+ def respond_to_missing?(id, priv)
+ !(id !~ /\Agadzoks\d+\z/) ^ priv
+ end
+ end
+ foo = c.new
+ assert_equal(false, foo.respond_to?("gadzooks16"))
+ assert_equal(true, foo.respond_to?("gadzooks17", true))
+ assert_equal(true, foo.respond_to?("gadzoks16"))
+ assert_equal(false, foo.respond_to?("gadzoks17", true))
+ end
+
+ def test_respond_to_missing
+ c = Class.new do
+ def respond_to_missing?(id, priv)
+ if id == :foobar
+ true
+ else
+ false
+ end
+ end
+ def method_missing(id, *args)
+ if id == :foobar
+ return [:foo, *args]
+ else
+ super
+ end
+ end
+ end
+
+ foo = c.new
+ assert_equal([:foo], foo.foobar);
+ assert_equal([:foo, 1], foo.foobar(1));
+ assert_equal([:foo, 1, 2, 3, 4, 5], foo.foobar(1, 2, 3, 4, 5));
+ assert_respond_to(foo, :foobar)
+ assert_not_respond_to(foo, :foobarbaz)
+ assert_raise(NoMethodError) do
+ foo.foobarbaz
+ end
+
+ foobar = foo.method(:foobar)
+ assert_equal(-1, foobar.arity);
+ assert_equal([:foo], foobar.call);
+ assert_equal([:foo, 1], foobar.call(1));
+ assert_equal([:foo, 1, 2, 3, 4, 5], foobar.call(1, 2, 3, 4, 5));
+ assert_equal(foobar, foo.method(:foobar))
+ assert_not_equal(foobar, c.new.method(:foobar))
+
+ c = Class.new(c)
+ assert_equal(false, c.method_defined?(:foobar))
+ assert_raise(NameError, '[ruby-core:25748]') do
+ c.instance_method(:foobar)
+ end
+
+ m = Module.new
+ assert_equal(false, m.method_defined?(:foobar))
+ assert_raise(NameError, '[ruby-core:25748]') do
+ m.instance_method(:foobar)
+ end
+ end
+
+ def test_implicit_respond_to
+ bug5158 = '[ruby-core:38799]'
+
+ p = Object.new
+
+ called = []
+ p.singleton_class.class_eval do
+ define_method(:to_ary) do
+ called << [:to_ary, bug5158]
+ end
+ end
+ [[p]].flatten
+ assert_equal([[:to_ary, bug5158]], called, bug5158)
+
+ called = []
+ p.singleton_class.class_eval do
+ define_method(:respond_to?) do |*a|
+ called << [:respond_to?, *a]
+ false
+ end
+ end
+ [[p]].flatten
+ assert_equal([[:respond_to?, :to_ary, true]], called, bug5158)
+ end
+
+ def test_implicit_respond_to_arity_1
+ p = Object.new
+
+ called = []
+ p.singleton_class.class_eval do
+ define_method(:respond_to?) do |a|
+ called << [:respond_to?, a]
+ false
+ end
+ end
+ [[p]].flatten
+ assert_equal([[:respond_to?, :to_ary]], called, '[bug:6000]')
+ end
+
+ def test_implicit_respond_to_arity_3
+ p = Object.new
+
+ called = []
+ p.singleton_class.class_eval do
+ define_method(:respond_to?) do |a, b, c|
+ called << [:respond_to?, a, b, c]
+ false
+ end
+ end
+
+ msg = 'respond_to? must accept 1 or 2 arguments (requires 3)'
+ assert_raise_with_message(ArgumentError, msg, '[bug:6000]') do
+ [[p]].flatten
+ end
+ end
+
+ def test_method_missing_passed_block
+ bug5731 = '[ruby-dev:44961]'
+
+ c = Class.new do
+ def method_missing(meth, *args) yield(meth, *args) end
+ end
+ a = c.new
+ result = nil
+ assert_nothing_raised(LocalJumpError, bug5731) do
+ a.foo {|x| result = x}
+ end
+ assert_equal(:foo, result, bug5731)
+ result = nil
+ e = a.enum_for(:foo)
+ assert_nothing_raised(LocalJumpError, bug5731) do
+ e.each {|x| result = x}
+ end
+ assert_equal(:foo, result, bug5731)
+
+ c = Class.new do
+ def respond_to_missing?(id, priv)
+ true
+ end
+ def method_missing(id, *args, &block)
+ return block.call(:foo, *args)
+ end
+ end
+ foo = c.new
+
+ result = nil
+ assert_nothing_raised(LocalJumpError, bug5731) do
+ foo.foobar {|x| result = x}
+ end
+ assert_equal(:foo, result, bug5731)
+ result = nil
+ assert_nothing_raised(LocalJumpError, bug5731) do
+ foo.enum_for(:foobar).each {|x| result = x}
+ end
+ assert_equal(:foo, result, bug5731)
+
+ result = nil
+ foobar = foo.method(:foobar)
+ foobar.call {|x| result = x}
+ assert_equal(:foo, result, bug5731)
+
+ result = nil
+ foobar = foo.method(:foobar)
+ foobar.enum_for(:call).each {|x| result = x}
+ assert_equal(:foo, result, bug5731)
+ end
+
+ def test_send_with_no_arguments
+ assert_raise(ArgumentError) { 1.send }
+ end
+
+ def test_send_with_block
+ x = :ng
+ 1.send(:times) { x = :ok }
+ assert_equal(:ok, x)
+
+ x = :ok
+ o = Object.new
+ def o.inspect
+ yield if block_given?
+ super
+ end
+ begin
+ nil.public_send(o) { x = :ng }
+ rescue TypeError
+ end
+ assert_equal(:ok, x)
+ end
+
+ def test_public_send
+ c = Class.new do
+ def pub
+ :ok
+ end
+
+ def invoke(m)
+ public_send(m)
+ end
+
+ protected
+ def prot
+ :ng
+ end
+
+ private
+ def priv
+ :ng
+ end
+ end.new
+ assert_equal(:ok, c.public_send(:pub))
+ assert_raise(NoMethodError) {c.public_send(:priv)}
+ assert_raise(NoMethodError) {c.public_send(:prot)}
+ assert_raise(NoMethodError) {c.invoke(:priv)}
+ bug7499 = '[ruby-core:50489]'
+ assert_raise(NoMethodError, bug7499) {c.invoke(:prot)}
+ end
+
+ def test_no_superclass_method
+ bug2312 = '[ruby-dev:39581]'
+
+ o = Object.new
+ e = assert_raise(NoMethodError) {
+ o.method(:__send__).call(:never_defined_test_no_superclass_method)
+ }
+ m1 = e.message
+ assert_no_match(/no superclass method/, m1, bug2312)
+ e = assert_raise(NoMethodError) {
+ o.method(:__send__).call(:never_defined_test_no_superclass_method)
+ }
+ assert_equal(m1, e.message, bug2312)
+ e = assert_raise(NoMethodError) {
+ o.never_defined_test_no_superclass_method
+ }
+ assert_equal(m1, e.message, bug2312)
+ end
+
+ def test_superclass_method
+ bug2312 = '[ruby-dev:39581]'
+ assert_in_out_err(["-e", "module Enumerable;undef min;end; (1..2).min{}"],
+ "", [], /no superclass method/, bug2312)
+ end
+
+ def test_specific_eval_with_wrong_arguments
+ assert_raise(ArgumentError) do
+ 1.instance_eval("foo") { foo }
+ end
+
+ assert_raise(ArgumentError) do
+ 1.instance_eval
+ end
+
+ assert_raise(ArgumentError) do
+ 1.instance_eval("", 1, 1, 1)
+ end
+ end
+
+ class InstanceExec
+ INSTANCE_EXEC = 123
+ end
+
+ def test_instance_exec
+ x = 1.instance_exec(42) {|a| self + a }
+ assert_equal(43, x)
+
+ x = "foo".instance_exec("bar") {|a| self + a }
+ assert_equal("foobar", x)
+
+ assert_raise(NameError) do
+ InstanceExec.new.instance_exec { INSTANCE_EXEC }
+ end
+ end
+
+ def test_extend
+ assert_raise(ArgumentError) do
+ 1.extend
+ end
+ end
+
+ def test_untrusted
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ obj = Object.new
+ assert_equal(false, obj.untrusted?)
+ assert_equal(false, obj.tainted?)
+ obj.untrust
+ assert_equal(true, obj.untrusted?)
+ assert_equal(true, obj.tainted?)
+ obj.trust
+ assert_equal(false, obj.untrusted?)
+ assert_equal(false, obj.tainted?)
+ obj.taint
+ assert_equal(true, obj.untrusted?)
+ assert_equal(true, obj.tainted?)
+ obj.untaint
+ assert_equal(false, obj.untrusted?)
+ assert_equal(false, obj.tainted?)
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ def test_to_s
+ x = Object.new
+ x.taint
+ s = x.to_s
+ assert_equal(true, s.tainted?)
+
+ x = eval(<<-EOS)
+ class ToS\u{3042}
+ new.to_s
+ end
+ EOS
+ assert_match(/\bToS\u{3042}:/, x)
+ end
+
+ def test_inspect
+ x = Object.new
+ assert_match(/\A#<Object:0x\h+>\z/, x.inspect)
+
+ x.instance_variable_set(:@ivar, :value)
+ assert_match(/\A#<Object:0x\h+ @ivar=:value>\z/, x.inspect)
+
+ x = Object.new
+ x.instance_variable_set(:@recur, x)
+ assert_match(/\A#<Object:0x\h+ @recur=#<Object:0x\h+ \.\.\.>>\z/, x.inspect)
+
+ x = Object.new
+ x.instance_variable_set(:@foo, "value")
+ x.instance_variable_set(:@bar, 42)
+ assert_match(/\A#<Object:0x\h+ (?:@foo="value", @bar=42|@bar=42, @foo="value")>\z/, x.inspect)
+
+ # #inspect does not call #to_s anymore
+ feature6130 = '[ruby-core:43238]'
+ x = Object.new
+ def x.to_s
+ "to_s"
+ end
+ assert_match(/\A#<Object:0x\h+>\z/, x.inspect, feature6130)
+
+ x = eval(<<-EOS)
+ class Inspect\u{3042}
+ new.inspect
+ end
+ EOS
+ assert_match(/\bInspect\u{3042}:/, x)
+
+ x = eval(<<-EOS)
+ class Inspect\u{3042}
+ def initialize
+ @\u{3044} = 42
+ end
+ new
+ end
+ EOS
+ assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x.inspect)
+ x.instance_variable_set("@\u{3046}".encode(Encoding::EUC_JP), 6)
+ assert_match(/@\u{3046}=6\b/, x.inspect)
+ end
+
+ def test_singleton_class
+ x = Object.new
+ xs = class << x; self; end
+ assert_equal(xs, x.singleton_class)
+
+ y = Object.new
+ ys = y.singleton_class
+ assert_equal(class << y; self; end, ys)
+
+ assert_equal(NilClass, nil.singleton_class)
+ assert_equal(TrueClass, true.singleton_class)
+ assert_equal(FalseClass, false.singleton_class)
+
+ assert_raise(TypeError) do
+ 123.singleton_class
+ end
+ assert_raise(TypeError) do
+ :foo.singleton_class
+ end
+ end
+
+ def test_redef_method_missing
+ bug5473 = '[ruby-core:40287]'
+ ['ArgumentError.new("bug5473")', 'ArgumentError, "bug5473"', '"bug5473"'].each do |code|
+ out, err, status = EnvUtil.invoke_ruby([], <<-SRC, true, true)
+ class ::Object
+ def method_missing(m, *a, &b)
+ raise #{code}
+ end
+ end
+
+ p((1.foo rescue $!))
+ SRC
+ assert_send([status, :success?], bug5473)
+ assert_equal("", err, bug5473)
+ assert_equal((eval("raise #{code}") rescue $!.inspect), out.chomp, bug5473)
+ end
+ end
+
+ def assert_not_initialize_copy
+ a = yield
+ b = yield
+ assert_nothing_raised("copy") {a.instance_eval {initialize_copy(b)}}
+ c = a.dup.freeze
+ assert_raise(RuntimeError, "frozen") {c.instance_eval {initialize_copy(b)}}
+ d = a.dup.trust
+ [a, b, c, d]
+ end
+
+ def test_bad_initialize_copy
+ assert_not_initialize_copy {Object.new}
+ assert_not_initialize_copy {[].to_enum}
+ assert_not_initialize_copy {Enumerator::Generator.new {}}
+ assert_not_initialize_copy {Enumerator::Yielder.new {}}
+ assert_not_initialize_copy {File.stat(__FILE__)}
+ assert_not_initialize_copy {open(__FILE__)}.each(&:close)
+ assert_not_initialize_copy {ARGF.class.new}
+ assert_not_initialize_copy {Random.new}
+ assert_not_initialize_copy {//}
+ assert_not_initialize_copy {/.*/.match("foo")}
+ st = Struct.new(:foo)
+ assert_not_initialize_copy {st.new}
+ end
+
+ def test_type_error_message
+ _issue = "Bug #7539"
+ assert_raise_with_message(TypeError, "can't convert Array into Integer") {Integer([42])}
+ assert_raise_with_message(TypeError, 'no implicit conversion of Array into Integer') {[].first([42])}
+ end
+
+ def test_copied_ivar_memory_leak
+ bug10191 = '[ruby-core:64700] [Bug #10191]'
+ assert_no_memory_leak([], <<-"end;", <<-"end;", bug10191, timeout: 60, limit: 1.8)
+ def (a = Object.new).set; @v = nil; end
+ num = 500_000
+ end;
+ num.times {a.clone.set}
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_objectspace.rb b/jni/ruby/test/ruby/test_objectspace.rb
new file mode 100644
index 0000000..d519041
--- /dev/null
+++ b/jni/ruby/test/ruby/test_objectspace.rb
@@ -0,0 +1,112 @@
+require 'test/unit'
+
+class TestObjectSpace < Test::Unit::TestCase
+ def self.deftest_id2ref(obj)
+ /:(\d+)/ =~ caller[0]
+ file = $`
+ line = $1.to_i
+ code = <<"End"
+ define_method("test_id2ref_#{line}") {\
+ o = ObjectSpace._id2ref(obj.object_id);\
+ assert_same(obj, o, "didn't round trip: \#{obj.inspect}");\
+ }
+End
+ eval code, binding, file, line
+ end
+
+ deftest_id2ref(-0x4000000000000001)
+ deftest_id2ref(-0x4000000000000000)
+ deftest_id2ref(-0x40000001)
+ deftest_id2ref(-0x40000000)
+ deftest_id2ref(-1)
+ deftest_id2ref(0)
+ deftest_id2ref(1)
+ deftest_id2ref(0x3fffffff)
+ deftest_id2ref(0x40000000)
+ deftest_id2ref(0x3fffffffffffffff)
+ deftest_id2ref(0x4000000000000000)
+ deftest_id2ref(:a)
+ deftest_id2ref(:abcdefghijilkjl)
+ deftest_id2ref(:==)
+ deftest_id2ref(Object.new)
+ deftest_id2ref(self)
+ deftest_id2ref(true)
+ deftest_id2ref(false)
+ deftest_id2ref(nil)
+
+ def test_count_objects
+ h = {}
+ ObjectSpace.count_objects(h)
+ assert_kind_of(Hash, h)
+ assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
+ assert_empty(h.values.delete_if {|x| x.is_a?(Integer) })
+
+ h = ObjectSpace.count_objects
+ assert_kind_of(Hash, h)
+ assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
+ assert_empty(h.values.delete_if {|x| x.is_a?(Integer) })
+
+ assert_raise(TypeError) { ObjectSpace.count_objects(1) }
+
+ h0 = {:T_FOO=>1000}
+ h = ObjectSpace.count_objects(h0)
+ assert_same(h0, h)
+ assert_equal(0, h0[:T_FOO])
+ end
+
+ def test_finalizer
+ assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok :ok), [])
+ a = []
+ ObjectSpace.define_finalizer(a) { p :ok }
+ b = a.dup
+ ObjectSpace.define_finalizer(a) { p :ok }
+ !b
+ END
+ assert_raise(ArgumentError) { ObjectSpace.define_finalizer([], Object.new) }
+
+ code = proc do |priv|
+ <<-"CODE"
+ fin = Object.new
+ class << fin
+ #{priv}def call(id)
+ puts "finalized"
+ end
+ end
+ ObjectSpace.define_finalizer([], fin)
+ CODE
+ end
+ assert_in_out_err([], code[""], ["finalized"])
+ assert_in_out_err([], code["private "], ["finalized"])
+ c = EnvUtil.labeled_class("C\u{3042}").new
+ o = Object.new
+ assert_raise_with_message(ArgumentError, /C\u{3042}/) {
+ ObjectSpace.define_finalizer(o, c)
+ }
+ end
+
+ def test_each_object
+ assert_separately([], <<-End)
+ GC.disable
+ eval('begin; 1.times{}; rescue; ensure; end')
+ arys = []
+ ObjectSpace.each_object(Array){|ary|
+ arys << ary
+ }
+ GC.enable
+ arys.each{|ary|
+ begin
+ assert_equal(String, ary.inspect.class) # should not cause SEGV
+ rescue RuntimeError
+ # rescue "can't modify frozen File" error.
+ end
+ }
+ End
+ end
+
+ def test_each_object_recursive_key
+ assert_normal_exit(<<-'end;', '[ruby-core:66742] [Bug #10579]')
+ h = {["foo"]=>nil}
+ p Thread.current[:__recursive_key__]
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_optimization.rb b/jni/ruby/test/ruby/test_optimization.rb
new file mode 100644
index 0000000..4a5484e
--- /dev/null
+++ b/jni/ruby/test/ruby/test_optimization.rb
@@ -0,0 +1,292 @@
+require 'test/unit'
+
+class TestRubyOptimization < Test::Unit::TestCase
+
+ BIGNUM_POS_MIN_32 = 1073741824 # 2 ** 30
+ if BIGNUM_POS_MIN_32.kind_of?(Fixnum)
+ FIXNUM_MAX = 4611686018427387903 # 2 ** 62 - 1
+ else
+ FIXNUM_MAX = 1073741823 # 2 ** 30 - 1
+ end
+
+ BIGNUM_NEG_MAX_32 = -1073741825 # -2 ** 30 - 1
+ if BIGNUM_NEG_MAX_32.kind_of?(Fixnum)
+ FIXNUM_MIN = -4611686018427387904 # -2 ** 62
+ else
+ FIXNUM_MIN = -1073741824 # -2 ** 30
+ end
+
+ def assert_redefine_method(klass, method, code, msg = nil)
+ assert_separately([], <<-"end;")# do
+ class #{klass}
+ undef #{method}
+ def #{method}(*args)
+ args[0]
+ end
+ end
+ #{code}
+ end;
+ end
+
+ def test_fixnum_plus
+ a, b = 1, 2
+ assert_equal 3, a + b
+ assert_instance_of Fixnum, FIXNUM_MAX
+ assert_instance_of Bignum, FIXNUM_MAX + 1
+
+ assert_equal 21, 10 + 11
+ assert_redefine_method('Fixnum', '+', 'assert_equal 11, 10 + 11')
+ end
+
+ def test_fixnum_minus
+ assert_equal 5, 8 - 3
+ assert_instance_of Fixnum, FIXNUM_MIN
+ assert_instance_of Bignum, FIXNUM_MIN - 1
+
+ assert_equal 5, 8 - 3
+ assert_redefine_method('Fixnum', '-', 'assert_equal 3, 8 - 3')
+ end
+
+ def test_fixnum_mul
+ assert_equal 15, 3 * 5
+ assert_redefine_method('Fixnum', '*', 'assert_equal 5, 3 * 5')
+ end
+
+ def test_fixnum_div
+ assert_equal 3, 15 / 5
+ assert_redefine_method('Fixnum', '/', 'assert_equal 5, 15 / 5')
+ end
+
+ def test_fixnum_mod
+ assert_equal 1, 8 % 7
+ assert_redefine_method('Fixnum', '%', 'assert_equal 7, 8 % 7')
+ end
+
+ def test_float_plus
+ assert_equal 4.0, 2.0 + 2.0
+ assert_redefine_method('Float', '+', 'assert_equal 2.0, 2.0 + 2.0')
+ end
+
+ def test_float_minus
+ assert_equal 4.0, 2.0 + 2.0
+ assert_redefine_method('Float', '+', 'assert_equal 2.0, 2.0 + 2.0')
+ end
+
+ def test_float_mul
+ assert_equal 29.25, 4.5 * 6.5
+ assert_redefine_method('Float', '*', 'assert_equal 6.5, 4.5 * 6.5')
+ end
+
+ def test_float_div
+ assert_in_delta 0.63063063063063063, 4.2 / 6.66
+ assert_redefine_method('Float', '/', 'assert_equal 6.66, 4.2 / 6.66', "[Bug #9238]")
+ end
+
+ def test_string_length
+ assert_equal 6, "string".length
+ assert_redefine_method('String', 'length', 'assert_nil "string".length')
+ end
+
+ def test_string_size
+ assert_equal 6, "string".size
+ assert_redefine_method('String', 'size', 'assert_nil "string".size')
+ end
+
+ def test_string_empty?
+ assert_equal true, "".empty?
+ assert_equal false, "string".empty?
+ assert_redefine_method('String', 'empty?', 'assert_nil "string".empty?')
+ end
+
+ def test_string_plus
+ assert_equal "", "" + ""
+ assert_equal "x", "x" + ""
+ assert_equal "x", "" + "x"
+ assert_equal "ab", "a" + "b"
+ assert_redefine_method('String', '+', 'assert_equal "b", "a" + "b"')
+ end
+
+ def test_string_succ
+ assert_equal 'b', 'a'.succ
+ assert_equal 'B', 'A'.succ
+ end
+
+ def test_string_format
+ assert_equal '2', '%d' % 2
+ assert_redefine_method('String', '%', 'assert_equal 2, "%d" % 2')
+ end
+
+ def test_string_freeze
+ assert_equal "foo", "foo".freeze
+ assert_equal "foo".freeze.object_id, "foo".freeze.object_id
+ assert_redefine_method('String', 'freeze', 'assert_nil "foo".freeze')
+ end
+
+ def test_string_eq_neq
+ %w(== !=).each do |m|
+ assert_redefine_method('String', m, <<-end)
+ assert_equal :b, ("a" #{m} "b").to_sym
+ b = 'b'
+ assert_equal :b, ("a" #{m} b).to_sym
+ assert_equal :b, (b #{m} "b").to_sym
+ end
+ end
+ end
+
+ def test_string_ltlt
+ assert_equal "", "" << ""
+ assert_equal "x", "x" << ""
+ assert_equal "x", "" << "x"
+ assert_equal "ab", "a" << "b"
+ assert_redefine_method('String', '<<', 'assert_equal "b", "a" << "b"')
+ end
+
+ def test_array_plus
+ assert_equal [1,2], [1]+[2]
+ assert_redefine_method('Array', '+', 'assert_equal [2], [1]+[2]')
+ end
+
+ def test_array_minus
+ assert_equal [2], [1,2] - [1]
+ assert_redefine_method('Array', '-', 'assert_equal [1], [1,2]-[1]')
+ end
+
+ def test_array_length
+ assert_equal 0, [].length
+ assert_equal 3, [1,2,3].length
+ assert_redefine_method('Array', 'length', 'assert_nil([].length); assert_nil([1,2,3].length)')
+ end
+
+ def test_array_empty?
+ assert_equal true, [].empty?
+ assert_equal false, [1,2,3].empty?
+ assert_redefine_method('Array', 'empty?', 'assert_nil([].empty?); assert_nil([1,2,3].empty?)')
+ end
+
+ def test_hash_length
+ assert_equal 0, {}.length
+ assert_equal 1, {1=>1}.length
+ assert_redefine_method('Hash', 'length', 'assert_nil({}.length); assert_nil({1=>1}.length)')
+ end
+
+ def test_hash_empty?
+ assert_equal true, {}.empty?
+ assert_equal false, {1=>1}.empty?
+ assert_redefine_method('Hash', 'empty?', 'assert_nil({}.empty?); assert_nil({1=>1}.empty?)')
+ end
+
+ def test_hash_aref_with
+ h = { "foo" => 1 }
+ assert_equal 1, h["foo"]
+ assert_redefine_method('Hash', '[]', <<-end)
+ h = { "foo" => 1 }
+ assert_equal "foo", h["foo"]
+ end
+ end
+
+ def test_hash_aset_with
+ h = {}
+ assert_equal 1, h["foo"] = 1
+ assert_redefine_method('Hash', '[]=', <<-end)
+ h = {}
+ assert_equal 1, h["foo"] = 1, "assignment always returns value set"
+ assert_nil h["foo"]
+ end
+ end
+
+ class MyObj
+ def ==(other)
+ true
+ end
+ end
+
+ def test_eq
+ assert_equal true, nil == nil
+ assert_equal true, 1 == 1
+ assert_equal true, 'string' == 'string'
+ assert_equal true, 1 == MyObj.new
+ assert_equal false, nil == MyObj.new
+ assert_equal true, MyObj.new == 1
+ assert_equal true, MyObj.new == nil
+ end
+
+ def test_tailcall
+ bug4082 = '[ruby-core:33289]'
+
+ option = {
+ tailcall_optimization: true,
+ trace_instruction: false,
+ }
+ RubyVM::InstructionSequence.new(<<-EOF, "Bug#4082", bug4082, nil, option).eval
+ class #{self.class}::Tailcall
+ def fact_helper(n, res)
+ if n == 1
+ res
+ else
+ fact_helper(n - 1, n * res)
+ end
+ end
+ def fact(n)
+ fact_helper(n, 1)
+ end
+ end
+ EOF
+ assert_equal(9131, Tailcall.new.fact(3000).to_s.size, bug4082)
+ end
+
+ def test_tailcall_with_block
+ bug6901 = '[ruby-dev:46065]'
+
+ option = {
+ tailcall_optimization: true,
+ trace_instruction: false,
+ }
+ RubyVM::InstructionSequence.new(<<-EOF, "Bug#6901", bug6901, nil, option).eval
+ def identity(val)
+ val
+ end
+
+ def delay
+ -> {
+ identity(yield)
+ }
+ end
+ EOF
+ assert_equal(123, delay { 123 }.call, bug6901)
+ end
+
+ class Bug10557
+ def [](_)
+ block_given?
+ end
+
+ def []=(_, _)
+ block_given?
+ end
+ end
+
+ def test_block_given_aset_aref
+ bug10557 = '[ruby-core:66595]'
+ assert_equal(true, Bug10557.new.[](nil){}, bug10557)
+ assert_equal(true, Bug10557.new.[](0){}, bug10557)
+ assert_equal(true, Bug10557.new.[](false){}, bug10557)
+ assert_equal(true, Bug10557.new.[](''){}, bug10557)
+ assert_equal(true, Bug10557.new.[]=(nil, 1){}, bug10557)
+ assert_equal(true, Bug10557.new.[]=(0, 1){}, bug10557)
+ assert_equal(true, Bug10557.new.[]=(false, 1){}, bug10557)
+ assert_equal(true, Bug10557.new.[]=('', 1){}, bug10557)
+ end
+
+ def test_string_freeze_block
+ assert_separately([], <<-"end;")# do
+ class String
+ undef freeze
+ def freeze
+ block_given?
+ end
+ end
+ assert_equal(true, "block".freeze {})
+ assert_equal(false, "block".freeze)
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_pack.rb b/jni/ruby/test/ruby/test_pack.rb
new file mode 100644
index 0000000..5d2b656
--- /dev/null
+++ b/jni/ruby/test/ruby/test_pack.rb
@@ -0,0 +1,730 @@
+# coding: US-ASCII
+require 'test/unit'
+
+class TestPack < Test::Unit::TestCase
+ def test_pack
+ $format = "c2x5CCxsdils_l_a6";
+ # Need the expression in here to force ary[5] to be numeric. This avoids
+ # test2 failing because ary2 goes str->numeric->str and ary does not.
+ ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"]
+ $x = ary.pack($format)
+ ary2 = $x.unpack($format)
+
+ assert_equal(ary.length, ary2.length)
+ assert_equal(ary.join(':'), ary2.join(':'))
+ assert_match(/def/, $x)
+
+ $x = [-1073741825]
+ assert_equal($x, $x.pack("q").unpack("q"))
+
+ $x = [-1]
+ assert_equal($x, $x.pack("l").unpack("l"))
+ end
+
+ def test_pack_n
+ assert_equal "\000\000", [0].pack('n')
+ assert_equal "\000\001", [1].pack('n')
+ assert_equal "\000\002", [2].pack('n')
+ assert_equal "\000\003", [3].pack('n')
+ assert_equal "\377\376", [65534].pack('n')
+ assert_equal "\377\377", [65535].pack('n')
+
+ assert_equal "\200\000", [2**15].pack('n')
+ assert_equal "\177\377", [-2**15-1].pack('n')
+ assert_equal "\377\377", [-1].pack('n')
+
+ assert_equal "\000\001\000\001", [1,1].pack('n*')
+ assert_equal "\000\001\000\001\000\001", [1,1,1].pack('n*')
+ end
+
+ def test_unpack_n
+ assert_equal 1, "\000\001".unpack('n')[0]
+ assert_equal 2, "\000\002".unpack('n')[0]
+ assert_equal 3, "\000\003".unpack('n')[0]
+ assert_equal 65535, "\377\377".unpack('n')[0]
+ assert_equal [1,1], "\000\001\000\001".unpack('n*')
+ assert_equal [1,1,1], "\000\001\000\001\000\001".unpack('n*')
+ end
+
+ def test_pack_N
+ assert_equal "\000\000\000\000", [0].pack('N')
+ assert_equal "\000\000\000\001", [1].pack('N')
+ assert_equal "\000\000\000\002", [2].pack('N')
+ assert_equal "\000\000\000\003", [3].pack('N')
+ assert_equal "\377\377\377\376", [4294967294].pack('N')
+ assert_equal "\377\377\377\377", [4294967295].pack('N')
+
+ assert_equal "\200\000\000\000", [2**31].pack('N')
+ assert_equal "\177\377\377\377", [-2**31-1].pack('N')
+ assert_equal "\377\377\377\377", [-1].pack('N')
+
+ assert_equal "\000\000\000\001\000\000\000\001", [1,1].pack('N*')
+ assert_equal "\000\000\000\001\000\000\000\001\000\000\000\001", [1,1,1].pack('N*')
+ end
+
+ def test_unpack_N
+ assert_equal 1, "\000\000\000\001".unpack('N')[0]
+ assert_equal 2, "\000\000\000\002".unpack('N')[0]
+ assert_equal 3, "\000\000\000\003".unpack('N')[0]
+ assert_equal 4294967295, "\377\377\377\377".unpack('N')[0]
+ assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*')
+ assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*')
+ end
+
+ def _integer_big_endian(mod='')
+ assert_equal("\x01\x02", [0x0102].pack("s"+mod))
+ assert_equal("\x01\x02", [0x0102].pack("S"+mod))
+ assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l"+mod))
+ assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"+mod))
+ assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"+mod))
+ assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"+mod))
+ assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"+mod))
+ assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"+mod))
+ assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"+mod))
+ %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
+ fmt += mod
+ nuls = [0].pack(fmt)
+ v = 0
+ s = "".force_encoding("ascii-8bit")
+ nuls.bytesize.times {|i|
+ j = i + 40
+ v = v * 256 + j
+ s << [j].pack("C")
+ }
+ assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
+ assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
+ s2 = s+s
+ fmt2 = fmt+"*"
+ assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
+ }
+ end
+
+ def _integer_little_endian(mod='')
+ assert_equal("\x02\x01", [0x0102].pack("s"+mod))
+ assert_equal("\x02\x01", [0x0102].pack("S"+mod))
+ assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l"+mod))
+ assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"+mod))
+ assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"+mod))
+ assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"+mod))
+ assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"+mod))
+ assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"+mod))
+ assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"+mod))
+ %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
+ fmt += mod
+ nuls = [0].pack(fmt)
+ v = 0
+ s = "".force_encoding("ascii-8bit")
+ nuls.bytesize.times {|i|
+ j = i+40
+ v = v * 256 + j
+ s << [j].pack("C")
+ }
+ s.reverse!
+ assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
+ assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
+ s2 = s+s
+ fmt2 = fmt+"*"
+ assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
+ }
+ end
+
+ def test_integer_endian
+ s = [1].pack("s")
+ assert_include(["\0\1", "\1\0"], s)
+ if s == "\0\1"
+ _integer_big_endian()
+ else
+ _integer_little_endian()
+ end
+ assert_equal("\x01\x02\x02\x01", [0x0102,0x0102].pack("s>s<"))
+ assert_equal([0x0102,0x0102], "\x01\x02\x02\x01".unpack("s>s<"))
+ end
+
+ def test_integer_endian_explicit
+ _integer_big_endian('>')
+ _integer_little_endian('<')
+ end
+
+ def test_pack_U
+ assert_raise(RangeError) { [-0x40000001].pack("U") }
+ assert_raise(RangeError) { [-0x40000000].pack("U") }
+ assert_raise(RangeError) { [-1].pack("U") }
+ assert_equal "\000", [0].pack("U")
+ assert_equal "\374\277\277\277\277\277".force_encoding(Encoding::UTF_8), [0x3fffffff].pack("U")
+ assert_equal "\375\200\200\200\200\200".force_encoding(Encoding::UTF_8), [0x40000000].pack("U")
+ assert_equal "\375\277\277\277\277\277".force_encoding(Encoding::UTF_8), [0x7fffffff].pack("U")
+ assert_raise(RangeError) { [0x80000000].pack("U") }
+ assert_raise(RangeError) { [0x100000000].pack("U") }
+ end
+
+ def test_pack_P
+ a = ["abc"]
+ assert_equal a, a.pack("P").unpack("P*")
+ assert_equal "a", a.pack("P").unpack("P")[0]
+ assert_equal a, a.pack("P").freeze.unpack("P*")
+ assert_raise(ArgumentError) { (a.pack("P") + "").unpack("P*") }
+ end
+
+ def test_pack_p
+ a = ["abc"]
+ assert_equal a, a.pack("p").unpack("p*")
+ assert_equal a[0], a.pack("p").unpack("p")[0]
+ assert_equal a, a.pack("p").freeze.unpack("p*")
+ assert_raise(ArgumentError) { (a.pack("p") + "").unpack("p*") }
+ assert_equal a, (a.pack("p") << "d").unpack("p*")
+ end
+
+ def test_format_string_modified
+ fmt = "CC"
+ o = Object.new
+ class << o; self; end.class_eval do
+ define_method(:to_int) { fmt.clear; 0 }
+ end
+ assert_raise(RuntimeError) do
+ [o, o].pack(fmt)
+ end
+ end
+
+ def test_comment
+ assert_equal("\0\1", [0,1].pack(" C #foo \n C "))
+ assert_equal([0,1], "\0\1".unpack(" C #foo \n C "))
+ end
+
+ def test_illegal_bang
+ assert_raise(ArgumentError) { [].pack("a!") }
+ assert_raise(ArgumentError) { "".unpack("a!") }
+ end
+
+ def test_pack_unpack_aA
+ assert_equal("f", ["foo"].pack("A"))
+ assert_equal("f", ["foo"].pack("a"))
+ assert_equal("foo", ["foo"].pack("A*"))
+ assert_equal("foo", ["foo"].pack("a*"))
+ assert_equal("fo", ["foo"].pack("A2"))
+ assert_equal("fo", ["foo"].pack("a2"))
+ assert_equal("foo ", ["foo"].pack("A4"))
+ assert_equal("foo\0", ["foo"].pack("a4"))
+ assert_equal(" ", [nil].pack("A"))
+ assert_equal("\0", [nil].pack("a"))
+ assert_equal("", [nil].pack("A*"))
+ assert_equal("", [nil].pack("a*"))
+ assert_equal(" ", [nil].pack("A2"))
+ assert_equal("\0\0", [nil].pack("a2"))
+
+ assert_equal("foo" + "\0" * 27, ["foo"].pack("a30"))
+
+ assert_equal(["f"], "foo\0".unpack("A"))
+ assert_equal(["f"], "foo\0".unpack("a"))
+ assert_equal(["foo"], "foo\0".unpack("A4"))
+ assert_equal(["foo\0"], "foo\0".unpack("a4"))
+ assert_equal(["foo"], "foo ".unpack("A4"))
+ assert_equal(["foo "], "foo ".unpack("a4"))
+ assert_equal(["foo"], "foo".unpack("A4"))
+ assert_equal(["foo"], "foo".unpack("a4"))
+ end
+
+ def test_pack_unpack_Z
+ assert_equal("f", ["foo"].pack("Z"))
+ assert_equal("foo\0", ["foo"].pack("Z*"))
+ assert_equal("fo", ["foo"].pack("Z2"))
+ assert_equal("foo\0\0", ["foo"].pack("Z5"))
+ assert_equal("\0", [nil].pack("Z"))
+ assert_equal("\0", [nil].pack("Z*"))
+ assert_equal("\0\0", [nil].pack("Z2"))
+
+ assert_equal(["f"], "foo\0".unpack("Z"))
+ assert_equal(["foo"], "foo".unpack("Z*"))
+ assert_equal(["foo"], "foo\0".unpack("Z*"))
+ assert_equal(["foo"], "foo".unpack("Z5"))
+ end
+
+ def test_pack_unpack_bB
+ assert_equal("\xff\x00", ["1111111100000000"].pack("b*"))
+ assert_equal("\x01\x02", ["1000000001000000"].pack("b*"))
+ assert_equal("", ["1"].pack("b0"))
+ assert_equal("\x01", ["1"].pack("b1"))
+ assert_equal("\x01\x00", ["1"].pack("b2"))
+ assert_equal("\x01\x00", ["1"].pack("b3"))
+ assert_equal("\x01\x00\x00", ["1"].pack("b4"))
+ assert_equal("\x01\x00\x00", ["1"].pack("b5"))
+ assert_equal("\x01\x00\x00\x00", ["1"].pack("b6"))
+
+ assert_equal("\xff\x00", ["1111111100000000"].pack("B*"))
+ assert_equal("\x01\x02", ["0000000100000010"].pack("B*"))
+ assert_equal("", ["1"].pack("B0"))
+ assert_equal("\x80", ["1"].pack("B1"))
+ assert_equal("\x80\x00", ["1"].pack("B2"))
+ assert_equal("\x80\x00", ["1"].pack("B3"))
+ assert_equal("\x80\x00\x00", ["1"].pack("B4"))
+ assert_equal("\x80\x00\x00", ["1"].pack("B5"))
+ assert_equal("\x80\x00\x00\x00", ["1"].pack("B6"))
+
+ assert_equal(["1111111100000000"], "\xff\x00".unpack("b*"))
+ assert_equal(["1000000001000000"], "\x01\x02".unpack("b*"))
+ assert_equal([""], "".unpack("b0"))
+ assert_equal(["1"], "\x01".unpack("b1"))
+ assert_equal(["10"], "\x01".unpack("b2"))
+ assert_equal(["100"], "\x01".unpack("b3"))
+
+ assert_equal(["1111111100000000"], "\xff\x00".unpack("B*"))
+ assert_equal(["0000000100000010"], "\x01\x02".unpack("B*"))
+ assert_equal([""], "".unpack("B0"))
+ assert_equal(["1"], "\x80".unpack("B1"))
+ assert_equal(["10"], "\x80".unpack("B2"))
+ assert_equal(["100"], "\x80".unpack("B3"))
+
+ assert_equal(Encoding::US_ASCII, "\xff\x00".unpack("b*")[0].encoding)
+ assert_equal(Encoding::US_ASCII, "\xff\x00".unpack("B*")[0].encoding)
+ end
+
+ def test_pack_unpack_hH
+ assert_equal("\x01\xfe", ["10ef"].pack("h*"))
+ assert_equal("", ["10ef"].pack("h0"))
+ assert_equal("\x01\x0e", ["10ef"].pack("h3"))
+ assert_equal("\x01\xfe\x0", ["10ef"].pack("h5"))
+ assert_equal("\xff\x0f", ["fff"].pack("h3"))
+ assert_equal("\xff\x0f", ["fff"].pack("h4"))
+ assert_equal("\xff\x0f\0", ["fff"].pack("h5"))
+ assert_equal("\xff\x0f\0", ["fff"].pack("h6"))
+ assert_equal("\xff\x0f\0\0", ["fff"].pack("h7"))
+ assert_equal("\xff\x0f\0\0", ["fff"].pack("h8"))
+
+ assert_equal("\x10\xef", ["10ef"].pack("H*"))
+ assert_equal("", ["10ef"].pack("H0"))
+ assert_equal("\x10\xe0", ["10ef"].pack("H3"))
+ assert_equal("\x10\xef\x0", ["10ef"].pack("H5"))
+ assert_equal("\xff\xf0", ["fff"].pack("H3"))
+ assert_equal("\xff\xf0", ["fff"].pack("H4"))
+ assert_equal("\xff\xf0\0", ["fff"].pack("H5"))
+ assert_equal("\xff\xf0\0", ["fff"].pack("H6"))
+ assert_equal("\xff\xf0\0\0", ["fff"].pack("H7"))
+ assert_equal("\xff\xf0\0\0", ["fff"].pack("H8"))
+
+ assert_equal(["10ef"], "\x01\xfe".unpack("h*"))
+ assert_equal([""], "\x01\xfe".unpack("h0"))
+ assert_equal(["1"], "\x01\xfe".unpack("h1"))
+ assert_equal(["10"], "\x01\xfe".unpack("h2"))
+ assert_equal(["10e"], "\x01\xfe".unpack("h3"))
+ assert_equal(["10ef"], "\x01\xfe".unpack("h4"))
+ assert_equal(["10ef"], "\x01\xfe".unpack("h5"))
+
+ assert_equal(["10ef"], "\x10\xef".unpack("H*"))
+ assert_equal([""], "\x10\xef".unpack("H0"))
+ assert_equal(["1"], "\x10\xef".unpack("H1"))
+ assert_equal(["10"], "\x10\xef".unpack("H2"))
+ assert_equal(["10e"], "\x10\xef".unpack("H3"))
+ assert_equal(["10ef"], "\x10\xef".unpack("H4"))
+ assert_equal(["10ef"], "\x10\xef".unpack("H5"))
+
+ assert_equal(Encoding::US_ASCII, "\x10\xef".unpack("h*")[0].encoding)
+ assert_equal(Encoding::US_ASCII, "\x10\xef".unpack("H*")[0].encoding)
+ end
+
+ def test_pack_unpack_cC
+ assert_equal("\0\1\xff", [0, 1, 255].pack("c*"))
+ assert_equal("\0\1\xff", [0, 1, -1].pack("c*"))
+
+ assert_equal("\0\1\xff", [0, 1, 255].pack("C*"))
+ assert_equal("\0\1\xff", [0, 1, -1].pack("C*"))
+
+ assert_equal([0, 1, -1], "\0\1\xff".unpack("c*"))
+
+ assert_equal([0, 1, 255], "\0\1\xff".unpack("C*"))
+ end
+
+ def test_pack_unpack_sS
+ s1 = [513, -514].pack("s*")
+ s2 = [513, 65022].pack("S*")
+ assert_equal(s1, s2)
+ assert_equal([513, -514], s2.unpack("s*"))
+ assert_equal([513, 65022], s1.unpack("S*"))
+
+ s1 = [513, -514].pack("s!*")
+ s2 = [513, 65022].pack("S!*")
+ assert_equal(s1, s2)
+ assert_equal([513, -514], s2.unpack("s!*"))
+ assert_equal([513, 65022], s1.unpack("S!*"))
+
+ assert_equal(2, [1].pack("s").bytesize)
+ assert_equal(2, [1].pack("S").bytesize)
+ assert_operator(2, :<=, [1].pack("s!").bytesize)
+ assert_operator(2, :<=, [1].pack("S!").bytesize)
+ end
+
+ def test_pack_unpack_iI
+ s1 = [67305985, -50462977].pack("i*")
+ s2 = [67305985, 4244504319].pack("I*")
+ assert_equal(s1, s2)
+ assert_equal([67305985, -50462977], s2.unpack("i*"))
+ assert_equal([67305985, 4244504319], s1.unpack("I*"))
+
+ s1 = [67305985, -50462977].pack("i!*")
+ s2 = [67305985, 4244504319].pack("I!*")
+ assert_equal([67305985, -50462977], s1.unpack("i!*"))
+ assert_equal([67305985, 4244504319], s2.unpack("I!*"))
+
+ assert_operator(4, :<=, [1].pack("i").bytesize)
+ assert_operator(4, :<=, [1].pack("I").bytesize)
+ assert_operator(4, :<=, [1].pack("i!").bytesize)
+ assert_operator(4, :<=, [1].pack("I!").bytesize)
+ end
+
+ def test_pack_unpack_lL
+ s1 = [67305985, -50462977].pack("l*")
+ s2 = [67305985, 4244504319].pack("L*")
+ assert_equal(s1, s2)
+ assert_equal([67305985, -50462977], s2.unpack("l*"))
+ assert_equal([67305985, 4244504319], s1.unpack("L*"))
+
+ s1 = [67305985, -50462977].pack("l!*")
+ s2 = [67305985, 4244504319].pack("L!*")
+ assert_equal([67305985, -50462977], s1.unpack("l!*"))
+ assert_equal([67305985, 4244504319], s2.unpack("L!*"))
+
+ assert_equal(4, [1].pack("l").bytesize)
+ assert_equal(4, [1].pack("L").bytesize)
+ assert_operator(4, :<=, [1].pack("l!").bytesize)
+ assert_operator(4, :<=, [1].pack("L!").bytesize)
+ end
+
+ def test_pack_unpack_qQ
+ s1 = [578437695752307201, -506097522914230529].pack("q*")
+ s2 = [578437695752307201, 17940646550795321087].pack("Q*")
+ assert_equal(s1, s2)
+ assert_equal([578437695752307201, -506097522914230529], s2.unpack("q*"))
+ assert_equal([578437695752307201, 17940646550795321087], s1.unpack("Q*"))
+
+ # Note: q! and Q! should not work on platform which has no long long type.
+ # Is there a such platform now?
+ s1 = [578437695752307201, -506097522914230529].pack("q!*")
+ s2 = [578437695752307201, 17940646550795321087].pack("Q!*")
+ assert_equal([578437695752307201, -506097522914230529], s2.unpack("q!*"))
+ assert_equal([578437695752307201, 17940646550795321087], s1.unpack("Q!*"))
+
+ assert_equal(8, [1].pack("q").bytesize)
+ assert_equal(8, [1].pack("Q").bytesize)
+ assert_operator(8, :<=, [1].pack("q!").bytesize)
+ assert_operator(8, :<=, [1].pack("Q!").bytesize)
+ end
+
+ def test_pack_unpack_nN
+ assert_equal("\000\000\000\001\377\377\177\377\200\000\377\377", [0,1,-1,32767,-32768,65535].pack("n*"))
+ assert_equal("\000\000\000\000\000\000\000\001\377\377\377\377", [0,1,-1].pack("N*"))
+
+ assert_equal([0,1,65535,32767,32768,65535], "\000\000\000\001\377\377\177\377\200\000\377\377".unpack("n*"))
+ assert_equal([0,1,4294967295], "\000\000\000\000\000\000\000\001\377\377\377\377".unpack("N*"))
+
+ assert_equal(2, [1].pack("n").bytesize)
+ assert_equal(4, [1].pack("N").bytesize)
+ end
+
+ def test_pack_unpack_vV
+ assert_equal("\000\000\001\000\377\377\377\177\000\200\377\377", [0,1,-1,32767,-32768,65535].pack("v*"))
+ assert_equal("\000\000\000\000\001\000\000\000\377\377\377\377", [0,1,-1].pack("V*"))
+
+ assert_equal([0,1,65535,32767,32768,65535], "\000\000\001\000\377\377\377\177\000\200\377\377".unpack("v*"))
+ assert_equal([0,1,4294967295], "\000\000\000\000\001\000\000\000\377\377\377\377".unpack("V*"))
+
+ assert_equal(2, [1].pack("v").bytesize)
+ assert_equal(4, [1].pack("V").bytesize)
+ end
+
+ def test_pack_unpack_fdeEgG
+ inf = 1.0/0.0
+ nan = inf/inf
+ [0.0, 1.0, 3.0, inf, -inf, nan].each do |x|
+ %w(f d e E g G).each do |f|
+ v = [x].pack(f).unpack(f)
+ if x.nan?
+ assert_predicate(v.first, :nan?)
+ else
+ assert_equal([x], v)
+ end
+ end
+ end
+ end
+
+ def test_pack_unpack_x
+ assert_equal("", [].pack("x0"))
+ assert_equal("\0", [].pack("x"))
+ assert_equal("\0" * 30, [].pack("x30"))
+
+ assert_equal([0, 2], "\x00\x00\x02".unpack("CxC"))
+ assert_raise(ArgumentError) { "".unpack("x") }
+ end
+
+ def test_pack_unpack_X
+ assert_equal("\x00\x02", [0, 1, 2].pack("CCXC"))
+ assert_equal("\x02", [0, 1, 2].pack("CCX2C"))
+ assert_raise(ArgumentError) { [].pack("X") }
+
+ assert_equal([0, 2, 2], "\x00\x02".unpack("CCXC"))
+ assert_raise(ArgumentError) { "".unpack("X") }
+ end
+
+ def test_pack_unpack_atmark
+ assert_equal("\x01\x00\x00\x02", [1, 2].pack("C@3C"))
+ assert_equal("\x02", [1, 2].pack("C@0C"))
+ assert_equal("\x01\x02", [1, 2].pack("C@1C"))
+
+ assert_equal([1, 2], "\x01\x00\x00\x02".unpack("C@3C"))
+ assert_equal([nil], "\x00".unpack("@1C")) # is it OK?
+ assert_raise(ArgumentError) { "\x00".unpack("@2C") }
+ end
+
+ def test_pack_unpack_percent
+ assert_raise(ArgumentError) { [].pack("%") }
+ assert_raise(ArgumentError) { "".unpack("%") }
+ end
+
+ def test_pack_unpack_U
+ assert_equal([0], [0].pack("U").unpack("U"))
+ assert_equal([0x80], [0x80].pack("U").unpack("U"))
+ assert_equal([0x800], [0x800].pack("U").unpack("U"))
+ assert_equal([0x10000], [0x10000].pack("U").unpack("U"))
+ assert_equal([0x400000], [0x400000].pack("U").unpack("U"))
+
+ assert_raise(ArgumentError) { "\x80".unpack("U") }
+ assert_raise(ArgumentError) { "\xff".unpack("U") }
+ assert_raise(ArgumentError) { "\xfc\x00".unpack("U") }
+ assert_raise(ArgumentError) { "\xc0\xc0".unpack("U") }
+ assert_raise(ArgumentError) { "\xe0\x80\x80".unpack("U") }
+ end
+
+ def test_pack_unpack_u
+ assert_equal("", [""].pack("u"))
+ assert_equal("!80``\n", ["a"].pack("u"))
+ assert_equal("#86)C\n", ["abc"].pack("u"))
+ assert_equal("$86)C9```\n", ["abcd"].pack("u"))
+ assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n", ["a"*45].pack("u"))
+ assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u"))
+ assert_equal("&86)C9&5F\n#9VAI\n", ["abcdefghi"].pack("u6"))
+
+ assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u0"))
+ assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u1"))
+ assert_equal("M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n", ["a"*46].pack("u2"))
+ assert_equal(<<EXPECTED, ["a"*80].pack("u68"))
+_86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A
+186%A86%A86%A86%A86%A86$`
+EXPECTED
+
+ assert_equal([""], "".unpack("u"))
+ assert_equal(["a"], "!80``\n".unpack("u"))
+ assert_equal(["abc"], "#86)C\n".unpack("u"))
+ assert_equal(["abcd"], "$86)C9```\n".unpack("u"))
+ assert_equal(["a"*45], "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n".unpack("u"))
+ assert_equal(["a"*46], "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n".unpack("u"))
+ assert_equal(["abcdefghi"], "&86)C9&5F\n#9VAI\n".unpack("u"))
+
+ assert_equal(["abcdef"], "#86)C\n#9&5F\n".unpack("u"))
+ assert_equal(["abcdef"], "#86)CX\n#9&5FX\n".unpack("u")) # X is a (dummy) checksum.
+ assert_equal(["abcdef"], "#86)C\r\n#9&5F\r\n".unpack("u"))
+ assert_equal(["abcdef"], "#86)CX\r\n#9&5FX\r\n".unpack("u")) # X is a (dummy) checksum.
+
+ assert_equal(["\x00"], "\"\n".unpack("u"))
+ assert_equal(["\x00"], "! \r \n".unpack("u"))
+ end
+
+ def test_pack_unpack_m
+ assert_equal("", [""].pack("m"))
+ assert_equal("AA==\n", ["\0"].pack("m"))
+ assert_equal("AAA=\n", ["\0\0"].pack("m"))
+ assert_equal("AAAA\n", ["\0\0\0"].pack("m"))
+ assert_equal("/w==\n", ["\377"].pack("m"))
+ assert_equal("//8=\n", ["\377\377"].pack("m"))
+ assert_equal("////\n", ["\377\377\377"].pack("m"))
+
+ assert_equal([""], "".unpack("m"))
+ assert_equal(["\0"], "AA==\n".unpack("m"))
+ assert_equal(["\0\0"], "AAA=\n".unpack("m"))
+ assert_equal(["\0\0\0"], "AAAA\n".unpack("m"))
+ assert_equal(["\377"], "/w==\n".unpack("m"))
+ assert_equal(["\377\377"], "//8=\n".unpack("m"))
+ assert_equal(["\377\377\377"], "////\n".unpack("m"))
+ assert_equal([""], "A\n".unpack("m"))
+ assert_equal(["\0"], "AA\n".unpack("m"))
+ assert_equal(["\0"], "AA=\n".unpack("m"))
+ assert_equal(["\0\0"], "AAA\n".unpack("m"))
+
+ bug10019 = '[ruby-core:63604] [Bug #10019]'
+ size = ((4096-4)/4*3+1)
+ assert_separately(%W[- #{size} #{bug10019}], <<-'end;')
+ size = ARGV.shift.to_i
+ bug = ARGV.shift
+ assert_equal(size, ["a"*size].pack("m#{size+2}").unpack("m")[0].size, bug)
+ end;
+ end
+
+ def test_pack_unpack_m0
+ assert_equal("", [""].pack("m0"))
+ assert_equal("AA==", ["\0"].pack("m0"))
+ assert_equal("AAA=", ["\0\0"].pack("m0"))
+ assert_equal("AAAA", ["\0\0\0"].pack("m0"))
+ assert_equal("/w==", ["\377"].pack("m0"))
+ assert_equal("//8=", ["\377\377"].pack("m0"))
+ assert_equal("////", ["\377\377\377"].pack("m0"))
+
+ assert_equal([""], "".unpack("m0"))
+ assert_equal(["\0"], "AA==".unpack("m0"))
+ assert_equal(["\0\0"], "AAA=".unpack("m0"))
+ assert_equal(["\0\0\0"], "AAAA".unpack("m0"))
+ assert_equal(["\377"], "/w==".unpack("m0"))
+ assert_equal(["\377\377"], "//8=".unpack("m0"))
+ assert_equal(["\377\377\377"], "////".unpack("m0"))
+
+ assert_raise(ArgumentError) { "^".unpack("m0") }
+ assert_raise(ArgumentError) { "A".unpack("m0") }
+ assert_raise(ArgumentError) { "A^".unpack("m0") }
+ assert_raise(ArgumentError) { "AA".unpack("m0") }
+ assert_raise(ArgumentError) { "AA=".unpack("m0") }
+ assert_raise(ArgumentError) { "AA===".unpack("m0") }
+ assert_raise(ArgumentError) { "AA=x".unpack("m0") }
+ assert_raise(ArgumentError) { "AAA".unpack("m0") }
+ assert_raise(ArgumentError) { "AAA^".unpack("m0") }
+ assert_raise(ArgumentError) { "AB==".unpack("m0") }
+ assert_raise(ArgumentError) { "AAB=".unpack("m0") }
+ end
+
+ def test_pack_unpack_M
+ assert_equal("a b c\td =\n\ne=\n", ["a b c\td \ne"].pack("M"))
+ assert_equal(["a b c\td \ne"], "a b c\td =\n\ne=\n".unpack("M"))
+ assert_equal("=00=\n", ["\0"].pack("M"))
+ assert_equal("a"*73+"=\na=\n", ["a"*74].pack("M"))
+ assert_equal(("a"*73+"=\n")*14+"a=\n", ["a"*1023].pack("M"))
+ assert_equal(["\0"], "=00=\n".unpack("M"))
+ assert_equal(["a"*74], ("a"*73+"=\na=\n").unpack("M"))
+ assert_equal(["a"*1023], (("a"*73+"=\n")*14+"a=\n").unpack("M"))
+ assert_equal(["\x0a"], "=0a=\n".unpack("M"))
+ assert_equal(["\x0a"], "=0A=\n".unpack("M"))
+ assert_equal(["=0Z=\n"], "=0Z=\n".unpack("M"))
+ assert_equal([""], "=\r\n".unpack("M"))
+ assert_equal(["\xC6\xF7"], "=C6=F7".unpack('M*'))
+
+ assert_equal(["pre123after"], "pre=31=32=33after".unpack("M"))
+ assert_equal(["preafter"], "pre=\nafter".unpack("M"))
+ assert_equal(["preafter"], "pre=\r\nafter".unpack("M"))
+ assert_equal(["pre="], "pre=".unpack("M"))
+ assert_equal(["pre=\r"], "pre=\r".unpack("M"))
+ assert_equal(["pre=hoge"], "pre=hoge".unpack("M"))
+ assert_equal(["pre==31after"], "pre==31after".unpack("M"))
+ assert_equal(["pre===31after"], "pre===31after".unpack("M"))
+ end
+
+ def test_pack_unpack_P2
+ assert_raise(ArgumentError) { ["abc"].pack("P4") }
+ assert_raise(ArgumentError) { [""].pack("P") }
+
+ assert_equal([], ".".unpack("P"))
+ assert_equal([], ".".unpack("p"))
+ assert_equal([nil], ("\0" * 1024).unpack("P"))
+ end
+
+ def test_pack_p2
+ assert_match(/\A\0*\Z/, [nil].pack("p"))
+ end
+
+ def test_pack_unpack_w
+ assert_equal("\000", [0].pack("w"))
+ assert_equal("\001", [1].pack("w"))
+ assert_equal("\177", [127].pack("w"))
+ assert_equal("\201\000", [128].pack("w"))
+ assert_equal("\377\177", [0x3fff].pack("w"))
+ assert_equal("\201\200\000", [0x4000].pack("w"))
+ assert_equal("\203\377\377\377\177", [0x3fffffff].pack("w"))
+ assert_equal("\204\200\200\200\000", [0x40000000].pack("w"))
+ assert_equal("\217\377\377\377\177", [0xffffffff].pack("w"))
+ assert_equal("\220\200\200\200\000", [0x100000000].pack("w"))
+ assert_raise(ArgumentError) { [-1].pack("w") }
+
+ assert_equal([0], "\000".unpack("w"))
+ assert_equal([1], "\001".unpack("w"), [1])
+ assert_equal([127], "\177".unpack("w"), [127])
+ assert_equal([128], "\201\000".unpack("w"), [128])
+ assert_equal([0x3fff], "\377\177".unpack("w"), [0x3fff])
+ assert_equal([0x4000], "\201\200\000".unpack("w"), [0x4000])
+ assert_equal([0x3fffffff], "\203\377\377\377\177".unpack("w"), [0x3fffffff])
+ assert_equal([0x40000000], "\204\200\200\200\000".unpack("w"), [0x40000000])
+ assert_equal([0xffffffff], "\217\377\377\377\177".unpack("w"), [0xffffffff])
+ assert_equal([0x100000000], "\220\200\200\200\000".unpack("w"), [0x100000000])
+ end
+
+ def test_length_too_big
+ assert_raise(RangeError) { [].pack("C100000000000000000000") }
+ end
+
+ def test_short_string
+ %w[n N v V s S i I l L q Q s! S! i! I! l! l!].each {|fmt|
+ str = [1].pack(fmt)
+ assert_equal([1,nil], str.unpack("#{fmt}2"))
+ }
+ end
+
+ def test_short_with_block
+ bug4059 = '[ruby-core:33193]'
+ result = :ok
+ assert_nil("".unpack("i") {|x| result = x}, bug4059)
+ assert_equal(:ok, result)
+ end
+
+ def test_pack_garbage
+ verbose = $VERBOSE
+ $VERBOSE = false
+
+ assert_silent do
+ assert_equal "\000", [0].pack("*U")
+ end
+
+ $VERBOSE = true
+
+ _, err = capture_io do
+ assert_equal "\000", [0].pack("*U")
+ end
+
+ assert_match %r%unknown pack directive '\*' in '\*U'$%, err
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_unpack_garbage
+ verbose = $VERBOSE
+ $VERBOSE = false
+
+ assert_silent do
+ assert_equal [0], "\000".unpack("*U")
+ end
+
+ $VERBOSE = true
+
+ _, err = capture_io do
+ assert_equal [0], "\000".unpack("*U")
+ end
+
+ assert_match %r%unknown unpack directive '\*' in '\*U'$%, err
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_invalid_warning
+ assert_warning(/unknown pack directive ',' in ','/) {
+ [].pack(",")
+ }
+ assert_warning(/\A[ -~]+\Z/) {
+ [].pack("\x7f")
+ }
+ assert_warning(/\A(.* in '\u{3042}'\n)+\z/) {
+ EnvUtil.with_default_external(Encoding::UTF_8) {
+ [].pack("\u{3042}")
+ }
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_parse.rb b/jni/ruby/test/ruby/test_parse.rb
new file mode 100644
index 0000000..43de64b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_parse.rb
@@ -0,0 +1,882 @@
+# coding: US-ASCII
+require 'test/unit'
+require 'stringio'
+
+class TestParse < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_else_without_rescue
+ x = eval <<-END, nil, __FILE__, __LINE__+1
+ begin
+ else
+ 42
+ end
+ END
+ assert_equal(42, x)
+ end
+
+ def test_alias_backref
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ alias $foo $1
+ END
+ end
+ end
+
+ def test_command_call
+ t = Object.new
+ def t.foo(x); x; end
+
+ a = false
+ b = c = d = true
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a &&= t.foo 42
+ b &&= t.foo 42
+ c &&= t.foo nil
+ d &&= t.foo false
+ END
+ end
+ assert_equal([false, 42, nil, false], [a, b, c, d])
+
+ a = 3
+ assert_nothing_raised { eval("a &= t.foo 5") }
+ assert_equal(1, a)
+
+ a = [nil, nil, true, true]
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a[0] ||= t.foo 42
+ a[1] &&= t.foo 42
+ a[2] ||= t.foo 42
+ a[3] &&= t.foo 42
+ END
+ end
+ assert_equal([42, nil, true, 42], a)
+
+ o = Object.new
+ class << o
+ attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
+ end
+ o.foo = o.Foo = o::baz = nil
+ o.bar = o.Bar = o::qux = 1
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ o.foo ||= t.foo 42
+ o.bar &&= t.foo 42
+ o.Foo ||= t.foo 42
+ o.Bar &&= t.foo 42
+ o::baz ||= t.foo 42
+ o::qux &&= t.foo 42
+ END
+ end
+ assert_equal([42, 42], [o.foo, o.bar])
+ assert_equal([42, 42], [o.Foo, o.Bar])
+ assert_equal([42, 42], [o::baz, o::qux])
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ $1 ||= t.foo 42
+ END
+ end
+
+ def t.bar(x); x + yield; end
+
+ a = b = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = t.bar "foo" do
+ "bar"
+ end.gsub "ob", "OB"
+ b = t.bar "foo" do
+ "bar"
+ end::gsub "ob", "OB"
+ END
+ end
+ assert_equal("foOBar", a)
+ assert_equal("foOBar", b)
+
+ a = nil
+ assert_nothing_raised do
+ t.instance_eval <<-END, __FILE__, __LINE__+1
+ a = bar "foo" do "bar" end
+ END
+ end
+ assert_equal("foobar", a)
+
+ a = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = t::bar "foo" do "bar" end
+ END
+ end
+ assert_equal("foobar", a)
+
+ def t.baz(*r)
+ @baz = r + (block_given? ? [yield] : [])
+ end
+
+ assert_nothing_raised do
+ t.instance_eval "baz (1), 2"
+ end
+ assert_equal([1, 2], t.instance_eval { @baz })
+ end
+
+ def test_mlhs_node
+ c = Class.new
+ class << c
+ attr_accessor :foo, :bar, :Foo, :Bar
+ FOO = BAR = nil
+ end
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ c::foo, c::bar = 1, 2
+ c.Foo, c.Bar = 1, 2
+ c::FOO, c::BAR = 1, 2
+ END
+ end
+ assert_equal([1, 2], [c::foo, c::bar])
+ assert_equal([1, 2], [c.Foo, c.Bar])
+ assert_equal([1, 2], [c::FOO, c::BAR])
+ end
+
+ def test_dynamic_constant_assignment
+ assert_raise(SyntaxError) do
+ Object.new.instance_eval <<-END, __FILE__, __LINE__+1
+ def foo
+ self::FOO, self::BAR = 1, 2
+ ::FOO, ::BAR = 1, 2
+ end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ $1, $2 = 1, 2
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ Object.new.instance_eval <<-END, __FILE__, __LINE__+1
+ def foo
+ ::FOO = 1
+ end
+ END
+ end
+
+ c = Class.new
+ assert_nothing_raised(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ if false
+ c::FOO &= 1
+ ::FOO &= 1
+ end
+ END
+ end
+
+ c = Class.new
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ $1 &= 1
+ END
+ end
+ end
+
+ def test_class_module
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ class foo; end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo
+ class Foo; end
+ module Bar; end
+ end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ class Foo Bar; end
+ END
+ end
+ end
+
+ def test_op_name
+ o = Object.new
+ def o.>(x); x; end
+ def o./(x); x; end
+
+ assert_nothing_raised do
+ o.instance_eval <<-END, __FILE__, __LINE__+1
+ undef >, /
+ END
+ end
+ end
+
+ def test_arg
+ o = Object.new
+ class << o
+ attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
+ end
+ o.foo = o.Foo = o::baz = nil
+ o.bar = o.Bar = o::qux = 1
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ o.foo ||= 42
+ o.bar &&= 42
+ o.Foo ||= 42
+ o.Bar &&= 42
+ o::baz ||= 42
+ o::qux &&= 42
+ END
+ end
+ assert_equal([42, 42], [o.foo, o.bar])
+ assert_equal([42, 42], [o.Foo, o.Bar])
+ assert_equal([42, 42], [o::baz, o::qux])
+
+ a = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = -2.0 ** 2
+ END
+ end
+ assert_equal(-4.0, a)
+ end
+
+ def test_block_variable
+ o = Object.new
+ def o.foo(*r); yield(*r); end
+
+ a = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ o.foo 1 do|; a| a = 42 end
+ END
+ end
+ assert_nil(a)
+ end
+
+ def test_bad_arg
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo(FOO); end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo(@foo); end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo($foo); end
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo(@@foo); end
+ END
+ end
+
+ o = Object.new
+ def o.foo(*r); yield(*r); end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ o.foo 1 {|; @a| @a = 42 }
+ END
+ end
+ end
+
+ def test_do_lambda
+ a = b = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = -> do
+ b = 42
+ end
+ END
+ end
+ a.call
+ assert_equal(42, b)
+ end
+
+ def test_block_call_colon2
+ o = Object.new
+ def o.foo(x); x + yield; end
+
+ a = b = nil
+ assert_nothing_raised do
+ o.instance_eval <<-END, __FILE__, __LINE__+1
+ a = foo 1 do 42 end.to_s
+ b = foo 1 do 42 end::to_s
+ END
+ end
+ assert_equal("43", a)
+ assert_equal("43", b)
+ end
+
+ def test_call_method
+ a = b = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = proc {|x| x + "bar" }.("foo")
+ b = proc {|x| x + "bar" }::("foo")
+ END
+ end
+ assert_equal("foobar", a)
+ assert_equal("foobar", b)
+ end
+
+ def test_xstring
+ assert_raise(Errno::ENOENT) do
+ eval("``")
+ end
+ end
+
+ def test_words
+ assert_equal([], %W( ))
+ end
+
+ def test_dstr
+ @@foo = 1
+ assert_equal("foo 1 bar", "foo #@@foo bar")
+ "1" =~ /(.)/
+ assert_equal("foo 1 bar", "foo #$1 bar")
+ end
+
+ def test_dstr_disallowed_variable
+ bug8375 = '[ruby-core:54885] [Bug #8375]'
+ %w[@ @1 @@. @@ @@1 @@. $ $%].each do |src|
+ src = '#'+src+' '
+ str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do
+ break eval('"'+src+'"')
+ end
+ assert_equal(src, str, bug8375)
+ end
+ end
+
+ def test_dsym
+ assert_nothing_raised { eval(':""') }
+ end
+
+ def test_arg2
+ o = Object.new
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def o.foo(a=42,*r,z,&b); b.call(r.inject(a*1000+z*100, :+)); end
+ END
+ end
+ assert_equal(-1405, o.foo(1,2,3,4) {|x| -x })
+ assert_equal(-1302, o.foo(1,2,3) {|x| -x })
+ assert_equal(-1200, o.foo(1,2) {|x| -x })
+ assert_equal(-42100, o.foo(1) {|x| -x })
+ assert_raise(ArgumentError) { o.foo() }
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def o.foo(a=42,z,&b); b.call(a*1000+z*100); end
+ END
+ end
+ assert_equal(-1200, o.foo(1,2) {|x| -x } )
+ assert_equal(-42100, o.foo(1) {|x| -x } )
+ assert_raise(ArgumentError) { o.foo() }
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def o.foo(*r,z,&b); b.call(r.inject(z*100, :+)); end
+ END
+ end
+ assert_equal(-303, o.foo(1,2,3) {|x| -x } )
+ assert_equal(-201, o.foo(1,2) {|x| -x } )
+ assert_equal(-100, o.foo(1) {|x| -x } )
+ assert_raise(ArgumentError) { o.foo() }
+ end
+
+ def test_duplicate_argument
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ 1.times {|&b?| }
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ 1.times {|a, a|}
+ END
+ end
+
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo(a, a); end
+ END
+ end
+ end
+
+ def test_define_singleton_error
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def ("foo").foo; end
+ END
+ end
+ end
+
+ def test_backquote
+ t = Object.new
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def t.`(x); "foo" + x + "bar"; end
+ END
+ end
+ a = b = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ a = t.` "zzz"
+ 1.times {|;z| t.` ("zzz") }
+ END
+ t.instance_eval <<-END, __FILE__, __LINE__+1
+ b = `zzz`
+ END
+ end
+ assert_equal("foozzzbar", a)
+ assert_equal("foozzzbar", b)
+ end
+
+ def test_carrige_return
+ assert_equal(2, eval("1 +\r\n1"))
+ end
+
+ def test_string
+ assert_raise(SyntaxError) do
+ eval '"\xg1"'
+ end
+
+ assert_raise(SyntaxError) do
+ eval '"\u{1234"'
+ end
+
+ assert_raise(SyntaxError) do
+ eval '"\M1"'
+ end
+
+ assert_raise(SyntaxError) do
+ eval '"\C1"'
+ end
+
+ assert_equal("\x81", eval('"\C-\M-a"'))
+ assert_equal("\177", eval('"\c?"'))
+ end
+
+ def test_question
+ assert_raise(SyntaxError) { eval('?') }
+ assert_raise(SyntaxError) { eval('? ') }
+ assert_raise(SyntaxError) { eval("?\n") }
+ assert_raise(SyntaxError) { eval("?\t") }
+ assert_raise(SyntaxError) { eval("?\v") }
+ assert_raise(SyntaxError) { eval("?\r") }
+ assert_raise(SyntaxError) { eval("?\f") }
+ assert_equal("\u{1234}", eval("?\u{1234}"))
+ assert_equal("\u{1234}", eval('?\u{1234}'))
+ end
+
+ def test_percent
+ assert_equal(:foo, eval('%s(foo)'))
+ assert_raise(SyntaxError) { eval('%s') }
+ assert_raise(SyntaxError) { eval('%ss') }
+ assert_raise(SyntaxError) { eval('%z()') }
+ end
+
+ def test_symbol
+ bug = '[ruby-dev:41447]'
+ sym = "foo\0bar".to_sym
+ assert_nothing_raised(SyntaxError, bug) do
+ assert_equal(sym, eval(":'foo\0bar'"))
+ end
+ assert_nothing_raised(SyntaxError, bug) do
+ assert_equal(sym, eval(':"foo\u0000bar"'))
+ end
+ assert_nothing_raised(SyntaxError, bug) do
+ assert_equal(sym, eval(':"foo\u{0}bar"'))
+ end
+ assert_raise(SyntaxError) do
+ eval ':"foo\u{}bar"'
+ end
+ end
+
+ def test_parse_string
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+/
+ END
+ end
+ end
+
+ def test_here_document
+ x = nil
+
+ assert_raise(SyntaxError) do
+ eval %Q(
+<\<FOO
+ )
+ end
+
+ assert_nothing_raised(SyntaxError) do
+ x = eval %q(
+<<FOO
+#$
+FOO
+ )
+ end
+ assert_equal "\#$\n", x
+
+ assert_raise(SyntaxError) do
+ eval %Q(
+<\<\"
+ )
+ end
+
+ assert_raise(SyntaxError) do
+ eval %q(
+<<``
+ )
+ end
+
+ assert_raise(SyntaxError) do
+ eval %q(
+<<--
+ )
+ end
+
+ assert_nothing_raised(SyntaxError) do
+ x = eval %q(
+<<FOO
+#$
+foo
+FOO
+ )
+ end
+ assert_equal "\#$\nfoo\n", x
+
+ assert_nothing_raised do
+ eval "x = <<""FOO\r\n1\r\nFOO"
+ end
+ assert_equal("1\n", x)
+ end
+
+ def test_magic_comment
+ x = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+# coding = utf-8
+x = __ENCODING__
+ END
+ end
+ assert_equal(Encoding.find("UTF-8"), x)
+
+ assert_raise(ArgumentError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+# coding = foobarbazquxquux_dummy_enconding
+x = __ENCODING__
+ END
+ end
+ end
+
+ def test_utf8_bom
+ x = nil
+ assert_nothing_raised do
+ eval "\xef\xbb\xbf x = __ENCODING__"
+ end
+ assert_equal(Encoding.find("UTF-8"), x)
+ assert_raise(NameError) { eval "\xef" }
+ end
+
+ def test_dot_in_next_line
+ x = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ x = 1
+ .to_s
+ END
+ end
+ assert_equal("1", x)
+ end
+
+ def test_pow_asgn
+ x = 3
+ assert_nothing_raised { eval("x **= 2") }
+ assert_equal(9, x)
+ end
+
+ def test_embedded_rd
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+=begin
+ END
+ end
+ end
+
+ def test_float
+ assert_equal(1.0/0, eval("1e10000"))
+ assert_raise(SyntaxError) { eval('1_E') }
+ assert_raise(SyntaxError) { eval('1E1E1') }
+ end
+
+ def test_global_variable
+ assert_equal(nil, eval('$-x'))
+ assert_equal(nil, eval('alias $preserve_last_match $&'))
+ assert_equal(nil, eval('alias $& $test_parse_foobarbazqux'))
+ $test_parse_foobarbazqux = nil
+ assert_equal(nil, $&)
+ assert_equal(nil, eval('alias $& $preserve_last_match'))
+ assert_raise(SyntaxError) { eval('$#') }
+ end
+
+ def test_invalid_instance_variable
+ assert_raise(SyntaxError) { eval('@#') }
+ assert_raise(SyntaxError) { eval('@') }
+ end
+
+ def test_invalid_class_variable
+ assert_raise(SyntaxError) { eval('@@1') }
+ assert_raise(SyntaxError) { eval('@@') }
+ end
+
+ def test_invalid_char
+ bug10117 = '[ruby-core:64243] [Bug #10117]'
+ invalid_char = /Invalid char `\\x01'/
+ x = 1
+ assert_in_out_err(%W"-e \x01x", "", [], invalid_char, bug10117)
+ assert_syntax_error("\x01x", invalid_char, bug10117)
+ assert_equal(nil, eval("\x04x"))
+ end
+
+ def test_literal_concat
+ x = "baz"
+ assert_equal("foobarbaz", eval('"foo" "bar#{x}"'))
+ end
+
+ def test_unassignable
+ assert_raise(SyntaxError) do
+ eval %q(self = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(nil = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(true = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(false = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(__FILE__ = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(__LINE__ = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval %q(__ENCODING__ = 1)
+ end
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ def foo
+ FOO = 1
+ end
+ END
+ end
+ end
+
+ def test_block_dup
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ foo(&proc{}) {}
+ END
+ end
+ end
+
+ def test_set_backref
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ $& = 1
+ END
+ end
+ end
+
+ def test_arg_concat
+ o = Object.new
+ class << o; self; end.instance_eval do
+ define_method(:[]=) {|*r, &b| b.call(r) }
+ end
+ r = nil
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ o[&proc{|x| r = x }] = 1
+ END
+ end
+ assert_equal([1], r)
+ end
+
+ def test_void_expr_stmts_value
+ # This test checks if void contexts are warned correctly.
+ # Thus, warnings MUST NOT be suppressed.
+ $VERBOSE = true
+ stderr = $stderr
+ $stderr = StringIO.new("")
+ x = 1
+ assert_nil eval("x; nil")
+ assert_nil eval("1+1; nil")
+ assert_nil eval("TestParse; nil")
+ assert_nil eval("::TestParse; nil")
+ assert_nil eval("x..x; nil")
+ assert_nil eval("x...x; nil")
+ assert_nil eval("self; nil")
+ assert_nil eval("nil; nil")
+ assert_nil eval("true; nil")
+ assert_nil eval("false; nil")
+ assert_nil eval("defined?(1); nil")
+
+ assert_raise(SyntaxError) do
+ eval %q(1; next; 2)
+ end
+
+ assert_equal(13, $stderr.string.lines.to_a.size)
+ $stderr = stderr
+ end
+
+ def test_assign_in_conditional
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ (x, y = 1, 2) ? 1 : 2
+ END
+ end
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ if @x = true
+ 1
+ else
+ 2
+ end
+ END
+ end
+ end
+
+ def test_literal_in_conditional
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ "foo" ? 1 : 2
+ END
+ end
+
+ assert_nothing_raised do
+ x = "bar"
+ eval <<-END, nil, __FILE__, __LINE__+1
+ /foo#{x}baz/ ? 1 : 2
+ END
+ end
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ (true..false) ? 1 : 2
+ END
+ end
+
+ assert_nothing_raised do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ ("foo".."bar") ? 1 : 2
+ END
+ end
+
+ assert_nothing_raised do
+ x = "bar"
+ eval <<-END, nil, __FILE__, __LINE__+1
+ :"foo#{"x"}baz" ? 1 : 2
+ END
+ end
+ end
+
+ def test_no_blockarg
+ assert_raise(SyntaxError) do
+ eval <<-END, nil, __FILE__, __LINE__+1
+ yield(&:+)
+ END
+ end
+ end
+
+ def test_intern
+ assert_equal(':""', ''.intern.inspect)
+ assert_equal(':$foo', '$foo'.intern.inspect)
+ assert_equal(':"!foo"', '!foo'.intern.inspect)
+ assert_equal(':"foo=="', "foo==".intern.inspect)
+ end
+
+ def test_all_symbols
+ x = Symbol.all_symbols
+ assert_kind_of(Array, x)
+ assert_empty(x.reject {|s| s.is_a?(Symbol) })
+ end
+
+ def test_is_class_id
+ c = Class.new
+ assert_raise(NameError) do
+ c.instance_eval { remove_class_variable(:@var) }
+ end
+ end
+
+ def test_method_block_location
+ bug5614 = '[ruby-core:40936]'
+ expected = nil
+ e = assert_raise(NoMethodError) do
+ 1.times do
+ expected = __LINE__+1
+ end.print do
+ #
+ end
+ end
+ actual = e.backtrace.first[/\A#{Regexp.quote(__FILE__)}:(\d+):/o, 1].to_i
+ assert_equal(expected, actual, bug5614)
+ end
+
+ def test_shadowing_variable
+ assert_warning(/shadowing outer local variable/) {eval("a=1; tap {|a|}")}
+ a = "\u{3042}"
+ assert_warning(/#{a}/o) {eval("#{a}=1; tap {|#{a}|}")}
+ end
+
+ def test_unused_variable
+ o = Object.new
+ assert_warning(/assigned but unused variable/) {o.instance_eval("def foo; a=1; nil; end")}
+ a = "\u{3042}"
+ assert_warning(/#{a}/) {o.instance_eval("def foo; #{a}=1; nil; end")}
+ end
+
+ def test_named_capture_conflict
+ a = 1
+ assert_warning(/named capture conflict/) {eval("a = 1; /(?<a>)/ =~ ''")}
+ a = "\u{3042}"
+ assert_warning(/#{a}/) {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")}
+ end
+
+=begin
+ def test_past_scope_variable
+ assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}}
+ end
+=end
+end
diff --git a/jni/ruby/test/ruby/test_path.rb b/jni/ruby/test/ruby/test_path.rb
new file mode 100644
index 0000000..2db7be0
--- /dev/null
+++ b/jni/ruby/test/ruby/test_path.rb
@@ -0,0 +1,259 @@
+require 'test/unit'
+
+class TestPath < Test::Unit::TestCase
+ def test_path
+ assert_equal("a", File.basename("a"))
+ assert_equal("b", File.basename("a/b"))
+ assert_equal("b", File.basename("a/b/"))
+ assert_equal("/", File.basename("/"))
+ assert_equal("/", File.basename("//"))
+ assert_equal("/", File.basename("///"))
+ assert_equal("b", File.basename("a/b////"))
+ assert_equal("a", File.basename("a.rb", ".rb"))
+ assert_equal("a", File.basename("a.rb///", ".rb"))
+ assert_equal("a", File.basename("a.rb///", ".*"))
+ assert_equal("a.rb", File.basename("a.rb///", ".c"))
+ assert_equal(".", File.dirname("a"))
+ assert_equal("/", File.dirname("/"))
+ assert_equal("/", File.dirname("/a"))
+ assert_equal("a", File.dirname("a/b"))
+ assert_equal("a/b", File.dirname("a/b/c"))
+ assert_equal("/a/b", File.dirname("/a/b/c"))
+ assert_equal("/a", File.dirname("/a/b/"))
+ assert_equal("/a", File.dirname("/a/b///"))
+ case Dir.pwd
+ when %r'\A\w:'
+ assert_match(/\A\w:\/\z/, File.expand_path(".", "/"))
+ assert_match(/\A\w:\/a\z/, File.expand_path("a", "/"))
+ dosish = true
+ when %r'\A//'
+ assert_match(%r'\A//[^/]+/[^/]+\z', File.expand_path(".", "/"))
+ assert_match(%r'\A//[^/]+/[^/]+/a\z', File.expand_path(".", "/"))
+ dosish = true
+ else
+ assert_equal("/", File.expand_path(".", "/"))
+ assert_equal("/sub", File.expand_path("sub", "/"))
+ end
+ if dosish
+ assert_equal("//127.0.0.1/share", File.expand_path("/", "//127.0.0.1/share/sub"))
+ assert_equal("//127.0.0.1/share/dir", File.expand_path("/dir", "//127.0.0.1/share/sub"))
+ assert_equal("z:/", File.expand_path("/", "z:/sub"))
+ assert_equal("z:/dir", File.expand_path("/dir", "z:/sub"))
+ end
+ assert_equal("//", File.expand_path(".", "//"))
+ assert_equal("//sub", File.expand_path("sub", "//"))
+
+ assert_equal("//127.0.0.1/\u3042", File.expand_path("\u3042", "//127.0.0.1"))
+ end
+
+ def test_dirname
+ if /(bcc|ms)win\d|mingw|cygwin|emx/ =~ RUBY_PLATFORM
+ # DOSISH_DRIVE_LETTER
+ assert_equal('C:.', File.dirname('C:'))
+ assert_equal('C:.', File.dirname('C:a'))
+ assert_equal('C:.', File.dirname('C:a/'))
+ assert_equal('C:a', File.dirname('C:a/b'), "[ruby-dev:27738]")
+
+ assert_equal('C:/', File.dirname('C:/'))
+ assert_equal('C:/', File.dirname('C:/a'))
+ assert_equal('C:/', File.dirname('C:/a/'))
+ assert_equal('C:/a', File.dirname('C:/a/b'))
+
+ assert_equal('C:/', File.dirname('C://'))
+ assert_equal('C:/', File.dirname('C://a'))
+ assert_equal('C:/', File.dirname('C://a/'))
+ assert_equal('C:/a', File.dirname('C://a/b'))
+
+ assert_equal('C:/', File.dirname('C:///'), "[ruby-dev:27738]")
+ assert_equal('C:/', File.dirname('C:///a'))
+ assert_equal('C:/', File.dirname('C:///a/'))
+ assert_equal('C:/a', File.dirname('C:///a/b'))
+ else
+ # others
+ assert_equal('.', File.dirname('C:'))
+ assert_equal('.', File.dirname('C:a'))
+ assert_equal('.', File.dirname('C:a/'))
+ assert_equal('C:a', File.dirname('C:a/b'))
+
+ assert_equal('.', File.dirname('C:/'))
+ assert_equal('C:', File.dirname('C:/a'))
+ assert_equal('C:', File.dirname('C:/a/'))
+ assert_equal('C:/a', File.dirname('C:/a/b'))
+
+ assert_equal('.', File.dirname('C://'))
+ assert_equal('C:', File.dirname('C://a'))
+ assert_equal('C:', File.dirname('C://a/'))
+ # not spec.
+ #assert_equal('C://a', File.dirname('C://a/b'))
+
+ assert_equal('.', File.dirname('C:///'))
+ assert_equal('C:', File.dirname('C:///a'))
+ assert_equal('C:', File.dirname('C:///a/'))
+ # not spec.
+ #assert_equal('C:///a', File.dirname('C:///a/b'))
+ end
+
+ assert_equal('.', File.dirname(''))
+ assert_equal('.', File.dirname('a'))
+ assert_equal('.', File.dirname('a/'))
+ assert_equal('a', File.dirname('a/b'))
+
+ assert_equal('/', File.dirname('/'))
+ assert_equal('/', File.dirname('/a'))
+ assert_equal('/', File.dirname('/a/'))
+ assert_equal('/a', File.dirname('/a/b'))
+
+ if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
+ # DOSISH_UNC
+ assert_equal('//', File.dirname('//'))
+ assert_equal('//a', File.dirname('//a'))
+ assert_equal('//a', File.dirname('//a/'))
+ assert_equal('//a/b', File.dirname('//a/b'))
+ assert_equal('//a/b', File.dirname('//a/b/'))
+ assert_equal('//a/b', File.dirname('//a/b/c'))
+
+ assert_equal('//', File.dirname('///'))
+ assert_equal('//a', File.dirname('///a'))
+ assert_equal('//a', File.dirname('///a/'))
+ assert_equal('//a/b', File.dirname('///a/b'))
+ assert_equal('//a/b', File.dirname('///a/b/'))
+ assert_equal('//a/b', File.dirname('///a/b/c'))
+ else
+ # others
+ assert_equal('/', File.dirname('//'))
+ assert_equal('/', File.dirname('//a'))
+ assert_equal('/', File.dirname('//a/'))
+ assert_equal('/a', File.dirname('//a/b'))
+ assert_equal('/a', File.dirname('//a/b/'))
+ assert_equal('/a/b', File.dirname('//a/b/c'))
+
+ assert_equal('/', File.dirname('///'))
+ assert_equal('/', File.dirname('///a'))
+ assert_equal('/', File.dirname('///a/'))
+ assert_equal('/a', File.dirname('///a/b'))
+ assert_equal('/a', File.dirname('///a/b/'))
+ assert_equal('/a/b', File.dirname('///a/b/c'))
+ end
+ end
+
+ def test_basename
+ if /(bcc|ms)win\d|mingw|cygwin|emx/ =~ RUBY_PLATFORM
+ # DOSISH_DRIVE_LETTER
+ assert_equal('', File.basename('C:'))
+ assert_equal('a', File.basename('C:a'))
+ assert_equal('a', File.basename('C:a/'))
+ assert_equal('b', File.basename('C:a/b'))
+
+ assert_equal('/', File.basename('C:/'))
+ assert_equal('a', File.basename('C:/a'))
+ assert_equal('a', File.basename('C:/a/'))
+ assert_equal('b', File.basename('C:/a/b'))
+
+ assert_equal('/', File.basename('C://'))
+ assert_equal('a', File.basename('C://a'))
+ assert_equal('a', File.basename('C://a/'))
+ assert_equal('b', File.basename('C://a/b'))
+
+ assert_equal('/', File.basename('C:///'))
+ assert_equal('a', File.basename('C:///a'))
+ assert_equal('a', File.basename('C:///a/'))
+ assert_equal('b', File.basename('C:///a/b'))
+ else
+ # others
+ assert_equal('C:', File.basename('C:'))
+ assert_equal('C:a', File.basename('C:a'))
+ assert_equal('C:a', File.basename('C:a/'))
+ assert_equal('b', File.basename('C:a/b'))
+
+ assert_equal('C:', File.basename('C:/'))
+ assert_equal('a', File.basename('C:/a'))
+ assert_equal('a', File.basename('C:/a/'))
+ assert_equal('b', File.basename('C:/a/b'))
+
+ assert_equal('C:', File.basename('C://'))
+ assert_equal('a', File.basename('C://a'))
+ assert_equal('a', File.basename('C://a/'))
+ assert_equal('b', File.basename('C://a/b'))
+
+ assert_equal('C:', File.basename('C:///'))
+ assert_equal('a', File.basename('C:///a'))
+ assert_equal('a', File.basename('C:///a/'))
+ assert_equal('b', File.basename('C:///a/b'))
+ end
+
+ assert_equal('', File.basename(''))
+ assert_equal('a', File.basename('a'))
+ assert_equal('a', File.basename('a/'))
+ assert_equal('b', File.basename('a/b'))
+
+ assert_equal('/', File.basename('/'))
+ assert_equal('a', File.basename('/a'))
+ assert_equal('a', File.basename('/a/'))
+ assert_equal('b', File.basename('/a/b'))
+
+ assert_equal("..", File.basename("..", ".*"))
+
+ if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
+ # DOSISH_UNC
+ assert_equal('/', File.basename('//'))
+ assert_equal('/', File.basename('//a'))
+ assert_equal('/', File.basename('//a/'))
+ assert_equal('/', File.basename('//a/b'), "[ruby-dev:27776]")
+ assert_equal('/', File.basename('//a/b/'))
+ assert_equal('c', File.basename('//a/b/c'))
+
+ assert_equal('/', File.basename('///'))
+ assert_equal('/', File.basename('///a'))
+ assert_equal('/', File.basename('///a/'))
+ assert_equal('/', File.basename('///a/b'))
+ assert_equal('/', File.basename('///a/b/'))
+ assert_equal('c', File.basename('///a/b/c'))
+ else
+ # others
+ assert_equal('/', File.basename('//'))
+ assert_equal('a', File.basename('//a'))
+ assert_equal('a', File.basename('//a/'))
+ assert_equal('b', File.basename('//a/b'))
+ assert_equal('b', File.basename('//a/b/'))
+ assert_equal('c', File.basename('//a/b/c'))
+
+ assert_equal('/', File.basename('///'))
+ assert_equal('a', File.basename('///a'))
+ assert_equal('a', File.basename('///a/'))
+ assert_equal('b', File.basename('///a/b'))
+ assert_equal('b', File.basename('///a/b/'))
+ assert_equal('c', File.basename('///a/b/c'))
+ end
+ end
+
+ def test_extname
+ assert_equal('', File.extname('a'))
+ ext = '.rb'
+ assert_equal(ext, File.extname('a.rb'))
+ unless /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ # trailing spaces and dots are ignored on NTFS.
+ ext = ''
+ end
+ assert_equal(ext, File.extname('a.rb.'))
+ assert_equal('', File.extname('a.'))
+ assert_equal('', File.extname('.x'))
+ assert_equal('', File.extname('..x'))
+ end
+
+ def test_ascii_incompatible_path
+ s = "\u{221e}\u{2603}"
+ assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-16be"))}
+ assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-16le"))}
+ assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-32be"))}
+ assert_raise(Encoding::CompatibilityError) {open(s.encode("utf-32le"))}
+ end
+
+ def test_join
+ bug5483 = '[ruby-core:40338]'
+ path = %w[a b]
+ Encoding.list.each do |e|
+ next unless e.ascii_compatible?
+ assert_equal(e, File.join(*path.map {|s| s.force_encoding(e)}).encoding, bug5483)
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_pipe.rb b/jni/ruby/test/ruby/test_pipe.rb
new file mode 100644
index 0000000..bcea91b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_pipe.rb
@@ -0,0 +1,29 @@
+require 'test/unit'
+require_relative 'ut_eof'
+
+class TestPipe < Test::Unit::TestCase
+ include TestEOF
+ def open_file(content)
+ r, w = IO.pipe
+ w << content
+ w.close
+ begin
+ yield r
+ ensure
+ r.close
+ end
+ end
+ class WithConversion < self
+ def open_file(content)
+ r, w = IO.pipe
+ w << content
+ w.close
+ r.set_encoding("us-ascii:utf-8")
+ begin
+ yield r
+ ensure
+ r.close
+ end
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_primitive.rb b/jni/ruby/test/ruby/test_primitive.rb
new file mode 100644
index 0000000..9d451e2
--- /dev/null
+++ b/jni/ruby/test/ruby/test_primitive.rb
@@ -0,0 +1,423 @@
+require 'test/unit'
+
+class TestRubyPrimitive < Test::Unit::TestCase
+
+ def test_not
+ assert_equal false, !true
+ assert_equal true, !false
+ assert_equal true, !nil
+ assert_equal false, !(1+1)
+ assert_equal false, !!nil
+ assert_equal true, !!1
+ end
+
+ def test_lvar
+ a = 1
+ assert_equal 1, a
+ b = 2
+ assert_equal 1, a
+ a = b = 3
+ assert_equal 3, a
+ assert_equal 3, b
+ a = b = c = 4
+ assert_equal 4, a
+ assert_equal 4, b
+ assert_equal 4, c
+ end
+
+ C = 1
+ class A
+ Const = 1
+ class B
+ Const = 2
+ class C
+ Const = 3
+ def const
+ Const
+ end
+ end
+ end
+ end
+ (1..2).map {
+ A::B::C::Const
+ }
+
+ def test_constant
+ assert_equal 1, C
+ assert_equal 1, C
+ assert_equal 1, A::Const
+ assert_equal 2, A::B::Const
+ assert_equal 3, A::B::C::Const
+ assert_equal 3, A::B::C.new.const
+ assert_equal 1, ::TestRubyPrimitive::A::Const
+ A::B::C.send(:remove_const, :Const)
+ assert_equal 2, A::B::C.new.const
+ assert_raise(TypeError) {
+ C::CONST
+ }
+ end
+
+ class A2
+ class B2
+ class C2
+ C = 7
+ end
+ end
+ end
+
+ def test_constant_cache
+ i = 0
+ while i < 3
+ r = A2::B2::C2::C
+ i += 1
+ end
+ assert_equal 7, r
+ end
+
+ class A3
+ class B3
+ C = 99
+ end
+ end
+ i = 0
+ while i < 3
+ r = A3::B3::C # cache
+ class A3::B3
+ remove_const :C
+ end
+ A3::B3::C = i ** i
+ i += 1
+ end
+
+ def test_constant_cache2
+ assert_equal 4, A3::B3::C
+ end
+
+ class A4
+ Const = 7
+ (1..3).map {
+ $test_ruby_primitive_constant_cache3 = self::Const
+ }
+ end
+
+ def test_constant_cache3
+ assert_equal 7, $test_ruby_primitive_constant_cache3
+ end
+
+ class A5
+ Const = 8
+ (1..3).map {
+ $test_ruby_primitive_constant_cache4 = eval('self')::Const
+ }
+ end
+
+ def test_constatant_cache4
+ assert_equal 8, $test_ruby_primitive_constant_cache4
+ end
+
+ class A6
+ Const = 0
+ def self.foo
+ self::Const
+ end
+ end
+ class B6 < A6
+ Const = 1
+ end
+ class C6 < B6
+ Const = 2
+ end
+ $test_ruby_primitive_constant_cache5 = [A6.foo, B6.foo, C6.foo]
+
+ def test_constant_cache5
+ assert_equal [0, 1, 2], $test_ruby_primitive_constant_cache5
+ end
+
+ def test_gvar
+ $test_ruby_primitive_gvar = 7
+ assert_equal 7, $test_ruby_primitive_gvar
+ assert_equal 7, $test_ruby_primitive_gvar
+ $test_ruby_primitive_gvar = 88
+ assert_equal 88, $test_ruby_primitive_gvar
+ assert_equal 88, $test_ruby_primitive_gvar
+ assert_equal 7, ($test_ruby_primitive_gvar = 7)
+ assert_equal 7, ($test_ruby_primitive_gvar = 7)
+ end
+
+ class A7
+ @@c = 1
+ def m
+ @@c += 1
+ end
+ end
+
+ def test_cvar_from_instance_method
+ assert_equal 2, A7.new.m
+ assert_equal 3, A7.new.m
+ assert_equal 4, A7.new.m
+ end
+
+ class A8
+ @@c = 1
+ class << self
+ def m
+ @@c += 1
+ end
+ end
+ end
+
+ def test_cvar_from_singleton_method
+ assert_equal 2, A8.m
+ assert_equal 3, A8.m
+ assert_equal 4, A8.m
+ end
+
+ class A9
+ @@c = 1
+ def self.m
+ @@c += 1
+ end
+ end
+
+ def test_cvar_from_singleton_method2
+ assert_equal 2, A9.m
+ assert_equal 3, A9.m
+ assert_equal 4, A9.m
+ end
+
+ class A10
+ attr_accessor :a
+ end
+
+ def test_opassign
+ i = 0
+ i += 1
+ assert_equal 1, i
+
+ @iv = 2
+ @iv += 2
+ assert_equal 4, @iv
+
+ @@cv ||= 1
+ assert_equal 1, @@cv
+ @@cv &&= 2
+ assert_equal 2, @@cv
+ @@cv ||= 99
+ assert_equal 2, @@cv
+
+ $gv = 3
+ $gv += 4
+ assert_equal 7, $gv
+
+ obj = A10.new
+ obj.a = 9
+ obj.a &&= 7
+ assert_equal 7, obj.a
+
+ obj.a = nil
+ obj.a ||= 2
+ assert_equal 2, obj.a
+
+ obj.a &&= 3
+ assert_equal 3, obj.a
+
+ a = []
+ a[0] ||= 3
+ assert_equal 3, a[0]
+ a[0] &&= 7
+ assert_equal 7, a[0]
+ a[0] ||= 3
+ assert_equal 7, a[0]
+
+ a = [0, 1, nil, 3, 4]
+ a[*[2]] ||= :foo
+ assert_equal [0, 1, :foo, 3, 4], a
+ a[*[1,3]] &&= [:bar]
+ assert_equal [0, :bar, 4], a
+ end
+
+ def test_opassign_and_or
+ a = 1
+ a ||= 2
+ assert_equal 1, a
+ a = nil
+ a ||= 2
+ assert_equal 2, a
+ a = 1
+ a &&= 3
+ assert_equal 3, a
+ a = nil
+ a &&= 4
+ assert_nil a
+
+ h = {}
+ h[0] ||= 1
+ assert_equal 1, h[0]
+ h = {}
+ h[0] &&= 1
+ assert_nil h[0]
+ h = {0 => 7}
+ h[0] ||= 1
+ assert_equal 7, h[0]
+ h = {0 => 7}
+ h[0] &&= 1
+ assert_equal 1, h[0]
+ end
+
+ def test_backref
+ /a(b)(c)d/ =~ 'xyzabcdefgabcdefg'
+ assert_equal 'b', $1
+ assert_equal 'c', $2
+ assert_nil $3
+ assert_instance_of MatchData, $~
+ assert_equal 'abcd', $&
+ assert_equal 'xyz', $`
+ assert_equal 'efgabcdefg', $'
+ assert_equal 'c', $+
+
+ /(?!)/ =~ 'xyzabcdefgabcdefg'
+ assert_nil $1
+ assert_nil $2
+ assert_nil $3
+ assert_nil $~
+ assert_nil $&
+ assert_nil $`
+ assert_nil $'
+ assert_nil $+
+ end
+
+ def test_fact
+ assert_equal 306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000, fact(300)
+ end
+
+ def fact(n)
+ if n > 1
+ n * fact(n - 1)
+ else
+ 1
+ end
+ end
+
+ def test_mul
+ assert_equal 0, 2 * 0
+ assert_equal 0, 0 * 2
+ assert_equal 4, 2 * 2
+ end
+
+ class MyNum
+ def /(a)
+ a * 100
+ end
+ end
+
+ def test_div
+ assert_equal 1, 3 / 2
+ assert_equal 1.5, 3.0 / 2.0
+ assert_equal 300, MyNum.new / 3
+ end
+
+ class MyArr
+ def length
+ 'string'
+ end
+ end
+
+ def test_length
+ assert_equal 0, [].length
+ assert_equal 1, [1].length
+ assert_equal 2, [1,2].length
+ assert_equal 0, {}.length
+ assert_equal 1, {1=>1}.length
+ assert_equal 2, {1=>1, 2=>2}.length
+ assert_equal 'string', MyArr.new.length
+ end
+
+ class MyNum2
+ def %(a)
+ a * 100
+ end
+ end
+
+ def test_mod
+ assert_equal 2, 5 % 3
+ assert_equal 1.0, 3.0 % 2.0
+ assert_equal 300, MyNum2.new % 3
+ end
+
+ class MyObj
+ def [](*args)
+ args
+ end
+
+ def []=(*args)
+ args
+ end
+ end
+
+ def test_aref
+ a = [0,1]
+ assert_equal 0, a[0]
+ assert_equal 1, a[1]
+ assert_nil a[2]
+ h = {0=>0, 1=>1}
+ obj = MyObj.new
+ assert_equal 0, h[0]
+ assert_equal 1, h[1]
+ assert_nil h[2]
+ assert_equal [0], obj[0]
+ assert_equal [0,1], obj[0,1]
+ assert_equal [0,1,2], obj[0,1,2]
+ end
+
+ def test_aset
+ obj = MyObj.new
+ assert_equal 7, (obj[0] = 7)
+ assert_equal 7, (obj[0,1] = 7)
+ assert_equal 7, (obj[0,1,2] = 7)
+ end
+
+ class MyObj2
+ def attr=(*args)
+ args
+ end
+ end
+
+ def test_attr_setter
+ obj = MyObj2.new
+ assert_equal 1, (obj.attr = 1)
+ end
+
+ def test_list_expand
+ a = []
+ assert_equal [0], [0, *a]
+ a = [1]
+ assert_equal [0,1], [0, *a]
+ a = [1,2]
+ assert_equal [0,1,2], [0, *a]
+ a = [1,2,3]
+ assert_equal [0,1,2,3], [0, *a]
+ #a = [1,2,3]
+ #assert_equal [0,1,2,3,4], [0, *a, 4]
+ end
+
+ def test_concatarray_ruby_dev_41933
+ bug3658 = '[ruby-dev:41933]'
+ [0, *x=1]
+ assert_equal(1, x, bug3658)
+ [0, *x=1, 2]
+ assert_equal(1, x, bug3658)
+ class << (x = Object.new)
+ attr_accessor :to_a_called
+ def to_a
+ @to_a_called = true
+ [self]
+ end
+ end
+ x.to_a_called = false
+ [0, *x]
+ assert_predicate(x, :to_a_called, bug3658)
+ x.to_a_called = false
+ [0, *x, 2]
+ assert_predicate(x, :to_a_called, bug3658)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_proc.rb b/jni/ruby/test/ruby/test_proc.rb
new file mode 100644
index 0000000..728e2b7
--- /dev/null
+++ b/jni/ruby/test/ruby/test_proc.rb
@@ -0,0 +1,1323 @@
+require 'test/unit'
+
+class TestProc < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_proc
+ p1 = proc{|i| i}
+ assert_equal(2, p1.call(2))
+ assert_equal(3, p1.call(3))
+
+ p1 = proc{|i| i*2}
+ assert_equal(4, p1.call(2))
+ assert_equal(6, p1.call(3))
+
+ p2 = nil
+ x=0
+
+ proc{
+ iii=5 # nested local variable
+ p1 = proc{|i|
+ iii = i
+ }
+ p2 = proc {
+ x = iii # nested variables shared by procs
+ }
+ # scope of nested variables
+ assert(defined?(iii))
+ }.call
+ assert(!defined?(iii)) # out of scope
+
+ loop{iii=iii=5; assert(eval("defined? iii")); break}
+ loop {
+ iii=iii = 10
+ def self.dyna_var_check
+ loop {
+ assert(!defined?(iii))
+ break
+ }
+ end
+ dyna_var_check
+ break
+ }
+ p1.call(5)
+ p2.call
+ assert_equal(5, x)
+ end
+
+ def assert_arity(n)
+ meta = class << self; self; end
+ meta.class_eval {define_method(:foo, Proc.new)}
+ assert_equal(n, method(:foo).arity)
+ end
+
+ def test_arity
+ assert_equal(0, proc{}.arity)
+ assert_equal(0, proc{||}.arity)
+ assert_equal(1, proc{|x|}.arity)
+ assert_equal(0, proc{|x=1|}.arity)
+ assert_equal(2, proc{|x, y|}.arity)
+ assert_equal(1, proc{|x=0, y|}.arity)
+ assert_equal(0, proc{|x=0, y=0|}.arity)
+ assert_equal(1, proc{|x, y=0|}.arity)
+ assert_equal(-2, proc{|x, *y|}.arity)
+ assert_equal(-1, proc{|x=0, *y|}.arity)
+ assert_equal(-1, proc{|*x|}.arity)
+ assert_equal(-1, proc{|*|}.arity)
+ assert_equal(-3, proc{|x, *y, z|}.arity)
+ assert_equal(-2, proc{|x=0, *y, z|}.arity)
+ assert_equal(2, proc{|(x, y), z|[x,y]}.arity)
+ assert_equal(1, proc{|(x, y), z=0|[x,y]}.arity)
+ assert_equal(-4, proc{|x, *y, z, a|}.arity)
+ assert_equal(0, proc{|**|}.arity)
+ assert_equal(0, proc{|**o|}.arity)
+ assert_equal(1, proc{|x, **o|}.arity)
+ assert_equal(0, proc{|x=0, **o|}.arity)
+ assert_equal(1, proc{|x, y=0, **o|}.arity)
+ assert_equal(2, proc{|x, y=0, z, **o|}.arity)
+ assert_equal(-3, proc{|x, y=0, *z, w, **o|}.arity)
+
+ assert_equal(2, proc{|x, y=0, z, a:1|}.arity)
+ assert_equal(3, proc{|x, y=0, z, a:|}.arity)
+ assert_equal(-4, proc{|x, y, *rest, a:, b:, c:|}.arity)
+ assert_equal(3, proc{|x, y=0, z, a:, **o|}.arity)
+
+ assert_equal(0, lambda{}.arity)
+ assert_equal(0, lambda{||}.arity)
+ assert_equal(1, lambda{|x|}.arity)
+ assert_equal(-1, lambda{|x=1|}.arity) # different from proc
+ assert_equal(2, lambda{|x, y|}.arity)
+ assert_equal(-2, lambda{|x=0, y|}.arity) # different from proc
+ assert_equal(-1, lambda{|x=0, y=0|}.arity) # different from proc
+ assert_equal(-2, lambda{|x, y=0|}.arity) # different from proc
+ assert_equal(-2, lambda{|x, *y|}.arity)
+ assert_equal(-1, lambda{|x=0, *y|}.arity)
+ assert_equal(-1, lambda{|*x|}.arity)
+ assert_equal(-1, lambda{|*|}.arity)
+ assert_equal(-3, lambda{|x, *y, z|}.arity)
+ assert_equal(-2, lambda{|x=0, *y, z|}.arity)
+ assert_equal(2, lambda{|(x, y), z|[x,y]}.arity)
+ assert_equal(-2, lambda{|(x, y), z=0|[x,y]}.arity)
+ assert_equal(-4, lambda{|x, *y, z, a|}.arity)
+ assert_equal(-1, lambda{|**|}.arity)
+ assert_equal(-1, lambda{|**o|}.arity)
+ assert_equal(-2, lambda{|x, **o|}.arity)
+ assert_equal(-1, lambda{|x=0, **o|}.arity)
+ assert_equal(-2, lambda{|x, y=0, **o|}.arity)
+ assert_equal(-3, lambda{|x, y=0, z, **o|}.arity)
+ assert_equal(-3, lambda{|x, y=0, *z, w, **o|}.arity)
+
+ assert_arity(0) {}
+ assert_arity(0) {||}
+ assert_arity(1) {|x|}
+ assert_arity(2) {|x, y|}
+ assert_arity(-2) {|x, *y|}
+ assert_arity(-3) {|x, *y, z|}
+ assert_arity(-1) {|*x|}
+ assert_arity(-1) {|*|}
+ assert_arity(-1) {|**o|}
+ assert_arity(-1) {|**|}
+ assert_arity(-2) {|x, *y, **|}
+ assert_arity(-3) {|x, *y, z, **|}
+ end
+
+ def m(x)
+ lambda { x }
+ end
+
+ def test_eq
+ a = m(1)
+ b = m(2)
+ assert_not_equal(a, b, "[ruby-dev:22592]")
+ assert_not_equal(a.call, b.call, "[ruby-dev:22592]")
+
+ assert_not_equal(proc {||}, proc {|x,y|}, "[ruby-dev:22599]")
+
+ a = lambda {|x| lambda {} }.call(1)
+ b = lambda {}
+ assert_not_equal(a, b, "[ruby-dev:22601]")
+ end
+
+ def test_block_par
+ assert_equal(10, Proc.new{|&b| b.call(10)}.call {|x| x})
+ assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x})
+ end
+
+ def test_safe
+ safe = $SAFE
+ c = Class.new
+ x = c.new
+
+ p = proc {
+ $SAFE += 1
+ proc {$SAFE}
+ }.call
+ assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, p.call)
+ assert_equal(safe, $SAFE)
+
+ c.class_eval {define_method(:safe, p)}
+ assert_equal(safe, x.safe)
+ assert_equal(safe, x.method(:safe).call)
+ assert_equal(safe, x.method(:safe).to_proc.call)
+
+ p = proc {$SAFE += 1}
+ assert_equal(safe + 1, p.call)
+ assert_equal(safe, $SAFE)
+
+ c.class_eval {define_method(:inc, p)}
+ assert_equal(safe + 1, proc {x.inc; $SAFE}.call)
+ assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, proc {x.method(:inc).call; $SAFE}.call)
+ assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, proc {x.method(:inc).to_proc.call; $SAFE}.call)
+ assert_equal(safe, $SAFE)
+ end
+
+ def m2
+ "OK"
+ end
+
+ def block
+ method(:m2).to_proc
+ end
+
+ def m1(var)
+ var
+ end
+
+ def m_block_given?
+ m1(block_given?)
+ end
+
+ # [yarv-dev:777] block made by Method#to_proc
+ def test_method_to_proc
+ b = block()
+ assert_equal "OK", b.call
+ b = b.binding
+ assert_instance_of(Binding, b, '[ruby-core:25589]')
+ bug10432 = '[ruby-core:65919] [Bug #10432]'
+ assert_same(self, b.receiver, bug10432)
+ assert_not_send [b, :local_variable_defined?, :value]
+ assert_raise(NameError) {
+ b.local_variable_get(:value)
+ }
+ assert_equal 42, b.local_variable_set(:value, 42)
+ assert_send [b, :local_variable_defined?, :value]
+ assert_equal 42, b.local_variable_get(:value)
+ end
+
+ def test_block_given_method
+ m = method(:m_block_given?)
+ assert(!m.call, "without block")
+ assert(m.call {}, "with block")
+ assert(!m.call, "without block second")
+ end
+
+ def test_block_given_method_to_proc
+ bug8341 = '[Bug #8341]'
+ m = method(:m_block_given?).to_proc
+ assert(!m.call, "#{bug8341} without block")
+ assert(m.call {}, "#{bug8341} with block")
+ assert(!m.call, "#{bug8341} without block second")
+ end
+
+ def test_block_persist_between_calls
+ bug8341 = '[Bug #8341]'
+ o = Object.new
+ def o.m1(top=true)
+ if top
+ [block_given?, @m.call(false)]
+ else
+ block_given?
+ end
+ end
+ m = o.method(:m1).to_proc
+ o.instance_variable_set(:@m, m)
+ assert_equal([true, false], m.call {}, "#{bug8341} nested with block")
+ assert_equal([false, false], m.call, "#{bug8341} nested without block")
+ end
+
+ def test_curry
+ b = proc {|x, y, z| (x||0) + (y||0) + (z||0) }
+ assert_equal(6, b.curry[1][2][3])
+ assert_equal(6, b.curry[1, 2][3, 4])
+ assert_equal(6, b.curry(5)[1][2][3][4][5])
+ assert_equal(6, b.curry(5)[1, 2][3, 4][5])
+ assert_equal(1, b.curry(1)[1])
+
+ b = proc {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) }
+ assert_equal(6, b.curry[1][2][3])
+ assert_equal(10, b.curry[1, 2][3, 4])
+ assert_equal(15, b.curry(5)[1][2][3][4][5])
+ assert_equal(15, b.curry(5)[1, 2][3, 4][5])
+ assert_equal(1, b.curry(1)[1])
+
+ b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) }
+ assert_equal(6, b.curry[1][2][3])
+ assert_raise(ArgumentError) { b.curry[1, 2][3, 4] }
+ assert_raise(ArgumentError) { b.curry(5) }
+ assert_raise(ArgumentError) { b.curry(1) }
+
+ b = lambda {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) }
+ assert_equal(6, b.curry[1][2][3])
+ assert_equal(10, b.curry[1, 2][3, 4])
+ assert_equal(15, b.curry(5)[1][2][3][4][5])
+ assert_equal(15, b.curry(5)[1, 2][3, 4][5])
+ assert_raise(ArgumentError) { b.curry(1) }
+
+ b = proc { :foo }
+ assert_equal(:foo, b.curry[])
+
+ b = lambda {|x, y, &blk| blk.call(x + y) }.curry
+ b = b.call(2) { raise }
+ b = b.call(3) {|x| x + 4 }
+ assert_equal(9, b)
+
+ l = proc {}
+ assert_equal(false, l.lambda?)
+ assert_equal(false, l.curry.lambda?, '[ruby-core:24127]')
+ l = lambda {}
+ assert_equal(true, l.lambda?)
+ assert_equal(true, l.curry.lambda?, '[ruby-core:24127]')
+ end
+
+ def test_curry_ski_fib
+ s = proc {|f, g, x| f[x][g[x]] }.curry
+ k = proc {|x, y| x }.curry
+ i = proc {|x| x }.curry
+
+ fib = []
+ inc = proc {|x| fib[-1] += 1; x }.curry
+ ret = proc {|x| throw :end if fib.size > 10; fib << 0; x }.curry
+
+ catch(:end) do
+ s[
+ s[s[i][i]][k[i]]
+ ][
+ k[inc]
+ ][
+ s[
+ s[
+ k[s]
+ ][
+ s[k[s[k[s]]]
+ ][
+ s[s[k[s]][s[k[s[k[ret]]]][s[k[s[i]]][k]]]][k]]
+ ]
+ ][
+ k[s[k[s]][k]]
+ ]
+ ]
+ end
+
+ assert_equal(fib, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89])
+ end
+
+ def test_curry_from_knownbug
+ a = lambda {|x, y, &b| b }
+ b = a.curry[1]
+
+ assert_equal(:ok,
+ if b.call(2){} == nil
+ :ng
+ else
+ :ok
+ end, 'moved from btest/knownbug, [ruby-core:15551]')
+ end
+
+ def test_curry_instance_exec
+ a = lambda { |x, y| [x + y, self] }
+ b = a.curry.call(1)
+ result = instance_exec 2, &b
+
+ assert_equal(3, result[0])
+ assert_equal(self, result[1])
+ end
+
+ def test_curry_optional_params
+ obj = Object.new
+ def obj.foo(a, b=42); end
+ assert_raise(ArgumentError) { obj.method(:foo).to_proc.curry(3) }
+ assert_raise(ArgumentError) { ->(a, b=42){}.curry(3) }
+ end
+
+ def test_dup_clone
+ b = proc {|x| x + "bar" }
+ class << b; attr_accessor :foo; end
+
+ bd = b.dup
+ assert_equal("foobar", bd.call("foo"))
+ assert_raise(NoMethodError) { bd.foo = :foo }
+ assert_raise(NoMethodError) { bd.foo }
+
+ bc = b.clone
+ assert_equal("foobar", bc.call("foo"))
+ bc.foo = :foo
+ assert_equal(:foo, bc.foo)
+ end
+
+ def test_binding
+ b = proc {|x, y, z| proc {}.binding }.call(1, 2, 3)
+ class << b; attr_accessor :foo; end
+
+ bd = b.dup
+ assert_equal([1, 2, 3], bd.eval("[x, y, z]"))
+ assert_raise(NoMethodError) { bd.foo = :foo }
+ assert_raise(NoMethodError) { bd.foo }
+
+ bc = b.clone
+ assert_equal([1, 2, 3], bc.eval("[x, y, z]"))
+ bc.foo = :foo
+ assert_equal(:foo, bc.foo)
+
+ b = nil
+ 1.times { x, y, z = 1, 2, 3; [x,y,z]; b = binding }
+ assert_equal([1, 2, 3], b.eval("[x, y, z]"))
+ end
+
+ def test_proc_lambda
+ assert_raise(ArgumentError) { proc }
+ assert_raise(ArgumentError) { lambda }
+
+ o = Object.new
+ def o.foo
+ b = nil
+ 1.times { b = lambda }
+ b
+ end
+ assert_equal(:foo, o.foo { :foo }.call)
+
+ def o.foo(&b)
+ b = nil
+ 1.times { b = lambda }
+ b
+ end
+ assert_equal(:foo, o.foo { :foo }.call)
+ end
+
+ def test_arity2
+ assert_equal(0, method(:proc).to_proc.arity)
+ assert_equal(-1, proc {}.curry.arity)
+
+ c = Class.new
+ c.class_eval { attr_accessor :foo }
+ assert_equal(1, c.new.method(:foo=).to_proc.arity)
+ end
+
+ def test_proc_location
+ t = Thread.new { sleep }
+ assert_raise(ThreadError) { t.instance_eval { initialize { } } }
+ t.kill
+ t.join
+ end
+
+ def test_to_proc
+ b = proc { :foo }
+ assert_equal(:foo, b.to_proc.call)
+ end
+
+ def test_localjump_error
+ o = o = Object.new
+ def foo; yield; end
+ exc = foo rescue $!
+ assert_nil(exc.exit_value)
+ assert_equal(:noreason, exc.reason)
+ end
+
+ def test_binding2
+ assert_raise(ArgumentError) { proc {}.curry.binding }
+ end
+
+ def test_proc_args_plain
+ pr = proc {|a,b,c,d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [nil,nil,nil,nil,nil], pr.call()
+ assert_equal [1,nil,nil,nil,nil], pr.call(1)
+ assert_equal [1,2,nil,nil,nil], pr.call(1,2)
+ assert_equal [1,2,3,nil,nil], pr.call(1,2,3)
+ assert_equal [1,2,3,4,nil], pr.call(1,2,3,4)
+ assert_equal [1,2,3,4,5], pr.call(1,2,3,4,5)
+ assert_equal [1,2,3,4,5], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil,nil,nil,nil,nil], pr.call([])
+ assert_equal [1,nil,nil,nil,nil], pr.call([1])
+ assert_equal [1,2,nil,nil,nil], pr.call([1,2])
+ assert_equal [1,2,3,nil,nil], pr.call([1,2,3])
+ assert_equal [1,2,3,4,nil], pr.call([1,2,3,4])
+ assert_equal [1,2,3,4,5], pr.call([1,2,3,4,5])
+ assert_equal [1,2,3,4,5], pr.call([1,2,3,4,5,6])
+
+ r = proc{|a| a}.call([1,2,3])
+ assert_equal [1,2,3], r
+
+ r = proc{|a,| a}.call([1,2,3])
+ assert_equal 1, r
+
+ r = proc{|a,| a}.call([])
+ assert_equal nil, r
+ end
+
+
+ def test_proc_args_rest
+ pr = proc {|a,b,c,*d|
+ [a,b,c,d]
+ }
+ assert_equal [nil,nil,nil,[]], pr.call()
+ assert_equal [1,nil,nil,[]], pr.call(1)
+ assert_equal [1,2,nil,[]], pr.call(1,2)
+ assert_equal [1,2,3,[]], pr.call(1,2,3)
+ assert_equal [1,2,3,[4]], pr.call(1,2,3,4)
+ assert_equal [1,2,3,[4,5]], pr.call(1,2,3,4,5)
+ assert_equal [1,2,3,[4,5,6]], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil,nil,nil,[]], pr.call([])
+ assert_equal [1,nil,nil,[]], pr.call([1])
+ assert_equal [1,2,nil,[]], pr.call([1,2])
+ assert_equal [1,2,3,[]], pr.call([1,2,3])
+ assert_equal [1,2,3,[4]], pr.call([1,2,3,4])
+ assert_equal [1,2,3,[4,5]], pr.call([1,2,3,4,5])
+ assert_equal [1,2,3,[4,5,6]], pr.call([1,2,3,4,5,6])
+
+ r = proc{|*a| a}.call([1,2,3])
+ assert_equal [[1,2,3]], r
+ end
+
+ def test_proc_args_pos_rest_post
+ pr = proc {|a,b,*c,d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [nil, nil, [], nil, nil], pr.call()
+ assert_equal [1, nil, [], nil, nil], pr.call(1)
+ assert_equal [1, 2, [], nil, nil], pr.call(1,2)
+ assert_equal [1, 2, [], 3, nil], pr.call(1,2,3)
+ assert_equal [1, 2, [], 3, 4], pr.call(1,2,3,4)
+ assert_equal [1, 2, [3], 4, 5], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, [3, 4], 5, 6], pr.call(1,2,3,4,5,6)
+ assert_equal [1, 2, [3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7)
+
+ assert_equal [nil, nil, [], nil, nil], pr.call([])
+ assert_equal [1, nil, [], nil, nil], pr.call([1])
+ assert_equal [1, 2, [], nil, nil], pr.call([1,2])
+ assert_equal [1, 2, [], 3, nil], pr.call([1,2,3])
+ assert_equal [1, 2, [], 3, 4], pr.call([1,2,3,4])
+ assert_equal [1, 2, [3], 4, 5], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, [3, 4], 5, 6], pr.call([1,2,3,4,5,6])
+ assert_equal [1, 2, [3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7])
+ end
+
+ def test_proc_args_rest_post
+ pr = proc {|*a,b,c|
+ [a,b,c]
+ }
+ assert_equal [[], nil, nil], pr.call()
+ assert_equal [[], 1, nil], pr.call(1)
+ assert_equal [[], 1, 2], pr.call(1,2)
+ assert_equal [[1], 2, 3], pr.call(1,2,3)
+ assert_equal [[1, 2], 3, 4], pr.call(1,2,3,4)
+ assert_equal [[1, 2, 3], 4, 5], pr.call(1,2,3,4,5)
+ assert_equal [[1, 2, 3, 4], 5, 6], pr.call(1,2,3,4,5,6)
+ assert_equal [[1, 2, 3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7)
+
+ assert_equal [[], nil, nil], pr.call([])
+ assert_equal [[], 1, nil], pr.call([1])
+ assert_equal [[], 1, 2], pr.call([1,2])
+ assert_equal [[1], 2, 3], pr.call([1,2,3])
+ assert_equal [[1, 2], 3, 4], pr.call([1,2,3,4])
+ assert_equal [[1, 2, 3], 4, 5], pr.call([1,2,3,4,5])
+ assert_equal [[1, 2, 3, 4], 5, 6], pr.call([1,2,3,4,5,6])
+ assert_equal [[1, 2, 3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7])
+ end
+
+ def test_proc_args_pos_opt
+ pr = proc {|a,b,c=:c|
+ [a,b,c]
+ }
+ assert_equal [nil, nil, :c], pr.call()
+ assert_equal [1, nil, :c], pr.call(1)
+ assert_equal [1, 2, :c], pr.call(1,2)
+ assert_equal [1, 2, 3], pr.call(1,2,3)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil, nil, :c], pr.call([])
+ assert_equal [1, nil, :c], pr.call([1])
+ assert_equal [1, 2, :c], pr.call([1,2])
+ assert_equal [1, 2, 3], pr.call([1,2,3])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_opt
+ pr = proc {|a=:a,b=:b,c=:c|
+ [a,b,c]
+ }
+ assert_equal [:a, :b, :c], pr.call()
+ assert_equal [1, :b, :c], pr.call(1)
+ assert_equal [1, 2, :c], pr.call(1,2)
+ assert_equal [1, 2, 3], pr.call(1,2,3)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3], pr.call(1,2,3,4,5,6)
+
+ assert_equal [:a, :b, :c], pr.call([])
+ assert_equal [1, :b, :c], pr.call([1])
+ assert_equal [1, 2, :c], pr.call([1,2])
+ assert_equal [1, 2, 3], pr.call([1,2,3])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_opt_signle
+ bug7621 = '[ruby-dev:46801]'
+ pr = proc {|a=:a|
+ a
+ }
+ assert_equal :a, pr.call()
+ assert_equal 1, pr.call(1)
+ assert_equal 1, pr.call(1,2)
+
+ assert_equal [], pr.call([]), bug7621
+ assert_equal [1], pr.call([1]), bug7621
+ assert_equal [1, 2], pr.call([1,2]), bug7621
+ assert_equal [1, 2, 3], pr.call([1,2,3]), bug7621
+ assert_equal [1, 2, 3, 4], pr.call([1,2,3,4]), bug7621
+ end
+
+ def test_proc_args_pos_opt_post
+ pr = proc {|a,b,c=:c,d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [nil, nil, :c, nil, nil], pr.call()
+ assert_equal [1, nil, :c, nil, nil], pr.call(1)
+ assert_equal [1, 2, :c, nil, nil], pr.call(1,2)
+ assert_equal [1, 2, :c, 3, nil], pr.call(1,2,3)
+ assert_equal [1, 2, :c, 3, 4], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil, nil, :c, nil, nil], pr.call([])
+ assert_equal [1, nil, :c, nil, nil], pr.call([1])
+ assert_equal [1, 2, :c, nil, nil], pr.call([1,2])
+ assert_equal [1, 2, :c, 3, nil], pr.call([1,2,3])
+ assert_equal [1, 2, :c, 3, 4], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_opt_post
+ pr = proc {|a=:a,b=:b,c=:c,d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [:a, :b, :c, nil, nil], pr.call()
+ assert_equal [:a, :b, :c, 1, nil], pr.call(1)
+ assert_equal [:a, :b, :c, 1, 2], pr.call(1,2)
+ assert_equal [1, :b, :c, 2, 3], pr.call(1,2,3)
+ assert_equal [1, 2, :c, 3, 4], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, 5], pr.call(1,2,3,4,5,6)
+
+ assert_equal [:a, :b, :c, nil, nil], pr.call([])
+ assert_equal [:a, :b, :c, 1, nil], pr.call([1])
+ assert_equal [:a, :b, :c, 1, 2], pr.call([1,2])
+ assert_equal [1, :b, :c, 2, 3], pr.call([1,2,3])
+ assert_equal [1, 2, :c, 3, 4], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3, 4, 5], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_pos_opt_rest
+ pr = proc {|a,b,c=:c,*d|
+ [a,b,c,d]
+ }
+ assert_equal [nil, nil, :c, []], pr.call()
+ assert_equal [1, nil, :c, []], pr.call(1)
+ assert_equal [1, 2, :c, []], pr.call(1,2)
+ assert_equal [1, 2, 3, []], pr.call(1,2,3)
+ assert_equal [1, 2, 3, [4]], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, [4, 5]], pr.call(1,2,3,4,5)
+
+ assert_equal [nil, nil, :c, []], pr.call([])
+ assert_equal [1, nil, :c, []], pr.call([1])
+ assert_equal [1, 2, :c, []], pr.call([1,2])
+ assert_equal [1, 2, 3, []], pr.call([1,2,3])
+ assert_equal [1, 2, 3, [4]], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, [4, 5]], pr.call([1,2,3,4,5])
+ end
+
+ def test_proc_args_opt_rest
+ pr = proc {|a=:a,b=:b,c=:c,*d|
+ [a,b,c,d]
+ }
+ assert_equal [:a, :b, :c, []], pr.call()
+ assert_equal [1, :b, :c, []], pr.call(1)
+ assert_equal [1, 2, :c, []], pr.call(1,2)
+ assert_equal [1, 2, 3, []], pr.call(1,2,3)
+ assert_equal [1, 2, 3, [4]], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, [4, 5]], pr.call(1,2,3,4,5)
+
+ assert_equal [:a, :b, :c, []], pr.call([])
+ assert_equal [1, :b, :c, []], pr.call([1])
+ assert_equal [1, 2, :c, []], pr.call([1,2])
+ assert_equal [1, 2, 3, []], pr.call([1,2,3])
+ assert_equal [1, 2, 3, [4]], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, [4, 5]], pr.call([1,2,3,4,5])
+ end
+
+ def test_proc_args_pos_opt_rest_post
+ pr = proc {|a,b,c=:c,*d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [nil, nil, :c, [], nil], pr.call()
+ assert_equal [1, nil, :c, [], nil], pr.call(1)
+ assert_equal [1, 2, :c, [], nil], pr.call(1,2)
+ assert_equal [1, 2, :c, [], 3], pr.call(1,2,3)
+ assert_equal [1, 2, 3, [], 4], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, [4], 5], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, [4,5], 6], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil, nil, :c, [], nil], pr.call([])
+ assert_equal [1, nil, :c, [], nil], pr.call([1])
+ assert_equal [1, 2, :c, [], nil], pr.call([1,2])
+ assert_equal [1, 2, :c, [], 3], pr.call([1,2,3])
+ assert_equal [1, 2, 3, [], 4], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, [4], 5], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3, [4,5], 6], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_opt_rest_post
+ pr = proc {|a=:a,b=:b,c=:c,*d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal [:a, :b, :c, [], nil], pr.call()
+ assert_equal [:a, :b, :c, [], 1], pr.call(1)
+ assert_equal [1, :b, :c, [], 2], pr.call(1,2)
+ assert_equal [1, 2, :c, [], 3], pr.call(1,2,3)
+ assert_equal [1, 2, 3, [], 4], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, [4], 5], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, [4,5], 6], pr.call(1,2,3,4,5,6)
+
+ assert_equal [:a, :b, :c, [], nil], pr.call([])
+ assert_equal [:a, :b, :c, [], 1], pr.call([1])
+ assert_equal [1, :b, :c, [], 2], pr.call([1,2])
+ assert_equal [1, 2, :c, [], 3], pr.call([1,2,3])
+ assert_equal [1, 2, 3, [], 4], pr.call([1,2,3,4])
+ assert_equal [1, 2, 3, [4], 5], pr.call([1,2,3,4,5])
+ assert_equal [1, 2, 3, [4,5], 6], pr.call([1,2,3,4,5,6])
+ end
+
+ def test_proc_args_pos_block
+ pr = proc {|a,b,&c|
+ [a, b, c.class, c&&c.call(:x)]
+ }
+ assert_equal [nil, nil, NilClass, nil], pr.call()
+ assert_equal [1, nil, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, NilClass, nil], pr.call(1,2,3,4)
+
+ assert_equal [nil, nil, NilClass, nil], pr.call([])
+ assert_equal [1, nil, NilClass, nil], pr.call([1])
+ assert_equal [1, 2, NilClass, nil], pr.call([1,2])
+ assert_equal [1, 2, NilClass, nil], pr.call([1,2,3])
+ assert_equal [1, 2, NilClass, nil], pr.call([1,2,3,4])
+
+ assert_equal [nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+
+ assert_equal [nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ end
+
+ def test_proc_args_pos_rest_block
+ pr = proc {|a,b,*c,&d|
+ [a, b, c, d.class, d&&d.call(:x)]
+ }
+ assert_equal [nil, nil, [], NilClass, nil], pr.call()
+ assert_equal [1, nil, [], NilClass, nil], pr.call(1)
+ assert_equal [1, 2, [], NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, [3], NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, [3,4], NilClass, nil], pr.call(1,2,3,4)
+
+ assert_equal [nil, nil, [], Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, [], Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, [], Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, [3], Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, [3,4], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+
+ assert_equal [nil, nil, [], Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, [], Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, [], Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, [3], Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, [3,4], Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ end
+
+ def test_proc_args_rest_block
+ pr = proc {|*c,&d|
+ [c, d.class, d&&d.call(:x)]
+ }
+ assert_equal [[], NilClass, nil], pr.call()
+ assert_equal [[1], NilClass, nil], pr.call(1)
+ assert_equal [[1, 2], NilClass, nil], pr.call(1,2)
+
+ assert_equal [[], Proc, :proc], (pr.call(){ :proc })
+ assert_equal [[1], Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [[1, 2], Proc, :proc], (pr.call(1, 2){ :proc })
+
+ assert_equal [[], Proc, :x], (pr.call(){|x| x})
+ assert_equal [[1], Proc, :x], (pr.call(1){|x| x})
+ assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x})
+ end
+
+ def test_proc_args_pos_rest_post_block
+ pr = proc {|a,b,*c,d,e,&f|
+ [a, b, c, d, e, f.class, f&&f.call(:x)]
+ }
+ assert_equal [nil, nil, [], nil, nil, NilClass, nil], pr.call()
+ assert_equal [1, nil, [], nil, nil, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, [], nil, nil, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, [], 3, nil, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, [], 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, [3], 4, 5, NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, [3,4], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil, nil, [], nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, [], nil, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, [], nil, nil, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, [], 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, [3], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, [3,4], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+
+ assert_equal [nil, nil, [], nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, [], nil, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, [], nil, nil, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, [], 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, [3], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, [3,4], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ end
+
+ def test_proc_args_rest_post_block
+ pr = proc {|*c,d,e,&f|
+ [c, d, e, f.class, f&&f.call(:x)]
+ }
+ assert_equal [[], nil, nil, NilClass, nil], pr.call()
+ assert_equal [[], 1, nil, NilClass, nil], pr.call(1)
+ assert_equal [[], 1, 2, NilClass, nil], pr.call(1,2)
+ assert_equal [[1], 2, 3, NilClass, nil], pr.call(1,2,3)
+ assert_equal [[1, 2], 3, 4, NilClass, nil], pr.call(1,2,3,4)
+
+ assert_equal [[], nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [[], 1, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [[], 1, 2, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [[1], 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [[1, 2], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+
+ assert_equal [[], nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [[], 1, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [[], 1, 2, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [[1], 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [[1, 2], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ end
+
+ def test_proc_args_pos_opt_block
+ pr = proc {|a,b,c=:c,d=:d,&e|
+ [a, b, c, d, e.class, e&&e.call(:x)]
+ }
+ assert_equal [nil, nil, :c, :d, NilClass, nil], pr.call()
+ assert_equal [1, nil, :c, :d, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, 3, :d, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4,5)
+
+ assert_equal [nil, nil, :c, :d, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, :c, :d, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, 3, :d, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+
+ assert_equal [nil, nil, :c, :d, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, :c, :d, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, 3, :d, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ end
+
+ def test_proc_args_opt_block
+ pr = proc {|a=:a,b=:b,c=:c,d=:d,&e|
+ [a, b, c, d, e.class, e&&e.call(:x)]
+ }
+ assert_equal [:a, :b, :c, :d, NilClass, nil], pr.call()
+ assert_equal [1, :b, :c, :d, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, 3, :d, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, NilClass, nil], pr.call(1,2,3,4,5)
+
+ assert_equal [:a, :b, :c, :d, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, :b, :c, :d, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, 3, :d, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+
+ assert_equal [:a, :b, :c, :d, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, :b, :c, :d, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, 3, :d, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ end
+
+ def test_proc_args_pos_opt_post_block
+ pr = proc {|a,b,c=:c,d=:d,e,f,&g|
+ [a, b, c, d, e, f, g.class, g&&g.call(:x)]
+ }
+ assert_equal [nil, nil, :c, :d, nil, nil, NilClass, nil], pr.call()
+ assert_equal [1, nil, :c, :d, nil, nil, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, nil, nil, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, :c, :d, 3, nil, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, :c, :d, 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, :d, 4, 5, NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6)
+ assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6,7)
+
+ assert_equal [nil, nil, :c, :d, nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, :c, :d, nil, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, nil, nil, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, :c, :d, 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, :c, :d, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, :d, 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc })
+
+ assert_equal [nil, nil, :c, :d, nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, :c, :d, nil, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, nil, nil, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, :c, :d, 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, :c, :d, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, :d, 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x})
+ end
+
+ def test_proc_args_opt_post_block
+ pr = proc {|a=:a,b=:b,c=:c,d=:d,e,f,&g|
+ [a, b, c, d, e, f, g.class, g&&g.call(:x)]
+ }
+ assert_equal [:a, :b, :c, :d, nil, nil, NilClass, nil], pr.call()
+ assert_equal [:a, :b, :c, :d, 1, nil, NilClass, nil], pr.call(1)
+ assert_equal [:a, :b, :c, :d, 1, 2, NilClass, nil], pr.call(1,2)
+ assert_equal [1, :b, :c, :d, 2, 3, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, :c, :d, 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, :d, 4, 5, NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6)
+ assert_equal [1, 2, 3, 4, 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6,7)
+
+ assert_equal [:a, :b, :c, :d, nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [:a, :b, :c, :d, 1, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [:a, :b, :c, :d, 1, 2, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, :b, :c, :d, 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, :c, :d, 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, :d, 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc })
+
+ assert_equal [:a, :b, :c, :d, nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [:a, :b, :c, :d, 1, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [:a, :b, :c, :d, 1, 2, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, :b, :c, :d, 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, :c, :d, 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, :d, 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ assert_equal [1, 2, 3, 4, 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x})
+ end
+
+ def test_proc_args_pos_opt_rest_block
+ pr = proc {|a,b,c=:c,d=:d,*e,&f|
+ [a, b, c, d, e, f.class, f&&f.call(:x)]
+ }
+ assert_equal [nil, nil, :c, :d, [], NilClass, nil], pr.call()
+ assert_equal [1, nil, :c, :d, [], NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, [], NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, 3, :d, [], NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, 3, 4, [], NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, [5], NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, [5,6], NilClass, nil], pr.call(1,2,3,4,5,6)
+
+ assert_equal [nil, nil, :c, :d, [], Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, :c, :d, [], Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, [], Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, 3, :d, [], Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, 3, 4, [], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, 4, [5], Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, [5,6], Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+
+ assert_equal [nil, nil, :c, :d, [], Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, :c, :d, [], Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, [], Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, 3, :d, [], Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, 3, 4, [], Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, 4, [5], Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, [5,6], Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ end
+
+ def test_proc_args_opt_rest_block
+ pr = proc {|a=:a,b=:b,c=:c,d=:d,*e,&f|
+ [a, b, c, d, e, f.class, f&&f.call(:x)]
+ }
+ assert_equal [:a, :b, :c, :d, [], NilClass, nil], pr.call()
+ assert_equal [1, :b, :c, :d, [], NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, [], NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, 3, :d, [], NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, 3, 4, [], NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, 4, [5], NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, [5,6], NilClass, nil], pr.call(1,2,3,4,5,6)
+
+ assert_equal [:a, :b, :c, :d, [], Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, :b, :c, :d, [], Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, [], Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, 3, :d, [], Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, 3, 4, [], Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, 4, [5], Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, [5,6], Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+
+ assert_equal [:a, :b, :c, :d, [], Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, :b, :c, :d, [], Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, [], Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, 3, :d, [], Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, 3, 4, [], Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, 4, [5], Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, [5,6], Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ end
+
+ def test_proc_args_pos_opt_rest_post_block
+ pr = proc {|a,b,c=:c,d=:d,*e,f,g,&h|
+ [a, b, c, d, e, f, g, h.class, h&&h.call(:x)]
+ }
+ assert_equal [nil, nil, :c, :d, [], nil, nil, NilClass, nil], pr.call()
+ assert_equal [1, nil, :c, :d, [], nil, nil, NilClass, nil], pr.call(1)
+ assert_equal [1, 2, :c, :d, [], nil, nil, NilClass, nil], pr.call(1,2)
+ assert_equal [1, 2, :c, :d, [], 3, nil, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, :c, :d, [], 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, :d, [], 4, 5, NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, [], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6)
+ assert_equal [1, 2, 3, 4, [5], 6, 7, NilClass, nil], pr.call(1,2,3,4,5,6,7)
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, NilClass, nil], pr.call(1,2,3,4,5,6,7,8)
+
+ assert_equal [nil, nil, :c, :d, [], nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, :c, :d, [], nil, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, :c, :d, [], nil, nil, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, :c, :d, [], 3, nil, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+ assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc })
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){ :proc })
+
+ assert_equal [nil, nil, :c, :d, [], nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, :c, :d, [], nil, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, :c, :d, [], nil, nil, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, :c, :d, [], 3, nil, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x})
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){|x| x})
+ end
+
+ def test_proc_args_opt_rest_post_block
+ pr = proc {|a=:a,b=:b,c=:c,d=:d,*e,f,g,&h|
+ [a, b, c, d, e, f, g, h.class, h&&h.call(:x)]
+ }
+ assert_equal [:a, :b, :c, :d, [], nil, nil, NilClass, nil], pr.call()
+ assert_equal [:a, :b, :c, :d, [], 1, nil, NilClass, nil], pr.call(1)
+ assert_equal [:a, :b, :c, :d, [], 1, 2, NilClass, nil], pr.call(1,2)
+ assert_equal [1, :b, :c, :d, [], 2, 3, NilClass, nil], pr.call(1,2,3)
+ assert_equal [1, 2, :c, :d, [], 3, 4, NilClass, nil], pr.call(1,2,3,4)
+ assert_equal [1, 2, 3, :d, [], 4, 5, NilClass, nil], pr.call(1,2,3,4,5)
+ assert_equal [1, 2, 3, 4, [], 5, 6, NilClass, nil], pr.call(1,2,3,4,5,6)
+ assert_equal [1, 2, 3, 4, [5], 6, 7, NilClass, nil], pr.call(1,2,3,4,5,6,7)
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, NilClass, nil], pr.call(1,2,3,4,5,6,7,8)
+
+ assert_equal [:a, :b, :c, :d, [], nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [:a, :b, :c, :d, [], 1, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [:a, :b, :c, :d, [], 1, 2, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, :b, :c, :d, [], 2, 3, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+ assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :proc], (pr.call(1, 2, 3, 4, 5){ :proc })
+ assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6){ :proc })
+ assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7){ :proc })
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :proc], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){ :proc })
+
+ assert_equal [:a, :b, :c, :d, [], nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [:a, :b, :c, :d, [], 1, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [:a, :b, :c, :d, [], 1, 2, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, :b, :c, :d, [], 2, 3, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ assert_equal [1, 2, :c, :d, [], 3, 4, Proc, :x], (pr.call(1, 2, 3, 4){|x| x})
+ assert_equal [1, 2, 3, :d, [], 4, 5, Proc, :x], (pr.call(1, 2, 3, 4, 5){|x| x})
+ assert_equal [1, 2, 3, 4, [], 5, 6, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6){|x| x})
+ assert_equal [1, 2, 3, 4, [5], 6, 7, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7){|x| x})
+ assert_equal [1, 2, 3, 4, [5,6], 7, 8, Proc, :x], (pr.call(1, 2, 3, 4, 5, 6, 7, 8){|x| x})
+ end
+
+ def test_proc_args_pos_unleashed
+ r = proc {|a,b=1,*c,d,e|
+ [a,b,c,d,e]
+ }.call(1,2,3,4,5)
+ assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]")
+ end
+
+ def test_parameters
+ assert_equal([], proc {}.parameters)
+ assert_equal([], proc {||}.parameters)
+ assert_equal([[:opt, :a]], proc {|a|}.parameters)
+ assert_equal([[:opt, :a], [:opt, :b]], proc {|a, b|}.parameters)
+ assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters)
+ assert_equal([[:opt, :a], [:opt, :b]], proc {|a, b=:b|}.parameters)
+ assert_equal([[:rest, :a]], proc {|*a|}.parameters)
+ assert_equal([[:opt, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters)
+ assert_equal([[:opt, :a], [:rest, :b], [:opt, :c]], proc {|a, *b, c|}.parameters)
+ assert_equal([[:opt, :a], [:rest, :b], [:opt, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters)
+ assert_equal([[:opt, :a], [:opt, :b], [:rest, :c], [:opt, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters)
+ assert_equal([[:opt, nil], [:block, :b]], proc {|(a), &b|a}.parameters)
+ assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
+
+ assert_equal([[:req]], method(:putc).parameters)
+ assert_equal([[:rest]], method(:p).parameters)
+ end
+
+ def pm0() end
+ def pm1(a) end
+ def pm2(a, b) end
+ def pmo1(a = :a, &b) end
+ def pmo2(a, b = :b) end
+ def pmo3(*a) end
+ def pmo4(a, *b, &c) end
+ def pmo5(a, *b, c) end
+ def pmo6(a, *b, c, &d) end
+ def pmo7(a, b = :b, *c, d, &e) end
+ def pma1((a), &b) a; end
+ def pmk1(**) end
+ def pmk2(**o) nil && o end
+ def pmk3(a, **o) nil && o end
+ def pmk4(a = nil, **o) nil && o end
+ def pmk5(a, b = nil, **o) nil && o end
+ def pmk6(a, b = nil, c, **o) nil && o end
+ def pmk7(a, b = nil, *c, d, **o) nil && o end
+
+
+ def test_bound_parameters
+ assert_equal([], method(:pm0).to_proc.parameters)
+ assert_equal([[:req, :a]], method(:pm1).to_proc.parameters)
+ assert_equal([[:req, :a], [:req, :b]], method(:pm2).to_proc.parameters)
+ assert_equal([[:opt, :a], [:block, :b]], method(:pmo1).to_proc.parameters)
+ assert_equal([[:req, :a], [:opt, :b]], method(:pmo2).to_proc.parameters)
+ assert_equal([[:rest, :a]], method(:pmo3).to_proc.parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).to_proc.parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).to_proc.parameters)
+ assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).to_proc.parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).to_proc.parameters)
+ assert_equal([[:req], [:block, :b]], method(:pma1).to_proc.parameters)
+ assert_equal([[:keyrest]], method(:pmk1).to_proc.parameters)
+ assert_equal([[:keyrest, :o]], method(:pmk2).to_proc.parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).to_proc.parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).to_proc.parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:pmk5).to_proc.parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:pmk6).to_proc.parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).to_proc.parameters)
+
+ assert_equal([], "".method(:upcase).to_proc.parameters)
+ assert_equal([[:rest]], "".method(:gsub).to_proc.parameters)
+ assert_equal([[:rest]], proc {}.curry.parameters)
+ end
+
+ def test_to_s
+ assert_match(/^#<Proc:0x\h+@#{ Regexp.quote(__FILE__) }:\d+>$/, proc {}.to_s)
+ assert_match(/^#<Proc:0x\h+@#{ Regexp.quote(__FILE__) }:\d+ \(lambda\)>$/, lambda {}.to_s)
+ assert_match(/^#<Proc:0x\h+ \(lambda\)>$/, method(:p).to_proc.to_s)
+ x = proc {}
+ x.taint
+ assert_predicate(x.to_s, :tainted?)
+ end
+
+ @@line_of_source_location_test = __LINE__ + 1
+ def source_location_test a=1,
+ b=2
+ end
+
+ def test_source_location
+ file, lineno = method(:source_location_test).source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427')
+ end
+
+ @@line_of_attr_reader_source_location_test = __LINE__ + 3
+ @@line_of_attr_writer_source_location_test = __LINE__ + 3
+ @@line_of_attr_accessor_source_location_test = __LINE__ + 3
+ attr_reader :attr_reader_source_location_test
+ attr_writer :attr_writer_source_location_test
+ attr_accessor :attr_accessor_source_location_test
+
+ def test_attr_source_location
+ file, lineno = method(:attr_reader_source_location_test).source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(@@line_of_attr_reader_source_location_test, lineno)
+
+ file, lineno = method(:attr_writer_source_location_test=).source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(@@line_of_attr_writer_source_location_test, lineno)
+
+ file, lineno = method(:attr_accessor_source_location_test).source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(@@line_of_attr_accessor_source_location_test, lineno)
+
+ file, lineno = method(:attr_accessor_source_location_test=).source_location
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(@@line_of_attr_accessor_source_location_test, lineno)
+ end
+
+ def block_source_location_test(*args, &block)
+ block.source_location
+ end
+
+ def test_block_source_location
+ exp_lineno = __LINE__ + 3
+ file, lineno = block_source_location_test(1,
+ 2,
+ 3) do
+ end
+ assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
+ assert_equal(exp_lineno, lineno)
+ end
+
+ def test_splat_without_respond_to
+ def (obj = Object.new).respond_to?(m,*); false end
+ [obj].each do |a, b|
+ assert_equal([obj, nil], [a, b], '[ruby-core:24139]')
+ end
+ end
+
+ def test_curry_with_trace
+ # bug3751 = '[ruby-core:31871]'
+ set_trace_func(proc {})
+ test_curry
+ ensure
+ set_trace_func(nil)
+ end
+
+ def test_block_propagation
+ bug3792 = '[ruby-core:32075]'
+ c = Class.new do
+ def foo
+ yield
+ end
+ end
+
+ o = c.new
+ f = :foo.to_proc
+ assert_nothing_raised(LocalJumpError, bug3792) {
+ assert_equal('bar', f.(o) {'bar'}, bug3792)
+ }
+ assert_nothing_raised(LocalJumpError, bug3792) {
+ assert_equal('zot', o.method(:foo).to_proc.() {'zot'}, bug3792)
+ }
+ end
+
+ def test_overridden_lambda
+ bug8345 = '[ruby-core:54687] [Bug #8345]'
+ assert_normal_exit('def lambda; end; method(:puts).to_proc', bug8345)
+ end
+
+ def test_overridden_proc
+ bug8345 = '[ruby-core:54688] [Bug #8345]'
+ assert_normal_exit('def proc; end; ->{}.curry', bug8345)
+ end
+
+ def get_binding if: 1, case: 2, when: 3, begin: 4, end: 5
+ a ||= 0
+ binding
+ end
+
+ def test_local_variables
+ b = get_binding
+ assert_equal(%i'if case when begin end a', b.local_variables)
+ a = tap {|;a, b| break binding.local_variables}
+ assert_equal(%i[a b], a.sort)
+ end
+
+ def test_local_variables_nested
+ b = tap {break binding}
+ assert_equal(%i[b], b.local_variables, '[ruby-dev:48351] [Bug #10001]')
+ end
+
+ def local_variables_of(bind)
+ this_should_not_be_in_bind = 2
+ bind.local_variables
+ end
+
+ def test_local_variables_in_other_context
+ feature8773 = '[Feature #8773]'
+ assert_equal([:feature8773], local_variables_of(binding), feature8773)
+ end
+
+ def test_local_variable_get
+ b = get_binding
+ assert_equal(0, b.local_variable_get(:a))
+ assert_raise(NameError){ b.local_variable_get(:b) }
+
+ # access keyword named local variables
+ assert_equal(1, b.local_variable_get(:if))
+ assert_equal(2, b.local_variable_get(:case))
+ assert_equal(3, b.local_variable_get(:when))
+ assert_equal(4, b.local_variable_get(:begin))
+ assert_equal(5, b.local_variable_get(:end))
+ end
+
+ def test_local_variable_set
+ b = get_binding
+ b.local_variable_set(:a, 10)
+ b.local_variable_set(:b, 20)
+ assert_equal(10, b.local_variable_get(:a))
+ assert_equal(20, b.local_variable_get(:b))
+ assert_equal(10, b.eval("a"))
+ assert_equal(20, b.eval("b"))
+ end
+
+ def test_local_variable_defined?
+ b = get_binding
+ assert_equal(true, b.local_variable_defined?(:a))
+ assert_equal(false, b.local_variable_defined?(:b))
+ end
+
+ def test_binding_receiver
+ feature8779 = '[ruby-dev:47613] [Feature #8779]'
+
+ assert_same(self, binding.receiver, feature8779)
+
+ obj = Object.new
+ def obj.b; binding; end
+ assert_same(obj, obj.b.receiver, feature8779)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_process.rb b/jni/ruby/test/ruby/test_process.rb
new file mode 100644
index 0000000..8847f6b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_process.rb
@@ -0,0 +1,2023 @@
+require 'test/unit'
+require 'tempfile'
+require 'timeout'
+require 'io/wait'
+require 'rbconfig'
+
+class TestProcess < Test::Unit::TestCase
+ RUBY = EnvUtil.rubybin
+
+ def setup
+ Process.waitall
+ end
+
+ def teardown
+ Process.waitall
+ end
+
+ def windows?
+ self.class.windows?
+ end
+ def self.windows?
+ return /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
+ end
+
+ def write_file(filename, content)
+ File.open(filename, "w") {|f|
+ f << content
+ }
+ end
+
+ def with_tmpchdir
+ Dir.mktmpdir {|d|
+ d = File.realpath(d)
+ Dir.chdir(d) {
+ yield d
+ }
+ }
+ end
+
+ def run_in_child(str) # should be called in a temporary directory
+ write_file("test-script", str)
+ Process.wait spawn(RUBY, "test-script")
+ $?
+ end
+
+ def test_rlimit_availability
+ begin
+ Process.getrlimit(nil)
+ rescue NotImplementedError
+ assert_raise(NotImplementedError) { Process.setrlimit }
+ rescue TypeError
+ assert_raise(ArgumentError) { Process.setrlimit }
+ end
+ end
+
+ def rlimit_exist?
+ Process.getrlimit(nil)
+ rescue NotImplementedError
+ return false
+ rescue TypeError
+ return true
+ end
+
+ def test_rlimit_nofile
+ return unless rlimit_exist?
+ with_tmpchdir {
+ write_file 's', <<-"End"
+ # Too small RLIMIT_NOFILE, such as zero, causes problems.
+ # [OpenBSD] Setting to zero freezes this test.
+ # [GNU/Linux] EINVAL on poll(). EINVAL on ruby's internal poll() ruby with "[ASYNC BUG] thread_timer: select".
+ pipes = IO.pipe
+ limit = pipes.map {|io| io.fileno }.min
+ result = 1
+ begin
+ Process.setrlimit(Process::RLIMIT_NOFILE, limit)
+ rescue Errno::EINVAL
+ result = 0
+ end
+ if result == 1
+ begin
+ IO.pipe
+ rescue Errno::EMFILE
+ result = 0
+ end
+ end
+ exit result
+ End
+ pid = spawn RUBY, "s"
+ Process.wait pid
+ assert_equal(0, $?.to_i, "#{$?}")
+ }
+ end
+
+ def test_rlimit_name
+ return unless rlimit_exist?
+ [
+ :AS, "AS",
+ :CORE, "CORE",
+ :CPU, "CPU",
+ :DATA, "DATA",
+ :FSIZE, "FSIZE",
+ :MEMLOCK, "MEMLOCK",
+ :MSGQUEUE, "MSGQUEUE",
+ :NICE, "NICE",
+ :NOFILE, "NOFILE",
+ :NPROC, "NPROC",
+ :RSS, "RSS",
+ :RTPRIO, "RTPRIO",
+ :RTTIME, "RTTIME",
+ :SBSIZE, "SBSIZE",
+ :SIGPENDING, "SIGPENDING",
+ :STACK, "STACK",
+ ].each {|name|
+ if Process.const_defined? "RLIMIT_#{name}"
+ assert_nothing_raised { Process.getrlimit(name) }
+ else
+ assert_raise(ArgumentError) { Process.getrlimit(name) }
+ end
+ }
+ assert_raise(ArgumentError) { Process.getrlimit(:FOO) }
+ assert_raise(ArgumentError) { Process.getrlimit("FOO") }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.getrlimit("\u{30eb 30d3 30fc}") }
+ end
+
+ def test_rlimit_value
+ return unless rlimit_exist?
+ assert_raise(ArgumentError) { Process.setrlimit(:FOO, 0) }
+ assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit("\u{30eb 30d3 30fc}", 0) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit(:CORE, "\u{30eb 30d3 30fc}") }
+ with_tmpchdir do
+ s = run_in_child(<<-'End')
+ cur, max = Process.getrlimit(:NOFILE)
+ Process.setrlimit(:NOFILE, [max-10, cur].min)
+ begin
+ Process.setrlimit(:NOFILE, :INFINITY)
+ rescue Errno::EPERM
+ exit false
+ end
+ End
+ assert_not_predicate(s, :success?)
+ s = run_in_child(<<-'End')
+ cur, max = Process.getrlimit(:NOFILE)
+ Process.setrlimit(:NOFILE, [max-10, cur].min)
+ begin
+ Process.setrlimit(:NOFILE, "INFINITY")
+ rescue Errno::EPERM
+ exit false
+ end
+ End
+ assert_not_predicate(s, :success?)
+ end
+ end
+
+ TRUECOMMAND = [RUBY, '-e', '']
+
+ def test_execopts_opts
+ assert_nothing_raised {
+ Process.wait Process.spawn(*TRUECOMMAND, {})
+ }
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*TRUECOMMAND, :foo => 100)
+ }
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*TRUECOMMAND, Process => 100)
+ }
+ end
+
+ def test_execopts_pgroup
+ skip "system(:pgroup) is not supported" if windows?
+ assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) }
+
+ io = IO.popen([RUBY, "-e", "print Process.getpgrp"])
+ assert_equal(Process.getpgrp.to_s, io.read)
+ io.close
+
+ io = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
+ assert_equal(io.pid.to_s, io.read)
+ io.close
+
+ assert_raise(ArgumentError) { system(*TRUECOMMAND, :pgroup=>-1) }
+ assert_raise(Errno::EPERM) { Process.wait spawn(*TRUECOMMAND, :pgroup=>2) }
+
+ io1 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
+ io2 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>io1.pid])
+ assert_equal(io1.pid.to_s, io1.read)
+ assert_equal(io1.pid.to_s, io2.read)
+ Process.wait io1.pid
+ Process.wait io2.pid
+ io1.close
+ io2.close
+ end
+
+ def test_execopts_rlimit
+ return unless rlimit_exist?
+ assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_foo=>0) }
+ assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_NOFILE=>0) }
+ assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[]) }
+ assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[1,2,3]) }
+
+ max = Process.getrlimit(:CORE).last
+
+ n = max
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
+ assert_equal("[#{n}, #{n}]\n", io.read)
+ }
+
+ n = 0
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
+ assert_equal("[#{n}, #{n}]\n", io.read)
+ }
+
+ n = max
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io|
+ assert_equal("[#{n}, #{n}]", io.read.chomp)
+ }
+
+ m, n = 0, max
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
+ assert_equal("[#{m}, #{n}]", io.read.chomp)
+ }
+
+ m, n = 0, 0
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
+ assert_equal("[#{m}, #{n}]", io.read.chomp)
+ }
+
+ n = max
+ IO.popen([RUBY, "-e",
+ "p Process.getrlimit(:CORE), Process.getrlimit(:CPU)",
+ :rlimit_core=>n, :rlimit_cpu=>3600]) {|io|
+ assert_equal("[#{n}, #{n}]\n[3600, 3600]", io.read.chomp)
+ }
+ end
+
+ MANDATORY_ENVS = %w[RUBYLIB]
+ case RbConfig::CONFIG['target_os']
+ when /linux/
+ MANDATORY_ENVS << 'LD_PRELOAD'
+ when /mswin|mingw/
+ MANDATORY_ENVS.concat(%w[HOME USER TMPDIR])
+ when /darwin/
+ MANDATORY_ENVS.concat(ENV.keys.grep(/\A__CF_/))
+ end
+ if e = RbConfig::CONFIG['LIBPATHENV']
+ MANDATORY_ENVS << e
+ end
+ PREENVARG = ['-e', "%w[#{MANDATORY_ENVS.join(' ')}].each{|e|ENV.delete(e)}"]
+ ENVARG = ['-e', 'ENV.each {|k,v| puts "#{k}=#{v}" }']
+ ENVCOMMAND = [RUBY].concat(PREENVARG).concat(ENVARG)
+
+ def test_execopts_env
+ assert_raise(ArgumentError) {
+ system({"F=O"=>"BAR"}, *TRUECOMMAND)
+ }
+
+ with_tmpchdir {|d|
+ prog = "#{d}/notexist"
+ e = assert_raise(Errno::ENOENT) {
+ Process.wait Process.spawn({"FOO"=>"BAR"}, prog)
+ }
+ assert_equal(prog, e.message.sub(/.* - /, ''))
+ e = assert_raise(Errno::ENOENT) {
+ Process.wait Process.spawn({"FOO"=>"BAR"}, [prog, "blar"])
+ }
+ assert_equal(prog, e.message.sub(/.* - /, ''))
+ }
+ h = {}
+ cmd = [h, RUBY]
+ (ENV.keys + MANDATORY_ENVS).each do |k|
+ case k
+ when /\APATH\z/i
+ when *MANDATORY_ENVS
+ cmd << '-e' << "ENV.delete('#{k}')"
+ else
+ h[k] = nil
+ end
+ end
+ cmd << '-e' << 'puts ENV.keys.map{|e|e.upcase}'
+ IO.popen(cmd) {|io|
+ assert_equal("PATH\n", io.read)
+ }
+
+ IO.popen([{"FOO"=>"BAR"}, *ENVCOMMAND]) {|io|
+ assert_match(/^FOO=BAR$/, io.read)
+ }
+
+ with_tmpchdir {|d|
+ system({"fofo"=>"haha"}, *ENVCOMMAND, STDOUT=>"out")
+ assert_match(/^fofo=haha$/, File.read("out").chomp)
+ }
+
+ old = ENV["hmm"]
+ begin
+ ENV["hmm"] = "fufu"
+ IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=fufu$/, io.read) }
+ IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
+ IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ ENV["hmm"] = ""
+ IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=$/, io.read) }
+ IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
+ IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ ENV["hmm"] = nil
+ IO.popen(ENVCOMMAND) {|io| assert_not_match(/^hmm=/, io.read) }
+ IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
+ IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ ensure
+ ENV["hmm"] = old
+ end
+ end
+
+ def _test_execopts_env_popen(cmd)
+ message = cmd.inspect
+ IO.popen({"FOO"=>"BAR"}, cmd) {|io|
+ assert_equal('FOO=BAR', io.read[/^FOO=.*/], message)
+ }
+
+ old = ENV["hmm"]
+ begin
+ ENV["hmm"] = "fufu"
+ IO.popen(cmd) {|io| assert_match(/^hmm=fufu$/, io.read, message)}
+ IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)}
+ ENV["hmm"] = ""
+ IO.popen(cmd) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)}
+ ENV["hmm"] = nil
+ IO.popen(cmd) {|io| assert_not_match(/^hmm=/, io.read, message)}
+ IO.popen({"hmm"=>""}, cmd) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen({"hmm"=>nil}, cmd) {|io| assert_not_match(/^hmm=/, io.read, message)}
+ ensure
+ ENV["hmm"] = old
+ end
+ end
+
+ def test_execopts_env_popen_vector
+ _test_execopts_env_popen(ENVCOMMAND)
+ end
+
+ def test_execopts_env_popen_string
+ with_tmpchdir do |d|
+ open('test-script', 'w') do |f|
+ ENVCOMMAND.each_with_index do |cmd, i|
+ next if i.zero? or cmd == "-e"
+ f.puts cmd
+ end
+ end
+ _test_execopts_env_popen("#{RUBY} test-script")
+ end
+ end
+
+ def test_execopts_preserve_env_on_exec_failure
+ with_tmpchdir {|d|
+ write_file 's', <<-"End"
+ ENV["mgg"] = nil
+ prog = "./nonexistent"
+ begin
+ Process.exec({"mgg" => "mggoo"}, [prog, prog])
+ rescue Errno::ENOENT
+ end
+ open('out', 'w') {|f|
+ f.print ENV["mgg"].inspect
+ }
+ End
+ system(RUBY, 's')
+ assert_equal(nil.inspect, File.read('out'),
+ "[ruby-core:44093] [ruby-trunk - Bug #6249]")
+ }
+ end
+
+ def test_execopts_env_single_word
+ with_tmpchdir {|d|
+ open("test_execopts_env_single_word.rb", "w") {|f|
+ f.puts "print ENV['hgga']"
+ }
+ system({"hgga"=>"ugu"}, RUBY,
+ :in => 'test_execopts_env_single_word.rb',
+ :out => 'test_execopts_env_single_word.out')
+ assert_equal('ugu', File.read('test_execopts_env_single_word.out'))
+ }
+ end
+
+ def test_execopts_unsetenv_others
+ h = {}
+ MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e}
+ IO.popen([h, *ENVCOMMAND, :unsetenv_others=>true]) {|io|
+ assert_equal("", io.read)
+ }
+ IO.popen([h.merge("A"=>"B"), *ENVCOMMAND, :unsetenv_others=>true]) {|io|
+ assert_equal("A=B\n", io.read)
+ }
+ end
+
+ PWD = [RUBY, '-e', 'puts Dir.pwd']
+
+ def test_execopts_chdir
+ with_tmpchdir {|d|
+ IO.popen([*PWD, :chdir => d]) {|io|
+ assert_equal(d, io.read.chomp)
+ }
+ assert_raise(Errno::ENOENT) {
+ Process.wait Process.spawn(*PWD, :chdir => "d/notexist")
+ }
+ }
+ end
+
+ def test_execopts_open_chdir
+ with_tmpchdir {|d|
+ Dir.mkdir "foo"
+ system(*PWD, :chdir => "foo", :out => "open_chdir_test")
+ assert_file.exist?("open_chdir_test")
+ assert_file.not_exist?("foo/open_chdir_test")
+ assert_equal("#{d}/foo", File.read("open_chdir_test").chomp)
+ }
+ end
+
+ UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask']
+
+ def test_execopts_umask
+ skip "umask is not supported" if windows?
+ IO.popen([*UMASK, :umask => 0]) {|io|
+ assert_equal("0000", io.read.chomp)
+ }
+ IO.popen([*UMASK, :umask => 0777]) {|io|
+ assert_equal("0777", io.read.chomp)
+ }
+ end
+
+ def with_pipe
+ begin
+ r, w = IO.pipe
+ yield r, w
+ ensure
+ r.close unless r.closed?
+ w.close unless w.closed?
+ end
+ end
+
+ def with_pipes(n)
+ ary = []
+ begin
+ n.times {
+ ary << IO.pipe
+ }
+ yield ary
+ ensure
+ ary.each {|r, w|
+ r.close unless r.closed?
+ w.close unless w.closed?
+ }
+ end
+ end
+
+ ECHO = lambda {|arg| [RUBY, '-e', "puts #{arg.dump}; STDOUT.flush"] }
+ SORT = [RUBY, '-e', "puts ARGF.readlines.sort"]
+ CAT = [RUBY, '-e', "IO.copy_stream STDIN, STDOUT"]
+
+ def test_execopts_redirect_fd
+ with_tmpchdir {|d|
+ Process.wait Process.spawn(*ECHO["a"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+ assert_equal("a", File.read("out").chomp)
+ if windows?
+ # currently telling to child the file modes is not supported.
+ open("out", "a") {|f| f.write "0\n"}
+ else
+ Process.wait Process.spawn(*ECHO["0"], STDOUT=>["out", File::WRONLY|File::CREAT|File::APPEND, 0644])
+ assert_equal("a\n0\n", File.read("out"))
+ end
+ Process.wait Process.spawn(*SORT, STDIN=>["out", File::RDONLY, 0644],
+ STDOUT=>["out2", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+ assert_equal("0\na\n", File.read("out2"))
+ Process.wait Process.spawn(*ECHO["b"], [STDOUT, STDERR]=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+ assert_equal("b", File.read("out").chomp)
+ # problem occur with valgrind
+ #Process.wait Process.spawn(*ECHO["a"], STDOUT=>:close, STDERR=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+ #p File.read("out")
+ #assert_not_empty(File.read("out")) # error message such as "-e:1:in `flush': Bad file descriptor (Errno::EBADF)"
+ Process.wait Process.spawn(*ECHO["c"], STDERR=>STDOUT, STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+ assert_equal("c", File.read("out").chomp)
+ File.open("out", "w") {|f|
+ Process.wait Process.spawn(*ECHO["d"], STDOUT=>f)
+ assert_equal("d", File.read("out").chomp)
+ }
+ opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]}
+ opts.merge(3=>STDOUT, 4=>STDOUT, 5=>STDOUT, 6=>STDOUT, 7=>STDOUT) unless windows?
+ Process.wait Process.spawn(*ECHO["e"], opts)
+ assert_equal("e", File.read("out").chomp)
+ opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]}
+ opts.merge(3=>0, 4=>:in, 5=>STDIN, 6=>1, 7=>:out, 8=>STDOUT, 9=>2, 10=>:err, 11=>STDERR) unless windows?
+ Process.wait Process.spawn(*ECHO["ee"], opts)
+ assert_equal("ee", File.read("out").chomp)
+ unless windows?
+ # passing non-stdio fds is not supported on Windows
+ File.open("out", "w") {|f|
+ h = {STDOUT=>f, f=>STDOUT}
+ 3.upto(30) {|i| h[i] = STDOUT if f.fileno != i }
+ Process.wait Process.spawn(*ECHO["f"], h)
+ assert_equal("f", File.read("out").chomp)
+ }
+ end
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*ECHO["f"], 1=>Process)
+ }
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*ECHO["f"], [Process]=>1)
+ }
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*ECHO["f"], [1, STDOUT]=>2)
+ }
+ assert_raise(ArgumentError) {
+ Process.wait Process.spawn(*ECHO["f"], -1=>2)
+ }
+ Process.wait Process.spawn(*ECHO["hhh\nggg\n"], STDOUT=>"out")
+ assert_equal("hhh\nggg\n", File.read("out"))
+ Process.wait Process.spawn(*SORT, STDIN=>"out", STDOUT=>"out2")
+ assert_equal("ggg\nhhh\n", File.read("out2"))
+
+ unless windows?
+ # passing non-stdio fds is not supported on Windows
+ assert_raise(Errno::ENOENT) {
+ Process.wait Process.spawn("non-existing-command", (3..60).to_a=>["err", File::WRONLY|File::CREAT])
+ }
+ assert_equal("", File.read("err"))
+ end
+
+ system(*ECHO["bb\naa\n"], STDOUT=>["out", "w"])
+ assert_equal("bb\naa\n", File.read("out"))
+ system(*SORT, STDIN=>["out"], STDOUT=>"out2")
+ assert_equal("aa\nbb\n", File.read("out2"))
+ }
+ end
+
+ def test_execopts_redirect_pipe
+ with_pipe {|r1, w1|
+ with_pipe {|r2, w2|
+ opts = {STDIN=>r1, STDOUT=>w2}
+ opts.merge(w1=>:close, r2=>:close) unless windows?
+ pid = spawn(*SORT, opts)
+ r1.close
+ w2.close
+ w1.puts "c"
+ w1.puts "a"
+ w1.puts "b"
+ w1.close
+ assert_equal("a\nb\nc\n", r2.read)
+ r2.close
+ Process.wait(pid)
+ }
+ }
+
+ unless windows?
+ # passing non-stdio fds is not supported on Windows
+ with_pipes(5) {|pipes|
+ ios = pipes.flatten
+ h = {}
+ ios.length.times {|i| h[ios[i]] = ios[(i-1)%ios.length] }
+ h2 = h.invert
+ _rios = pipes.map {|r, w| r }
+ wios = pipes.map {|r, w| w }
+ child_wfds = wios.map {|w| h2[w].fileno }
+ pid = spawn(RUBY, "-e",
+ "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h)
+ pipes.each {|r, w|
+ assert_equal("#{h2[w].fileno}\n", r.gets)
+ }
+ Process.wait pid;
+ }
+
+ with_pipes(5) {|pipes|
+ ios = pipes.flatten
+ h = {}
+ ios.length.times {|i| h[ios[i]] = ios[(i+1)%ios.length] }
+ h2 = h.invert
+ _rios = pipes.map {|r, w| r }
+ wios = pipes.map {|r, w| w }
+ child_wfds = wios.map {|w| h2[w].fileno }
+ pid = spawn(RUBY, "-e",
+ "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h)
+ pipes.each {|r, w|
+ assert_equal("#{h2[w].fileno}\n", r.gets)
+ }
+ Process.wait pid
+ }
+
+ closed_fd = nil
+ with_pipes(5) {|pipes|
+ io = pipes.last.last
+ closed_fd = io.fileno
+ }
+ assert_raise(Errno::EBADF) { Process.wait spawn(*TRUECOMMAND, closed_fd=>closed_fd) }
+
+ with_pipe {|r, w|
+ if w.respond_to?(:"close_on_exec=")
+ w.close_on_exec = true
+ pid = spawn(RUBY, "-e", "IO.new(#{w.fileno}, 'w').print 'a'", w=>w)
+ w.close
+ assert_equal("a", r.read)
+ Process.wait pid
+ end
+ }
+ end
+ end
+
+ def test_execopts_redirect_symbol
+ with_tmpchdir {|d|
+ system(*ECHO["funya"], :out=>"out")
+ assert_equal("funya\n", File.read("out"))
+ system(RUBY, '-e', 'STDOUT.reopen(STDERR); puts "henya"', :err=>"out")
+ assert_equal("henya\n", File.read("out"))
+ IO.popen([*CAT, :in=>"out"]) {|io|
+ assert_equal("henya\n", io.read)
+ }
+ }
+ end
+
+ def test_execopts_redirect_nonascii_path
+ bug9946 = '[ruby-core:63185] [Bug #9946]'
+ with_tmpchdir {|d|
+ path = "t-\u{30c6 30b9 30c8 f6}.txt"
+ system(*ECHO["a"], out: path)
+ assert_file.for(bug9946).exist?(path)
+ assert_equal("a\n", File.read(path), bug9946)
+ }
+ end
+
+ def test_execopts_redirect_to_out_and_err
+ with_tmpchdir {|d|
+ ret = system(RUBY, "-e", 'STDERR.print "e"; STDOUT.print "o"', [:out, :err] => "foo")
+ assert_equal(true, ret)
+ assert_equal("eo", File.read("foo"))
+ ret = system(RUBY, "-e", 'STDERR.print "E"; STDOUT.print "O"', [:err, :out] => "bar")
+ assert_equal(true, ret)
+ assert_equal("EO", File.read("bar"))
+ }
+ end
+
+ def test_execopts_redirect_dup2_child
+ with_tmpchdir {|d|
+ Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+ STDOUT=>"out", STDERR=>[:child, STDOUT])
+ assert_equal("errout", File.read("out"))
+
+ Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+ STDERR=>"out", STDOUT=>[:child, STDERR])
+ assert_equal("errout", File.read("out"))
+
+ skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
+ Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+ STDOUT=>"out",
+ STDERR=>[:child, 3],
+ 3=>[:child, 4],
+ 4=>[:child, STDOUT]
+ )
+ assert_equal("errout", File.read("out"))
+
+ IO.popen([RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>[:child, STDOUT]]) {|io|
+ assert_equal("errout", io.read)
+ }
+
+ assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT]) }
+ assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 3]) }
+ assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 5], 5=>[:child, 3]) }
+ assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3]) }
+ }
+ end
+
+ def test_execopts_exec
+ with_tmpchdir {|d|
+ write_file("s", 'exec "echo aaa", STDOUT=>"foo"')
+ pid = spawn RUBY, 's'
+ Process.wait pid
+ assert_equal("aaa\n", File.read("foo"))
+ }
+ end
+
+ def test_execopts_popen
+ with_tmpchdir {|d|
+ IO.popen("#{RUBY} -e 'puts :foo'") {|io| assert_equal("foo\n", io.read) }
+ assert_raise(Errno::ENOENT) { IO.popen(["echo bar"]) {} } # assuming "echo bar" command not exist.
+ IO.popen(ECHO["baz"]) {|io| assert_equal("baz\n", io.read) }
+ assert_raise(ArgumentError) {
+ IO.popen([*ECHO["qux"], STDOUT=>STDOUT]) {|io| }
+ }
+ IO.popen([*ECHO["hoge"], STDERR=>STDOUT]) {|io|
+ assert_equal("hoge\n", io.read)
+ }
+ assert_raise(ArgumentError) {
+ IO.popen([*ECHO["fuga"], STDOUT=>"out"]) {|io| }
+ }
+ skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
+ with_pipe {|r, w|
+ IO.popen([RUBY, '-e', 'IO.new(3, "w").puts("a"); puts "b"', 3=>w]) {|io|
+ assert_equal("b\n", io.read)
+ }
+ w.close
+ assert_equal("a\n", r.read)
+ }
+ IO.popen([RUBY, '-e', "IO.new(9, 'w').puts(:b)",
+ 9=>["out2", File::WRONLY|File::CREAT|File::TRUNC]]) {|io|
+ assert_equal("", io.read)
+ }
+ assert_equal("b\n", File.read("out2"))
+ }
+ end
+
+ def test_popen_fork
+ IO.popen("-") {|io|
+ if !io
+ puts "fooo"
+ else
+ assert_equal("fooo\n", io.read)
+ end
+ }
+ rescue NotImplementedError
+ end
+
+ def test_fd_inheritance
+ skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
+ with_pipe {|r, w|
+ system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s, w=>w)
+ w.close
+ assert_equal("ba\n", r.read)
+ }
+ with_pipe {|r, w|
+ Process.wait spawn(RUBY, '-e',
+ 'IO.new(ARGV[0].to_i, "w").puts("bi") rescue nil',
+ w.fileno.to_s)
+ w.close
+ assert_equal("", r.read)
+ }
+ with_pipe {|r, w|
+ with_tmpchdir {|d|
+ write_file("s", <<-"End")
+ exec(#{RUBY.dump}, '-e',
+ 'IO.new(ARGV[0].to_i, "w").puts("bu") rescue nil',
+ #{w.fileno.to_s.dump}, :close_others=>false)
+ End
+ w.close_on_exec = false
+ Process.wait spawn(RUBY, "s", :close_others=>false)
+ w.close
+ assert_equal("bu\n", r.read)
+ }
+ }
+ with_pipe {|r, w|
+ io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')"])
+ begin
+ w.close
+ errmsg = io.read
+ assert_equal("", r.read)
+ assert_not_equal("", errmsg)
+ ensure
+ io.close
+ end
+ }
+ with_pipe {|r, w|
+ errmsg = `#{RUBY} -e "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts(123)"`
+ w.close
+ assert_equal("", r.read)
+ assert_not_equal("", errmsg)
+ }
+ end
+
+ def test_execopts_close_others
+ skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
+ with_tmpchdir {|d|
+ with_pipe {|r, w|
+ system(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("ma")', w.fileno.to_s, :close_others=>true)
+ w.close
+ assert_equal("", r.read)
+ assert_not_equal("", File.read("err"))
+ File.unlink("err")
+ }
+ with_pipe {|r, w|
+ Process.wait spawn(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mi")', w.fileno.to_s, :close_others=>true)
+ w.close
+ assert_equal("", r.read)
+ assert_not_equal("", File.read("err"))
+ File.unlink("err")
+ }
+ with_pipe {|r, w|
+ w.close_on_exec = false
+ Process.wait spawn(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts("bi")', w.fileno.to_s, :close_others=>false)
+ w.close
+ assert_equal("bi\n", r.read)
+ }
+ with_pipe {|r, w|
+ write_file("s", <<-"End")
+ exec(#{RUBY.dump}, '-e',
+ 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mu")',
+ #{w.fileno.to_s.dump},
+ :close_others=>true)
+ End
+ Process.wait spawn(RUBY, "s", :close_others=>false)
+ w.close
+ assert_equal("", r.read)
+ assert_not_equal("", File.read("err"))
+ File.unlink("err")
+ }
+ with_pipe {|r, w|
+ io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')", :close_others=>true])
+ begin
+ w.close
+ errmsg = io.read
+ assert_equal("", r.read)
+ assert_not_equal("", errmsg)
+ ensure
+ io.close
+ end
+ }
+ with_pipe {|r, w|
+ w.close_on_exec = false
+ io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>false])
+ begin
+ w.close
+ errmsg = io.read
+ assert_equal("mo\n", r.read)
+ assert_equal("", errmsg)
+ ensure
+ io.close
+ end
+ }
+ with_pipe {|r, w|
+ w.close_on_exec = false
+ io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>nil])
+ begin
+ w.close
+ errmsg = io.read
+ assert_equal("mo\n", r.read)
+ assert_equal("", errmsg)
+ ensure
+ io.close
+ end
+ }
+
+ }
+ end
+
+ def test_execopts_redirect_self
+ begin
+ with_pipe {|r, w|
+ w << "haha\n"
+ w.close
+ r.close_on_exec = true
+ IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}, 'r').read", r.fileno=>r.fileno, :close_others=>false]) {|io|
+ assert_equal("haha\n", io.read)
+ }
+ }
+ rescue NotImplementedError
+ skip "IO#close_on_exec= is not supported"
+ end
+ end
+
+ def test_execopts_redirect_tempfile
+ bug6269 = '[ruby-core:44181]'
+ Tempfile.create("execopts") do |tmp|
+ pid = assert_nothing_raised(ArgumentError, bug6269) do
+ break spawn(RUBY, "-e", "print $$", out: tmp)
+ end
+ Process.wait(pid)
+ tmp.rewind
+ assert_equal(pid.to_s, tmp.read)
+ end
+ end
+
+ def test_execopts_duplex_io
+ IO.popen("#{RUBY} -e ''", "r+") {|duplex|
+ assert_raise(ArgumentError) { system("#{RUBY} -e ''", duplex=>STDOUT) }
+ assert_raise(ArgumentError) { system("#{RUBY} -e ''", STDOUT=>duplex) }
+ }
+ end
+
+ def test_execopts_modification
+ h = {}
+ Process.wait spawn(*TRUECOMMAND, h)
+ assert_equal({}, h)
+
+ h = {}
+ system(*TRUECOMMAND, h)
+ assert_equal({}, h)
+
+ h = {}
+ io = IO.popen([*TRUECOMMAND, h])
+ io.close
+ assert_equal({}, h)
+ end
+
+ def test_system_noshell
+ str = "echo non existing command name which contains spaces"
+ assert_nil(system([str, str]))
+ end
+
+ def test_spawn_noshell
+ str = "echo non existing command name which contains spaces"
+ assert_raise(Errno::ENOENT) { spawn([str, str]) }
+ end
+
+ def test_popen_noshell
+ str = "echo non existing command name which contains spaces"
+ assert_raise(Errno::ENOENT) { IO.popen([str, str]) }
+ end
+
+ def test_exec_noshell
+ with_tmpchdir {|d|
+ write_file("s", <<-"End")
+ str = "echo non existing command name which contains spaces"
+ STDERR.reopen(STDOUT)
+ begin
+ exec [str, str]
+ rescue Errno::ENOENT
+ print "Errno::ENOENT success"
+ end
+ End
+ r = IO.popen([RUBY, "s", :close_others=>false], "r") {|f| f.read}
+ assert_equal("Errno::ENOENT success", r)
+ }
+ end
+
+ def test_system_wordsplit
+ with_tmpchdir {|d|
+ write_file("script", <<-'End')
+ File.open("result", "w") {|t| t << "haha pid=#{$$} ppid=#{Process.ppid}" }
+ exit 5
+ End
+ str = "#{RUBY} script"
+ ret = system(str)
+ status = $?
+ assert_equal(false, ret)
+ assert_predicate(status, :exited?)
+ assert_equal(5, status.exitstatus)
+ assert_equal("haha pid=#{status.pid} ppid=#{$$}", File.read("result"))
+ }
+ end
+
+ def test_spawn_wordsplit
+ with_tmpchdir {|d|
+ write_file("script", <<-'End')
+ File.open("result", "w") {|t| t << "hihi pid=#{$$} ppid=#{Process.ppid}" }
+ exit 6
+ End
+ str = "#{RUBY} script"
+ pid = spawn(str)
+ Process.wait pid
+ status = $?
+ assert_equal(pid, status.pid)
+ assert_predicate(status, :exited?)
+ assert_equal(6, status.exitstatus)
+ assert_equal("hihi pid=#{status.pid} ppid=#{$$}", File.read("result"))
+ }
+ end
+
+ def test_popen_wordsplit
+ with_tmpchdir {|d|
+ write_file("script", <<-'End')
+ print "fufu pid=#{$$} ppid=#{Process.ppid}"
+ exit 7
+ End
+ str = "#{RUBY} script"
+ io = IO.popen(str)
+ pid = io.pid
+ result = io.read
+ io.close
+ status = $?
+ assert_equal(pid, status.pid)
+ assert_predicate(status, :exited?)
+ assert_equal(7, status.exitstatus)
+ assert_equal("fufu pid=#{status.pid} ppid=#{$$}", result)
+ }
+ end
+
+ def test_popen_wordsplit_beginning_and_trailing_spaces
+ with_tmpchdir {|d|
+ write_file("script", <<-'End')
+ print "fufumm pid=#{$$} ppid=#{Process.ppid}"
+ exit 7
+ End
+ str = " #{RUBY} script "
+ io = IO.popen(str)
+ pid = io.pid
+ result = io.read
+ io.close
+ status = $?
+ assert_equal(pid, status.pid)
+ assert_predicate(status, :exited?)
+ assert_equal(7, status.exitstatus)
+ assert_equal("fufumm pid=#{status.pid} ppid=#{$$}", result)
+ }
+ end
+
+ def test_exec_wordsplit
+ with_tmpchdir {|d|
+ write_file("script", <<-'End')
+ File.open("result", "w") {|t|
+ if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ t << "hehe ppid=#{Process.ppid}"
+ else
+ t << "hehe pid=#{$$} ppid=#{Process.ppid}"
+ end
+ }
+ exit 6
+ End
+ write_file("s", <<-"End")
+ ruby = #{RUBY.dump}
+ exec "\#{ruby} script"
+ End
+ pid = spawn(RUBY, "s")
+ Process.wait pid
+ status = $?
+ assert_equal(pid, status.pid)
+ assert_predicate(status, :exited?)
+ assert_equal(6, status.exitstatus)
+ if windows?
+ expected = "hehe ppid=#{status.pid}"
+ else
+ expected = "hehe pid=#{status.pid} ppid=#{$$}"
+ end
+ assert_equal(expected, File.read("result"))
+ }
+ end
+
+ def test_system_shell
+ with_tmpchdir {|d|
+ write_file("script1", <<-'End')
+ File.open("result1", "w") {|t| t << "taka pid=#{$$} ppid=#{Process.ppid}" }
+ exit 7
+ End
+ write_file("script2", <<-'End')
+ File.open("result2", "w") {|t| t << "taki pid=#{$$} ppid=#{Process.ppid}" }
+ exit 8
+ End
+ ret = system("#{RUBY} script1 || #{RUBY} script2")
+ status = $?
+ assert_equal(false, ret)
+ assert_predicate(status, :exited?)
+ result1 = File.read("result1")
+ result2 = File.read("result2")
+ assert_match(/\Ataka pid=\d+ ppid=\d+\z/, result1)
+ assert_match(/\Ataki pid=\d+ ppid=\d+\z/, result2)
+ assert_not_equal(result1[/\d+/].to_i, status.pid)
+
+ if windows?
+ Dir.mkdir(path = "path with space")
+ write_file(bat = path + "/bat test.bat", "@echo %1>out")
+ system(bat, "foo 'bar'")
+ assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
+ system(%[#{bat.dump} "foo 'bar'"])
+ assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
+ end
+ }
+ end
+
+ def test_spawn_shell
+ with_tmpchdir {|d|
+ write_file("script1", <<-'End')
+ File.open("result1", "w") {|t| t << "taku pid=#{$$} ppid=#{Process.ppid}" }
+ exit 7
+ End
+ write_file("script2", <<-'End')
+ File.open("result2", "w") {|t| t << "take pid=#{$$} ppid=#{Process.ppid}" }
+ exit 8
+ End
+ pid = spawn("#{RUBY} script1 || #{RUBY} script2")
+ Process.wait pid
+ status = $?
+ assert_predicate(status, :exited?)
+ assert_not_predicate(status, :success?)
+ result1 = File.read("result1")
+ result2 = File.read("result2")
+ assert_match(/\Ataku pid=\d+ ppid=\d+\z/, result1)
+ assert_match(/\Atake pid=\d+ ppid=\d+\z/, result2)
+ assert_not_equal(result1[/\d+/].to_i, status.pid)
+
+ if windows?
+ Dir.mkdir(path = "path with space")
+ write_file(bat = path + "/bat test.bat", "@echo %1>out")
+ pid = spawn(bat, "foo 'bar'")
+ Process.wait pid
+ status = $?
+ assert_predicate(status, :exited?)
+ assert_predicate(status, :success?)
+ assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
+ pid = spawn(%[#{bat.dump} "foo 'bar'"])
+ Process.wait pid
+ status = $?
+ assert_predicate(status, :exited?)
+ assert_predicate(status, :success?)
+ assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
+ end
+ }
+ end
+
+ def test_popen_shell
+ with_tmpchdir {|d|
+ write_file("script1", <<-'End')
+ puts "tako pid=#{$$} ppid=#{Process.ppid}"
+ exit 7
+ End
+ write_file("script2", <<-'End')
+ puts "tika pid=#{$$} ppid=#{Process.ppid}"
+ exit 8
+ End
+ io = IO.popen("#{RUBY} script1 || #{RUBY} script2")
+ result = io.read
+ io.close
+ status = $?
+ assert_predicate(status, :exited?)
+ assert_not_predicate(status, :success?)
+ assert_match(/\Atako pid=\d+ ppid=\d+\ntika pid=\d+ ppid=\d+\n\z/, result)
+ assert_not_equal(result[/\d+/].to_i, status.pid)
+
+ if windows?
+ Dir.mkdir(path = "path with space")
+ write_file(bat = path + "/bat test.bat", "@echo %1")
+ r = IO.popen([bat, "foo 'bar'"]) {|f| f.read}
+ assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]')
+ r = IO.popen(%[#{bat.dump} "foo 'bar'"]) {|f| f.read}
+ assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]')
+ end
+ }
+ end
+
+ def test_exec_shell
+ with_tmpchdir {|d|
+ write_file("script1", <<-'End')
+ File.open("result1", "w") {|t| t << "tiki pid=#{$$} ppid=#{Process.ppid}" }
+ exit 7
+ End
+ write_file("script2", <<-'End')
+ File.open("result2", "w") {|t| t << "tiku pid=#{$$} ppid=#{Process.ppid}" }
+ exit 8
+ End
+ write_file("s", <<-"End")
+ ruby = #{RUBY.dump}
+ exec("\#{ruby} script1 || \#{ruby} script2")
+ End
+ pid = spawn RUBY, "s"
+ Process.wait pid
+ status = $?
+ assert_predicate(status, :exited?)
+ assert_not_predicate(status, :success?)
+ result1 = File.read("result1")
+ result2 = File.read("result2")
+ assert_match(/\Atiki pid=\d+ ppid=\d+\z/, result1)
+ assert_match(/\Atiku pid=\d+ ppid=\d+\z/, result2)
+ assert_not_equal(result1[/\d+/].to_i, status.pid)
+ }
+ end
+
+ def test_argv0
+ with_tmpchdir {|d|
+ assert_equal(false, system([RUBY, "asdfg"], "-e", "exit false"))
+ assert_equal(true, system([RUBY, "zxcvb"], "-e", "exit true"))
+
+ Process.wait spawn([RUBY, "poiu"], "-e", "exit 4")
+ assert_equal(4, $?.exitstatus)
+
+ assert_equal("1", IO.popen([[RUBY, "qwerty"], "-e", "print 1"]) {|f| f.read })
+
+ write_file("s", <<-"End")
+ exec([#{RUBY.dump}, "lkjh"], "-e", "exit 5")
+ End
+ pid = spawn RUBY, "s"
+ Process.wait pid
+ assert_equal(5, $?.exitstatus)
+ }
+ end
+
+ def with_stdin(filename)
+ open(filename) {|f|
+ begin
+ old = STDIN.dup
+ begin
+ STDIN.reopen(filename)
+ yield
+ ensure
+ STDIN.reopen(old)
+ end
+ ensure
+ old.close
+ end
+ }
+ end
+
+ def test_argv0_noarg
+ with_tmpchdir {|d|
+ open("t", "w") {|f| f.print "exit true" }
+ open("f", "w") {|f| f.print "exit false" }
+
+ with_stdin("t") { assert_equal(true, system([RUBY, "qaz"])) }
+ with_stdin("f") { assert_equal(false, system([RUBY, "wsx"])) }
+
+ with_stdin("t") { Process.wait spawn([RUBY, "edc"]) }
+ assert_predicate($?, :success?)
+ with_stdin("f") { Process.wait spawn([RUBY, "rfv"]) }
+ assert_not_predicate($?, :success?)
+
+ with_stdin("t") { IO.popen([[RUBY, "tgb"]]) {|io| assert_equal("", io.read) } }
+ assert_predicate($?, :success?)
+ with_stdin("f") { IO.popen([[RUBY, "yhn"]]) {|io| assert_equal("", io.read) } }
+ assert_not_predicate($?, :success?)
+
+ status = run_in_child "STDIN.reopen('t'); exec([#{RUBY.dump}, 'ujm'])"
+ assert_predicate(status, :success?)
+ status = run_in_child "STDIN.reopen('f'); exec([#{RUBY.dump}, 'ik,'])"
+ assert_not_predicate(status, :success?)
+ }
+ end
+
+ def test_status
+ with_tmpchdir do
+ s = run_in_child("exit 1")
+ assert_equal("#<Process::Status: pid #{ s.pid } exit #{ s.exitstatus }>", s.inspect)
+
+ assert_equal(s, s)
+ assert_equal(s, s.to_i)
+
+ assert_equal(s.to_i & 0x55555555, s & 0x55555555)
+ assert_equal(s.to_i >> 1, s >> 1)
+ assert_equal(false, s.stopped?)
+ assert_equal(nil, s.stopsig)
+ end
+ end
+
+ def test_status_kill
+ return unless Process.respond_to?(:kill)
+ return unless Signal.list.include?("KILL")
+
+ # assume the system supports signal if SIGQUIT is available
+ expected = Signal.list.include?("QUIT") ? [false, true, false, nil] : [true, false, false, true]
+
+ with_tmpchdir do
+ write_file("foo", "Process.kill(:KILL, $$); exit(42)")
+ system(RUBY, "foo")
+ s = $?
+ assert_equal(expected,
+ [s.exited?, s.signaled?, s.stopped?, s.success?],
+ "[s.exited?, s.signaled?, s.stopped?, s.success?]")
+ end
+ end
+
+ def test_status_quit
+ return unless Process.respond_to?(:kill)
+ return unless Signal.list.include?("QUIT")
+
+ with_tmpchdir do
+ write_file("foo", "puts;STDOUT.flush;sleep 30")
+ pid = nil
+ IO.pipe do |r, w|
+ pid = spawn(RUBY, "foo", out: w)
+ w.close
+ th = Thread.new { r.read(1); Process.kill(:SIGQUIT, pid) }
+ Process.wait(pid)
+ th.join
+ end
+ t = Time.now
+ s = $?
+ assert_equal([false, true, false, nil],
+ [s.exited?, s.signaled?, s.stopped?, s.success?],
+ "[s.exited?, s.signaled?, s.stopped?, s.success?]")
+ assert_send(
+ [["#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig })>",
+ "#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig }) (core dumped)>"],
+ :include?,
+ s.inspect])
+ EnvUtil.diagnostic_reports("QUIT", RUBY, pid, t)
+ end
+ end
+
+ def test_wait_without_arg
+ with_tmpchdir do
+ write_file("foo", "sleep 0.1")
+ pid = spawn(RUBY, "foo")
+ assert_equal(pid, Process.wait)
+ end
+ end
+
+ def test_wait2
+ with_tmpchdir do
+ write_file("foo", "sleep 0.1")
+ pid = spawn(RUBY, "foo")
+ assert_equal([pid, 0], Process.wait2)
+ end
+ end
+
+ def test_waitall
+ with_tmpchdir do
+ write_file("foo", "sleep 0.1")
+ ps = (0...3).map { spawn(RUBY, "foo") }.sort
+ ss = Process.waitall.sort
+ ps.zip(ss) do |p1, (p2, s)|
+ assert_equal(p1, p2)
+ assert_equal(p1, s.pid)
+ end
+ end
+ end
+
+ def test_wait_exception
+ bug11340 = '[ruby-dev:49176] [Bug #11340]'
+ t0 = t1 = nil
+ IO.popen([RUBY, '-e', 'puts;STDOUT.flush;Thread.start{gets;exit};sleep(3)'], 'r+') do |f|
+ pid = f.pid
+ f.gets
+ t0 = Time.now
+ th = Thread.start(Thread.current) do |main|
+ Thread.pass until main.stop?
+ main.raise Interrupt
+ end
+ begin
+ assert_raise(Interrupt) {Process.wait(pid)}
+ ensure
+ th.kill.join
+ end
+ t1 = Time.now
+ f.puts
+ end
+ assert_operator(t1 - t0, :<, 3,
+ ->{"#{bug11340}: #{t1-t0} seconds to interrupt Process.wait"})
+ end
+
+ def test_abort
+ with_tmpchdir do
+ s = run_in_child("abort")
+ assert_not_equal(0, s.exitstatus)
+ end
+ end
+
+ def test_sleep
+ assert_raise(ArgumentError) { sleep(1, 1) }
+ end
+
+ def test_getpgid
+ assert_kind_of(Integer, Process.getpgid(Process.ppid))
+ rescue NotImplementedError
+ end
+
+ def test_getpriority
+ assert_kind_of(Integer, Process.getpriority(Process::PRIO_PROCESS, $$))
+ rescue NameError, NotImplementedError
+ end
+
+ def test_setpriority
+ if defined? Process::PRIO_USER
+ assert_nothing_raised do
+ pr = Process.getpriority(Process::PRIO_PROCESS, $$)
+ Process.setpriority(Process::PRIO_PROCESS, $$, pr)
+ end
+ end
+ end
+
+ def test_getuid
+ assert_kind_of(Integer, Process.uid)
+ end
+
+ def test_groups
+ gs = Process.groups
+ assert_instance_of(Array, gs)
+ gs.each {|g| assert_kind_of(Integer, g) }
+ rescue NotImplementedError
+ end
+
+ def test_maxgroups
+ assert_kind_of(Integer, Process.maxgroups)
+ rescue NotImplementedError
+ end
+
+ def test_geteuid
+ assert_kind_of(Integer, Process.euid)
+ end
+
+ def test_seteuid
+ assert_nothing_raised(TypeError) {Process.euid += 0}
+ rescue NotImplementedError
+ end
+
+ def test_seteuid_name
+ user = ENV["USER"] or return
+ assert_nothing_raised(TypeError) {Process.euid = user}
+ rescue NotImplementedError
+ end
+
+ def test_getegid
+ assert_kind_of(Integer, Process.egid)
+ end
+
+ def test_setegid
+ assert_nothing_raised(TypeError) {Process.egid += 0}
+ rescue NotImplementedError
+ end
+
+ def test_uid_re_exchangeable_p
+ r = Process::UID.re_exchangeable?
+ assert_include([true, false], r)
+ end
+
+ def test_gid_re_exchangeable_p
+ r = Process::GID.re_exchangeable?
+ assert_include([true, false], r)
+ end
+
+ def test_uid_sid_available?
+ r = Process::UID.sid_available?
+ assert_include([true, false], r)
+ end
+
+ def test_gid_sid_available?
+ r = Process::GID.sid_available?
+ assert_include([true, false], r)
+ end
+
+ def test_pst_inspect
+ assert_nothing_raised { Process::Status.allocate.inspect }
+ end
+
+ def test_wait_and_sigchild
+ if /freebsd|openbsd/ =~ RUBY_PLATFORM
+ # this relates #4173
+ # When ruby can use 2 cores, signal and wait4 may miss the signal.
+ skip "this fails on FreeBSD and OpenBSD on multithreaded environment"
+ end
+ signal_received = []
+ Signal.trap(:CHLD) { signal_received << true }
+ pid = nil
+ IO.pipe do |r, w|
+ pid = fork { r.read(1); exit }
+ Thread.start { raise }
+ w.puts
+ end
+ Process.wait pid
+ 10.times do
+ break unless signal_received.empty?
+ sleep 0.01
+ end
+ assert_equal [true], signal_received, " [ruby-core:19744]"
+ rescue NotImplementedError, ArgumentError
+ ensure
+ begin
+ Signal.trap(:CHLD, 'DEFAULT')
+ rescue ArgumentError
+ end
+ end
+
+ def test_no_curdir
+ with_tmpchdir {|d|
+ Dir.mkdir("vd")
+ status = nil
+ Dir.chdir("vd") {
+ dir = "#{d}/vd"
+ # OpenSolaris cannot remove the current directory.
+ system(RUBY, "--disable-gems", "-e", "Dir.chdir '..'; Dir.rmdir #{dir.dump}", err: File::NULL)
+ system({"RUBYLIB"=>nil}, RUBY, "--disable-gems", "-e", "exit true")
+ status = $?
+ }
+ assert_predicate(status, :success?, "[ruby-dev:38105]")
+ }
+ end
+
+ def test_fallback_to_sh
+ feature = '[ruby-core:32745]'
+ with_tmpchdir do |d|
+ open("tmp_script.#{$$}", "w") {|f| f.puts ": ;"; f.chmod(0755)}
+ assert_not_nil(pid = Process.spawn("./tmp_script.#{$$}"), feature)
+ wpid, st = Process.waitpid2(pid)
+ assert_equal([pid, true], [wpid, st.success?], feature)
+
+ open("tmp_script.#{$$}", "w") {|f| f.puts "echo $#: $@"; f.chmod(0755)}
+ result = IO.popen(["./tmp_script.#{$$}", "a b", "c"]) {|f| f.read}
+ assert_equal("2: a b c\n", result, feature)
+
+ open("tmp_script.#{$$}", "w") {|f| f.puts "echo $hghg"; f.chmod(0755)}
+ result = IO.popen([{"hghg" => "mogomogo"}, "./tmp_script.#{$$}", "a b", "c"]) {|f| f.read}
+ assert_equal("mogomogo\n", result, feature)
+
+ end
+ end if File.executable?("/bin/sh")
+
+ def test_spawn_too_long_path
+ bug4314 = '[ruby-core:34842]'
+ assert_fail_too_long_path(%w"echo", bug4314)
+ end
+
+ def test_aspawn_too_long_path
+ bug4315 = '[ruby-core:34833]'
+ assert_fail_too_long_path(%w"echo |", bug4315)
+ end
+
+ def assert_fail_too_long_path((cmd, sep), mesg)
+ sep ||= ""
+ min = 1_000 / (cmd.size + sep.size)
+ cmds = Array.new(min, cmd)
+ exs = [Errno::ENOENT]
+ exs << Errno::E2BIG if defined?(Errno::E2BIG)
+ EnvUtil.suppress_warning do
+ assert_raise(*exs, mesg) do
+ begin
+ loop do
+ Process.spawn(cmds.join(sep), [STDOUT, STDERR]=>File::NULL)
+ min = [cmds.size, min].max
+ cmds *= 100
+ end
+ rescue NoMemoryError
+ size = cmds.size
+ raise if min >= size - 1
+ min = [min, size /= 2].max
+ cmds[size..-1] = []
+ raise if size < 250
+ retry
+ end
+ end
+ end
+ end
+
+ def test_system_sigpipe
+ return if windows?
+
+ pid = 0
+
+ with_tmpchdir do
+ assert_nothing_raised('[ruby-dev:12261]') do
+ timeout(3) do
+ pid = spawn('yes | ls')
+ Process.waitpid pid
+ end
+ end
+ end
+ ensure
+ Process.kill(:KILL, pid) if (pid != 0) rescue false
+ end
+
+ if Process.respond_to?(:daemon)
+ def test_daemon_default
+ data = IO.popen("-", "r+") do |f|
+ break f.read if f
+ Process.daemon
+ puts "ng"
+ end
+ assert_equal("", data)
+ end
+
+ def test_daemon_noclose
+ data = IO.popen("-", "r+") do |f|
+ break f.read if f
+ Process.daemon(false, true)
+ puts "ok", Dir.pwd
+ end
+ assert_equal("ok\n/\n", data)
+ end
+
+ def test_daemon_nochdir_noclose
+ data = IO.popen("-", "r+") do |f|
+ break f.read if f
+ Process.daemon(true, true)
+ puts "ok", Dir.pwd
+ end
+ assert_equal("ok\n#{Dir.pwd}\n", data)
+ end
+
+ def test_daemon_readwrite
+ data = IO.popen("-", "r+") do |f|
+ if f
+ f.puts "ok?"
+ break f.read
+ end
+ Process.daemon(true, true)
+ puts STDIN.gets
+ end
+ assert_equal("ok?\n", data)
+ end
+
+ def test_daemon_pid
+ cpid, dpid = IO.popen("-", "r+") do |f|
+ break f.pid, Integer(f.read) if f
+ Process.daemon(false, true)
+ puts $$
+ end
+ assert_not_equal(cpid, dpid)
+ end
+
+ if File.directory?("/proc/self/task") && /netbsd[a-z]*[1-6]/ !~ RUBY_PLATFORM
+ def test_daemon_no_threads
+ pid, data = IO.popen("-", "r+") do |f|
+ break f.pid, f.readlines if f
+ Process.daemon(true, true)
+ puts Dir.entries("/proc/self/task") - %W[. ..]
+ end
+ bug4920 = '[ruby-dev:43873]'
+ assert_equal(2, data.size, bug4920)
+ assert_not_include(data.map(&:to_i), pid)
+ end
+ else # darwin
+ def test_daemon_no_threads
+ data = Timeout.timeout(3) do
+ IO.popen("-") do |f|
+ break f.readlines.map(&:chomp) if f
+ th = Thread.start {sleep 3}
+ Process.daemon(true, true)
+ puts Thread.list.size, th.status.inspect
+ end
+ end
+ assert_equal(["1", "false"], data)
+ end
+ end
+ end
+
+ def test_popen_cloexec
+ return unless defined? Fcntl::FD_CLOEXEC
+ IO.popen([RUBY, "-e", ""]) {|io|
+ assert_predicate(io, :close_on_exec?)
+ }
+ end
+
+ def test_execopts_new_pgroup
+ return unless windows?
+
+ assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>true) }
+ assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>false) }
+ assert_nothing_raised { spawn(*TRUECOMMAND, :new_pgroup=>true) }
+ assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} }
+ end
+
+ def test_execopts_uid
+ feature6975 = '[ruby-core:47414]'
+
+ [30000, [Process.uid, ENV["USER"]]].each do |uid, user|
+ if user
+ assert_nothing_raised(feature6975) do
+ begin
+ system(*TRUECOMMAND, uid: user)
+ rescue Errno::EPERM, NotImplementedError
+ end
+ end
+ end
+
+ assert_nothing_raised(feature6975) do
+ begin
+ system(*TRUECOMMAND, uid: uid)
+ rescue Errno::EPERM, NotImplementedError
+ end
+ end
+
+ assert_nothing_raised(feature6975) do
+ begin
+ u = IO.popen([RUBY, "-e", "print Process.uid", uid: user||uid], &:read)
+ assert_equal(uid.to_s, u, feature6975)
+ rescue Errno::EPERM, NotImplementedError
+ end
+ end
+ end
+ end
+
+ def test_execopts_gid
+ skip "Process.groups not implemented on Windows platform" if windows?
+ feature6975 = '[ruby-core:47414]'
+
+ [30000, *Process.groups.map {|g| g = Etc.getgrgid(g); [g.name, g.gid]}].each do |group, gid|
+ assert_nothing_raised(feature6975) do
+ begin
+ system(*TRUECOMMAND, gid: group)
+ rescue Errno::EPERM, NotImplementedError
+ end
+ end
+
+ gid = "#{gid || group}"
+ assert_nothing_raised(feature6975) do
+ begin
+ g = IO.popen([RUBY, "-e", "print Process.gid", gid: group], &:read)
+ assert_equal(gid, g, feature6975)
+ rescue Errno::EPERM, NotImplementedError
+ end
+ end
+ end
+ end
+
+ def test_sigpipe
+ system(RUBY, "-e", "")
+ with_pipe {|r, w|
+ r.close
+ assert_raise(Errno::EPIPE) { w.print "a" }
+ }
+ end
+
+ def test_sh_comment
+ IO.popen("echo a # fofoof") {|f|
+ assert_equal("a\n", f.read)
+ }
+ end if File.executable?("/bin/sh")
+
+ def test_sh_env
+ IO.popen("foofoo=barbar env") {|f|
+ lines = f.readlines
+ assert_operator(lines, :include?, "foofoo=barbar\n")
+ }
+ end if File.executable?("/bin/sh")
+
+ def test_sh_exec
+ IO.popen("exec echo exexexec") {|f|
+ assert_equal("exexexec\n", f.read)
+ }
+ end if File.executable?("/bin/sh")
+
+ def test_setsid
+ return unless Process.respond_to?(:setsid)
+ return unless Process.respond_to?(:getsid)
+ # OpenBSD and AIX don't allow Process::getsid(pid) when pid is in
+ # different session.
+ return if /openbsd|aix/ =~ RUBY_PLATFORM
+
+ IO.popen([RUBY, "-e", <<EOS]) do|io|
+ Marshal.dump(Process.getsid, STDOUT)
+ newsid = Process.setsid
+ Marshal.dump(newsid, STDOUT)
+ STDOUT.flush
+ # getsid() on MacOS X return ESRCH when target process is zombie
+ # even if it is valid process id.
+ sleep
+EOS
+ begin
+ # test Process.getsid() w/o arg
+ assert_equal(Marshal.load(io), Process.getsid)
+
+ # test Process.setsid return value and Process::getsid(pid)
+ assert_equal(Marshal.load(io), Process.getsid(io.pid))
+ ensure
+ Process.kill(:KILL, io.pid) rescue nil
+ Process.wait(io.pid)
+ end
+ end
+ end
+
+ def test_spawn_nonascii
+ bug1771 = '[ruby-core:24309] [Bug #1771]'
+
+ with_tmpchdir do
+ [
+ "\u{7d05 7389}",
+ "zuf\u{00E4}llige_\u{017E}lu\u{0165}ou\u{010D}k\u{00FD}_\u{10D2 10D0 10DB 10D4 10DD 10E0 10D4 10D1}_\u{0440 0430 0437 043B 043E 0433 0430}_\u{548C 65B0 52A0 5761 4EE5 53CA 4E1C}",
+ "c\u{1EE7}a",
+ ].each do |name|
+ msg = "#{bug1771} #{name}"
+ exename = "./#{name}.exe"
+ FileUtils.cp(ENV["COMSPEC"], exename)
+ assert_equal(true, system("#{exename} /c exit"), msg)
+ system("#{exename} /c exit 12")
+ assert_equal(12, $?.exitstatus, msg)
+ _, status = Process.wait2(Process.spawn("#{exename} /c exit 42"))
+ assert_equal(42, status.exitstatus, msg)
+ assert_equal("ok\n", `#{exename} /c echo ok`, msg)
+ assert_equal("ok\n", IO.popen("#{exename} /c echo ok", &:read), msg)
+ assert_equal("ok\n", IO.popen(%W"#{exename} /c echo ok", &:read), msg)
+ File.binwrite("#{name}.txt", "ok")
+ assert_equal("ok", `type #{name}.txt`)
+ end
+ end
+ end if windows?
+
+ def test_clock_gettime
+ t1 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
+ t2 = Time.now; t2 = t2.tv_sec * 1000000000 + t2.tv_nsec
+ t3 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
+ assert_operator(t1, :<=, t2)
+ assert_operator(t2, :<=, t3)
+ assert_raise(Errno::EINVAL) { Process.clock_gettime(:foo) }
+ end
+
+ def test_clock_gettime_unit
+ t0 = Time.now.to_f
+ [
+ [:nanosecond, 1_000_000_000],
+ [:microsecond, 1_000_000],
+ [:millisecond, 1_000],
+ [:second, 1],
+ [:float_microsecond, 1_000_000.0],
+ [:float_millisecond, 1_000.0],
+ [:float_second, 1.0],
+ [nil, 1.0],
+ [:foo],
+ ].each do |unit, num|
+ unless num
+ assert_raise(ArgumentError){ Process.clock_gettime(Process::CLOCK_REALTIME, unit) }
+ next
+ end
+ t1 = Process.clock_gettime(Process::CLOCK_REALTIME, unit)
+ assert_kind_of num.integer? ? Integer : num.class, t1, [unit, num].inspect
+ assert_in_delta t0, t1/num, 1, [unit, num].inspect
+ end
+ end
+
+ def test_clock_gettime_constants
+ Process.constants.grep(/\ACLOCK_/).each {|n|
+ c = Process.const_get(n)
+ begin
+ t = Process.clock_gettime(c)
+ rescue Errno::EINVAL
+ next
+ end
+ assert_kind_of(Float, t, "Process.clock_gettime(Process::#{n})")
+ }
+ end
+
+ def test_clock_gettime_GETTIMEOFDAY_BASED_CLOCK_REALTIME
+ n = :GETTIMEOFDAY_BASED_CLOCK_REALTIME
+ t = Process.clock_gettime(n)
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_TIME_BASED_CLOCK_REALTIME
+ n = :TIME_BASED_CLOCK_REALTIME
+ t = Process.clock_gettime(n)
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_TIMES_BASED_CLOCK_MONOTONIC
+ n = :TIMES_BASED_CLOCK_MONOTONIC
+ begin
+ t = Process.clock_gettime(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+ begin
+ t = Process.clock_gettime(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+ begin
+ t = Process.clock_gettime(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+ t = Process.clock_gettime(n)
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_gettime_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+ n = :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+ begin
+ t = Process.clock_gettime(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
+ end
+
+ def test_clock_getres
+ r = Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond)
+ rescue Errno::EINVAL
+ else
+ assert_kind_of(Integer, r)
+ assert_raise(Errno::EINVAL) { Process.clock_getres(:foo) }
+ end
+
+ def test_clock_getres_constants
+ Process.constants.grep(/\ACLOCK_/).each {|n|
+ c = Process.const_get(n)
+ begin
+ t = Process.clock_getres(c)
+ rescue Errno::EINVAL
+ next
+ end
+ assert_kind_of(Float, t, "Process.clock_getres(Process::#{n})")
+ }
+ end
+
+ def test_clock_getres_GETTIMEOFDAY_BASED_CLOCK_REALTIME
+ n = :GETTIMEOFDAY_BASED_CLOCK_REALTIME
+ t = Process.clock_getres(n)
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ assert_equal(1000, Process.clock_getres(n, :nanosecond))
+ end
+
+ def test_clock_getres_TIME_BASED_CLOCK_REALTIME
+ n = :TIME_BASED_CLOCK_REALTIME
+ t = Process.clock_getres(n)
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ assert_equal(1000000000, Process.clock_getres(n, :nanosecond))
+ end
+
+ def test_clock_getres_TIMES_BASED_CLOCK_MONOTONIC
+ n = :TIMES_BASED_CLOCK_MONOTONIC
+ begin
+ t = Process.clock_getres(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ f = Process.clock_getres(n, :hertz)
+ assert_equal(0, f - f.floor)
+ end
+
+ def test_clock_getres_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+ begin
+ t = Process.clock_getres(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ assert_equal(1000, Process.clock_getres(n, :nanosecond))
+ end
+
+ def test_clock_getres_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+ begin
+ t = Process.clock_getres(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ f = Process.clock_getres(n, :hertz)
+ assert_equal(0, f - f.floor)
+ end
+
+ def test_clock_getres_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+ n = :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+ t = Process.clock_getres(n)
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ f = Process.clock_getres(n, :hertz)
+ assert_equal(0, f - f.floor)
+ end
+
+ def test_clock_getres_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+ n = :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+ begin
+ t = Process.clock_getres(n)
+ rescue Errno::EINVAL
+ return
+ end
+ assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+ end
+
+ def test_deadlock_by_signal_at_forking
+ assert_separately([], <<-INPUT, timeout: 60)
+ require 'io/wait'
+ begin
+ GC.start # reduce garbage
+ buf = ''
+ ruby = EnvUtil.rubybin
+ er, ew = IO.pipe
+ unless runner = IO.popen("-".freeze)
+ er.close
+ status = true
+ GC.disable # avoid triggering CoW after forks
+ begin
+ $stderr.reopen($stdout)
+ trap(:QUIT) {}
+ parent = $$
+ 100.times do |i|
+ pid = fork {Process.kill(:QUIT, parent)}
+ IO.popen(ruby, 'r+'.freeze){}
+ Process.wait(pid)
+ $stdout.puts
+ $stdout.flush
+ end
+ ensure
+ if $!
+ ew.puts([Marshal.dump($!)].pack("m0"))
+ status = false
+ end
+ ew.close
+ exit!(status)
+ end
+ end
+ ew.close
+ begin
+ loop do
+ runner.wait_readable(5)
+ runner.read_nonblock(100, buf)
+ end
+ rescue EOFError => e
+ _, status = Process.wait2(runner.pid)
+ rescue IO::WaitReadable => e
+ Process.kill(:INT, runner.pid)
+ exc = Marshal.load(er.read.unpack("m")[0])
+ if exc.kind_of? Interrupt
+ # Don't raise Interrupt. It aborts test-all.
+ flunk "timeout"
+ else
+ raise exc
+ end
+ end
+ assert_predicate(status, :success?)
+ ensure
+ er.close unless er.closed?
+ ew.close unless ew.closed?
+ if runner
+ begin
+ Process.kill(:TERM, runner.pid)
+ sleep 1
+ Process.kill(:KILL, runner.pid)
+ rescue Errno::ESRCH
+ end
+ runner.close
+ end
+ end
+ INPUT
+ end if defined?(fork)
+
+ def test_process_detach
+ pid = fork {}
+ th = Process.detach(pid)
+ assert_equal pid, th.pid
+ status = th.value
+ assert status.success?, status.inspect
+ end if defined?(fork)
+end
diff --git a/jni/ruby/test/ruby/test_rand.rb b/jni/ruby/test/ruby/test_rand.rb
new file mode 100644
index 0000000..d2a1244
--- /dev/null
+++ b/jni/ruby/test/ruby/test_rand.rb
@@ -0,0 +1,527 @@
+require 'test/unit'
+
+class TestRand < Test::Unit::TestCase
+ def assert_random_int(ws, m, init = 0)
+ srand(init)
+ rnds = [Random.new(init)]
+ rnds2 = [rnds[0].dup]
+ rnds3 = [rnds[0].dup]
+ ws.each_with_index do |w, i|
+ w = w.to_i
+ assert_equal(w, rand(m))
+ rnds.each do |rnd|
+ assert_equal(w, rnd.rand(m))
+ end
+ rnds2.each do |rnd|
+ r=rnd.rand(i...(m+i))
+ assert_equal(w+i, r)
+ end
+ rnds3.each do |rnd|
+ r=rnd.rand(i..(m+i-1))
+ assert_equal(w+i, r)
+ end
+ rnds << Marshal.load(Marshal.dump(rnds[-1]))
+ rnds2 << Marshal.load(Marshal.dump(rnds2[-1]))
+ end
+ end
+
+ def test_mt
+ assert_random_int(%w(1067595299 955945823 477289528 4107218783 4228976476),
+ 0x100000000, 0x00000456_00000345_00000234_00000123)
+ end
+
+ def test_0x3fffffff
+ assert_random_int(%w(209652396 398764591 924231285 404868288 441365315),
+ 0x3fffffff)
+ end
+
+ def test_0x40000000
+ assert_random_int(%w(209652396 398764591 924231285 404868288 441365315),
+ 0x40000000)
+ end
+
+ def test_0x40000001
+ assert_random_int(%w(209652396 398764591 924231285 441365315 192771779),
+ 0x40000001)
+ end
+
+ def test_0xffffffff
+ assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963),
+ 0xffffffff)
+ end
+
+ def test_0x100000000
+ assert_random_int(%w(2357136044 2546248239 3071714933 3626093760 2588848963),
+ 0x100000000)
+ end
+
+ def test_0x100000001
+ assert_random_int(%w(2546248239 1277901399 243580376 1171049868 2051556033),
+ 0x100000001)
+ end
+
+ def test_rand_0x100000000
+ assert_random_int(%w(4119812344 3870378946 80324654 4294967296 410016213),
+ 0x100000001, 311702798)
+ end
+
+ def test_0x1000000000000
+ assert_random_int(%w(11736396900911
+ 183025067478208
+ 197104029029115
+ 130583529618791
+ 180361239846611),
+ 0x1000000000000)
+ end
+
+ def test_0x1000000000001
+ assert_random_int(%w(187121911899765
+ 197104029029115
+ 180361239846611
+ 236336749852452
+ 208739549485656),
+ 0x1000000000001)
+ end
+
+ def test_0x3fffffffffffffff
+ assert_random_int(%w(900450186894289455
+ 3969543146641149120
+ 1895649597198586619
+ 827948490035658087
+ 3203365596207111891),
+ 0x3fffffffffffffff)
+ end
+
+ def test_0x4000000000000000
+ assert_random_int(%w(900450186894289455
+ 3969543146641149120
+ 1895649597198586619
+ 827948490035658087
+ 3203365596207111891),
+ 0x4000000000000000)
+ end
+
+ def test_0x4000000000000001
+ assert_random_int(%w(900450186894289455
+ 3969543146641149120
+ 1895649597198586619
+ 827948490035658087
+ 2279347887019741461),
+ 0x4000000000000001)
+ end
+
+ def test_0x10000000000
+ ws = %w(455570294424 1073054410371 790795084744 2445173525 1088503892627)
+ assert_random_int(ws, 0x10000000000, 3)
+ end
+
+ def test_0x10000
+ ws = %w(2732 43567 42613 52416 45891)
+ assert_random_int(ws, 0x10000)
+ end
+
+ def test_types
+ srand(0)
+ rnd = Random.new(0)
+ assert_equal(44, rand(100.0))
+ assert_equal(44, rnd.rand(100))
+ assert_equal(1245085576965981900420779258691, rand((2**100).to_f))
+ assert_equal(1245085576965981900420779258691, rnd.rand(2**100))
+ assert_equal(914679880601515615685077935113, rand(-(2**100).to_f))
+
+ srand(0)
+ rnd = Random.new(0)
+ assert_equal(997707939797331598305742933184, rand(2**100))
+ assert_equal(997707939797331598305742933184, rnd.rand(2**100))
+ assert_in_delta(0.602763376071644, rand((2**100).coerce(0).first),
+ 0.000000000000001)
+ assert_raise(ArgumentError) {rnd.rand((2**100).coerce(0).first)}
+
+ srand(0)
+ rnd = Random.new(0)
+ assert_in_delta(0.548813503927325, rand(nil),
+ 0.000000000000001)
+ assert_in_delta(0.548813503927325, rnd.rand(),
+ 0.000000000000001)
+ srand(0)
+ rnd = Random.new(0)
+ o = Object.new
+ def o.to_int; 100; end
+ assert_equal(44, rand(o))
+ assert_equal(44, rnd.rand(o))
+ assert_equal(47, rand(o))
+ assert_equal(47, rnd.rand(o))
+ assert_equal(64, rand(o))
+ assert_equal(64, rnd.rand(o))
+ end
+
+ def test_srand
+ srand
+ assert_kind_of(Integer, rand(2))
+ assert_kind_of(Integer, Random.new.rand(2))
+
+ srand(2**100)
+ rnd = Random.new(2**100)
+ %w(3258412053).each {|w|
+ assert_equal(w.to_i, rand(0x100000000))
+ assert_equal(w.to_i, rnd.rand(0x100000000))
+ }
+ end
+
+ def test_shuffle
+ srand(0)
+ result = [*1..5].shuffle
+ assert_equal([*1..5], result.sort)
+ assert_equal(result, [*1..5].shuffle(random: Random.new(0)))
+ end
+
+ def test_big_seed
+ assert_random_int(%w(2757555016), 0x100000000, 2**1000000-1)
+ end
+
+ def test_random_gc
+ r = Random.new(0)
+ %w(2357136044 2546248239 3071714933).each do |w|
+ assert_equal(w.to_i, r.rand(0x100000000))
+ end
+ GC.start
+ %w(3626093760 2588848963 3684848379).each do |w|
+ assert_equal(w.to_i, r.rand(0x100000000))
+ end
+ end
+
+ def test_random_type_error
+ assert_raise(TypeError) { Random.new(Object.new) }
+ assert_raise(TypeError) { Random.new(0).rand(Object.new) }
+ end
+
+ def test_random_argument_error
+ r = Random.new(0)
+ assert_raise(ArgumentError) { r.rand(0, 0) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1.0) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(0) }
+ assert_equal(0, r.rand(1), '[ruby-dev:39166]')
+ assert_equal(0, r.rand(0...1), '[ruby-dev:39166]')
+ assert_equal(0, r.rand(0..0), '[ruby-dev:39166]')
+ assert_equal(0.0, r.rand(0.0..0.0), '[ruby-dev:39166]')
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0...0) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0..-1) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...0.0) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...-0.1) }
+ bug3027 = '[ruby-core:29075]'
+ assert_raise(ArgumentError, bug3027) { r.rand(nil) }
+ end
+
+ def test_random_seed
+ assert_equal(0, Random.new(0).seed)
+ assert_equal(0x100000000, Random.new(0x100000000).seed)
+ assert_equal(2**100, Random.new(2**100).seed)
+ end
+
+ def test_random_dup
+ r1 = Random.new(0)
+ r2 = r1.dup
+ %w(2357136044 2546248239 3071714933).each do |w|
+ assert_equal(w.to_i, r1.rand(0x100000000))
+ end
+ %w(2357136044 2546248239 3071714933).each do |w|
+ assert_equal(w.to_i, r2.rand(0x100000000))
+ end
+ r2 = r1.dup
+ %w(3626093760 2588848963 3684848379).each do |w|
+ assert_equal(w.to_i, r1.rand(0x100000000))
+ end
+ %w(3626093760 2588848963 3684848379).each do |w|
+ assert_equal(w.to_i, r2.rand(0x100000000))
+ end
+ end
+
+ def test_random_state
+ state = <<END
+3877134065023083674777481835852171977222677629000095857864323111193832400974413
+4782302161934463784850675209112299537259006497924090422596764895633625964527441
+6943943249411681406395713106007661119327771293929504639878577616749110507385924
+0173026285378896836022134086386136835407107422834685854738117043791709411958489
+3504364936306163473541948635570644161010981140452515307286926529085424765299100
+1255453260115310687580777474046203049197643434654645011966794531914127596390825
+0832232869378617194193100828000236737535657699356156021286278281306055217995213
+8911536025132779573429499813926910299964681785069915877910855089314686097947757
+2621451199734871158015842198110309034467412292693435515184023707918034746119728
+8223459645048255809852819129671833854560563104716892857257229121211527031509280
+2390605053896565646658122125171846129817536096211475312518457776328637574563312
+8113489216547503743508184872149896518488714209752552442327273883060730945969461
+6568672445225657265545983966820639165285082194907591432296265618266901318398982
+0560425129536975583916120558652408261759226803976460322062347123360444839683204
+9868507788028894111577023917218846128348302845774997500569465902983227180328307
+3735301552935104196244116381766459468172162284042207680945316590536094294865648
+5953156978630954893391701383648157037914019502853776972615500142898763385846315
+8457790690531675205213829055442306187692107777193071680668153335688203945049935
+3404449910419303330872435985327845889440458370416464132629866593538629877042969
+7589948685901343135964343582727302330074331803900821801076139161904900333497836
+6627028345784450211920229170280462474456504317367706849373957309797251052447898
+8436235456995644876515032202483449807136139063937892187299239634252391529822163
+9187055268750679730919937006195967184206072757082920250075756273182004964087790
+3812024063897424219316687828337007888030994779068081666133751070479581394604974
+6022215489604777611774245181115126041390161592199230774968475944753915533936834
+4740049163514318351045644344358598159463605453475585370226041981040238023241538
+4958436364776113598408428801867643946791659645708540669432995503575075657406359
+8086928867900590554805639837071298576728564946552163206007997000988745940681607
+4542883814997403673656291618517107133421335645430345871041730410669209035640945
+5024601618318371192091626092482640364669969307766919645222516407626038616667754
+5781148898846306894862390724358039251444333889446128074209417936830253204064223
+3424784857908022314095011879203259864909560830176189727132432100010493659154644
+8407326292884826469503093409465946018496358514999175268200846200025235441426140
+7783386235191526371372655894290440356560751680752191224383460972099834655086068
+9989413443881686756951804138910911737670495391762470293978321414964443502180391
+4665982575919524372985773336921990352313629822677022891307943536442258282401255
+5387646898976193134193506239982621725093291970351083631367582570375381334759004
+1784150668048523676387894646666460369896619585113435743180899362844070393586212
+5023920017185866399742380706352739465848708746963693663004068892056705603018655
+8686663087894205699555906146534549176352859823832196938386172810274748624517052
+8356758650653040545267425513047130342286119889879774951060662713807133125543465
+5104086026298674827575216701372513525846650644773241437066782037334367982012148
+7987782004646896468089089826267467005660035604553432197455616078731159778086155
+9443250946037119223468305483694093795324036812927501783593256716590840500905291
+2096608538205270323065573109227029887731553399324547696295234105140157179430410
+4003109602564833086703863221058381556776789018351726488797845637981974580864082
+1630093543020854542240690897858757985640869209737744458407777584279553258261599
+0246922348101147034463235613998979344685018577901996218099622190722307356620796
+5137485271371502385527388080824050288371607602101805675021790116223360483508538
+8832149997794718410946818866375912486788005950091851067237358294899771385995876
+7088239104394332452501033090159333224995108984871426750597513314521294001864578
+2353528356752869732412552685554334966798888534847483030947310518891788722418172
+6008607577773612004956373863580996793809969715725508939568919714424871639667201
+7922255031431159347210833846575355772055570279673262115911154370983086189948124
+4653677615895887099814174914248255026619941911735341818489822197472499295786997
+7728418516719104857455960900092226749725407204388193002835497055305427730656889
+1508308778869166073740855838213112709306743479676740893150000714099064468263284
+1873435518542972182497755500300784177067568586395485329021157235696300013490087
+2866571034916258390528533374944905429089028336079264760836949419754851422499614
+5732326011260304142074554782259843903215064144396140106592193961703288125005023
+5334375212799817540775536847622032852415253966587517800661605905489339306359573
+2234947905196298436841723673626428243649931398749552780311877734063703985375067
+1239508613417041942487245370152912391885566432830659640677893488723724763120121
+4111855277511356759926232894062814360449757490961653026194107761340614059045172
+1123363102660719217740126157997033682099769790976313166682432732518101889210276
+9574144065390305904944821051736021310524344626348851573631697771556587859836330
+6997324121866564283654784470215100159122764509197570402997911258816526554863326
+9877535269005418736225944874608987238997316999444215865249840762640949599725696
+0773083894168959823152054508672272612355108904098579447774398451678239199426513
+3439507737424049578587487505080347686371029156845461151278198605267053408259090
+3158676794894709281917034995611352710898103415304769654883981727681820369090169
+9295163908214854813365413456264812190842699054830709079275249714169405719140093
+1347572458245530016346604698682269779841803667099480215265926316505737171177810
+9969036572310084022695109125200937135540995157279354438704321290061646592229860
+0156566013602344870223183295508278359111174872740360473845615437106413256386849
+2286259982118315248148847764929974917157683083659364623458927512616369119194574
+2254080
+END
+ state = state.split.join.to_i
+ r = Random.new(0)
+ srand(0)
+ assert_equal(state, r.instance_eval { state })
+ assert_equal(state, Random.instance_eval { state })
+ r.rand(0x100)
+ assert_equal(state, r.instance_eval { state })
+ end
+
+ def test_random_left
+ r = Random.new(0)
+ assert_equal(1, r.instance_eval { left })
+ r.rand(0x100)
+ assert_equal(624, r.instance_eval { left })
+ r.rand(0x100)
+ assert_equal(623, r.instance_eval { left })
+ srand(0)
+ assert_equal(1, Random.instance_eval { left })
+ rand(0x100)
+ assert_equal(624, Random.instance_eval { left })
+ rand(0x100)
+ assert_equal(623, Random.instance_eval { left })
+ end
+
+ def test_random_bytes
+ assert_random_bytes(Random.new(0))
+ end
+
+ def assert_random_bytes(r)
+ assert_equal("", r.bytes(0))
+ assert_equal("\xAC".force_encoding("ASCII-8BIT"), r.bytes(1))
+ assert_equal("/\xAA\xC4\x97u\xA6\x16\xB7\xC0\xCC".force_encoding("ASCII-8BIT"),
+ r.bytes(10))
+ end
+
+ def test_random_range
+ srand(0)
+ r = Random.new(0)
+ %w(9 5 8).each {|w|
+ assert_equal(w.to_i, rand(5..9))
+ assert_equal(w.to_i, r.rand(5..9))
+ }
+ %w(-237 731 383).each {|w|
+ assert_equal(w.to_i, rand(-1000..1000))
+ assert_equal(w.to_i, r.rand(-1000..1000))
+ }
+ %w(1267650600228229401496703205382
+ 1267650600228229401496703205384
+ 1267650600228229401496703205383).each do |w|
+ assert_equal(w.to_i, rand(2**100+5..2**100+9))
+ assert_equal(w.to_i, r.rand(2**100+5..2**100+9))
+ end
+
+ v = rand(3.1..4)
+ assert_instance_of(Float, v, '[ruby-core:24679]')
+ assert_include(3.1..4, v)
+
+ v = r.rand(3.1..4)
+ assert_instance_of(Float, v, '[ruby-core:24679]')
+ assert_include(3.1..4, v)
+
+ now = Time.now
+ assert_equal(now, rand(now..now))
+ assert_equal(now, r.rand(now..now))
+ end
+
+ def test_random_float
+ r = Random.new(0)
+ assert_in_delta(0.5488135039273248, r.rand, 0.0001)
+ assert_in_delta(0.7151893663724195, r.rand, 0.0001)
+ assert_in_delta(0.6027633760716439, r.rand, 0.0001)
+ assert_in_delta(1.0897663659937937, r.rand(2.0), 0.0001)
+ assert_in_delta(5.3704626067153264e+29, r.rand((2**100).to_f), 10**25)
+
+ assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(1.0 / 0.0) }
+ assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(0.0 / 0.0) }
+
+ r = Random.new(0)
+ assert_in_delta(1.5488135039273248, r.rand(1.0...2.0), 0.0001, '[ruby-core:24655]')
+ assert_in_delta(1.7151893663724195, r.rand(1.0...2.0), 0.0001, '[ruby-core:24655]')
+ assert_in_delta(7.027633760716439, r.rand(1.0...11.0), 0.0001, '[ruby-core:24655]')
+ assert_in_delta(3.0897663659937937, r.rand(2.0...4.0), 0.0001, '[ruby-core:24655]')
+
+ assert_nothing_raised {r.rand(-Float::MAX..Float::MAX)}
+ end
+
+ def test_random_equal
+ r = Random.new(0)
+ assert_equal(r, r)
+ assert_equal(r, r.dup)
+ r1 = r.dup
+ r2 = r.dup
+ r1.rand(0x100)
+ assert_not_equal(r1, r2)
+ r2.rand(0x100)
+ assert_equal(r1, r2)
+ end
+
+ def test_fork_shuffle
+ pid = fork do
+ (1..10).to_a.shuffle
+ raise 'default seed is not set' if srand == 0
+ end
+ _, st = Process.waitpid2(pid)
+ assert_predicate(st, :success?, "#{st.inspect}")
+ rescue NotImplementedError, ArgumentError
+ end
+
+ def assert_fork_status(n, mesg, &block)
+ IO.pipe do |r, w|
+ (1..n).map do
+ p1 = fork {w.puts(block.call.to_s)}
+ _, st = Process.waitpid2(p1)
+ assert_send([st, :success?], mesg)
+ r.gets.strip
+ end
+ end
+ end
+
+ def test_rand_reseed_on_fork
+ GC.start
+ bug5661 = '[ruby-core:41209]'
+
+ assert_fork_status(1, bug5661) {Random.rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {Random.rand}
+ assert_not_equal(r1, r2, bug5661)
+
+ assert_fork_status(1, bug5661) {rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {rand}
+ assert_not_equal(r1, r2, bug5661)
+
+ stable = Random.new
+ assert_fork_status(1, bug5661) {stable.rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {stable.rand}
+ assert_equal(r1, r2, bug5661)
+ rescue NotImplementedError
+ end
+
+ def test_seed
+ bug3104 = '[ruby-core:29292]'
+ rand_1 = Random.new(-1).rand
+ assert_not_equal(rand_1, Random.new((1 << 31) -1).rand, "#{bug3104} (2)")
+ assert_not_equal(rand_1, Random.new((1 << 63) -1).rand, "#{bug3104} (2)")
+
+ [-1, -2**10, -2**40].each {|n|
+ b = (2**64).coerce(n)[0]
+ r1 = Random.new(n).rand
+ r2 = Random.new(b).rand
+ assert_equal(r1, r2)
+ }
+ end
+
+ def test_default
+ r1 = Random::DEFAULT.dup
+ r2 = Random::DEFAULT.dup
+ 3.times do
+ x0 = rand
+ x1 = r1.rand
+ x2 = r2.rand
+ assert_equal(x0, x1)
+ assert_equal(x0, x2)
+ end
+ end
+
+ def test_marshal
+ bug3656 = '[ruby-core:31622]'
+ assert_raise(TypeError, bug3656) {
+ Random.new.__send__(:marshal_load, 0)
+ }
+ end
+
+ def test_initialize_frozen
+ r = Random.new(0)
+ r.freeze
+ assert_raise(RuntimeError, '[Bug #6540]') do
+ r.__send__(:initialize, r)
+ end
+ end
+
+ def test_marshal_load_frozen
+ r = Random.new(0)
+ d = r.__send__(:marshal_dump)
+ r.freeze
+ assert_raise(RuntimeError, '[Bug #6540]') do
+ r.__send__(:marshal_load, d)
+ end
+ end
+
+ def test_random_ulong_limited
+ def (gen = Object.new).rand(*) 1 end
+ assert_equal([2], (1..100).map {[1,2,3].sample(random: gen)}.uniq)
+
+ def (gen = Object.new).rand(*) 100 end
+ assert_raise_with_message(RangeError, /big 100\z/) {[1,2,3].sample(random: gen)}
+
+ bug7903 = '[ruby-dev:47061] [Bug #7903]'
+ def (gen = Object.new).rand(*) -1 end
+ assert_raise_with_message(RangeError, /small -1\z/, bug7903) {[1,2,3].sample(random: gen)}
+
+ bug7935 = '[ruby-core:52779] [Bug #7935]'
+ class << (gen = Object.new)
+ def rand(limit) @limit = limit; 0 end
+ attr_reader :limit
+ end
+ [1, 2].sample(1, random: gen)
+ assert_equal(2, gen.limit, bug7935)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_range.rb b/jni/ruby/test/ruby/test_range.rb
new file mode 100644
index 0000000..852515f
--- /dev/null
+++ b/jni/ruby/test/ruby/test_range.rb
@@ -0,0 +1,583 @@
+require 'test/unit'
+require 'delegate'
+require 'timeout'
+require 'bigdecimal'
+
+class TestRange < Test::Unit::TestCase
+ def test_range_string
+ # XXX: Is this really the test of Range?
+ assert_equal([], ("a" ... "a").to_a)
+ assert_equal(["a"], ("a" .. "a").to_a)
+ assert_equal(["a"], ("a" ... "b").to_a)
+ assert_equal(["a", "b"], ("a" .. "b").to_a)
+ end
+
+ def test_range_numeric_string
+ assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]")
+ assert_equal(["6", "7"], ("6"..."8").to_a)
+ assert_equal(["9", "10"], ("9".."10").to_a)
+ assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]")
+ assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a)
+ assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a)
+ end
+
+ def test_range_symbol
+ assert_equal([:a, :b], (:a .. :b).to_a)
+ end
+
+ def test_evaluation_order
+ arr = [1,2]
+ r = (arr.shift)..(arr.shift)
+ assert_equal(1..2, r, "[ruby-dev:26383]")
+ end
+
+ class DuckRange
+ def initialize(b,e,excl=false)
+ @begin = b
+ @end = e
+ @excl = excl
+ end
+ attr_reader :begin, :end
+
+ def exclude_end?
+ @excl
+ end
+ end
+
+ def test_duckrange
+ assert_equal("bc", "abcd"[DuckRange.new(1,2)])
+ end
+
+ def test_min
+ assert_equal(1, (1..2).min)
+ assert_equal(nil, (2..1).min)
+ assert_equal(1, (1...2).min)
+
+ assert_equal(1.0, (1.0..2.0).min)
+ assert_equal(nil, (2.0..1.0).min)
+ assert_equal(1, (1.0...2.0).min)
+
+ assert_equal(0, (0..0).min)
+ assert_equal(nil, (0...0).min)
+
+ assert_equal([0,1,2], (0..10).min(3))
+ assert_equal([0,1], (0..1).min(3))
+ end
+
+ def test_max
+ assert_equal(2, (1..2).max)
+ assert_equal(nil, (2..1).max)
+ assert_equal(1, (1...2).max)
+
+ assert_equal(2.0, (1.0..2.0).max)
+ assert_equal(nil, (2.0..1.0).max)
+ assert_raise(TypeError) { (1.0...2.0).max }
+ assert_raise(TypeError) { (1...1.5).max }
+ assert_raise(TypeError) { (1.5...2).max }
+
+ assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)
+
+ assert_equal(0, (0..0).max)
+ assert_equal(nil, (0...0).max)
+
+ assert_equal([10,9,8], (0..10).max(3))
+ assert_equal([9,8,7], (0...10).max(3))
+ end
+
+ def test_initialize_twice
+ r = eval("1..2")
+ assert_raise(NameError) { r.instance_eval { initialize 3, 4 } }
+ assert_raise(NameError) { r.instance_eval { initialize_copy 3..4 } }
+ end
+
+ def test_uninitialized_range
+ r = Range.allocate
+ s = Marshal.dump(r)
+ r = Marshal.load(s)
+ assert_nothing_raised { r.instance_eval { initialize 5, 6} }
+ end
+
+ def test_bad_value
+ assert_raise(ArgumentError) { (1 .. :a) }
+ end
+
+ def test_exclude_end
+ assert_not_predicate(0..1, :exclude_end?)
+ assert_predicate(0...1, :exclude_end?)
+ end
+
+ def test_eq
+ r = (0..1)
+ assert_equal(r, r)
+ assert_equal(r, (0..1))
+ assert_not_equal(r, 0)
+ assert_not_equal(r, (1..2))
+ assert_not_equal(r, (0..2))
+ assert_not_equal(r, (0...1))
+ subclass = Class.new(Range)
+ assert_equal(r, subclass.new(0,1))
+ end
+
+ def test_eql
+ r = (0..1)
+ assert_operator(r, :eql?, r)
+ assert_operator(r, :eql?, 0..1)
+ assert_not_operator(r, :eql?, 0)
+ assert_not_operator(r, :eql?, 1..2)
+ assert_not_operator(r, :eql?, 0..2)
+ assert_not_operator(r, :eql?, 0...1)
+ subclass = Class.new(Range)
+ assert_operator(r, :eql?, subclass.new(0,1))
+ end
+
+ def test_hash
+ assert_kind_of(Fixnum, (0..1).hash)
+ end
+
+ def test_step
+ a = []
+ (0..10).step {|x| a << x }
+ assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
+
+ a = []
+ (0..10).step(2) {|x| a << x }
+ assert_equal([0, 2, 4, 6, 8, 10], a)
+
+ assert_raise(ArgumentError) { (0..10).step(-1) { } }
+ assert_raise(ArgumentError) { (0..10).step(0) { } }
+
+ a = []
+ ("a" .. "z").step(2) {|x| a << x }
+ assert_equal(%w(a c e g i k m o q s u w y), a)
+
+ a = []
+ ("a" .. "z").step(2**32) {|x| a << x }
+ assert_equal(["a"], a)
+
+ a = []
+ (2**32-1 .. 2**32+1).step(2) {|x| a << x }
+ assert_equal([4294967295, 4294967297], a)
+ zero = (2**32).coerce(0).first
+ assert_raise(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } }
+
+ o1 = Object.new
+ o2 = Object.new
+ def o1.<=>(x); -1; end
+ def o2.<=>(x); 0; end
+ assert_raise(TypeError) { (o1..o2).step(1) { } }
+
+ class << o1; self; end.class_eval do
+ define_method(:succ) { o2 }
+ end
+ a = []
+ (o1..o2).step(1) {|x| a << x }
+ assert_equal([o1, o2], a)
+
+ a = []
+ (o1...o2).step(1) {|x| a << x }
+ assert_equal([o1], a)
+
+ assert_nothing_raised("[ruby-dev:34557]") { (0..2).step(0.5) {|x| } }
+
+ a = []
+ (0..2).step(0.5) {|x| a << x }
+ assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
+
+ a = []
+ (0x40000000..0x40000002).step(0.5) {|x| a << x }
+ assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)
+
+ o = Object.new
+ def o.to_int() 1 end
+ assert_nothing_raised("[ruby-dev:34558]") { (0..2).step(o) {|x| } }
+ end
+
+ def test_step_ruby_core_35753
+ assert_equal(6, (1...6.3).step.to_a.size)
+ assert_equal(5, (1.1...6).step.to_a.size)
+ assert_equal(5, (1...6).step(1.1).to_a.size)
+ assert_equal(3, (1.0...5.4).step(1.5).to_a.size)
+ assert_equal(3, (1.0...5.5).step(1.5).to_a.size)
+ assert_equal(4, (1.0...5.6).step(1.5).to_a.size)
+ end
+
+ def test_each
+ a = []
+ (0..10).each {|x| a << x }
+ assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
+
+ o1 = Object.new
+ o2 = Object.new
+ def o1.setcmp(v) @cmpresult = v end
+ o1.setcmp(-1)
+ def o1.<=>(x); @cmpresult; end
+ def o2.setcmp(v) @cmpresult = v end
+ o2.setcmp(0)
+ def o2.<=>(x); @cmpresult; end
+ class << o1; self; end.class_eval do
+ define_method(:succ) { o2 }
+ end
+
+ r1 = (o1..o2)
+ r2 = (o1...o2)
+
+ a = []
+ r1.each {|x| a << x }
+ assert_equal([o1, o2], a)
+
+ a = []
+ r2.each {|x| a << x }
+ assert_equal([o1], a)
+
+ o2.setcmp(1)
+
+ a = []
+ r1.each {|x| a << x }
+ assert_equal([o1], a)
+
+ o2.setcmp(nil)
+
+ a = []
+ r1.each {|x| a << x }
+ assert_equal([o1], a)
+
+ o1.setcmp(nil)
+
+ a = []
+ r2.each {|x| a << x }
+ assert_equal([], a)
+ end
+
+ def test_begin_end
+ assert_equal(0, (0..1).begin)
+ assert_equal(1, (0..1).end)
+ end
+
+ def test_first_last
+ assert_equal([0, 1, 2], (0..10).first(3))
+ assert_equal([8, 9, 10], (0..10).last(3))
+ assert_equal(0, (0..10).first)
+ assert_equal(10, (0..10).last)
+ assert_equal("a", ("a".."c").first)
+ assert_equal("c", ("a".."c").last)
+ assert_equal(0, (2..0).last)
+
+ assert_equal([0, 1, 2], (0...10).first(3))
+ assert_equal([7, 8, 9], (0...10).last(3))
+ assert_equal(0, (0...10).first)
+ assert_equal("a", ("a"..."c").first)
+ end
+
+ def test_to_s
+ assert_equal("0..1", (0..1).to_s)
+ assert_equal("0...1", (0...1).to_s)
+ end
+
+ def test_inspect
+ assert_equal("0..1", (0..1).inspect)
+ assert_equal("0...1", (0...1).inspect)
+ end
+
+ def test_eqq
+ assert_operator(0..10, :===, 5)
+ assert_not_operator(0..10, :===, 11)
+ end
+
+ def test_eqq_time
+ bug11113 = '[ruby-core:69052] [Bug #11113]'
+ t = Time.now
+ assert_nothing_raised(TypeError, bug11113) {
+ assert_operator(t..(t+10), :===, t+5)
+ }
+ end
+
+ def test_include
+ assert_include("a".."z", "c")
+ assert_not_include("a".."z", "5")
+ assert_include("a"..."z", "y")
+ assert_not_include("a"..."z", "z")
+ assert_not_include("a".."z", "cc")
+ assert_include(0...10, 5)
+ end
+
+ def test_cover
+ assert_operator("a".."z", :cover?, "c")
+ assert_not_operator("a".."z", :cover?, "5")
+ assert_operator("a"..."z", :cover?, "y")
+ assert_not_operator("a"..."z", :cover?, "z")
+ assert_operator("a".."z", :cover?, "cc")
+ end
+
+ def test_beg_len
+ o = Object.new
+ assert_raise(TypeError) { [][o] }
+ class << o; attr_accessor :begin end
+ o.begin = -10
+ assert_raise(TypeError) { [][o] }
+ class << o; attr_accessor :end end
+ o.end = 0
+ assert_raise(NoMethodError) { [][o] }
+ def o.exclude_end=(v) @exclude_end = v end
+ def o.exclude_end?() @exclude_end end
+ o.exclude_end = false
+ assert_nil([0][o])
+ assert_raise(RangeError) { [0][o] = 1 }
+ o.begin = 10
+ o.end = 10
+ assert_nil([0][o])
+ o.begin = 0
+ assert_equal([0], [0][o])
+ o.begin = 2
+ o.end = 0
+ assert_equal([], [0, 1, 2][o])
+ end
+
+ class CyclicRange < Range
+ def <=>(other); true; end
+ end
+ def test_cyclic_range_inspect
+ o = CyclicRange.allocate
+ o.instance_eval { initialize(o, 1) }
+ assert_equal("(... .. ...)..1", o.inspect)
+ end
+
+ def test_comparison_when_recursive
+ x = CyclicRange.allocate; x.send(:initialize, x, 1)
+ y = CyclicRange.allocate; y.send(:initialize, y, 1)
+ Timeout.timeout(1) {
+ assert_equal x, y
+ assert_operator x, :eql?, y
+ }
+
+ z = CyclicRange.allocate; z.send(:initialize, z, :another)
+ Timeout.timeout(1) {
+ assert_not_equal x, z
+ assert_not_operator x, :eql?, z
+ }
+
+ x = CyclicRange.allocate
+ y = CyclicRange.allocate
+ x.send(:initialize, y, 1)
+ y.send(:initialize, x, 1)
+ Timeout.timeout(1) {
+ assert_equal x, y
+ assert_operator x, :eql?, y
+ }
+
+ x = CyclicRange.allocate
+ z = CyclicRange.allocate
+ x.send(:initialize, z, 1)
+ z.send(:initialize, x, :other)
+ Timeout.timeout(1) {
+ assert_not_equal x, z
+ assert_not_operator x, :eql?, z
+ }
+ end
+
+ def test_size
+ assert_equal 42, (1..42).size
+ assert_equal 41, (1...42).size
+ assert_equal 6, (1...6.3).size
+ assert_equal 5, (1.1...6).size
+ assert_equal 42, (1..42).each.size
+ end
+
+ def test_bsearch_typechecks_return_values
+ assert_raise(TypeError) do
+ (1..42).bsearch{ "not ok" }
+ end
+ assert_equal (1..42).bsearch{}, (1..42).bsearch{false}
+ end
+
+ def test_bsearch_with_no_block
+ enum = (42...666).bsearch
+ assert_nil enum.size
+ assert_equal 200, enum.each{|x| x >= 200 }
+ end
+
+ def test_bsearch_for_other_numerics
+ assert_raise(TypeError) {
+ (Rational(-1,2)..Rational(9,4)).bsearch
+ }
+ assert_raise(TypeError) {
+ (BigDecimal('0.5')..BigDecimal('2.25')).bsearch
+ }
+ end
+
+ def test_bsearch_for_fixnum
+ ary = [3, 4, 7, 9, 12]
+ assert_equal(0, (0...ary.size).bsearch {|i| ary[i] >= 2 })
+ assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 4 })
+ assert_equal(2, (0...ary.size).bsearch {|i| ary[i] >= 6 })
+ assert_equal(3, (0...ary.size).bsearch {|i| ary[i] >= 8 })
+ assert_equal(4, (0...ary.size).bsearch {|i| ary[i] >= 10 })
+ assert_equal(nil, (0...ary.size).bsearch {|i| ary[i] >= 100 })
+ assert_equal(0, (0...ary.size).bsearch {|i| true })
+ assert_equal(nil, (0...ary.size).bsearch {|i| false })
+
+ ary = [0, 100, 100, 100, 200]
+ assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 100 })
+ end
+
+ def test_bsearch_for_float
+ inf = Float::INFINITY
+ assert_in_delta(10.0, (0.0...100.0).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+ assert_in_delta(10.0, (0.0...inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+ assert_in_delta(-10.0, (-inf..100.0).bsearch {|x| x >= 0 || Math.log(-x / 10) < 0 }, 0.0001)
+ assert_in_delta(10.0, (-inf..inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+ assert_equal(nil, (-inf..5).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+
+ assert_in_delta(10.0, (-inf.. 10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+ assert_equal(nil, (-inf...10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
+
+ assert_equal(nil, (-inf..inf).bsearch { false })
+ assert_equal(-inf, (-inf..inf).bsearch { true })
+
+ assert_equal(inf, (0..inf).bsearch {|x| x == inf })
+ assert_equal(nil, (0...inf).bsearch {|x| x == inf })
+
+ v = (-inf..0).bsearch {|x| x != -inf }
+ assert_operator(-Float::MAX, :>=, v)
+ assert_operator(-inf, :<, v)
+
+ v = (0.0..1.0).bsearch {|x| x > 0 } # the nearest positive value to 0.0
+ assert_in_delta(0, v, 0.0001)
+ assert_operator(0, :<, v)
+ assert_equal(0.0, (-1.0..0.0).bsearch {|x| x >= 0 })
+ assert_equal(nil, (-1.0...0.0).bsearch {|x| x >= 0 })
+
+ v = (0..Float::MAX).bsearch {|x| x >= Float::MAX }
+ assert_in_delta(Float::MAX, v)
+ assert_equal(nil, v.infinite?)
+
+ v = (0..inf).bsearch {|x| x >= Float::MAX }
+ assert_in_delta(Float::MAX, v)
+ assert_equal(nil, v.infinite?)
+
+ v = (-Float::MAX..0).bsearch {|x| x > -Float::MAX }
+ assert_operator(-Float::MAX, :<, v)
+ assert_equal(nil, v.infinite?)
+
+ v = (-inf..0).bsearch {|x| x >= -Float::MAX }
+ assert_in_delta(-Float::MAX, v)
+ assert_equal(nil, v.infinite?)
+
+ v = (-inf..0).bsearch {|x| x > -Float::MAX }
+ assert_operator(-Float::MAX, :<, v)
+ assert_equal(nil, v.infinite?)
+
+ assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 })
+ assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x })
+ end
+
+ def check_bsearch_values(range, search)
+ from, to = range.begin, range.end
+ cmp = range.exclude_end? ? :< : :<=
+
+ # (0) trivial test
+ r = Range.new(to, from, range.exclude_end?).bsearch do |x|
+ fail "#{to}, #{from}, #{range.exclude_end?}, #{x}"
+ end
+ assert_equal nil, r
+
+ r = (to...to).bsearch do
+ fail
+ end
+ assert_equal nil, r
+
+ # prepare for others
+ yielded = []
+ r = range.bsearch do |val|
+ yielded << val
+ val >= search
+ end
+
+ # (1) log test
+ max = case from
+ when Float then 65
+ when Integer then Math.log(to-from+(range.exclude_end? ? 0 : 1), 2).to_i + 1
+ end
+ assert_operator yielded.size, :<=, max
+
+ # (2) coverage test
+ expect = if search < from
+ from
+ elsif search.send(cmp, to)
+ search
+ else
+ nil
+ end
+ assert_equal expect, r
+
+ # (3) uniqueness test
+ assert_equal nil, yielded.uniq!
+
+ # (4) end of range test
+ case
+ when range.exclude_end?
+ assert_not_include yielded, to
+ assert_not_equal r, to
+ when search >= to
+ assert_include yielded, to
+ assert_equal search == to ? to : nil, r
+ end
+
+ # start of range test
+ if search <= from
+ assert_include yielded, from
+ assert_equal from, r
+ end
+
+ # (5) out of range test
+ yielded.each do |val|
+ assert_operator from, :<=, val
+ assert_send [val, cmp, to]
+ end
+ end
+
+ def test_range_bsearch_for_floats
+ ints = [-1 << 100, -123456789, -42, -1, 0, 1, 42, 123456789, 1 << 100]
+ floats = [-Float::INFINITY, -Float::MAX, -42.0, -4.2, -Float::EPSILON, -Float::MIN, 0.0, Float::MIN, Float::EPSILON, Math::PI, 4.2, 42.0, Float::MAX, Float::INFINITY]
+
+ [ints, floats].each do |values|
+ values.combination(2).to_a.product(values).each do |(from, to), search|
+ check_bsearch_values(from..to, search)
+ check_bsearch_values(from...to, search)
+ end
+ end
+ end
+
+ def test_bsearch_for_bignum
+ bignum = 2**100
+ ary = [3, 4, 7, 9, 12]
+ assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 2 })
+ assert_equal(bignum + 1, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 4 })
+ assert_equal(bignum + 2, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 6 })
+ assert_equal(bignum + 3, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 8 })
+ assert_equal(bignum + 4, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 10 })
+ assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 })
+ assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true })
+ assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false })
+
+ assert_raise(TypeError) { ("a".."z").bsearch {} }
+ end
+
+ def test_bsearch_with_mathn
+ assert_separately ['-r', 'mathn'], %q{
+ msg = '[ruby-core:25740]'
+ answer = (1..(1 << 100)).bsearch{|x|
+ assert_predicate(x, :integer?, msg)
+ x >= 42
+ }
+ assert_equal(42, answer, msg)
+ }, ignore_stderr: true
+ end
+
+ def test_each_no_blockarg
+ a = "a"
+ def a.upto(x, e, &b)
+ super {|y| b.call(y) {|z| assert(false)}}
+ end
+ (a.."c").each {|x, &b| assert_nil(b)}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_rational.rb b/jni/ruby/test/ruby/test_rational.rb
new file mode 100644
index 0000000..ae4a2c6
--- /dev/null
+++ b/jni/ruby/test/ruby/test_rational.rb
@@ -0,0 +1,927 @@
+require 'test/unit'
+
+class RationalSub < Rational; end
+
+class Rational_Test < Test::Unit::TestCase
+
+ def test_ratsub
+ c = RationalSub.__send__(:convert, 1)
+
+ assert_kind_of(Numeric, c)
+
+ assert_instance_of(RationalSub, c)
+
+ c2 = c + 1
+ assert_instance_of(RationalSub, c2)
+ c2 = c - 1
+ assert_instance_of(RationalSub, c2)
+
+ c3 = c - c2
+ assert_instance_of(RationalSub, c3)
+
+ s = Marshal.dump(c)
+ c5 = Marshal.load(s)
+ assert_equal(c, c5)
+ assert_instance_of(RationalSub, c5)
+
+ c1 = Rational(1)
+ assert_equal(c1.hash, c.hash, '[ruby-dev:38850]')
+ assert_equal([true, true], [c.eql?(c1), c1.eql?(c)])
+ end
+
+ def test_eql_p
+ c = Rational(0)
+ c2 = Rational(0)
+ c3 = Rational(1)
+
+ assert_equal(true, c.eql?(c2))
+ assert_equal(false, c.eql?(c3))
+
+ assert_equal(false, c.eql?(0))
+ end
+
+ def test_hash
+ assert_instance_of(Fixnum, Rational(1,2).hash)
+
+ h = {}
+ h[Rational(0)] = 0
+ h[Rational(1,1)] = 1
+ h[Rational(2,1)] = 2
+ h[Rational(3,1)] = 3
+
+ assert_equal(4, h.size)
+ assert_equal(2, h[Rational(2,1)])
+
+ h[Rational(0,1)] = 9
+ assert_equal(4, h.size)
+ end
+
+ def test_freeze
+ c = Rational(1)
+ c.freeze
+ assert_equal(true, c.frozen?)
+ assert_instance_of(String, c.to_s)
+ end
+
+ def test_conv
+ c = Rational(0,1)
+ assert_equal(Rational(0,1), c)
+
+ c = Rational(2**32, 2**32)
+ assert_equal(Rational(2**32,2**32), c)
+ assert_equal([1,1], [c.numerator,c.denominator])
+
+ c = Rational(-2**32, 2**32)
+ assert_equal(Rational(-2**32,2**32), c)
+ assert_equal([-1,1], [c.numerator,c.denominator])
+
+ c = Rational(2**32, -2**32)
+ assert_equal(Rational(2**32,-2**32), c)
+ assert_equal([-1,1], [c.numerator,c.denominator])
+
+ c = Rational(-2**32, -2**32)
+ assert_equal(Rational(-2**32,-2**32), c)
+ assert_equal([1,1], [c.numerator,c.denominator])
+
+ c = Rational(Rational(1,2),2)
+ assert_equal(Rational(1,4), c)
+
+ c = Rational(2,Rational(1,2))
+ assert_equal(Rational(4), c)
+
+ c = Rational(Rational(1,2),Rational(1,2))
+ assert_equal(Rational(1), c)
+
+ c = Rational(Complex(1,2),2)
+ assert_equal(Complex(Rational(1,2),1), c)
+
+ c = Rational(2,Complex(1,2))
+ assert_equal(Complex(Rational(2,5),Rational(-4,5)), c)
+
+ c = Rational(Complex(1,2),Complex(1,2))
+ assert_equal(Rational(1), c)
+
+ assert_equal(Rational(3),Rational(3))
+ assert_equal(Rational(1),Rational(3,3))
+ assert_equal(3.3.to_r,Rational(3.3))
+ assert_equal(1,Rational(3.3,3.3))
+ assert_equal(Rational(3),Rational('3'))
+ assert_equal(Rational(1),Rational('3.0','3.0'))
+ assert_equal(Rational(1),Rational('3/3','3/3'))
+ assert_raise(TypeError){Rational(nil)}
+ assert_raise(ArgumentError){Rational('')}
+ assert_raise(TypeError){Rational(Object.new)}
+ assert_raise(ArgumentError){Rational()}
+ assert_raise(ArgumentError){Rational(1,2,3)}
+
+ if (0.0/0).nan?
+ assert_raise(FloatDomainError){Rational(0.0/0)}
+ end
+ if (1.0/0).infinite?
+ assert_raise(FloatDomainError){Rational(1.0/0)}
+ end
+ end
+
+ def test_attr
+ c = Rational(4)
+
+ assert_equal(4, c.numerator)
+ assert_equal(1, c.denominator)
+
+ c = Rational(4,5)
+
+ assert_equal(4, c.numerator)
+ assert_equal(5, c.denominator)
+
+ c = Rational(4)
+
+ assert_equal(4, c.numerator)
+ assert_equal(1, c.denominator)
+
+ c = Rational(4,5)
+
+ assert_equal(4, c.numerator)
+ assert_equal(5, c.denominator)
+
+ c = Rational(4)
+
+ assert_equal(4, c.numerator)
+ assert_equal(1, c.denominator)
+
+ c = Rational(4,5)
+
+ assert_equal(4, c.numerator)
+ assert_equal(5, c.denominator)
+ end
+
+ def test_attr2
+ c = Rational(1)
+
+ assert_equal(false, c.integer?)
+ assert_equal(true, c.real?)
+
+ assert_equal(true, Rational(0).zero?)
+ assert_equal(true, Rational(0,1).zero?)
+ assert_equal(false, Rational(1,1).zero?)
+
+ assert_equal(nil, Rational(0).nonzero?)
+ assert_equal(nil, Rational(0,1).nonzero?)
+ assert_equal(Rational(1,1), Rational(1,1).nonzero?)
+ end
+
+ def test_uplus
+ assert_equal(Rational(1), +Rational(1))
+ assert_equal(Rational(-1), +Rational(-1))
+ assert_equal(Rational(1,1), +Rational(1,1))
+ assert_equal(Rational(-1,1), +Rational(-1,1))
+ assert_equal(Rational(-1,1), +Rational(1,-1))
+ assert_equal(Rational(1,1), +Rational(-1,-1))
+ end
+
+ def test_negate
+ assert_equal(Rational(-1), -Rational(1))
+ assert_equal(Rational(1), -Rational(-1))
+ assert_equal(Rational(-1,1), -Rational(1,1))
+ assert_equal(Rational(1,1), -Rational(-1,1))
+ assert_equal(Rational(1,1), -Rational(1,-1))
+ assert_equal(Rational(-1,1), -Rational(-1,-1))
+ end
+
+ def test_add
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(Rational(7,6), c + c2)
+
+ assert_equal(Rational(5,2), c + 2)
+ assert_equal(2.5, c + 2.0)
+ end
+
+ def test_sub
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(Rational(-1,6), c - c2)
+
+ assert_equal(Rational(-3,2), c - 2)
+ assert_equal(-1.5, c - 2.0)
+ end
+
+ def test_mul
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(Rational(1,3), c * c2)
+
+ assert_equal(Rational(1,1), c * 2)
+ assert_equal(1.0, c * 2.0)
+ end
+
+ def test_div
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(Rational(3,4), c / c2)
+
+ assert_equal(Rational(1,4), c / 2)
+ assert_equal(0.25, c / 2.0)
+
+ assert_raise(ZeroDivisionError){Rational(1, 3) / 0}
+ assert_raise(ZeroDivisionError){Rational(1, 3) / Rational(0)}
+
+ assert_equal(0, Rational(1, 3) / Float::INFINITY)
+ assert_predicate(Rational(1, 3) / 0.0, :infinite?, '[ruby-core:31626]')
+ end
+
+ def assert_eql(exp, act, *args)
+ unless Array === exp
+ exp = [exp]
+ end
+ unless Array === act
+ act = [act]
+ end
+ exp.zip(act).each do |e, a|
+ na = [e, a] + args
+ assert_equal(*na)
+ na = [e.class, a] + args
+ assert_instance_of(*na)
+ end
+ end
+
+ def test_idiv
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_eql(0, c.div(c2))
+ assert_eql(0, c.div(2))
+ assert_eql(0, c.div(2.0))
+
+ c = Rational(301,100)
+ c2 = Rational(7,5)
+
+ assert_equal(2, c.div(c2))
+ assert_equal(-3, c.div(-c2))
+ assert_equal(-3, (-c).div(c2))
+ assert_equal(2, (-c).div(-c2))
+
+ c = Rational(301,100)
+ c2 = Rational(2)
+
+ assert_equal(1, c.div(c2))
+ assert_equal(-2, c.div(-c2))
+ assert_equal(-2, (-c).div(c2))
+ assert_equal(1, (-c).div(-c2))
+
+ c = Rational(11)
+ c2 = Rational(3)
+
+ assert_equal(3, c.div(c2))
+ assert_equal(-4, c.div(-c2))
+ assert_equal(-4, (-c).div(c2))
+ assert_equal(3, (-c).div(-c2))
+ end
+
+ def test_modulo
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_eql(Rational(1,2), c.modulo(c2))
+ assert_eql(Rational(1,2), c.modulo(2))
+ assert_eql(0.5, c.modulo(2.0))
+
+ c = Rational(301,100)
+ c2 = Rational(7,5)
+
+ assert_equal(Rational(21,100), c.modulo(c2))
+ assert_equal(Rational(-119,100), c.modulo(-c2))
+ assert_equal(Rational(119,100), (-c).modulo(c2))
+ assert_equal(Rational(-21,100), (-c).modulo(-c2))
+
+ c = Rational(301,100)
+ c2 = Rational(2)
+
+ assert_equal(Rational(101,100), c.modulo(c2))
+ assert_equal(Rational(-99,100), c.modulo(-c2))
+ assert_equal(Rational(99,100), (-c).modulo(c2))
+ assert_equal(Rational(-101,100), (-c).modulo(-c2))
+
+ c = Rational(11)
+ c2 = Rational(3)
+
+ assert_equal(2, c.modulo(c2))
+ assert_equal(-1, c.modulo(-c2))
+ assert_equal(1, (-c).modulo(c2))
+ assert_equal(-2, (-c).modulo(-c2))
+ end
+
+ def test_divmod
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_eql([0, Rational(1,2)], c.divmod(c2))
+ assert_eql([0, Rational(1,2)], c.divmod(2))
+ assert_eql([0, 0.5], c.divmod(2.0))
+
+ c = Rational(301,100)
+ c2 = Rational(7,5)
+
+ assert_equal([2, Rational(21,100)], c.divmod(c2))
+ assert_equal([-3, Rational(-119,100)], c.divmod(-c2))
+ assert_equal([-3, Rational(119,100)], (-c).divmod(c2))
+ assert_equal([2, Rational(-21,100)], (-c).divmod(-c2))
+
+ c = Rational(301,100)
+ c2 = Rational(2)
+
+ assert_equal([1, Rational(101,100)], c.divmod(c2))
+ assert_equal([-2, Rational(-99,100)], c.divmod(-c2))
+ assert_equal([-2, Rational(99,100)], (-c).divmod(c2))
+ assert_equal([1, Rational(-101,100)], (-c).divmod(-c2))
+
+ c = Rational(11)
+ c2 = Rational(3)
+
+ assert_equal([3,2], c.divmod(c2))
+ assert_equal([-4,-1], c.divmod(-c2))
+ assert_equal([-4,1], (-c).divmod(c2))
+ assert_equal([3,-2], (-c).divmod(-c2))
+ end
+
+ def test_remainder
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_eql(Rational(1,2), c.remainder(c2))
+ assert_eql(Rational(1,2), c.remainder(2))
+ assert_eql(0.5, c.remainder(2.0))
+
+ c = Rational(301,100)
+ c2 = Rational(7,5)
+
+ assert_equal(Rational(21,100), c.remainder(c2))
+ assert_equal(Rational(21,100), c.remainder(-c2))
+ assert_equal(Rational(-21,100), (-c).remainder(c2))
+ assert_equal(Rational(-21,100), (-c).remainder(-c2))
+
+ c = Rational(301,100)
+ c2 = Rational(2)
+
+ assert_equal(Rational(101,100), c.remainder(c2))
+ assert_equal(Rational(101,100), c.remainder(-c2))
+ assert_equal(Rational(-101,100), (-c).remainder(c2))
+ assert_equal(Rational(-101,100), (-c).remainder(-c2))
+
+ c = Rational(11)
+ c2 = Rational(3)
+
+ assert_equal(2, c.remainder(c2))
+ assert_equal(2, c.remainder(-c2))
+ assert_equal(-2, (-c).remainder(c2))
+ assert_equal(-2, (-c).remainder(-c2))
+ end
+
+ def test_quo
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(Rational(3,4), c.quo(c2))
+
+ assert_equal(Rational(1,4), c.quo(2))
+ assert_equal(0.25, c.quo(2.0))
+ end
+
+ def test_fdiv
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ assert_equal(0.75, c.fdiv(c2))
+
+ assert_equal(0.25, c.fdiv(2))
+ assert_equal(0.25, c.fdiv(2.0))
+ assert_equal(0, c.fdiv(Float::INFINITY))
+ assert_predicate(c.fdiv(0), :infinite?, '[ruby-core:31626]')
+ end
+
+ def test_expt
+ c = Rational(1,2)
+ c2 = Rational(2,3)
+
+ r = c ** c2
+ assert_in_delta(0.6299, r, 0.001)
+
+ assert_equal(Rational(1,4), c ** 2)
+ assert_equal(Rational(4), c ** -2)
+ assert_equal(Rational(1,4), (-c) ** 2)
+ assert_equal(Rational(4), (-c) ** -2)
+
+ assert_equal(0.25, c ** 2.0)
+ assert_equal(4.0, c ** -2.0)
+
+ assert_equal(Rational(1,4), c ** Rational(2))
+ assert_equal(Rational(4), c ** Rational(-2))
+
+ assert_equal(Rational(1), 0 ** Rational(0))
+ assert_equal(Rational(1), Rational(0) ** 0)
+ assert_equal(Rational(1), Rational(0) ** Rational(0))
+
+ # p ** p
+ x = 2 ** Rational(2)
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ x = Rational(2) ** 2
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ x = Rational(2) ** Rational(2)
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ # -p ** p
+ x = (-2) ** Rational(2)
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ x = Rational(-2) ** 2
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ x = Rational(-2) ** Rational(2)
+ assert_equal(Rational(4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(4, x.numerator)
+ assert_equal(1, x.denominator)
+
+ # p ** -p
+ x = 2 ** Rational(-2)
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ x = Rational(2) ** -2
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ x = Rational(2) ** Rational(-2)
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ # -p ** -p
+ x = (-2) ** Rational(-2)
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ x = Rational(-2) ** -2
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ x = Rational(-2) ** Rational(-2)
+ assert_equal(Rational(1,4), x)
+ assert_instance_of(Rational, x)
+ assert_equal(1, x.numerator)
+ assert_equal(4, x.denominator)
+
+ assert_raise(ZeroDivisionError){0 ** -1}
+ end
+
+ def test_cmp
+ assert_equal(-1, Rational(-1) <=> Rational(0))
+ assert_equal(0, Rational(0) <=> Rational(0))
+ assert_equal(+1, Rational(+1) <=> Rational(0))
+
+ assert_equal(-1, Rational(-1) <=> 0)
+ assert_equal(0, Rational(0) <=> 0)
+ assert_equal(+1, Rational(+1) <=> 0)
+
+ assert_equal(-1, Rational(-1) <=> 0.0)
+ assert_equal(0, Rational(0) <=> 0.0)
+ assert_equal(+1, Rational(+1) <=> 0.0)
+
+ assert_equal(-1, Rational(1,2) <=> Rational(2,3))
+ assert_equal(0, Rational(2,3) <=> Rational(2,3))
+ assert_equal(+1, Rational(2,3) <=> Rational(1,2))
+
+ f = 2**30-1
+ b = 2**30
+
+ assert_equal(0, Rational(f) <=> Rational(f))
+ assert_equal(-1, Rational(f) <=> Rational(b))
+ assert_equal(+1, Rational(b) <=> Rational(f))
+ assert_equal(0, Rational(b) <=> Rational(b))
+
+ assert_equal(-1, Rational(f-1) <=> Rational(f))
+ assert_equal(+1, Rational(f) <=> Rational(f-1))
+ assert_equal(-1, Rational(b-1) <=> Rational(b))
+ assert_equal(+1, Rational(b) <=> Rational(b-1))
+
+ assert_equal(false, Rational(0) < Rational(0))
+ assert_equal(true, Rational(0) <= Rational(0))
+ assert_equal(true, Rational(0) >= Rational(0))
+ assert_equal(false, Rational(0) > Rational(0))
+
+ assert_equal(nil, Rational(0) <=> nil)
+ assert_equal(nil, Rational(0) <=> 'foo')
+ end
+
+ def test_eqeq
+ assert_equal(Rational(1,1), Rational(1))
+ assert_equal(Rational(-1,1), Rational(-1))
+
+ assert_equal(false, Rational(2,1) == Rational(1))
+ assert_equal(true, Rational(2,1) != Rational(1))
+ assert_equal(false, Rational(1) == nil)
+ assert_equal(false, Rational(1) == '')
+ end
+
+ def test_coerce
+ assert_equal([Rational(2),Rational(1)], Rational(1).coerce(2))
+ assert_equal([Rational(2.2),Rational(1)], Rational(1).coerce(2.2))
+ assert_equal([Rational(2),Rational(1)], Rational(1).coerce(Rational(2)))
+
+ assert_nothing_raised(TypeError, '[Bug #5020] [ruby-devl:44088]') do
+ Rational(1,2).coerce(Complex(1,1))
+ end
+ end
+
+ class ObjectX
+ def + (x) Rational(1) end
+ alias - +
+ alias * +
+ alias / +
+ alias quo +
+ alias div +
+ alias % +
+ alias remainder +
+ alias ** +
+ def coerce(x) [x, Rational(1)] end
+ end
+
+ def test_coerce2
+ x = ObjectX.new
+ %w(+ - * / quo div % remainder **).each do |op|
+ assert_kind_of(Numeric, Rational(1).__send__(op, x))
+ end
+ end
+
+ def test_math
+ assert_equal(Rational(1,2), Rational(1,2).abs)
+ assert_equal(Rational(1,2), Rational(-1,2).abs)
+ assert_equal(Rational(1,2), Rational(1,2).magnitude)
+ assert_equal(Rational(1,2), Rational(-1,2).magnitude)
+
+ assert_equal(1, Rational(1,2).numerator)
+ assert_equal(2, Rational(1,2).denominator)
+ end
+
+ def test_trunc
+ [[Rational(13, 5), [ 2, 3, 2, 3]], # 2.6
+ [Rational(5, 2), [ 2, 3, 2, 3]], # 2.5
+ [Rational(12, 5), [ 2, 3, 2, 2]], # 2.4
+ [Rational(-12,5), [-3, -2, -2, -2]], # -2.4
+ [Rational(-5, 2), [-3, -2, -2, -3]], # -2.5
+ [Rational(-13, 5), [-3, -2, -2, -3]], # -2.6
+ ].each do |i, a|
+ assert_equal(a[0], i.floor)
+ assert_equal(a[1], i.ceil)
+ assert_equal(a[2], i.truncate)
+ assert_equal(a[3], i.round)
+ end
+ end
+
+ def test_to_s
+ c = Rational(1,2)
+
+ assert_instance_of(String, c.to_s)
+ assert_equal('1/2', c.to_s)
+
+ assert_equal('0/1', Rational(0,2).to_s)
+ assert_equal('0/1', Rational(0,-2).to_s)
+ assert_equal('1/2', Rational(1,2).to_s)
+ assert_equal('-1/2', Rational(-1,2).to_s)
+ assert_equal('1/2', Rational(-1,-2).to_s)
+ assert_equal('-1/2', Rational(1,-2).to_s)
+ assert_equal('1/2', Rational(-1,-2).to_s)
+ end
+
+ def test_inspect
+ c = Rational(1,2)
+
+ assert_instance_of(String, c.inspect)
+ assert_equal('(1/2)', c.inspect)
+ end
+
+ def test_marshal
+ c = Rational(1,2)
+ c.instance_eval{@ivar = 9}
+
+ s = Marshal.dump(c)
+ c2 = Marshal.load(s)
+ assert_equal(c, c2)
+ assert_equal(9, c2.instance_variable_get(:@ivar))
+ assert_instance_of(Rational, c2)
+
+ assert_raise(ZeroDivisionError){
+ Marshal.load("\x04\bU:\rRational[\ai\x06i\x05")
+ }
+
+ bug3656 = '[ruby-core:31622]'
+ c = Rational(1,2)
+ c.freeze
+ assert_predicate(c, :frozen?)
+ result = c.marshal_load([2,3]) rescue :fail
+ assert_equal(:fail, result, bug3656)
+ end
+
+ def test_marshal_compatibility
+ bug6625 = '[ruby-core:45775]'
+ dump = "\x04\x08o:\x0dRational\x07:\x11@denominatori\x07:\x0f@numeratori\x06"
+ assert_nothing_raised(bug6625) do
+ assert_equal(Rational(1, 2), Marshal.load(dump), bug6625)
+ end
+ end
+
+ def test_parse
+ assert_equal(Rational(5), '5'.to_r)
+ assert_equal(Rational(-5), '-5'.to_r)
+ assert_equal(Rational(5,3), '5/3'.to_r)
+ assert_equal(Rational(-5,3), '-5/3'.to_r)
+
+ assert_equal(Rational(5), '5.0'.to_r)
+ assert_equal(Rational(-5), '-5.0'.to_r)
+ assert_equal(Rational(5,3), '5.0/3'.to_r)
+ assert_equal(Rational(-5,3), '-5.0/3'.to_r)
+
+ assert_equal(Rational(5), '5e0'.to_r)
+ assert_equal(Rational(-5), '-5e0'.to_r)
+ assert_equal(Rational(5,3), '5e0/3'.to_r)
+ assert_equal(Rational(-5,3), '-5e0/3'.to_r)
+
+ assert_equal(Rational(5e1), '5e1'.to_r)
+ assert_equal(Rational(-5e2), '-5e2'.to_r)
+ assert_equal(Rational(5e3,3), '5e003/3'.to_r)
+ assert_equal(Rational(-5e4,3), '-5e004/3'.to_r)
+
+ assert_equal(Rational(33,100), '.33'.to_r)
+ assert_equal(Rational(33,100), '0.33'.to_r)
+ assert_equal(Rational(-33,100), '-.33'.to_r)
+ assert_equal(Rational(-33,100), '-0.33'.to_r)
+ assert_equal(Rational(-33,100), '-0.3_3'.to_r)
+
+ assert_equal(Rational(1,2), '5e-1'.to_r)
+ assert_equal(Rational(50), '5e+1'.to_r)
+ assert_equal(Rational(1,2), '5.0e-1'.to_r)
+ assert_equal(Rational(50), '5.0e+1'.to_r)
+ assert_equal(Rational(50), '5e1'.to_r)
+ assert_equal(Rational(50), '5E1'.to_r)
+ assert_equal(Rational(500), '5e2'.to_r)
+ assert_equal(Rational(5000), '5e3'.to_r)
+ assert_equal(Rational(500000000000), '5e1_1'.to_r)
+
+ assert_equal(Rational(5), Rational('5'))
+ assert_equal(Rational(-5), Rational('-5'))
+ assert_equal(Rational(5,3), Rational('5/3'))
+ assert_equal(Rational(-5,3), Rational('-5/3'))
+
+ assert_equal(Rational(5), Rational('5.0'))
+ assert_equal(Rational(-5), Rational('-5.0'))
+ assert_equal(Rational(5,3), Rational('5.0/3'))
+ assert_equal(Rational(-5,3), Rational('-5.0/3'))
+
+ assert_equal(Rational(5), Rational('5e0'))
+ assert_equal(Rational(-5), Rational('-5e0'))
+ assert_equal(Rational(5,3), Rational('5e0/3'))
+ assert_equal(Rational(-5,3), Rational('-5e0/3'))
+
+ assert_equal(Rational(5e1), Rational('5e1'))
+ assert_equal(Rational(-5e2), Rational('-5e2'))
+ assert_equal(Rational(5e3,3), Rational('5e003/3'))
+ assert_equal(Rational(-5e4,3), Rational('-5e004/3'))
+
+ assert_equal(Rational(33,100), Rational('.33'))
+ assert_equal(Rational(33,100), Rational('0.33'))
+ assert_equal(Rational(-33,100), Rational('-.33'))
+ assert_equal(Rational(-33,100), Rational('-0.33'))
+ assert_equal(Rational(-33,100), Rational('-0.3_3'))
+
+ assert_equal(Rational(1,2), Rational('5e-1'))
+ assert_equal(Rational(50), Rational('5e+1'))
+ assert_equal(Rational(1,2), Rational('5.0e-1'))
+ assert_equal(Rational(50), Rational('5.0e+1'))
+ assert_equal(Rational(50), Rational('5e1'))
+ assert_equal(Rational(50), Rational('5E1'))
+ assert_equal(Rational(500), Rational('5e2'))
+ assert_equal(Rational(5000), Rational('5e3'))
+ assert_equal(Rational(500000000000), Rational('5e1_1'))
+
+ assert_equal(Rational(0), ''.to_r)
+ assert_equal(Rational(0), ' '.to_r)
+ assert_equal(Rational(5), "\f\n\r\t\v5\0".to_r)
+ assert_equal(Rational(0), '_'.to_r)
+ assert_equal(Rational(0), '_5'.to_r)
+ assert_equal(Rational(5), '5_'.to_r)
+ assert_equal(Rational(5), '5x'.to_r)
+ assert_equal(Rational(5), '5/_3'.to_r)
+ assert_equal(Rational(5,3), '5/3_'.to_r)
+ assert_equal(Rational(5,3), '5/3.3'.to_r)
+ assert_equal(Rational(5,3), '5/3x'.to_r)
+ assert_raise(ArgumentError){ Rational('')}
+ assert_raise(ArgumentError){ Rational('_')}
+ assert_raise(ArgumentError){ Rational("\f\n\r\t\v5\0")}
+ assert_raise(ArgumentError){ Rational('_5')}
+ assert_raise(ArgumentError){ Rational('5_')}
+ assert_raise(ArgumentError){ Rational('5x')}
+ assert_raise(ArgumentError){ Rational('5/_3')}
+ assert_raise(ArgumentError){ Rational('5/3_')}
+ assert_raise(ArgumentError){ Rational('5/3.3')}
+ assert_raise(ArgumentError){ Rational('5/3x')}
+ end
+
+ def test_to_i
+ assert_equal(1, Rational(3,2).to_i)
+ assert_equal(1, Integer(Rational(3,2)))
+ end
+
+ def test_to_f
+ assert_equal(1.5, Rational(3,2).to_f)
+ assert_equal(1.5, Float(Rational(3,2)))
+ end
+
+ def test_to_c
+ assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c)
+ assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2)))
+ end
+
+ def test_to_r
+ c = nil.to_r
+ assert_equal([0,1], [c.numerator, c.denominator])
+
+ c = 0.to_r
+ assert_equal([0,1], [c.numerator, c.denominator])
+
+ c = 1.to_r
+ assert_equal([1,1], [c.numerator, c.denominator])
+
+ c = 1.1.to_r
+ assert_equal([2476979795053773, 2251799813685248],
+ [c.numerator, c.denominator])
+
+ c = Rational(1,2).to_r
+ assert_equal([1,2], [c.numerator, c.denominator])
+
+ assert_raise(RangeError){Complex(1,2).to_r}
+
+ if (0.0/0).nan?
+ assert_raise(FloatDomainError){(0.0/0).to_r}
+ end
+ if (1.0/0).infinite?
+ assert_raise(FloatDomainError){(1.0/0).to_r}
+ end
+ end
+
+ def test_rationalize
+ c = nil.rationalize
+ assert_equal([0,1], [c.numerator, c.denominator])
+
+ c = 0.rationalize
+ assert_equal([0,1], [c.numerator, c.denominator])
+
+ c = 1.rationalize
+ assert_equal([1,1], [c.numerator, c.denominator])
+
+ c = 1.1.rationalize
+ assert_equal([11, 10], [c.numerator, c.denominator])
+
+ c = Rational(1,2).rationalize
+ assert_equal([1,2], [c.numerator, c.denominator])
+
+ assert_equal(nil.rationalize(Rational(1,10)), Rational(0))
+ assert_equal(0.rationalize(Rational(1,10)), Rational(0))
+ assert_equal(10.rationalize(Rational(1,10)), Rational(10))
+
+ r = 0.3333
+ assert_equal(r.rationalize, Rational(3333, 10000))
+ assert_equal(r.rationalize(Rational(1,10)), Rational(1,3))
+ assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3))
+
+ r = Rational(5404319552844595,18014398509481984)
+ assert_equal(r.rationalize, r)
+ assert_equal(r.rationalize(Rational(1,10)), Rational(1,3))
+ assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3))
+
+ r = -0.3333
+ assert_equal(r.rationalize, Rational(-3333, 10000))
+ assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3))
+ assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3))
+
+ r = Rational(-5404319552844595,18014398509481984)
+ assert_equal(r.rationalize, r)
+ assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3))
+ assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3))
+
+ assert_raise(RangeError){Complex(1,2).rationalize}
+
+ if (0.0/0).nan?
+ assert_raise(FloatDomainError){(0.0/0).rationalize}
+ end
+ if (1.0/0).infinite?
+ assert_raise(FloatDomainError){(1.0/0).rationalize}
+ end
+ end
+
+ def test_gcdlcm
+ assert_equal(7, 91.gcd(-49))
+ assert_equal(5, 5.gcd(0))
+ assert_equal(5, 0.gcd(5))
+ assert_equal(70, 14.lcm(35))
+ assert_equal(0, 5.lcm(0))
+ assert_equal(0, 0.lcm(5))
+ assert_equal([5,0], 0.gcdlcm(5))
+ assert_equal([5,0], 5.gcdlcm(0))
+
+ assert_equal(1, 1073741827.gcd(1073741789))
+ assert_equal(1152921470247108503, 1073741827.lcm(1073741789))
+
+ assert_equal(1, 1073741789.gcd(1073741827))
+ assert_equal(1152921470247108503, 1073741789.lcm(1073741827))
+ end
+
+ def test_supp
+ assert_equal(true, 1.real?)
+ assert_equal(true, 1.1.real?)
+
+ assert_equal(1, 1.numerator)
+ assert_equal(9, 9.numerator)
+ assert_equal(1, 1.denominator)
+ assert_equal(1, 9.denominator)
+
+ assert_equal(1.0, 1.0.numerator)
+ assert_equal(9.0, 9.0.numerator)
+ assert_equal(1.0, 1.0.denominator)
+ assert_equal(1.0, 9.0.denominator)
+
+ assert_equal(Rational(1,2), 1.quo(2))
+ assert_equal(Rational(5000000000), 10000000000.quo(2))
+ assert_equal(0.5, 1.0.quo(2))
+ assert_equal(Rational(1,4), Rational(1,2).quo(2))
+ assert_equal(0, Rational(1,2).quo(Float::INFINITY))
+ assert_predicate(Rational(1,2).quo(0.0), :infinite?, '[ruby-core:31626]')
+
+ assert_equal(0.5, 1.fdiv(2))
+ assert_equal(5000000000.0, 10000000000.fdiv(2))
+ assert_equal(0.5, 1.0.fdiv(2))
+ assert_equal(0.25, Rational(1,2).fdiv(2))
+ end
+
+ def test_ruby19
+ assert_raise(NoMethodError){ Rational.new(1) }
+ assert_raise(NoMethodError){ Rational.new!(1) }
+ end
+
+ def test_fixed_bug
+ n = Float::MAX.to_i * 2
+ assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]')
+ end
+
+ def test_power_of_1_and_minus_1
+ bug5715 = '[ruby-core:41498]'
+ big = 1 << 66
+ one = Rational( 1, 1)
+ assert_eql one, one ** -big , bug5715
+ assert_eql one, (-one) ** -big , bug5715
+ assert_eql -one, (-one) ** -(big+1) , bug5715
+ assert_equal Complex, ((-one) ** Rational(1,3)).class
+ end
+
+ def test_power_of_0
+ bug5713 = '[ruby-core:41494]'
+ big = 1 << 66
+ zero = Rational(0, 1)
+ assert_eql zero, zero ** big
+ assert_eql zero, zero ** Rational(2, 3)
+ assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** -big }
+ assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** Rational(-2,3) }
+ end
+
+ def test_known_bug
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_rational2.rb b/jni/ruby/test/ruby/test_rational2.rb
new file mode 100644
index 0000000..3b6a985
--- /dev/null
+++ b/jni/ruby/test/ruby/test_rational2.rb
@@ -0,0 +1,1386 @@
+require 'test/unit'
+
+class Rational_Test2 < Test::Unit::TestCase
+
+ def test_kumi
+ assert_equal(Rational(1, 1), +Rational(1, 1))
+ assert_equal(Rational(-1, 1), -Rational(1, 1))
+ assert_equal(Rational(2, 1),
+ Rational(1, 1) + Rational(1, 1))
+ assert_equal(Rational(0, 1),
+ Rational(1, 1) - Rational(1, 1))
+ assert_equal(Rational(1, 1),
+ Rational(1, 1) * Rational(1, 1))
+ assert_equal(Rational(1, 1),
+ Rational(1, 1) / Rational(1, 1))
+ assert_equal(Rational(3, 1),
+ Rational(1, 1) + Rational(2, 1))
+ assert_equal(Rational(-1, 1),
+ Rational(1, 1) - Rational(2, 1))
+ assert_equal(Rational(2, 1),
+ Rational(1, 1) * Rational(2, 1))
+ assert_equal(Rational(1, 2),
+ Rational(1, 1) / Rational(2, 1))
+ assert_equal(Rational(4, 1),
+ Rational(1, 1) + Rational(3, 1))
+ assert_equal(Rational(-2, 1),
+ Rational(1, 1) - Rational(3, 1))
+ assert_equal(Rational(3, 1),
+ Rational(1, 1) * Rational(3, 1))
+ assert_equal(Rational(1, 3),
+ Rational(1, 1) / Rational(3, 1))
+ assert_equal(Rational(1073741790, 1),
+ Rational(1, 1) + Rational(1073741789, 1))
+ assert_equal(Rational(-1073741788, 1),
+ Rational(1, 1) - Rational(1073741789, 1))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1, 1) * Rational(1073741789, 1))
+ assert_equal(Rational(1, 1073741789),
+ Rational(1, 1) / Rational(1073741789, 1))
+ assert_equal(Rational(1073741828, 1),
+ Rational(1, 1) + Rational(1073741827, 1))
+ assert_equal(Rational(-1073741826, 1),
+ Rational(1, 1) - Rational(1073741827, 1))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1, 1) * Rational(1073741827, 1))
+ assert_equal(Rational(1, 1073741827),
+ Rational(1, 1) / Rational(1073741827, 1))
+ assert_equal(Rational(5, 3),
+ Rational(1, 1) + Rational(2, 3))
+ assert_equal(Rational(1, 3),
+ Rational(1, 1) - Rational(2, 3))
+ assert_equal(Rational(2, 3),
+ Rational(1, 1) * Rational(2, 3))
+ assert_equal(Rational(3, 2),
+ Rational(1, 1) / Rational(2, 3))
+ assert_equal(Rational(5, 2),
+ Rational(1, 1) + Rational(3, 2))
+ assert_equal(Rational(-1, 2),
+ Rational(1, 1) - Rational(3, 2))
+ assert_equal(Rational(3, 2),
+ Rational(1, 1) * Rational(3, 2))
+ assert_equal(Rational(2, 3),
+ Rational(1, 1) / Rational(3, 2))
+ assert_equal(Rational(1073741792, 1073741789),
+ Rational(1, 1) + Rational(3, 1073741789))
+ assert_equal(Rational(1073741786, 1073741789),
+ Rational(1, 1) - Rational(3, 1073741789))
+ assert_equal(Rational(3, 1073741789),
+ Rational(1, 1) * Rational(3, 1073741789))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1, 1) / Rational(3, 1073741789))
+ assert_equal(Rational(1073741792, 3),
+ Rational(1, 1) + Rational(1073741789, 3))
+ assert_equal(Rational(-1073741786, 3),
+ Rational(1, 1) - Rational(1073741789, 3))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1, 1) * Rational(1073741789, 3))
+ assert_equal(Rational(3, 1073741789),
+ Rational(1, 1) / Rational(1073741789, 3))
+ assert_equal(Rational(1073741830, 1073741827),
+ Rational(1, 1) + Rational(3, 1073741827))
+ assert_equal(Rational(1073741824, 1073741827),
+ Rational(1, 1) - Rational(3, 1073741827))
+ assert_equal(Rational(3, 1073741827),
+ Rational(1, 1) * Rational(3, 1073741827))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1, 1) / Rational(3, 1073741827))
+ assert_equal(Rational(1073741830, 3),
+ Rational(1, 1) + Rational(1073741827, 3))
+ assert_equal(Rational(-1073741824, 3),
+ Rational(1, 1) - Rational(1073741827, 3))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1, 1) * Rational(1073741827, 3))
+ assert_equal(Rational(3, 1073741827),
+ Rational(1, 1) / Rational(1073741827, 3))
+ assert_equal(Rational(2147483616, 1073741827),
+ Rational(1, 1) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(38, 1073741827),
+ Rational(1, 1) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1, 1) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1, 1) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483616, 1073741789),
+ Rational(1, 1) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(-38, 1073741789),
+ Rational(1, 1) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1, 1) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1, 1) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(2, 1), +Rational(2, 1))
+ assert_equal(Rational(-2, 1), -Rational(2, 1))
+ assert_equal(Rational(3, 1),
+ Rational(2, 1) + Rational(1, 1))
+ assert_equal(Rational(1, 1),
+ Rational(2, 1) - Rational(1, 1))
+ assert_equal(Rational(2, 1),
+ Rational(2, 1) * Rational(1, 1))
+ assert_equal(Rational(2, 1),
+ Rational(2, 1) / Rational(1, 1))
+ assert_equal(Rational(4, 1),
+ Rational(2, 1) + Rational(2, 1))
+ assert_equal(Rational(0, 1),
+ Rational(2, 1) - Rational(2, 1))
+ assert_equal(Rational(4, 1),
+ Rational(2, 1) * Rational(2, 1))
+ assert_equal(Rational(1, 1),
+ Rational(2, 1) / Rational(2, 1))
+ assert_equal(Rational(5, 1),
+ Rational(2, 1) + Rational(3, 1))
+ assert_equal(Rational(-1, 1),
+ Rational(2, 1) - Rational(3, 1))
+ assert_equal(Rational(6, 1),
+ Rational(2, 1) * Rational(3, 1))
+ assert_equal(Rational(2, 3),
+ Rational(2, 1) / Rational(3, 1))
+ assert_equal(Rational(1073741791, 1),
+ Rational(2, 1) + Rational(1073741789, 1))
+ assert_equal(Rational(-1073741787, 1),
+ Rational(2, 1) - Rational(1073741789, 1))
+ assert_equal(Rational(2147483578, 1),
+ Rational(2, 1) * Rational(1073741789, 1))
+ assert_equal(Rational(2, 1073741789),
+ Rational(2, 1) / Rational(1073741789, 1))
+ assert_equal(Rational(1073741829, 1),
+ Rational(2, 1) + Rational(1073741827, 1))
+ assert_equal(Rational(-1073741825, 1),
+ Rational(2, 1) - Rational(1073741827, 1))
+ assert_equal(Rational(2147483654, 1),
+ Rational(2, 1) * Rational(1073741827, 1))
+ assert_equal(Rational(2, 1073741827),
+ Rational(2, 1) / Rational(1073741827, 1))
+ assert_equal(Rational(8, 3),
+ Rational(2, 1) + Rational(2, 3))
+ assert_equal(Rational(4, 3),
+ Rational(2, 1) - Rational(2, 3))
+ assert_equal(Rational(4, 3),
+ Rational(2, 1) * Rational(2, 3))
+ assert_equal(Rational(3, 1),
+ Rational(2, 1) / Rational(2, 3))
+ assert_equal(Rational(7, 2),
+ Rational(2, 1) + Rational(3, 2))
+ assert_equal(Rational(1, 2),
+ Rational(2, 1) - Rational(3, 2))
+ assert_equal(Rational(3, 1),
+ Rational(2, 1) * Rational(3, 2))
+ assert_equal(Rational(4, 3),
+ Rational(2, 1) / Rational(3, 2))
+ assert_equal(Rational(2147483581, 1073741789),
+ Rational(2, 1) + Rational(3, 1073741789))
+ assert_equal(Rational(2147483575, 1073741789),
+ Rational(2, 1) - Rational(3, 1073741789))
+ assert_equal(Rational(6, 1073741789),
+ Rational(2, 1) * Rational(3, 1073741789))
+ assert_equal(Rational(2147483578, 3),
+ Rational(2, 1) / Rational(3, 1073741789))
+ assert_equal(Rational(1073741795, 3),
+ Rational(2, 1) + Rational(1073741789, 3))
+ assert_equal(Rational(-1073741783, 3),
+ Rational(2, 1) - Rational(1073741789, 3))
+ assert_equal(Rational(2147483578, 3),
+ Rational(2, 1) * Rational(1073741789, 3))
+ assert_equal(Rational(6, 1073741789),
+ Rational(2, 1) / Rational(1073741789, 3))
+ assert_equal(Rational(2147483657, 1073741827),
+ Rational(2, 1) + Rational(3, 1073741827))
+ assert_equal(Rational(2147483651, 1073741827),
+ Rational(2, 1) - Rational(3, 1073741827))
+ assert_equal(Rational(6, 1073741827),
+ Rational(2, 1) * Rational(3, 1073741827))
+ assert_equal(Rational(2147483654, 3),
+ Rational(2, 1) / Rational(3, 1073741827))
+ assert_equal(Rational(1073741833, 3),
+ Rational(2, 1) + Rational(1073741827, 3))
+ assert_equal(Rational(-1073741821, 3),
+ Rational(2, 1) - Rational(1073741827, 3))
+ assert_equal(Rational(2147483654, 3),
+ Rational(2, 1) * Rational(1073741827, 3))
+ assert_equal(Rational(6, 1073741827),
+ Rational(2, 1) / Rational(1073741827, 3))
+ assert_equal(Rational(3221225443, 1073741827),
+ Rational(2, 1) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741865, 1073741827),
+ Rational(2, 1) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483578, 1073741827),
+ Rational(2, 1) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483654, 1073741789),
+ Rational(2, 1) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225405, 1073741789),
+ Rational(2, 1) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741751, 1073741789),
+ Rational(2, 1) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483654, 1073741789),
+ Rational(2, 1) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483578, 1073741827),
+ Rational(2, 1) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 1), +Rational(3, 1))
+ assert_equal(Rational(-3, 1), -Rational(3, 1))
+ assert_equal(Rational(4, 1),
+ Rational(3, 1) + Rational(1, 1))
+ assert_equal(Rational(2, 1),
+ Rational(3, 1) - Rational(1, 1))
+ assert_equal(Rational(3, 1),
+ Rational(3, 1) * Rational(1, 1))
+ assert_equal(Rational(3, 1),
+ Rational(3, 1) / Rational(1, 1))
+ assert_equal(Rational(5, 1),
+ Rational(3, 1) + Rational(2, 1))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1) - Rational(2, 1))
+ assert_equal(Rational(6, 1),
+ Rational(3, 1) * Rational(2, 1))
+ assert_equal(Rational(3, 2),
+ Rational(3, 1) / Rational(2, 1))
+ assert_equal(Rational(6, 1),
+ Rational(3, 1) + Rational(3, 1))
+ assert_equal(Rational(0, 1),
+ Rational(3, 1) - Rational(3, 1))
+ assert_equal(Rational(9, 1),
+ Rational(3, 1) * Rational(3, 1))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1) / Rational(3, 1))
+ assert_equal(Rational(1073741792, 1),
+ Rational(3, 1) + Rational(1073741789, 1))
+ assert_equal(Rational(-1073741786, 1),
+ Rational(3, 1) - Rational(1073741789, 1))
+ assert_equal(Rational(3221225367, 1),
+ Rational(3, 1) * Rational(1073741789, 1))
+ assert_equal(Rational(3, 1073741789),
+ Rational(3, 1) / Rational(1073741789, 1))
+ assert_equal(Rational(1073741830, 1),
+ Rational(3, 1) + Rational(1073741827, 1))
+ assert_equal(Rational(-1073741824, 1),
+ Rational(3, 1) - Rational(1073741827, 1))
+ assert_equal(Rational(3221225481, 1),
+ Rational(3, 1) * Rational(1073741827, 1))
+ assert_equal(Rational(3, 1073741827),
+ Rational(3, 1) / Rational(1073741827, 1))
+ assert_equal(Rational(11, 3),
+ Rational(3, 1) + Rational(2, 3))
+ assert_equal(Rational(7, 3),
+ Rational(3, 1) - Rational(2, 3))
+ assert_equal(Rational(2, 1),
+ Rational(3, 1) * Rational(2, 3))
+ assert_equal(Rational(9, 2),
+ Rational(3, 1) / Rational(2, 3))
+ assert_equal(Rational(9, 2),
+ Rational(3, 1) + Rational(3, 2))
+ assert_equal(Rational(3, 2),
+ Rational(3, 1) - Rational(3, 2))
+ assert_equal(Rational(9, 2),
+ Rational(3, 1) * Rational(3, 2))
+ assert_equal(Rational(2, 1),
+ Rational(3, 1) / Rational(3, 2))
+ assert_equal(Rational(3221225370, 1073741789),
+ Rational(3, 1) + Rational(3, 1073741789))
+ assert_equal(Rational(3221225364, 1073741789),
+ Rational(3, 1) - Rational(3, 1073741789))
+ assert_equal(Rational(9, 1073741789),
+ Rational(3, 1) * Rational(3, 1073741789))
+ assert_equal(Rational(1073741789, 1),
+ Rational(3, 1) / Rational(3, 1073741789))
+ assert_equal(Rational(1073741798, 3),
+ Rational(3, 1) + Rational(1073741789, 3))
+ assert_equal(Rational(-1073741780, 3),
+ Rational(3, 1) - Rational(1073741789, 3))
+ assert_equal(Rational(1073741789, 1),
+ Rational(3, 1) * Rational(1073741789, 3))
+ assert_equal(Rational(9, 1073741789),
+ Rational(3, 1) / Rational(1073741789, 3))
+ assert_equal(Rational(3221225484, 1073741827),
+ Rational(3, 1) + Rational(3, 1073741827))
+ assert_equal(Rational(3221225478, 1073741827),
+ Rational(3, 1) - Rational(3, 1073741827))
+ assert_equal(Rational(9, 1073741827),
+ Rational(3, 1) * Rational(3, 1073741827))
+ assert_equal(Rational(1073741827, 1),
+ Rational(3, 1) / Rational(3, 1073741827))
+ assert_equal(Rational(1073741836, 3),
+ Rational(3, 1) + Rational(1073741827, 3))
+ assert_equal(Rational(-1073741818, 3),
+ Rational(3, 1) - Rational(1073741827, 3))
+ assert_equal(Rational(1073741827, 1),
+ Rational(3, 1) * Rational(1073741827, 3))
+ assert_equal(Rational(9, 1073741827),
+ Rational(3, 1) / Rational(1073741827, 3))
+ assert_equal(Rational(4294967270, 1073741827),
+ Rational(3, 1) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483692, 1073741827),
+ Rational(3, 1) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(3, 1) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(3, 1) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(4294967194, 1073741789),
+ Rational(3, 1) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483540, 1073741789),
+ Rational(3, 1) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(3, 1) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(3, 1) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 1), +Rational(1073741789, 1))
+ assert_equal(Rational(-1073741789, 1), -Rational(1073741789, 1))
+ assert_equal(Rational(1073741790, 1),
+ Rational(1073741789, 1) + Rational(1, 1))
+ assert_equal(Rational(1073741788, 1),
+ Rational(1073741789, 1) - Rational(1, 1))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741789, 1) * Rational(1, 1))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741789, 1) / Rational(1, 1))
+ assert_equal(Rational(1073741791, 1),
+ Rational(1073741789, 1) + Rational(2, 1))
+ assert_equal(Rational(1073741787, 1),
+ Rational(1073741789, 1) - Rational(2, 1))
+ assert_equal(Rational(2147483578, 1),
+ Rational(1073741789, 1) * Rational(2, 1))
+ assert_equal(Rational(1073741789, 2),
+ Rational(1073741789, 1) / Rational(2, 1))
+ assert_equal(Rational(1073741792, 1),
+ Rational(1073741789, 1) + Rational(3, 1))
+ assert_equal(Rational(1073741786, 1),
+ Rational(1073741789, 1) - Rational(3, 1))
+ assert_equal(Rational(3221225367, 1),
+ Rational(1073741789, 1) * Rational(3, 1))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741789, 1) / Rational(3, 1))
+ assert_equal(Rational(2147483578, 1),
+ Rational(1073741789, 1) + Rational(1073741789, 1))
+ assert_equal(Rational(0, 1),
+ Rational(1073741789, 1) - Rational(1073741789, 1))
+ assert_equal(Rational(1152921429444920521, 1),
+ Rational(1073741789, 1) * Rational(1073741789, 1))
+ assert_equal(Rational(1, 1),
+ Rational(1073741789, 1) / Rational(1073741789, 1))
+ assert_equal(Rational(2147483616, 1),
+ Rational(1073741789, 1) + Rational(1073741827, 1))
+ assert_equal(Rational(-38, 1),
+ Rational(1073741789, 1) - Rational(1073741827, 1))
+ assert_equal(Rational(1152921470247108503, 1),
+ Rational(1073741789, 1) * Rational(1073741827, 1))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1073741789, 1) / Rational(1073741827, 1))
+ assert_equal(Rational(3221225369, 3),
+ Rational(1073741789, 1) + Rational(2, 3))
+ assert_equal(Rational(3221225365, 3),
+ Rational(1073741789, 1) - Rational(2, 3))
+ assert_equal(Rational(2147483578, 3),
+ Rational(1073741789, 1) * Rational(2, 3))
+ assert_equal(Rational(3221225367, 2),
+ Rational(1073741789, 1) / Rational(2, 3))
+ assert_equal(Rational(2147483581, 2),
+ Rational(1073741789, 1) + Rational(3, 2))
+ assert_equal(Rational(2147483575, 2),
+ Rational(1073741789, 1) - Rational(3, 2))
+ assert_equal(Rational(3221225367, 2),
+ Rational(1073741789, 1) * Rational(3, 2))
+ assert_equal(Rational(2147483578, 3),
+ Rational(1073741789, 1) / Rational(3, 2))
+ assert_equal(Rational(1152921429444920524, 1073741789),
+ Rational(1073741789, 1) + Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920518, 1073741789),
+ Rational(1073741789, 1) - Rational(3, 1073741789))
+ assert_equal(Rational(3, 1),
+ Rational(1073741789, 1) * Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920521, 3),
+ Rational(1073741789, 1) / Rational(3, 1073741789))
+ assert_equal(Rational(4294967156, 3),
+ Rational(1073741789, 1) + Rational(1073741789, 3))
+ assert_equal(Rational(2147483578, 3),
+ Rational(1073741789, 1) - Rational(1073741789, 3))
+ assert_equal(Rational(1152921429444920521, 3),
+ Rational(1073741789, 1) * Rational(1073741789, 3))
+ assert_equal(Rational(3, 1),
+ Rational(1073741789, 1) / Rational(1073741789, 3))
+ assert_equal(Rational(1152921470247108506, 1073741827),
+ Rational(1073741789, 1) + Rational(3, 1073741827))
+ assert_equal(Rational(1152921470247108500, 1073741827),
+ Rational(1073741789, 1) - Rational(3, 1073741827))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(1073741789, 1) * Rational(3, 1073741827))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741789, 1) / Rational(3, 1073741827))
+ assert_equal(Rational(4294967194, 3),
+ Rational(1073741789, 1) + Rational(1073741827, 3))
+ assert_equal(Rational(2147483540, 3),
+ Rational(1073741789, 1) - Rational(1073741827, 3))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741789, 1) * Rational(1073741827, 3))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(1073741789, 1) / Rational(1073741827, 3))
+ assert_equal(Rational(1152921471320850292, 1073741827),
+ Rational(1073741789, 1) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921469173366714, 1073741827),
+ Rational(1073741789, 1) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921429444920521, 1073741827),
+ Rational(1073741789, 1) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741789, 1) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921430518662348, 1073741789),
+ Rational(1073741789, 1) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921428371178694, 1073741789),
+ Rational(1073741789, 1) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741789, 1) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921429444920521, 1073741827),
+ Rational(1073741789, 1) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 1), +Rational(1073741827, 1))
+ assert_equal(Rational(-1073741827, 1), -Rational(1073741827, 1))
+ assert_equal(Rational(1073741828, 1),
+ Rational(1073741827, 1) + Rational(1, 1))
+ assert_equal(Rational(1073741826, 1),
+ Rational(1073741827, 1) - Rational(1, 1))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741827, 1) * Rational(1, 1))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741827, 1) / Rational(1, 1))
+ assert_equal(Rational(1073741829, 1),
+ Rational(1073741827, 1) + Rational(2, 1))
+ assert_equal(Rational(1073741825, 1),
+ Rational(1073741827, 1) - Rational(2, 1))
+ assert_equal(Rational(2147483654, 1),
+ Rational(1073741827, 1) * Rational(2, 1))
+ assert_equal(Rational(1073741827, 2),
+ Rational(1073741827, 1) / Rational(2, 1))
+ assert_equal(Rational(1073741830, 1),
+ Rational(1073741827, 1) + Rational(3, 1))
+ assert_equal(Rational(1073741824, 1),
+ Rational(1073741827, 1) - Rational(3, 1))
+ assert_equal(Rational(3221225481, 1),
+ Rational(1073741827, 1) * Rational(3, 1))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741827, 1) / Rational(3, 1))
+ assert_equal(Rational(2147483616, 1),
+ Rational(1073741827, 1) + Rational(1073741789, 1))
+ assert_equal(Rational(38, 1),
+ Rational(1073741827, 1) - Rational(1073741789, 1))
+ assert_equal(Rational(1152921470247108503, 1),
+ Rational(1073741827, 1) * Rational(1073741789, 1))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1073741827, 1) / Rational(1073741789, 1))
+ assert_equal(Rational(2147483654, 1),
+ Rational(1073741827, 1) + Rational(1073741827, 1))
+ assert_equal(Rational(0, 1),
+ Rational(1073741827, 1) - Rational(1073741827, 1))
+ assert_equal(Rational(1152921511049297929, 1),
+ Rational(1073741827, 1) * Rational(1073741827, 1))
+ assert_equal(Rational(1, 1),
+ Rational(1073741827, 1) / Rational(1073741827, 1))
+ assert_equal(Rational(3221225483, 3),
+ Rational(1073741827, 1) + Rational(2, 3))
+ assert_equal(Rational(3221225479, 3),
+ Rational(1073741827, 1) - Rational(2, 3))
+ assert_equal(Rational(2147483654, 3),
+ Rational(1073741827, 1) * Rational(2, 3))
+ assert_equal(Rational(3221225481, 2),
+ Rational(1073741827, 1) / Rational(2, 3))
+ assert_equal(Rational(2147483657, 2),
+ Rational(1073741827, 1) + Rational(3, 2))
+ assert_equal(Rational(2147483651, 2),
+ Rational(1073741827, 1) - Rational(3, 2))
+ assert_equal(Rational(3221225481, 2),
+ Rational(1073741827, 1) * Rational(3, 2))
+ assert_equal(Rational(2147483654, 3),
+ Rational(1073741827, 1) / Rational(3, 2))
+ assert_equal(Rational(1152921470247108506, 1073741789),
+ Rational(1073741827, 1) + Rational(3, 1073741789))
+ assert_equal(Rational(1152921470247108500, 1073741789),
+ Rational(1073741827, 1) - Rational(3, 1073741789))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(1073741827, 1) * Rational(3, 1073741789))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741827, 1) / Rational(3, 1073741789))
+ assert_equal(Rational(4294967270, 3),
+ Rational(1073741827, 1) + Rational(1073741789, 3))
+ assert_equal(Rational(2147483692, 3),
+ Rational(1073741827, 1) - Rational(1073741789, 3))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741827, 1) * Rational(1073741789, 3))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(1073741827, 1) / Rational(1073741789, 3))
+ assert_equal(Rational(1152921511049297932, 1073741827),
+ Rational(1073741827, 1) + Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297926, 1073741827),
+ Rational(1073741827, 1) - Rational(3, 1073741827))
+ assert_equal(Rational(3, 1),
+ Rational(1073741827, 1) * Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297929, 3),
+ Rational(1073741827, 1) / Rational(3, 1073741827))
+ assert_equal(Rational(4294967308, 3),
+ Rational(1073741827, 1) + Rational(1073741827, 3))
+ assert_equal(Rational(2147483654, 3),
+ Rational(1073741827, 1) - Rational(1073741827, 3))
+ assert_equal(Rational(1152921511049297929, 3),
+ Rational(1073741827, 1) * Rational(1073741827, 3))
+ assert_equal(Rational(3, 1),
+ Rational(1073741827, 1) / Rational(1073741827, 3))
+ assert_equal(Rational(1152921512123039718, 1073741827),
+ Rational(1073741827, 1) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921509975556140, 1073741827),
+ Rational(1073741827, 1) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741827, 1) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921511049297929, 1073741789),
+ Rational(1073741827, 1) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921471320850330, 1073741789),
+ Rational(1073741827, 1) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921469173366676, 1073741789),
+ Rational(1073741827, 1) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921511049297929, 1073741789),
+ Rational(1073741827, 1) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741827, 1) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(2, 3), +Rational(2, 3))
+ assert_equal(Rational(-2, 3), -Rational(2, 3))
+ assert_equal(Rational(5, 3),
+ Rational(2, 3) + Rational(1, 1))
+ assert_equal(Rational(-1, 3),
+ Rational(2, 3) - Rational(1, 1))
+ assert_equal(Rational(2, 3),
+ Rational(2, 3) * Rational(1, 1))
+ assert_equal(Rational(2, 3),
+ Rational(2, 3) / Rational(1, 1))
+ assert_equal(Rational(8, 3),
+ Rational(2, 3) + Rational(2, 1))
+ assert_equal(Rational(-4, 3),
+ Rational(2, 3) - Rational(2, 1))
+ assert_equal(Rational(4, 3),
+ Rational(2, 3) * Rational(2, 1))
+ assert_equal(Rational(1, 3),
+ Rational(2, 3) / Rational(2, 1))
+ assert_equal(Rational(11, 3),
+ Rational(2, 3) + Rational(3, 1))
+ assert_equal(Rational(-7, 3),
+ Rational(2, 3) - Rational(3, 1))
+ assert_equal(Rational(2, 1),
+ Rational(2, 3) * Rational(3, 1))
+ assert_equal(Rational(2, 9),
+ Rational(2, 3) / Rational(3, 1))
+ assert_equal(Rational(3221225369, 3),
+ Rational(2, 3) + Rational(1073741789, 1))
+ assert_equal(Rational(-3221225365, 3),
+ Rational(2, 3) - Rational(1073741789, 1))
+ assert_equal(Rational(2147483578, 3),
+ Rational(2, 3) * Rational(1073741789, 1))
+ assert_equal(Rational(2, 3221225367),
+ Rational(2, 3) / Rational(1073741789, 1))
+ assert_equal(Rational(3221225483, 3),
+ Rational(2, 3) + Rational(1073741827, 1))
+ assert_equal(Rational(-3221225479, 3),
+ Rational(2, 3) - Rational(1073741827, 1))
+ assert_equal(Rational(2147483654, 3),
+ Rational(2, 3) * Rational(1073741827, 1))
+ assert_equal(Rational(2, 3221225481),
+ Rational(2, 3) / Rational(1073741827, 1))
+ assert_equal(Rational(4, 3),
+ Rational(2, 3) + Rational(2, 3))
+ assert_equal(Rational(0, 1),
+ Rational(2, 3) - Rational(2, 3))
+ assert_equal(Rational(4, 9),
+ Rational(2, 3) * Rational(2, 3))
+ assert_equal(Rational(1, 1),
+ Rational(2, 3) / Rational(2, 3))
+ assert_equal(Rational(13, 6),
+ Rational(2, 3) + Rational(3, 2))
+ assert_equal(Rational(-5, 6),
+ Rational(2, 3) - Rational(3, 2))
+ assert_equal(Rational(1, 1),
+ Rational(2, 3) * Rational(3, 2))
+ assert_equal(Rational(4, 9),
+ Rational(2, 3) / Rational(3, 2))
+ assert_equal(Rational(2147483587, 3221225367),
+ Rational(2, 3) + Rational(3, 1073741789))
+ assert_equal(Rational(2147483569, 3221225367),
+ Rational(2, 3) - Rational(3, 1073741789))
+ assert_equal(Rational(2, 1073741789),
+ Rational(2, 3) * Rational(3, 1073741789))
+ assert_equal(Rational(2147483578, 9),
+ Rational(2, 3) / Rational(3, 1073741789))
+ assert_equal(Rational(1073741791, 3),
+ Rational(2, 3) + Rational(1073741789, 3))
+ assert_equal(Rational(-357913929, 1),
+ Rational(2, 3) - Rational(1073741789, 3))
+ assert_equal(Rational(2147483578, 9),
+ Rational(2, 3) * Rational(1073741789, 3))
+ assert_equal(Rational(2, 1073741789),
+ Rational(2, 3) / Rational(1073741789, 3))
+ assert_equal(Rational(2147483663, 3221225481),
+ Rational(2, 3) + Rational(3, 1073741827))
+ assert_equal(Rational(2147483645, 3221225481),
+ Rational(2, 3) - Rational(3, 1073741827))
+ assert_equal(Rational(2, 1073741827),
+ Rational(2, 3) * Rational(3, 1073741827))
+ assert_equal(Rational(2147483654, 9),
+ Rational(2, 3) / Rational(3, 1073741827))
+ assert_equal(Rational(357913943, 1),
+ Rational(2, 3) + Rational(1073741827, 3))
+ assert_equal(Rational(-1073741825, 3),
+ Rational(2, 3) - Rational(1073741827, 3))
+ assert_equal(Rational(2147483654, 9),
+ Rational(2, 3) * Rational(1073741827, 3))
+ assert_equal(Rational(2, 1073741827),
+ Rational(2, 3) / Rational(1073741827, 3))
+ assert_equal(Rational(5368709021, 3221225481),
+ Rational(2, 3) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(-1073741713, 3221225481),
+ Rational(2, 3) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483578, 3221225481),
+ Rational(2, 3) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483654, 3221225367),
+ Rational(2, 3) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(5368709059, 3221225367),
+ Rational(2, 3) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(-1073741903, 3221225367),
+ Rational(2, 3) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483654, 3221225367),
+ Rational(2, 3) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483578, 3221225481),
+ Rational(2, 3) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 2), +Rational(3, 2))
+ assert_equal(Rational(-3, 2), -Rational(3, 2))
+ assert_equal(Rational(5, 2),
+ Rational(3, 2) + Rational(1, 1))
+ assert_equal(Rational(1, 2),
+ Rational(3, 2) - Rational(1, 1))
+ assert_equal(Rational(3, 2),
+ Rational(3, 2) * Rational(1, 1))
+ assert_equal(Rational(3, 2),
+ Rational(3, 2) / Rational(1, 1))
+ assert_equal(Rational(7, 2),
+ Rational(3, 2) + Rational(2, 1))
+ assert_equal(Rational(-1, 2),
+ Rational(3, 2) - Rational(2, 1))
+ assert_equal(Rational(3, 1),
+ Rational(3, 2) * Rational(2, 1))
+ assert_equal(Rational(3, 4),
+ Rational(3, 2) / Rational(2, 1))
+ assert_equal(Rational(9, 2),
+ Rational(3, 2) + Rational(3, 1))
+ assert_equal(Rational(-3, 2),
+ Rational(3, 2) - Rational(3, 1))
+ assert_equal(Rational(9, 2),
+ Rational(3, 2) * Rational(3, 1))
+ assert_equal(Rational(1, 2),
+ Rational(3, 2) / Rational(3, 1))
+ assert_equal(Rational(2147483581, 2),
+ Rational(3, 2) + Rational(1073741789, 1))
+ assert_equal(Rational(-2147483575, 2),
+ Rational(3, 2) - Rational(1073741789, 1))
+ assert_equal(Rational(3221225367, 2),
+ Rational(3, 2) * Rational(1073741789, 1))
+ assert_equal(Rational(3, 2147483578),
+ Rational(3, 2) / Rational(1073741789, 1))
+ assert_equal(Rational(2147483657, 2),
+ Rational(3, 2) + Rational(1073741827, 1))
+ assert_equal(Rational(-2147483651, 2),
+ Rational(3, 2) - Rational(1073741827, 1))
+ assert_equal(Rational(3221225481, 2),
+ Rational(3, 2) * Rational(1073741827, 1))
+ assert_equal(Rational(3, 2147483654),
+ Rational(3, 2) / Rational(1073741827, 1))
+ assert_equal(Rational(13, 6),
+ Rational(3, 2) + Rational(2, 3))
+ assert_equal(Rational(5, 6),
+ Rational(3, 2) - Rational(2, 3))
+ assert_equal(Rational(1, 1),
+ Rational(3, 2) * Rational(2, 3))
+ assert_equal(Rational(9, 4),
+ Rational(3, 2) / Rational(2, 3))
+ assert_equal(Rational(3, 1),
+ Rational(3, 2) + Rational(3, 2))
+ assert_equal(Rational(0, 1),
+ Rational(3, 2) - Rational(3, 2))
+ assert_equal(Rational(9, 4),
+ Rational(3, 2) * Rational(3, 2))
+ assert_equal(Rational(1, 1),
+ Rational(3, 2) / Rational(3, 2))
+ assert_equal(Rational(3221225373, 2147483578),
+ Rational(3, 2) + Rational(3, 1073741789))
+ assert_equal(Rational(3221225361, 2147483578),
+ Rational(3, 2) - Rational(3, 1073741789))
+ assert_equal(Rational(9, 2147483578),
+ Rational(3, 2) * Rational(3, 1073741789))
+ assert_equal(Rational(1073741789, 2),
+ Rational(3, 2) / Rational(3, 1073741789))
+ assert_equal(Rational(2147483587, 6),
+ Rational(3, 2) + Rational(1073741789, 3))
+ assert_equal(Rational(-2147483569, 6),
+ Rational(3, 2) - Rational(1073741789, 3))
+ assert_equal(Rational(1073741789, 2),
+ Rational(3, 2) * Rational(1073741789, 3))
+ assert_equal(Rational(9, 2147483578),
+ Rational(3, 2) / Rational(1073741789, 3))
+ assert_equal(Rational(3221225487, 2147483654),
+ Rational(3, 2) + Rational(3, 1073741827))
+ assert_equal(Rational(3221225475, 2147483654),
+ Rational(3, 2) - Rational(3, 1073741827))
+ assert_equal(Rational(9, 2147483654),
+ Rational(3, 2) * Rational(3, 1073741827))
+ assert_equal(Rational(1073741827, 2),
+ Rational(3, 2) / Rational(3, 1073741827))
+ assert_equal(Rational(2147483663, 6),
+ Rational(3, 2) + Rational(1073741827, 3))
+ assert_equal(Rational(-2147483645, 6),
+ Rational(3, 2) - Rational(1073741827, 3))
+ assert_equal(Rational(1073741827, 2),
+ Rational(3, 2) * Rational(1073741827, 3))
+ assert_equal(Rational(9, 2147483654),
+ Rational(3, 2) / Rational(1073741827, 3))
+ assert_equal(Rational(5368709059, 2147483654),
+ Rational(3, 2) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741903, 2147483654),
+ Rational(3, 2) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225367, 2147483654),
+ Rational(3, 2) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225481, 2147483578),
+ Rational(3, 2) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(5368709021, 2147483578),
+ Rational(3, 2) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741713, 2147483578),
+ Rational(3, 2) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225481, 2147483578),
+ Rational(3, 2) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225367, 2147483654),
+ Rational(3, 2) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 1073741789), +Rational(3, 1073741789))
+ assert_equal(Rational(-3, 1073741789), -Rational(3, 1073741789))
+ assert_equal(Rational(1073741792, 1073741789),
+ Rational(3, 1073741789) + Rational(1, 1))
+ assert_equal(Rational(-1073741786, 1073741789),
+ Rational(3, 1073741789) - Rational(1, 1))
+ assert_equal(Rational(3, 1073741789),
+ Rational(3, 1073741789) * Rational(1, 1))
+ assert_equal(Rational(3, 1073741789),
+ Rational(3, 1073741789) / Rational(1, 1))
+ assert_equal(Rational(2147483581, 1073741789),
+ Rational(3, 1073741789) + Rational(2, 1))
+ assert_equal(Rational(-2147483575, 1073741789),
+ Rational(3, 1073741789) - Rational(2, 1))
+ assert_equal(Rational(6, 1073741789),
+ Rational(3, 1073741789) * Rational(2, 1))
+ assert_equal(Rational(3, 2147483578),
+ Rational(3, 1073741789) / Rational(2, 1))
+ assert_equal(Rational(3221225370, 1073741789),
+ Rational(3, 1073741789) + Rational(3, 1))
+ assert_equal(Rational(-3221225364, 1073741789),
+ Rational(3, 1073741789) - Rational(3, 1))
+ assert_equal(Rational(9, 1073741789),
+ Rational(3, 1073741789) * Rational(3, 1))
+ assert_equal(Rational(1, 1073741789),
+ Rational(3, 1073741789) / Rational(3, 1))
+ assert_equal(Rational(1152921429444920524, 1073741789),
+ Rational(3, 1073741789) + Rational(1073741789, 1))
+ assert_equal(Rational(-1152921429444920518, 1073741789),
+ Rational(3, 1073741789) - Rational(1073741789, 1))
+ assert_equal(Rational(3, 1),
+ Rational(3, 1073741789) * Rational(1073741789, 1))
+ assert_equal(Rational(3, 1152921429444920521),
+ Rational(3, 1073741789) / Rational(1073741789, 1))
+ assert_equal(Rational(1152921470247108506, 1073741789),
+ Rational(3, 1073741789) + Rational(1073741827, 1))
+ assert_equal(Rational(-1152921470247108500, 1073741789),
+ Rational(3, 1073741789) - Rational(1073741827, 1))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(3, 1073741789) * Rational(1073741827, 1))
+ assert_equal(Rational(3, 1152921470247108503),
+ Rational(3, 1073741789) / Rational(1073741827, 1))
+ assert_equal(Rational(2147483587, 3221225367),
+ Rational(3, 1073741789) + Rational(2, 3))
+ assert_equal(Rational(-2147483569, 3221225367),
+ Rational(3, 1073741789) - Rational(2, 3))
+ assert_equal(Rational(2, 1073741789),
+ Rational(3, 1073741789) * Rational(2, 3))
+ assert_equal(Rational(9, 2147483578),
+ Rational(3, 1073741789) / Rational(2, 3))
+ assert_equal(Rational(3221225373, 2147483578),
+ Rational(3, 1073741789) + Rational(3, 2))
+ assert_equal(Rational(-3221225361, 2147483578),
+ Rational(3, 1073741789) - Rational(3, 2))
+ assert_equal(Rational(9, 2147483578),
+ Rational(3, 1073741789) * Rational(3, 2))
+ assert_equal(Rational(2, 1073741789),
+ Rational(3, 1073741789) / Rational(3, 2))
+ assert_equal(Rational(6, 1073741789),
+ Rational(3, 1073741789) + Rational(3, 1073741789))
+ assert_equal(Rational(0, 1),
+ Rational(3, 1073741789) - Rational(3, 1073741789))
+ assert_equal(Rational(9, 1152921429444920521),
+ Rational(3, 1073741789) * Rational(3, 1073741789))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1073741789) / Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920530, 3221225367),
+ Rational(3, 1073741789) + Rational(1073741789, 3))
+ assert_equal(Rational(-1152921429444920512, 3221225367),
+ Rational(3, 1073741789) - Rational(1073741789, 3))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1073741789) * Rational(1073741789, 3))
+ assert_equal(Rational(9, 1152921429444920521),
+ Rational(3, 1073741789) / Rational(1073741789, 3))
+ assert_equal(Rational(6442450848, 1152921470247108503),
+ Rational(3, 1073741789) + Rational(3, 1073741827))
+ assert_equal(Rational(114, 1152921470247108503),
+ Rational(3, 1073741789) - Rational(3, 1073741827))
+ assert_equal(Rational(9, 1152921470247108503),
+ Rational(3, 1073741789) * Rational(3, 1073741827))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(3, 1073741789) / Rational(3, 1073741827))
+ assert_equal(Rational(1152921470247108512, 3221225367),
+ Rational(3, 1073741789) + Rational(1073741827, 3))
+ assert_equal(Rational(-1152921470247108494, 3221225367),
+ Rational(3, 1073741789) - Rational(1073741827, 3))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(3, 1073741789) * Rational(1073741827, 3))
+ assert_equal(Rational(9, 1152921470247108503),
+ Rational(3, 1073741789) / Rational(1073741827, 3))
+ assert_equal(Rational(1152921432666146002, 1152921470247108503),
+ Rational(3, 1073741789) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(-1152921426223695040, 1152921470247108503),
+ Rational(3, 1073741789) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(3, 1073741827),
+ Rational(3, 1073741789) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225481, 1152921429444920521),
+ Rational(3, 1073741789) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741830, 1073741789),
+ Rational(3, 1073741789) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(-1073741824, 1073741789),
+ Rational(3, 1073741789) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225481, 1152921429444920521),
+ Rational(3, 1073741789) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 1073741827),
+ Rational(3, 1073741789) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 3), +Rational(1073741789, 3))
+ assert_equal(Rational(-1073741789, 3), -Rational(1073741789, 3))
+ assert_equal(Rational(1073741792, 3),
+ Rational(1073741789, 3) + Rational(1, 1))
+ assert_equal(Rational(1073741786, 3),
+ Rational(1073741789, 3) - Rational(1, 1))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741789, 3) * Rational(1, 1))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741789, 3) / Rational(1, 1))
+ assert_equal(Rational(1073741795, 3),
+ Rational(1073741789, 3) + Rational(2, 1))
+ assert_equal(Rational(1073741783, 3),
+ Rational(1073741789, 3) - Rational(2, 1))
+ assert_equal(Rational(2147483578, 3),
+ Rational(1073741789, 3) * Rational(2, 1))
+ assert_equal(Rational(1073741789, 6),
+ Rational(1073741789, 3) / Rational(2, 1))
+ assert_equal(Rational(1073741798, 3),
+ Rational(1073741789, 3) + Rational(3, 1))
+ assert_equal(Rational(1073741780, 3),
+ Rational(1073741789, 3) - Rational(3, 1))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741789, 3) * Rational(3, 1))
+ assert_equal(Rational(1073741789, 9),
+ Rational(1073741789, 3) / Rational(3, 1))
+ assert_equal(Rational(4294967156, 3),
+ Rational(1073741789, 3) + Rational(1073741789, 1))
+ assert_equal(Rational(-2147483578, 3),
+ Rational(1073741789, 3) - Rational(1073741789, 1))
+ assert_equal(Rational(1152921429444920521, 3),
+ Rational(1073741789, 3) * Rational(1073741789, 1))
+ assert_equal(Rational(1, 3),
+ Rational(1073741789, 3) / Rational(1073741789, 1))
+ assert_equal(Rational(4294967270, 3),
+ Rational(1073741789, 3) + Rational(1073741827, 1))
+ assert_equal(Rational(-2147483692, 3),
+ Rational(1073741789, 3) - Rational(1073741827, 1))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741789, 3) * Rational(1073741827, 1))
+ assert_equal(Rational(1073741789, 3221225481),
+ Rational(1073741789, 3) / Rational(1073741827, 1))
+ assert_equal(Rational(1073741791, 3),
+ Rational(1073741789, 3) + Rational(2, 3))
+ assert_equal(Rational(357913929, 1),
+ Rational(1073741789, 3) - Rational(2, 3))
+ assert_equal(Rational(2147483578, 9),
+ Rational(1073741789, 3) * Rational(2, 3))
+ assert_equal(Rational(1073741789, 2),
+ Rational(1073741789, 3) / Rational(2, 3))
+ assert_equal(Rational(2147483587, 6),
+ Rational(1073741789, 3) + Rational(3, 2))
+ assert_equal(Rational(2147483569, 6),
+ Rational(1073741789, 3) - Rational(3, 2))
+ assert_equal(Rational(1073741789, 2),
+ Rational(1073741789, 3) * Rational(3, 2))
+ assert_equal(Rational(2147483578, 9),
+ Rational(1073741789, 3) / Rational(3, 2))
+ assert_equal(Rational(1152921429444920530, 3221225367),
+ Rational(1073741789, 3) + Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920512, 3221225367),
+ Rational(1073741789, 3) - Rational(3, 1073741789))
+ assert_equal(Rational(1, 1),
+ Rational(1073741789, 3) * Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920521, 9),
+ Rational(1073741789, 3) / Rational(3, 1073741789))
+ assert_equal(Rational(2147483578, 3),
+ Rational(1073741789, 3) + Rational(1073741789, 3))
+ assert_equal(Rational(0, 1),
+ Rational(1073741789, 3) - Rational(1073741789, 3))
+ assert_equal(Rational(1152921429444920521, 9),
+ Rational(1073741789, 3) * Rational(1073741789, 3))
+ assert_equal(Rational(1, 1),
+ Rational(1073741789, 3) / Rational(1073741789, 3))
+ assert_equal(Rational(1152921470247108512, 3221225481),
+ Rational(1073741789, 3) + Rational(3, 1073741827))
+ assert_equal(Rational(1152921470247108494, 3221225481),
+ Rational(1073741789, 3) - Rational(3, 1073741827))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1073741789, 3) * Rational(3, 1073741827))
+ assert_equal(Rational(1152921470247108503, 9),
+ Rational(1073741789, 3) / Rational(3, 1073741827))
+ assert_equal(Rational(715827872, 1),
+ Rational(1073741789, 3) + Rational(1073741827, 3))
+ assert_equal(Rational(-38, 3),
+ Rational(1073741789, 3) - Rational(1073741827, 3))
+ assert_equal(Rational(1152921470247108503, 9),
+ Rational(1073741789, 3) * Rational(1073741827, 3))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1073741789, 3) / Rational(1073741827, 3))
+ assert_equal(Rational(1152921473468333870, 3221225481),
+ Rational(1073741789, 3) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921467025883136, 3221225481),
+ Rational(1073741789, 3) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921429444920521, 3221225481),
+ Rational(1073741789, 3) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741789, 3) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921432666146002, 3221225367),
+ Rational(1073741789, 3) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921426223695040, 3221225367),
+ Rational(1073741789, 3) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741789, 3) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921429444920521, 3221225481),
+ Rational(1073741789, 3) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 1073741827), +Rational(3, 1073741827))
+ assert_equal(Rational(-3, 1073741827), -Rational(3, 1073741827))
+ assert_equal(Rational(1073741830, 1073741827),
+ Rational(3, 1073741827) + Rational(1, 1))
+ assert_equal(Rational(-1073741824, 1073741827),
+ Rational(3, 1073741827) - Rational(1, 1))
+ assert_equal(Rational(3, 1073741827),
+ Rational(3, 1073741827) * Rational(1, 1))
+ assert_equal(Rational(3, 1073741827),
+ Rational(3, 1073741827) / Rational(1, 1))
+ assert_equal(Rational(2147483657, 1073741827),
+ Rational(3, 1073741827) + Rational(2, 1))
+ assert_equal(Rational(-2147483651, 1073741827),
+ Rational(3, 1073741827) - Rational(2, 1))
+ assert_equal(Rational(6, 1073741827),
+ Rational(3, 1073741827) * Rational(2, 1))
+ assert_equal(Rational(3, 2147483654),
+ Rational(3, 1073741827) / Rational(2, 1))
+ assert_equal(Rational(3221225484, 1073741827),
+ Rational(3, 1073741827) + Rational(3, 1))
+ assert_equal(Rational(-3221225478, 1073741827),
+ Rational(3, 1073741827) - Rational(3, 1))
+ assert_equal(Rational(9, 1073741827),
+ Rational(3, 1073741827) * Rational(3, 1))
+ assert_equal(Rational(1, 1073741827),
+ Rational(3, 1073741827) / Rational(3, 1))
+ assert_equal(Rational(1152921470247108506, 1073741827),
+ Rational(3, 1073741827) + Rational(1073741789, 1))
+ assert_equal(Rational(-1152921470247108500, 1073741827),
+ Rational(3, 1073741827) - Rational(1073741789, 1))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(3, 1073741827) * Rational(1073741789, 1))
+ assert_equal(Rational(3, 1152921470247108503),
+ Rational(3, 1073741827) / Rational(1073741789, 1))
+ assert_equal(Rational(1152921511049297932, 1073741827),
+ Rational(3, 1073741827) + Rational(1073741827, 1))
+ assert_equal(Rational(-1152921511049297926, 1073741827),
+ Rational(3, 1073741827) - Rational(1073741827, 1))
+ assert_equal(Rational(3, 1),
+ Rational(3, 1073741827) * Rational(1073741827, 1))
+ assert_equal(Rational(3, 1152921511049297929),
+ Rational(3, 1073741827) / Rational(1073741827, 1))
+ assert_equal(Rational(2147483663, 3221225481),
+ Rational(3, 1073741827) + Rational(2, 3))
+ assert_equal(Rational(-2147483645, 3221225481),
+ Rational(3, 1073741827) - Rational(2, 3))
+ assert_equal(Rational(2, 1073741827),
+ Rational(3, 1073741827) * Rational(2, 3))
+ assert_equal(Rational(9, 2147483654),
+ Rational(3, 1073741827) / Rational(2, 3))
+ assert_equal(Rational(3221225487, 2147483654),
+ Rational(3, 1073741827) + Rational(3, 2))
+ assert_equal(Rational(-3221225475, 2147483654),
+ Rational(3, 1073741827) - Rational(3, 2))
+ assert_equal(Rational(9, 2147483654),
+ Rational(3, 1073741827) * Rational(3, 2))
+ assert_equal(Rational(2, 1073741827),
+ Rational(3, 1073741827) / Rational(3, 2))
+ assert_equal(Rational(6442450848, 1152921470247108503),
+ Rational(3, 1073741827) + Rational(3, 1073741789))
+ assert_equal(Rational(-114, 1152921470247108503),
+ Rational(3, 1073741827) - Rational(3, 1073741789))
+ assert_equal(Rational(9, 1152921470247108503),
+ Rational(3, 1073741827) * Rational(3, 1073741789))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(3, 1073741827) / Rational(3, 1073741789))
+ assert_equal(Rational(1152921470247108512, 3221225481),
+ Rational(3, 1073741827) + Rational(1073741789, 3))
+ assert_equal(Rational(-1152921470247108494, 3221225481),
+ Rational(3, 1073741827) - Rational(1073741789, 3))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(3, 1073741827) * Rational(1073741789, 3))
+ assert_equal(Rational(9, 1152921470247108503),
+ Rational(3, 1073741827) / Rational(1073741789, 3))
+ assert_equal(Rational(6, 1073741827),
+ Rational(3, 1073741827) + Rational(3, 1073741827))
+ assert_equal(Rational(0, 1),
+ Rational(3, 1073741827) - Rational(3, 1073741827))
+ assert_equal(Rational(9, 1152921511049297929),
+ Rational(3, 1073741827) * Rational(3, 1073741827))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1073741827) / Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297938, 3221225481),
+ Rational(3, 1073741827) + Rational(1073741827, 3))
+ assert_equal(Rational(-1152921511049297920, 3221225481),
+ Rational(3, 1073741827) - Rational(1073741827, 3))
+ assert_equal(Rational(1, 1),
+ Rational(3, 1073741827) * Rational(1073741827, 3))
+ assert_equal(Rational(9, 1152921511049297929),
+ Rational(3, 1073741827) / Rational(1073741827, 3))
+ assert_equal(Rational(1073741792, 1073741827),
+ Rational(3, 1073741827) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(-1073741786, 1073741827),
+ Rational(3, 1073741827) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(3221225367, 1152921511049297929),
+ Rational(3, 1073741827) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(3, 1073741789),
+ Rational(3, 1073741827) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921514270523296, 1152921470247108503),
+ Rational(3, 1073741827) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(-1152921507828072562, 1152921470247108503),
+ Rational(3, 1073741827) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(3, 1073741789),
+ Rational(3, 1073741827) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(3221225367, 1152921511049297929),
+ Rational(3, 1073741827) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 3), +Rational(1073741827, 3))
+ assert_equal(Rational(-1073741827, 3), -Rational(1073741827, 3))
+ assert_equal(Rational(1073741830, 3),
+ Rational(1073741827, 3) + Rational(1, 1))
+ assert_equal(Rational(1073741824, 3),
+ Rational(1073741827, 3) - Rational(1, 1))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741827, 3) * Rational(1, 1))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741827, 3) / Rational(1, 1))
+ assert_equal(Rational(1073741833, 3),
+ Rational(1073741827, 3) + Rational(2, 1))
+ assert_equal(Rational(1073741821, 3),
+ Rational(1073741827, 3) - Rational(2, 1))
+ assert_equal(Rational(2147483654, 3),
+ Rational(1073741827, 3) * Rational(2, 1))
+ assert_equal(Rational(1073741827, 6),
+ Rational(1073741827, 3) / Rational(2, 1))
+ assert_equal(Rational(1073741836, 3),
+ Rational(1073741827, 3) + Rational(3, 1))
+ assert_equal(Rational(1073741818, 3),
+ Rational(1073741827, 3) - Rational(3, 1))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741827, 3) * Rational(3, 1))
+ assert_equal(Rational(1073741827, 9),
+ Rational(1073741827, 3) / Rational(3, 1))
+ assert_equal(Rational(4294967194, 3),
+ Rational(1073741827, 3) + Rational(1073741789, 1))
+ assert_equal(Rational(-2147483540, 3),
+ Rational(1073741827, 3) - Rational(1073741789, 1))
+ assert_equal(Rational(1152921470247108503, 3),
+ Rational(1073741827, 3) * Rational(1073741789, 1))
+ assert_equal(Rational(1073741827, 3221225367),
+ Rational(1073741827, 3) / Rational(1073741789, 1))
+ assert_equal(Rational(4294967308, 3),
+ Rational(1073741827, 3) + Rational(1073741827, 1))
+ assert_equal(Rational(-2147483654, 3),
+ Rational(1073741827, 3) - Rational(1073741827, 1))
+ assert_equal(Rational(1152921511049297929, 3),
+ Rational(1073741827, 3) * Rational(1073741827, 1))
+ assert_equal(Rational(1, 3),
+ Rational(1073741827, 3) / Rational(1073741827, 1))
+ assert_equal(Rational(357913943, 1),
+ Rational(1073741827, 3) + Rational(2, 3))
+ assert_equal(Rational(1073741825, 3),
+ Rational(1073741827, 3) - Rational(2, 3))
+ assert_equal(Rational(2147483654, 9),
+ Rational(1073741827, 3) * Rational(2, 3))
+ assert_equal(Rational(1073741827, 2),
+ Rational(1073741827, 3) / Rational(2, 3))
+ assert_equal(Rational(2147483663, 6),
+ Rational(1073741827, 3) + Rational(3, 2))
+ assert_equal(Rational(2147483645, 6),
+ Rational(1073741827, 3) - Rational(3, 2))
+ assert_equal(Rational(1073741827, 2),
+ Rational(1073741827, 3) * Rational(3, 2))
+ assert_equal(Rational(2147483654, 9),
+ Rational(1073741827, 3) / Rational(3, 2))
+ assert_equal(Rational(1152921470247108512, 3221225367),
+ Rational(1073741827, 3) + Rational(3, 1073741789))
+ assert_equal(Rational(1152921470247108494, 3221225367),
+ Rational(1073741827, 3) - Rational(3, 1073741789))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1073741827, 3) * Rational(3, 1073741789))
+ assert_equal(Rational(1152921470247108503, 9),
+ Rational(1073741827, 3) / Rational(3, 1073741789))
+ assert_equal(Rational(715827872, 1),
+ Rational(1073741827, 3) + Rational(1073741789, 3))
+ assert_equal(Rational(38, 3),
+ Rational(1073741827, 3) - Rational(1073741789, 3))
+ assert_equal(Rational(1152921470247108503, 9),
+ Rational(1073741827, 3) * Rational(1073741789, 3))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1073741827, 3) / Rational(1073741789, 3))
+ assert_equal(Rational(1152921511049297938, 3221225481),
+ Rational(1073741827, 3) + Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297920, 3221225481),
+ Rational(1073741827, 3) - Rational(3, 1073741827))
+ assert_equal(Rational(1, 1),
+ Rational(1073741827, 3) * Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297929, 9),
+ Rational(1073741827, 3) / Rational(3, 1073741827))
+ assert_equal(Rational(2147483654, 3),
+ Rational(1073741827, 3) + Rational(1073741827, 3))
+ assert_equal(Rational(0, 1),
+ Rational(1073741827, 3) - Rational(1073741827, 3))
+ assert_equal(Rational(1152921511049297929, 9),
+ Rational(1073741827, 3) * Rational(1073741827, 3))
+ assert_equal(Rational(1, 1),
+ Rational(1073741827, 3) / Rational(1073741827, 3))
+ assert_equal(Rational(1152921514270523296, 3221225481),
+ Rational(1073741827, 3) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921507828072562, 3221225481),
+ Rational(1073741827, 3) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741827, 3) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921511049297929, 3221225367),
+ Rational(1073741827, 3) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921473468333984, 3221225367),
+ Rational(1073741827, 3) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921467025883022, 3221225367),
+ Rational(1073741827, 3) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921511049297929, 3221225367),
+ Rational(1073741827, 3) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741827, 3) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741789, 1073741827), +Rational(1073741789, 1073741827))
+ assert_equal(Rational(-1073741789, 1073741827), -Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483616, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(1, 1))
+ assert_equal(Rational(-38, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(1, 1))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1073741789, 1073741827) * Rational(1, 1))
+ assert_equal(Rational(1073741789, 1073741827),
+ Rational(1073741789, 1073741827) / Rational(1, 1))
+ assert_equal(Rational(3221225443, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(2, 1))
+ assert_equal(Rational(-1073741865, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(2, 1))
+ assert_equal(Rational(2147483578, 1073741827),
+ Rational(1073741789, 1073741827) * Rational(2, 1))
+ assert_equal(Rational(1073741789, 2147483654),
+ Rational(1073741789, 1073741827) / Rational(2, 1))
+ assert_equal(Rational(4294967270, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(3, 1))
+ assert_equal(Rational(-2147483692, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(3, 1))
+ assert_equal(Rational(3221225367, 1073741827),
+ Rational(1073741789, 1073741827) * Rational(3, 1))
+ assert_equal(Rational(1073741789, 3221225481),
+ Rational(1073741789, 1073741827) / Rational(3, 1))
+ assert_equal(Rational(1152921471320850292, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(1073741789, 1))
+ assert_equal(Rational(-1152921469173366714, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(1073741789, 1))
+ assert_equal(Rational(1152921429444920521, 1073741827),
+ Rational(1073741789, 1073741827) * Rational(1073741789, 1))
+ assert_equal(Rational(1, 1073741827),
+ Rational(1073741789, 1073741827) / Rational(1073741789, 1))
+ assert_equal(Rational(1152921512123039718, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(1073741827, 1))
+ assert_equal(Rational(-1152921509975556140, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(1073741827, 1))
+ assert_equal(Rational(1073741789, 1),
+ Rational(1073741789, 1073741827) * Rational(1073741827, 1))
+ assert_equal(Rational(1073741789, 1152921511049297929),
+ Rational(1073741789, 1073741827) / Rational(1073741827, 1))
+ assert_equal(Rational(5368709021, 3221225481),
+ Rational(1073741789, 1073741827) + Rational(2, 3))
+ assert_equal(Rational(1073741713, 3221225481),
+ Rational(1073741789, 1073741827) - Rational(2, 3))
+ assert_equal(Rational(2147483578, 3221225481),
+ Rational(1073741789, 1073741827) * Rational(2, 3))
+ assert_equal(Rational(3221225367, 2147483654),
+ Rational(1073741789, 1073741827) / Rational(2, 3))
+ assert_equal(Rational(5368709059, 2147483654),
+ Rational(1073741789, 1073741827) + Rational(3, 2))
+ assert_equal(Rational(-1073741903, 2147483654),
+ Rational(1073741789, 1073741827) - Rational(3, 2))
+ assert_equal(Rational(3221225367, 2147483654),
+ Rational(1073741789, 1073741827) * Rational(3, 2))
+ assert_equal(Rational(2147483578, 3221225481),
+ Rational(1073741789, 1073741827) / Rational(3, 2))
+ assert_equal(Rational(1152921432666146002, 1152921470247108503),
+ Rational(1073741789, 1073741827) + Rational(3, 1073741789))
+ assert_equal(Rational(1152921426223695040, 1152921470247108503),
+ Rational(1073741789, 1073741827) - Rational(3, 1073741789))
+ assert_equal(Rational(3, 1073741827),
+ Rational(1073741789, 1073741827) * Rational(3, 1073741789))
+ assert_equal(Rational(1152921429444920521, 3221225481),
+ Rational(1073741789, 1073741827) / Rational(3, 1073741789))
+ assert_equal(Rational(1152921473468333870, 3221225481),
+ Rational(1073741789, 1073741827) + Rational(1073741789, 3))
+ assert_equal(Rational(-1152921467025883136, 3221225481),
+ Rational(1073741789, 1073741827) - Rational(1073741789, 3))
+ assert_equal(Rational(1152921429444920521, 3221225481),
+ Rational(1073741789, 1073741827) * Rational(1073741789, 3))
+ assert_equal(Rational(3, 1073741827),
+ Rational(1073741789, 1073741827) / Rational(1073741789, 3))
+ assert_equal(Rational(1073741792, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(3, 1073741827))
+ assert_equal(Rational(1073741786, 1073741827),
+ Rational(1073741789, 1073741827) - Rational(3, 1073741827))
+ assert_equal(Rational(3221225367, 1152921511049297929),
+ Rational(1073741789, 1073741827) * Rational(3, 1073741827))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741789, 1073741827) / Rational(3, 1073741827))
+ assert_equal(Rational(1152921514270523296, 3221225481),
+ Rational(1073741789, 1073741827) + Rational(1073741827, 3))
+ assert_equal(Rational(-1152921507828072562, 3221225481),
+ Rational(1073741789, 1073741827) - Rational(1073741827, 3))
+ assert_equal(Rational(1073741789, 3),
+ Rational(1073741789, 1073741827) * Rational(1073741827, 3))
+ assert_equal(Rational(3221225367, 1152921511049297929),
+ Rational(1073741789, 1073741827) / Rational(1073741827, 3))
+ assert_equal(Rational(2147483578, 1073741827),
+ Rational(1073741789, 1073741827) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(0, 1),
+ Rational(1073741789, 1073741827) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921429444920521, 1152921511049297929),
+ Rational(1073741789, 1073741827) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1, 1),
+ Rational(1073741789, 1073741827) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(2305842940494218450, 1152921470247108503),
+ Rational(1073741789, 1073741827) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(-81604377408, 1152921470247108503),
+ Rational(1073741789, 1073741827) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1, 1),
+ Rational(1073741789, 1073741827) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921429444920521, 1152921511049297929),
+ Rational(1073741789, 1073741827) / Rational(1073741827, 1073741789))
+ assert_equal(Rational(1073741827, 1073741789), +Rational(1073741827, 1073741789))
+ assert_equal(Rational(-1073741827, 1073741789), -Rational(1073741827, 1073741789))
+ assert_equal(Rational(2147483616, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(1, 1))
+ assert_equal(Rational(38, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(1, 1))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1073741827, 1073741789) * Rational(1, 1))
+ assert_equal(Rational(1073741827, 1073741789),
+ Rational(1073741827, 1073741789) / Rational(1, 1))
+ assert_equal(Rational(3221225405, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(2, 1))
+ assert_equal(Rational(-1073741751, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(2, 1))
+ assert_equal(Rational(2147483654, 1073741789),
+ Rational(1073741827, 1073741789) * Rational(2, 1))
+ assert_equal(Rational(1073741827, 2147483578),
+ Rational(1073741827, 1073741789) / Rational(2, 1))
+ assert_equal(Rational(4294967194, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(3, 1))
+ assert_equal(Rational(-2147483540, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(3, 1))
+ assert_equal(Rational(3221225481, 1073741789),
+ Rational(1073741827, 1073741789) * Rational(3, 1))
+ assert_equal(Rational(1073741827, 3221225367),
+ Rational(1073741827, 1073741789) / Rational(3, 1))
+ assert_equal(Rational(1152921430518662348, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(1073741789, 1))
+ assert_equal(Rational(-1152921428371178694, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(1073741789, 1))
+ assert_equal(Rational(1073741827, 1),
+ Rational(1073741827, 1073741789) * Rational(1073741789, 1))
+ assert_equal(Rational(1073741827, 1152921429444920521),
+ Rational(1073741827, 1073741789) / Rational(1073741789, 1))
+ assert_equal(Rational(1152921471320850330, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(1073741827, 1))
+ assert_equal(Rational(-1152921469173366676, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(1073741827, 1))
+ assert_equal(Rational(1152921511049297929, 1073741789),
+ Rational(1073741827, 1073741789) * Rational(1073741827, 1))
+ assert_equal(Rational(1, 1073741789),
+ Rational(1073741827, 1073741789) / Rational(1073741827, 1))
+ assert_equal(Rational(5368709059, 3221225367),
+ Rational(1073741827, 1073741789) + Rational(2, 3))
+ assert_equal(Rational(1073741903, 3221225367),
+ Rational(1073741827, 1073741789) - Rational(2, 3))
+ assert_equal(Rational(2147483654, 3221225367),
+ Rational(1073741827, 1073741789) * Rational(2, 3))
+ assert_equal(Rational(3221225481, 2147483578),
+ Rational(1073741827, 1073741789) / Rational(2, 3))
+ assert_equal(Rational(5368709021, 2147483578),
+ Rational(1073741827, 1073741789) + Rational(3, 2))
+ assert_equal(Rational(-1073741713, 2147483578),
+ Rational(1073741827, 1073741789) - Rational(3, 2))
+ assert_equal(Rational(3221225481, 2147483578),
+ Rational(1073741827, 1073741789) * Rational(3, 2))
+ assert_equal(Rational(2147483654, 3221225367),
+ Rational(1073741827, 1073741789) / Rational(3, 2))
+ assert_equal(Rational(1073741830, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(3, 1073741789))
+ assert_equal(Rational(1073741824, 1073741789),
+ Rational(1073741827, 1073741789) - Rational(3, 1073741789))
+ assert_equal(Rational(3221225481, 1152921429444920521),
+ Rational(1073741827, 1073741789) * Rational(3, 1073741789))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741827, 1073741789) / Rational(3, 1073741789))
+ assert_equal(Rational(1152921432666146002, 3221225367),
+ Rational(1073741827, 1073741789) + Rational(1073741789, 3))
+ assert_equal(Rational(-1152921426223695040, 3221225367),
+ Rational(1073741827, 1073741789) - Rational(1073741789, 3))
+ assert_equal(Rational(1073741827, 3),
+ Rational(1073741827, 1073741789) * Rational(1073741789, 3))
+ assert_equal(Rational(3221225481, 1152921429444920521),
+ Rational(1073741827, 1073741789) / Rational(1073741789, 3))
+ assert_equal(Rational(1152921514270523296, 1152921470247108503),
+ Rational(1073741827, 1073741789) + Rational(3, 1073741827))
+ assert_equal(Rational(1152921507828072562, 1152921470247108503),
+ Rational(1073741827, 1073741789) - Rational(3, 1073741827))
+ assert_equal(Rational(3, 1073741789),
+ Rational(1073741827, 1073741789) * Rational(3, 1073741827))
+ assert_equal(Rational(1152921511049297929, 3221225367),
+ Rational(1073741827, 1073741789) / Rational(3, 1073741827))
+ assert_equal(Rational(1152921473468333984, 3221225367),
+ Rational(1073741827, 1073741789) + Rational(1073741827, 3))
+ assert_equal(Rational(-1152921467025883022, 3221225367),
+ Rational(1073741827, 1073741789) - Rational(1073741827, 3))
+ assert_equal(Rational(1152921511049297929, 3221225367),
+ Rational(1073741827, 1073741789) * Rational(1073741827, 3))
+ assert_equal(Rational(3, 1073741789),
+ Rational(1073741827, 1073741789) / Rational(1073741827, 3))
+ assert_equal(Rational(2305842940494218450, 1152921470247108503),
+ Rational(1073741827, 1073741789) + Rational(1073741789, 1073741827))
+ assert_equal(Rational(81604377408, 1152921470247108503),
+ Rational(1073741827, 1073741789) - Rational(1073741789, 1073741827))
+ assert_equal(Rational(1, 1),
+ Rational(1073741827, 1073741789) * Rational(1073741789, 1073741827))
+ assert_equal(Rational(1152921511049297929, 1152921429444920521),
+ Rational(1073741827, 1073741789) / Rational(1073741789, 1073741827))
+ assert_equal(Rational(2147483654, 1073741789),
+ Rational(1073741827, 1073741789) + Rational(1073741827, 1073741789))
+ assert_equal(Rational(0, 1),
+ Rational(1073741827, 1073741789) - Rational(1073741827, 1073741789))
+ assert_equal(Rational(1152921511049297929, 1152921429444920521),
+ Rational(1073741827, 1073741789) * Rational(1073741827, 1073741789))
+ assert_equal(Rational(1, 1),
+ Rational(1073741827, 1073741789) / Rational(1073741827, 1073741789))
+ end
+
+end
diff --git a/jni/ruby/test/ruby/test_readpartial.rb b/jni/ruby/test/ruby/test_readpartial.rb
new file mode 100644
index 0000000..7f2ec65
--- /dev/null
+++ b/jni/ruby/test/ruby/test_readpartial.rb
@@ -0,0 +1,72 @@
+require 'test/unit'
+require 'timeout'
+require 'fcntl'
+
+class TestReadPartial < Test::Unit::TestCase
+ def make_pipe
+ r, w = IO.pipe
+ r.binmode
+ w.binmode
+ begin
+ yield r, w
+ ensure
+ r.close unless r.closed?
+ w.close unless w.closed?
+ end
+ end
+
+ def pipe
+ make_pipe {|r, w|
+ yield r, w
+ }
+ return unless defined?(Fcntl::F_SETFL)
+ return unless defined?(Fcntl::F_GETFL)
+ return unless defined?(Fcntl::O_NONBLOCK)
+ make_pipe {|r, w|
+ r.fcntl(Fcntl::F_SETFL, r.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
+ yield r, w
+ }
+ end
+
+ def test_length_zero
+ pipe {|r, w|
+ assert_equal('', r.readpartial(0))
+ }
+ end
+
+ def test_closed_pipe
+ pipe {|r, w|
+ w << 'abc'
+ w.close
+ assert_equal('ab', r.readpartial(2))
+ assert_equal('c', r.readpartial(2))
+ assert_raise(EOFError) { r.readpartial(2) }
+ assert_raise(EOFError) { r.readpartial(2) }
+ }
+ end
+
+ def test_open_pipe
+ pipe {|r, w|
+ w << 'abc'
+ assert_equal('ab', r.readpartial(2))
+ assert_equal('c', r.readpartial(2))
+ assert_raise(Timeout::Error) {
+ timeout(0.1) { r.readpartial(2) }
+ }
+ }
+ end
+
+ def test_with_stdio
+ pipe {|r, w|
+ w << "abc\ndef\n"
+ assert_equal("abc\n", r.gets)
+ w << "ghi\n"
+ assert_equal("de", r.readpartial(2))
+ assert_equal("f\n", r.readpartial(4096))
+ assert_equal("ghi\n", r.readpartial(4096))
+ assert_raise(Timeout::Error) {
+ timeout(0.1) { r.readpartial(2) }
+ }
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_refinement.rb b/jni/ruby/test/ruby/test_refinement.rb
new file mode 100644
index 0000000..557dc38
--- /dev/null
+++ b/jni/ruby/test/ruby/test_refinement.rb
@@ -0,0 +1,1450 @@
+require 'test/unit'
+
+# to supress warnings for future calls of Module#refine
+EnvUtil.suppress_warning do
+ Module.new {
+ refine(Object) {}
+ }
+end
+
+class TestRefinement < Test::Unit::TestCase
+ class Foo
+ def x
+ return "Foo#x"
+ end
+
+ def y
+ return "Foo#y"
+ end
+
+ def a
+ return "Foo#a"
+ end
+
+ def call_x
+ return x
+ end
+ end
+
+ module FooExt
+ refine Foo do
+ def x
+ return "FooExt#x"
+ end
+
+ def y
+ return "FooExt#y " + super
+ end
+
+ def z
+ return "FooExt#z"
+ end
+
+ def a
+ return "FooExt#a"
+ end
+ end
+ end
+
+ module FooExt2
+ refine Foo do
+ def x
+ return "FooExt2#x"
+ end
+
+ def y
+ return "FooExt2#y " + super
+ end
+
+ def z
+ return "FooExt2#z"
+ end
+ end
+ end
+
+ class FooSub < Foo
+ def x
+ return "FooSub#x"
+ end
+
+ def y
+ return "FooSub#y " + super
+ end
+ end
+
+ eval <<-EOF, TOPLEVEL_BINDING
+ using TestRefinement::FooExt
+
+ class TestRefinement::FooExtClient
+ def self.invoke_x_on(foo)
+ return foo.x
+ end
+
+ def self.invoke_y_on(foo)
+ return foo.y
+ end
+
+ def self.invoke_z_on(foo)
+ return foo.z
+ end
+
+ def self.send_z_on(foo)
+ return foo.send(:z)
+ end
+
+ def self.method_z(foo)
+ return foo.method(:z)
+ end
+
+ def self.invoke_call_x_on(foo)
+ return foo.call_x
+ end
+ end
+ EOF
+
+ eval <<-EOF, TOPLEVEL_BINDING
+ using TestRefinement::FooExt
+ using TestRefinement::FooExt2
+
+ class TestRefinement::FooExtClient2
+ def self.invoke_y_on(foo)
+ return foo.y
+ end
+
+ def self.invoke_a_on(foo)
+ return foo.a
+ end
+ end
+ EOF
+
+ def test_override
+ foo = Foo.new
+ assert_equal("Foo#x", foo.x)
+ assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
+ assert_equal("Foo#x", foo.x)
+ end
+
+ def test_super
+ foo = Foo.new
+ assert_equal("Foo#y", foo.y)
+ assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
+ assert_equal("Foo#y", foo.y)
+ end
+
+ def test_super_not_chained
+ foo = Foo.new
+ assert_equal("Foo#y", foo.y)
+ assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo))
+ assert_equal("Foo#y", foo.y)
+ end
+
+ def test_using_same_class_refinements
+ foo = Foo.new
+ assert_equal("Foo#a", foo.a)
+ assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo))
+ assert_equal("Foo#a", foo.a)
+ end
+
+ def test_new_method
+ foo = Foo.new
+ assert_raise(NoMethodError) { foo.z }
+ assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
+ assert_raise(NoMethodError) { foo.z }
+ end
+
+ module RespondTo
+ class Super
+ def foo
+ end
+ end
+
+ class Sub < Super
+ end
+
+ module M
+ refine Sub do
+ def foo
+ end
+ end
+ end
+ end
+
+ def test_send_should_not_use_refinements
+ foo = Foo.new
+ assert_raise(NoMethodError) { foo.send(:z) }
+ assert_raise(NoMethodError) { FooExtClient.send_z_on(foo) }
+ assert_raise(NoMethodError) { foo.send(:z) }
+
+ assert_equal(true, RespondTo::Sub.new.respond_to?(:foo))
+ end
+
+ def test_method_should_not_use_refinements
+ foo = Foo.new
+ assert_raise(NameError) { foo.method(:z) }
+ assert_raise(NameError) { FooExtClient.method_z(foo) }
+ assert_raise(NameError) { foo.method(:z) }
+ end
+
+ def test_no_local_rebinding
+ foo = Foo.new
+ assert_equal("Foo#x", foo.call_x)
+ assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
+ assert_equal("Foo#x", foo.call_x)
+ end
+
+ def test_subclass_is_prior
+ sub = FooSub.new
+ assert_equal("FooSub#x", sub.x)
+ assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
+ assert_equal("FooSub#x", sub.x)
+ end
+
+ def test_super_in_subclass
+ sub = FooSub.new
+ assert_equal("FooSub#y Foo#y", sub.y)
+ # not "FooSub#y FooExt#y Foo#y"
+ assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
+ assert_equal("FooSub#y Foo#y", sub.y)
+ end
+
+ def test_new_method_on_subclass
+ sub = FooSub.new
+ assert_raise(NoMethodError) { sub.z }
+ assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
+ assert_raise(NoMethodError) { sub.z }
+ end
+
+ def test_module_eval
+ foo = Foo.new
+ assert_equal("Foo#x", foo.x)
+ assert_equal("Foo#x", FooExt.module_eval { foo.x })
+ assert_equal("Foo#x", FooExt.module_eval("foo.x"))
+ assert_equal("Foo#x", foo.x)
+ end
+
+ def test_instance_eval_without_refinement
+ foo = Foo.new
+ ext_client = FooExtClient.new
+ assert_equal("Foo#x", foo.x)
+ assert_equal("Foo#x", ext_client.instance_eval { foo.x })
+ assert_equal("Foo#x", foo.x)
+ end
+
+ module FixnumSlashExt
+ refine Fixnum do
+ def /(other) quo(other) end
+ end
+ end
+
+ def test_override_builtin_method
+ assert_equal(0, 1 / 2)
+ assert_equal(Rational(1, 2), eval_using(FixnumSlashExt, "1 / 2"))
+ assert_equal(0, 1 / 2)
+ end
+
+ module FixnumPlusExt
+ refine Fixnum do
+ def self.method_added(*args); end
+ def +(other) "overridden" end
+ end
+ end
+
+ def test_override_builtin_method_with_method_added
+ assert_equal(3, 1 + 2)
+ assert_equal("overridden", eval_using(FixnumPlusExt, "1 + 2"))
+ assert_equal(3, 1 + 2)
+ end
+
+ def test_return_value_of_refine
+ mod = nil
+ result = nil
+ Module.new {
+ result = refine(Object) {
+ mod = self
+ }
+ }
+ assert_equal mod, result
+ end
+
+ module RefineSameClass
+ REFINEMENT1 = refine(Fixnum) {
+ def foo; return "foo" end
+ }
+ REFINEMENT2 = refine(Fixnum) {
+ def bar; return "bar" end
+ }
+ REFINEMENT3 = refine(String) {
+ def baz; return "baz" end
+ }
+ end
+
+ def test_refine_same_class_twice
+ assert_equal("foo", eval_using(RefineSameClass, "1.foo"))
+ assert_equal("bar", eval_using(RefineSameClass, "1.bar"))
+ assert_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT2)
+ assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3)
+ end
+
+ module FixnumFooExt
+ refine Fixnum do
+ def foo; "foo"; end
+ end
+ end
+
+ def test_respond_to_should_not_use_refinements
+ assert_equal(false, 1.respond_to?(:foo))
+ assert_equal(false, eval_using(FixnumFooExt, "1.respond_to?(:foo)"))
+ end
+
+ module StringCmpExt
+ refine String do
+ def <=>(other) return 0 end
+ end
+ end
+
+ module ArrayEachExt
+ refine Array do
+ def each
+ super do |i|
+ yield 2 * i
+ end
+ end
+ end
+ end
+
+ def test_builtin_method_no_local_rebinding
+ assert_equal(false, eval_using(StringCmpExt, '"1" >= "2"'))
+ assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min"))
+ end
+
+ module RefinePrependedClass
+ module M1
+ def foo
+ super << :m1
+ end
+ end
+
+ class C
+ prepend M1
+
+ def foo
+ [:c]
+ end
+ end
+
+ module M2
+ refine C do
+ def foo
+ super << :m2
+ end
+ end
+ end
+ end
+
+ def test_refine_prepended_class
+ x = eval_using(RefinePrependedClass::M2,
+ "TestRefinement::RefinePrependedClass::C.new.foo")
+ assert_equal([:c, :m1, :m2], x)
+ end
+
+ def test_refine_module
+ m1 = Module.new
+ assert_raise(TypeError) do
+ Module.new {
+ refine m1 do
+ def foo
+ :m2
+ end
+ end
+ }
+ end
+ end
+
+ def test_refine_neither_class_nor_module
+ assert_raise(TypeError) do
+ Module.new {
+ refine Object.new do
+ end
+ }
+ end
+ assert_raise(TypeError) do
+ Module.new {
+ refine 123 do
+ end
+ }
+ end
+ assert_raise(TypeError) do
+ Module.new {
+ refine "foo" do
+ end
+ }
+ end
+ end
+
+ def test_refine_in_class
+ assert_raise(NoMethodError) do
+ Class.new {
+ refine Fixnum do
+ def foo
+ "c"
+ end
+ end
+ }
+ end
+ end
+
+ def test_main_using
+ assert_in_out_err([], <<-INPUT, %w(:C :M), [])
+ class C
+ def foo
+ :C
+ end
+ end
+
+ module M
+ refine C do
+ def foo
+ :M
+ end
+ end
+ end
+
+ c = C.new
+ p c.foo
+ using M
+ p c.foo
+ INPUT
+ end
+
+ def test_main_using_is_private
+ assert_raise(NoMethodError) do
+ eval("self.using Module.new", TOPLEVEL_BINDING)
+ end
+ end
+
+ def test_no_kernel_using
+ assert_raise(NoMethodError) do
+ using Module.new
+ end
+ end
+
+ class UsingClass
+ end
+
+ def test_module_using_class
+ assert_raise(TypeError) do
+ eval("using TestRefinement::UsingClass", TOPLEVEL_BINDING)
+ end
+ end
+
+ def test_refine_without_block
+ c1 = Class.new
+ assert_raise_with_message(ArgumentError, "no block given") {
+ Module.new do
+ refine c1
+ end
+ }
+ end
+
+ module Inspect
+ module M
+ Fixnum = refine(Fixnum) {}
+ end
+ end
+
+ def test_inspect
+ assert_equal("#<refinement:Fixnum@TestRefinement::Inspect::M>",
+ Inspect::M::Fixnum.inspect)
+ end
+
+ def test_using_method_cache
+ assert_in_out_err([], <<-INPUT, %w(:M1 :M2), [])
+ class C
+ def foo
+ "original"
+ end
+ end
+
+ module M1
+ refine C do
+ def foo
+ :M1
+ end
+ end
+ end
+
+ module M2
+ refine C do
+ def foo
+ :M2
+ end
+ end
+ end
+
+ c = C.new
+ using M1
+ p c.foo
+ using M2
+ p c.foo
+ INPUT
+ end
+
+ module RedefineRefinedMethod
+ class C
+ def foo
+ "original"
+ end
+ end
+
+ module M
+ refine C do
+ def foo
+ "refined"
+ end
+ end
+ end
+
+ class C
+ def foo
+ "redefined"
+ end
+ end
+ end
+
+ def test_redefine_refined_method
+ x = eval_using(RedefineRefinedMethod::M,
+ "TestRefinement::RedefineRefinedMethod::C.new.foo")
+ assert_equal("refined", x)
+ end
+
+ module StringExt
+ refine String do
+ def foo
+ "foo"
+ end
+ end
+ end
+
+ module RefineScoping
+ refine String do
+ def foo
+ "foo"
+ end
+
+ def RefineScoping.call_in_refine_block
+ "".foo
+ end
+ end
+
+ def self.call_outside_refine_block
+ "".foo
+ end
+ end
+
+ def test_refine_scoping
+ assert_equal("foo", RefineScoping.call_in_refine_block)
+ assert_raise(NoMethodError) do
+ RefineScoping.call_outside_refine_block
+ end
+ end
+
+ module StringRecursiveLength
+ refine String do
+ def recursive_length
+ if empty?
+ 0
+ else
+ self[1..-1].recursive_length + 1
+ end
+ end
+ end
+ end
+
+ def test_refine_recursion
+ x = eval_using(StringRecursiveLength, "'foo'.recursive_length")
+ assert_equal(3, x)
+ end
+
+ module ToJSON
+ refine Integer do
+ def to_json; to_s; end
+ end
+
+ refine Array do
+ def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end
+ end
+
+ refine Hash do
+ def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end
+ end
+ end
+
+ def test_refine_mutual_recursion
+ x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json")
+ assert_equal('[{"1":2},{"3":4}]', x)
+ end
+
+ def test_refine_with_proc
+ assert_raise(ArgumentError) do
+ Module.new {
+ refine(String, &Proc.new {})
+ }
+ end
+ end
+
+ def test_using_in_module
+ assert_raise(RuntimeError) do
+ eval(<<-EOF, TOPLEVEL_BINDING)
+ $main = self
+ module M
+ end
+ module M2
+ $main.send(:using, M)
+ end
+ EOF
+ end
+ end
+
+ def test_using_in_method
+ assert_raise(RuntimeError) do
+ eval(<<-EOF, TOPLEVEL_BINDING)
+ $main = self
+ module M
+ end
+ def call_using_in_method
+ $main.send(:using, M)
+ end
+ call_using_in_method
+ EOF
+ end
+ end
+
+ module IncludeIntoRefinement
+ class C
+ def bar
+ return "C#bar"
+ end
+
+ def baz
+ return "C#baz"
+ end
+ end
+
+ module Mixin
+ def foo
+ return "Mixin#foo"
+ end
+
+ def bar
+ return super << " Mixin#bar"
+ end
+
+ def baz
+ return super << " Mixin#baz"
+ end
+ end
+
+ module M
+ refine C do
+ include Mixin
+
+ def baz
+ return super << " M#baz"
+ end
+ end
+ end
+ end
+
+ eval <<-EOF, TOPLEVEL_BINDING
+ using TestRefinement::IncludeIntoRefinement::M
+
+ module TestRefinement::IncludeIntoRefinement::User
+ def self.invoke_foo_on(x)
+ x.foo
+ end
+
+ def self.invoke_bar_on(x)
+ x.bar
+ end
+
+ def self.invoke_baz_on(x)
+ x.baz
+ end
+ end
+ EOF
+
+ def test_include_into_refinement
+ x = IncludeIntoRefinement::C.new
+ assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x))
+ assert_equal("C#bar Mixin#bar",
+ IncludeIntoRefinement::User.invoke_bar_on(x))
+ assert_equal("C#baz Mixin#baz M#baz",
+ IncludeIntoRefinement::User.invoke_baz_on(x))
+ end
+
+ module PrependIntoRefinement
+ class C
+ def bar
+ return "C#bar"
+ end
+
+ def baz
+ return "C#baz"
+ end
+ end
+
+ module Mixin
+ def foo
+ return "Mixin#foo"
+ end
+
+ def bar
+ return super << " Mixin#bar"
+ end
+
+ def baz
+ return super << " Mixin#baz"
+ end
+ end
+
+ module M
+ refine C do
+ prepend Mixin
+
+ def baz
+ return super << " M#baz"
+ end
+ end
+ end
+ end
+
+ eval <<-EOF, TOPLEVEL_BINDING
+ using TestRefinement::PrependIntoRefinement::M
+
+ module TestRefinement::PrependIntoRefinement::User
+ def self.invoke_foo_on(x)
+ x.foo
+ end
+
+ def self.invoke_bar_on(x)
+ x.bar
+ end
+
+ def self.invoke_baz_on(x)
+ x.baz
+ end
+ end
+ EOF
+
+ def test_prepend_into_refinement
+ x = PrependIntoRefinement::C.new
+ assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x))
+ assert_equal("C#bar Mixin#bar",
+ PrependIntoRefinement::User.invoke_bar_on(x))
+ assert_equal("C#baz M#baz Mixin#baz",
+ PrependIntoRefinement::User.invoke_baz_on(x))
+ end
+
+ module PrependAfterRefine
+ class C
+ def foo
+ "original"
+ end
+ end
+
+ module M
+ refine C do
+ def foo
+ "refined"
+ end
+
+ def bar
+ "refined"
+ end
+ end
+ end
+
+ module Mixin
+ def foo
+ "mixin"
+ end
+
+ def bar
+ "mixin"
+ end
+ end
+
+ class C
+ prepend Mixin
+ end
+ end
+
+ def test_prepend_after_refine
+ x = eval_using(PrependAfterRefine::M,
+ "TestRefinement::PrependAfterRefine::C.new.foo")
+ assert_equal("refined", x)
+ assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo)
+ y = eval_using(PrependAfterRefine::M,
+ "TestRefinement::PrependAfterRefine::C.new.bar")
+ assert_equal("refined", y)
+ assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar)
+ end
+
+ module SuperInBlock
+ class C
+ def foo(*args)
+ [:foo, *args]
+ end
+ end
+
+ module R
+ refine C do
+ def foo(*args)
+ tap do
+ return super(:ref, *args)
+ end
+ end
+ end
+ end
+ end
+
+ def test_super_in_block
+ bug7925 = '[ruby-core:52750] [Bug #7925]'
+ x = eval_using(SuperInBlock::R,
+ "TestRefinement:: SuperInBlock::C.new.foo(#{bug7925.dump})")
+ assert_equal([:foo, :ref, bug7925], x, bug7925)
+ end
+
+ module ModuleUsing
+ using FooExt
+
+ def self.invoke_x_on(foo)
+ return foo.x
+ end
+
+ def self.invoke_y_on(foo)
+ return foo.y
+ end
+
+ def self.invoke_z_on(foo)
+ return foo.z
+ end
+
+ def self.send_z_on(foo)
+ return foo.send(:z)
+ end
+
+ def self.method_z(foo)
+ return foo.method(:z)
+ end
+
+ def self.invoke_call_x_on(foo)
+ return foo.call_x
+ end
+ end
+
+ def test_module_using
+ foo = Foo.new
+ assert_equal("Foo#x", foo.x)
+ assert_equal("Foo#y", foo.y)
+ assert_raise(NoMethodError) { foo.z }
+ assert_equal("FooExt#x", ModuleUsing.invoke_x_on(foo))
+ assert_equal("FooExt#y Foo#y", ModuleUsing.invoke_y_on(foo))
+ assert_equal("FooExt#z", ModuleUsing.invoke_z_on(foo))
+ assert_equal("Foo#x", foo.x)
+ assert_equal("Foo#y", foo.y)
+ assert_raise(NoMethodError) { foo.z }
+ end
+
+ def test_module_using_in_method
+ assert_raise(RuntimeError) do
+ Module.new.send(:using, FooExt)
+ end
+ end
+
+ def test_module_using_invalid_self
+ assert_raise(RuntimeError) do
+ eval <<-EOF, TOPLEVEL_BINDING
+ module TestRefinement::TestModuleUsingInvalidSelf
+ Module.new.send(:using, TestRefinement::FooExt)
+ end
+ EOF
+ end
+ end
+
+ class Bar
+ end
+
+ module BarExt
+ refine Bar do
+ def x
+ return "BarExt#x"
+ end
+ end
+ end
+
+ module FooBarExt
+ include FooExt
+ include BarExt
+ end
+
+ module FooBarExtClient
+ using FooBarExt
+
+ def self.invoke_x_on(foo)
+ return foo.x
+ end
+ end
+
+ def test_module_inclusion
+ foo = Foo.new
+ assert_equal("FooExt#x", FooBarExtClient.invoke_x_on(foo))
+ bar = Bar.new
+ assert_equal("BarExt#x", FooBarExtClient.invoke_x_on(bar))
+ end
+
+ module FooFoo2Ext
+ include FooExt
+ include FooExt2
+ end
+
+ module FooFoo2ExtClient
+ using FooFoo2Ext
+
+ def self.invoke_x_on(foo)
+ return foo.x
+ end
+
+ def self.invoke_y_on(foo)
+ return foo.y
+ end
+ end
+
+ def test_module_inclusion2
+ foo = Foo.new
+ assert_equal("FooExt2#x", FooFoo2ExtClient.invoke_x_on(foo))
+ assert_equal("FooExt2#y Foo#y", FooFoo2ExtClient.invoke_y_on(foo))
+ end
+
+ def test_eval_scoping
+ assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "HELLO WORLD"], [])
+ module M
+ refine String do
+ def upcase
+ reverse
+ end
+ end
+ end
+
+ puts "hello world".upcase
+ puts eval(%{using M; "hello world".upcase})
+ puts "hello world".upcase
+ INPUT
+ end
+
+ def test_eval_with_binding_scoping
+ assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "HELLO WORLD"], [])
+ module M
+ refine String do
+ def upcase
+ reverse
+ end
+ end
+ end
+
+ puts "hello world".upcase
+ puts eval(%{using M; "hello world".upcase}, TOPLEVEL_BINDING)
+ puts eval(%{"hello world".upcase}, TOPLEVEL_BINDING)
+ INPUT
+ end
+
+ def test_case_dispatch_is_aware_of_refinements
+ assert_in_out_err([], <<-RUBY, ["refinement used"], [])
+ module RefineSymbol
+ refine Symbol do
+ def ===(other)
+ true
+ end
+ end
+ end
+
+ using RefineSymbol
+
+ case :a
+ when :b
+ puts "refinement used"
+ else
+ puts "refinement not used"
+ end
+ RUBY
+ end
+
+ def test_refine_after_using
+ assert_separately([], <<-"end;")
+ bug8880 = '[ruby-core:57079] [Bug #8880]'
+ module Test
+ refine(String) do
+ end
+ end
+ using Test
+ def t
+ 'Refinements are broken!'.chop!
+ end
+ t
+ module Test
+ refine(String) do
+ def chop!
+ self.sub!(/broken/, 'fine')
+ end
+ end
+ end
+ assert_equal('Refinements are fine!', t, bug8880)
+ end;
+ end
+
+ def test_instance_methods
+ bug8881 = '[ruby-core:57080] [Bug #8881]'
+ assert_not_include(Foo.instance_methods(false), :z, bug8881)
+ assert_not_include(FooSub.instance_methods(true), :z, bug8881)
+ end
+
+ def test_method_defined
+ assert_not_send([Foo, :method_defined?, :z])
+ assert_not_send([FooSub, :method_defined?, :z])
+ end
+
+ def test_undef_refined_method
+ bug8966 = '[ruby-core:57466] [Bug #8966]'
+
+ assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
+ module Foo
+ refine Object do
+ def foo
+ puts "foo"
+ end
+ end
+ end
+
+ using Foo
+
+ class Object
+ begin
+ undef foo
+ rescue Exception => e
+ p e.class
+ end
+ end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
+ module Foo
+ refine Object do
+ def foo
+ puts "foo"
+ end
+ end
+ end
+
+ # without `using Foo'
+
+ class Object
+ begin
+ undef foo
+ rescue Exception => e
+ p e.class
+ end
+ end
+ INPUT
+ end
+
+ def test_refine_undefed_method_and_call
+ assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
+ class Foo
+ def foo
+ end
+
+ undef foo
+ end
+
+ module FooExt
+ refine Foo do
+ def foo
+ end
+ end
+ end
+
+ begin
+ Foo.new.foo
+ rescue => e
+ p e.class
+ end
+ INPUT
+ end
+
+ def test_refine_undefed_method_and_send
+ assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
+ class Foo
+ def foo
+ end
+
+ undef foo
+ end
+
+ module FooExt
+ refine Foo do
+ def foo
+ end
+ end
+ end
+
+ begin
+ Foo.new.send(:foo)
+ rescue => e
+ p e.class
+ end
+ INPUT
+ end
+
+ def test_adding_private_method
+ bug9452 = '[ruby-core:60111] [Bug #9452]'
+
+ assert_in_out_err([], <<-INPUT, ["Success!", "NoMethodError"], [], bug9452)
+ module R
+ refine Object do
+ def m
+ puts "Success!"
+ end
+
+ private(:m)
+ end
+ end
+
+ using R
+
+ m
+ 42.m rescue p($!.class)
+ INPUT
+ end
+
+ def test_making_private_method_public
+ bug9452 = '[ruby-core:60111] [Bug #9452]'
+
+ assert_in_out_err([], <<-INPUT, ["Success!", "Success!"], [], bug9452)
+ class Object
+ private
+ def m
+ end
+ end
+
+ module R
+ refine Object do
+ def m
+ puts "Success!"
+ end
+ end
+ end
+
+ using R
+ m
+ 42.m
+ INPUT
+ end
+
+ def test_refine_basic_object
+ assert_separately([], <<-"end;")
+ bug10106 = '[ruby-core:64166] [Bug #10106]'
+ module RefinementBug
+ refine BasicObject do
+ def foo
+ 1
+ end
+ end
+ end
+
+ assert_raise(NoMethodError, bug10106) {Object.new.foo}
+ end;
+
+ assert_separately([], <<-"end;")
+ bug10707 = '[ruby-core:67389] [Bug #10707]'
+ module RefinementBug
+ refine BasicObject do
+ def foo
+ end
+ end
+ end
+
+ assert(methods, bug10707)
+ assert_raise(NameError, bug10707) {method(:foo)}
+ end;
+ end
+
+ def test_change_refined_new_method_visibility
+ assert_separately([], <<-"end;")
+ bug10706 = '[ruby-core:67387] [Bug #10706]'
+ module RefinementBug
+ refine Object do
+ def foo
+ end
+ end
+ end
+
+ assert_raise(NameError, bug10706) {private(:foo)}
+ end;
+ end
+
+ def test_alias_refined_method
+ assert_separately([], <<-"end;")
+ bug10731 = '[ruby-core:67523] [Bug #10731]'
+
+ class C
+ end
+
+ module RefinementBug
+ refine C do
+ def foo
+ end
+
+ def bar
+ end
+ end
+ end
+
+ assert_raise(NameError, bug10731) do
+ class C
+ alias foo bar
+ end
+ end
+ end;
+ end
+
+ def test_singleton_method_should_not_use_refinements
+ assert_separately([], <<-"end;")
+ bug10744 = '[ruby-core:67603] [Bug #10744]'
+
+ class C
+ end
+
+ module RefinementBug
+ refine C.singleton_class do
+ def foo
+ end
+ end
+ end
+
+ assert_raise(NameError, bug10744) { C.singleton_method(:foo) }
+ end;
+ end
+
+ def test_refined_method_defined
+ assert_separately([], <<-"end;")
+ bug10753 = '[ruby-core:67656] [Bug #10753]'
+
+ c = Class.new do
+ def refined_public; end
+ def refined_protected; end
+ def refined_private; end
+
+ public :refined_public
+ protected :refined_protected
+ private :refined_private
+ end
+
+ m = Module.new do
+ refine(c) do
+ def refined_public; end
+ def refined_protected; end
+ def refined_private; end
+
+ public :refined_public
+ protected :refined_protected
+ private :refined_private
+ end
+ end
+
+ using m
+
+ assert_equal(true, c.public_method_defined?(:refined_public), bug10753)
+ assert_equal(false, c.public_method_defined?(:refined_protected), bug10753)
+ assert_equal(false, c.public_method_defined?(:refined_private), bug10753)
+
+ assert_equal(false, c.protected_method_defined?(:refined_public), bug10753)
+ assert_equal(true, c.protected_method_defined?(:refined_protected), bug10753)
+ assert_equal(false, c.protected_method_defined?(:refined_private), bug10753)
+
+ assert_equal(false, c.private_method_defined?(:refined_public), bug10753)
+ assert_equal(false, c.private_method_defined?(:refined_protected), bug10753)
+ assert_equal(true, c.private_method_defined?(:refined_private), bug10753)
+ end;
+ end
+
+ def test_undefined_refined_method_defined
+ assert_separately([], <<-"end;")
+ bug10753 = '[ruby-core:67656] [Bug #10753]'
+
+ c = Class.new
+
+ m = Module.new do
+ refine(c) do
+ def undefined_refined_public; end
+ def undefined_refined_protected; end
+ def undefined_refined_private; end
+ public :undefined_refined_public
+ protected :undefined_refined_protected
+ private :undefined_refined_private
+ end
+ end
+
+ using m
+
+ assert_equal(false, c.public_method_defined?(:undefined_refined_public), bug10753)
+ assert_equal(false, c.public_method_defined?(:undefined_refined_protected), bug10753)
+ assert_equal(false, c.public_method_defined?(:undefined_refined_private), bug10753)
+
+ assert_equal(false, c.protected_method_defined?(:undefined_refined_public), bug10753)
+ assert_equal(false, c.protected_method_defined?(:undefined_refined_protected), bug10753)
+ assert_equal(false, c.protected_method_defined?(:undefined_refined_private), bug10753)
+
+ assert_equal(false, c.private_method_defined?(:undefined_refined_public), bug10753)
+ assert_equal(false, c.private_method_defined?(:undefined_refined_protected), bug10753)
+ assert_equal(false, c.private_method_defined?(:undefined_refined_private), bug10753)
+ end;
+ end
+
+ def test_remove_refined_method
+ assert_separately([], <<-"end;")
+ bug10765 = '[ruby-core:67722] [Bug #10765]'
+
+ class C
+ def foo
+ "C#foo"
+ end
+ end
+
+ module RefinementBug
+ refine C do
+ def foo
+ "RefinementBug#foo"
+ end
+ end
+ end
+
+ using RefinementBug
+
+ class C
+ remove_method :foo
+ end
+
+ assert_equal("RefinementBug#foo", C.new.foo, bug10765)
+ end;
+ end
+
+ def test_remove_undefined_refined_method
+ assert_separately([], <<-"end;")
+ bug10765 = '[ruby-core:67722] [Bug #10765]'
+
+ class C
+ end
+
+ module RefinementBug
+ refine C do
+ def foo
+ end
+ end
+ end
+
+ using RefinementBug
+
+ assert_raise(NameError, bug10765) {
+ class C
+ remove_method :foo
+ end
+ }
+ end;
+ end
+
+ module NotIncludeSuperclassMethod
+ class X
+ def foo
+ end
+ end
+
+ class Y < X
+ end
+
+ module Bar
+ refine Y do
+ def foo
+ end
+ end
+ end
+ end
+
+ def test_instance_methods_not_include_superclass_method
+ bug10826 = '[ruby-dev:48854] [Bug #10826]'
+ assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false),
+ :foo, bug10826)
+ assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true),
+ :foo, bug10826)
+ end
+
+ def test_call_refined_method_in_duplicate_module
+ bug10885 = '[ruby-dev:48878]'
+ assert_in_out_err([], <<-INPUT, [], [], bug10885)
+ module M
+ refine Object do
+ def raise
+ # do nothing
+ end
+ end
+
+ class << self
+ using M
+ def m0
+ raise
+ end
+ end
+
+ using M
+ def M.m1
+ raise
+ end
+ end
+
+ M.dup.m0
+ M.dup.m1
+ INPUT
+ end
+
+ def test_check_funcall_undefined
+ bug11117 = '[ruby-core:69064] [Bug #11117]'
+
+ x = Class.new
+ Module.new do
+ refine x do
+ def to_regexp
+ //
+ end
+ end
+ end
+
+ assert_nothing_raised(NoMethodError, bug11117) {
+ assert_nil(Regexp.try_convert(x.new))
+ }
+ end
+
+ def test_funcall_inherited
+ bug11117 = '[ruby-core:69064] [Bug #11117]'
+
+ Module.new {refine(Dir) {def to_s; end}}
+ x = Class.new(Dir).allocate
+ assert_nothing_raised(NoMethodError, bug11117) {
+ x.inspect
+ }
+ end
+
+ private
+
+ def eval_using(mod, s)
+ eval("using #{mod}; #{s}", TOPLEVEL_BINDING)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_regexp.rb b/jni/ruby/test/ruby/test_regexp.rb
new file mode 100644
index 0000000..cef21b9
--- /dev/null
+++ b/jni/ruby/test/ruby/test_regexp.rb
@@ -0,0 +1,1102 @@
+# coding: US-ASCII
+require 'test/unit'
+
+class TestRegexp < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def test_has_NOENCODING
+ assert Regexp::NOENCODING
+ re = //n
+ assert_equal Regexp::NOENCODING, re.options
+ end
+
+ def test_ruby_dev_999
+ assert_match(/(?<=a).*b/, "aab")
+ assert_match(/(?<=\u3042).*b/, "\u3042ab")
+ end
+
+ def test_ruby_core_27247
+ assert_match(/(a){2}z/, "aaz")
+ end
+
+ def test_ruby_dev_24643
+ assert_nothing_raised("[ruby-dev:24643]") {
+ /(?:(?:[a]*[a])?b)*a*$/ =~ "aabaaca"
+ }
+ end
+
+ def test_ruby_talk_116455
+ assert_match(/^(\w{2,}).* ([A-Za-z\xa2\xc0-\xff]{2,}?)$/n, "Hallo Welt")
+ end
+
+ def test_ruby_dev_24887
+ assert_equal("a".gsub(/a\Z/, ""), "")
+ end
+
+ def test_yoshidam_net_20041111_1
+ s = "[\xC2\xA0-\xC3\xBE]"
+ assert_match(Regexp.new(s, nil, "u"), "\xC3\xBE")
+ end
+
+ def test_yoshidam_net_20041111_2
+ assert_raise(RegexpError) do
+ s = "[\xFF-\xFF]".force_encoding("utf-8")
+ Regexp.new(s, nil, "u")
+ end
+ end
+
+ def test_ruby_dev_31309
+ assert_equal('Ruby', 'Ruby'.sub(/[^a-z]/i, '-'))
+ end
+
+ def test_assert_normal_exit
+ # moved from knownbug. It caused core.
+ Regexp.union("a", "a")
+ end
+
+ def test_to_s
+ assert_equal '(?-mix:\x00)', Regexp.new("\0").to_s
+
+ str = "abcd\u3042"
+ [:UTF_16BE, :UTF_16LE, :UTF_32BE, :UTF_32LE].each do |es|
+ enc = Encoding.const_get(es)
+ rs = Regexp.new(str.encode(enc)).to_s
+ assert_equal("(?-mix:abcd\u3042)".encode(enc), rs)
+ assert_equal(enc, rs.encoding)
+ end
+ end
+
+ def test_union
+ assert_equal :ok, begin
+ Regexp.union(
+ "a",
+ Regexp.new("\xc2\xa1".force_encoding("euc-jp")),
+ Regexp.new("\xc2\xa1".force_encoding("utf-8")))
+ :ng
+ rescue ArgumentError
+ :ok
+ end
+ end
+
+ def test_word_boundary
+ assert_match(/\u3042\b /, "\u3042 ")
+ assert_not_match(/\u3042\ba/, "\u3042a")
+ end
+
+ def test_named_capture
+ m = /&(?<foo>.*?);/.match("aaa &amp; 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 &amp; yyy".sub(/&(?<foo>.*?);/, '[\k<foo>]'))
+
+ assert_equal('#<MatchData "&amp; y" foo:"amp">',
+ /&(?<foo>.*?); (y)/.match("aaa &amp; yyy").inspect)
+ assert_equal('#<MatchData "&amp; y" 1:"amp" 2:"y">',
+ /&(.*?); (y)/.match("aaa &amp; yyy").inspect)
+ assert_equal('#<MatchData "&amp; y" foo:"amp" bar:"y">',
+ /&(?<foo>.*?); (?<bar>y)/.match("aaa &amp; yyy").inspect)
+ assert_equal('#<MatchData "&amp; y" foo:"amp" foo:"y">',
+ /&(?<foo>.*?); (?<foo>y)/.match("aaa &amp; yyy").inspect)
+
+ /(?<id>[A-Za-z_]+)/ =~ "!abc"
+ assert_equal("abc", Regexp.last_match(:id))
+
+ /a/ =~ "b" # doesn't match.
+ assert_equal(nil, Regexp.last_match)
+ assert_equal(nil, Regexp.last_match(1))
+ assert_equal(nil, Regexp.last_match(:foo))
+
+ assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.names)
+ assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.names)
+ assert_equal([], /(.)(.)/.names)
+
+ assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.match("ab").names)
+ assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.match("ab").names)
+ assert_equal([], /(.)(.)/.match("ab").names)
+
+ assert_equal({"foo"=>[1], "bar"=>[2]},
+ /(?<foo>.)(?<bar>.)/.named_captures)
+ assert_equal({"foo"=>[1, 2]},
+ /(?<foo>.)(?<foo>.)/.named_captures)
+ assert_equal({}, /(.)(.)/.named_captures)
+
+ assert_equal("a[b]c", "abc".sub(/(?<x>[bc])/, "[\\k<x>]"))
+
+ assert_equal("o", "foo"[/(?<bar>o)/, "bar"])
+
+ s = "foo"
+ s[/(?<bar>o)/, "bar"] = "baz"
+ assert_equal("fbazo", s)
+ end
+
+ def test_named_capture_with_nul
+ bug9902 = '[ruby-dev:48275] [Bug #9902]'
+
+ m = /(?<a>.*)/.match("foo")
+ assert_raise(IndexError, bug9902) {m["a\0foo"]}
+ assert_raise(IndexError, bug9902) {m["a\0foo".to_sym]}
+
+ m = Regexp.new("(?<foo\0bar>.*)").match("xxx")
+ assert_raise(IndexError, bug9902) {m["foo"]}
+ assert_raise(IndexError, bug9902) {m["foo".to_sym]}
+ assert_nothing_raised(IndexError, bug9902) {
+ assert_equal("xxx", m["foo\0bar"], bug9902)
+ assert_equal("xxx", m["foo\0bar".to_sym], bug9902)
+ }
+ end
+
+ def test_named_capture_nonascii
+ bug9903 = '[ruby-dev:48278] [Bug #9903]'
+
+ key = "\xb1\xb2".force_encoding(Encoding::EUC_JP)
+ m = /(?<#{key}>.*)/.match("xxx")
+ assert_equal("xxx", m[key])
+ assert_raise(IndexError, bug9903) {m[key.dup.force_encoding(Encoding::Shift_JIS)]}
+ end
+
+ def test_assign_named_capture
+ assert_equal("a", eval('/(?<foo>.)/ =~ "a"; foo'))
+ assert_equal("a", eval('foo = 1; /(?<foo>.)/ =~ "a"; foo'))
+ assert_equal("a", eval('1.times {|foo| /(?<foo>.)/ =~ "a"; break foo }'))
+ assert_nothing_raised { eval('/(?<Foo>.)/ =~ "a"') }
+ assert_nil(eval('/(?<Foo>.)/ =~ "a"; defined? Foo'))
+ end
+
+ def test_assign_named_capture_to_reserved_word
+ /(?<nil>.)/ =~ "a"
+ assert_not_include(local_variables, :nil, "[ruby-dev:32675]")
+ end
+
+ def test_match_regexp
+ r = /./
+ m = r.match("a")
+ assert_equal(r, m.regexp)
+ re = /foo/
+ assert_equal(re, re.match("foo").regexp)
+ end
+
+ def test_source
+ bug5484 = '[ruby-core:40364]'
+ assert_equal('', //.source)
+ assert_equal('\:', /\:/.source, bug5484)
+ assert_equal(':', %r:\::.source, bug5484)
+ end
+
+ def test_source_escaped
+ expected, result = "$*+.?^|".each_char.map {|c|
+ [
+ ["\\#{c}", "\\#{c}", 1],
+ begin
+ re = eval("%r#{c}\\#{c}#{c}", nil, __FILE__, __LINE__)
+ t = eval("/\\#{c}/", nil, __FILE__, __LINE__).source
+ rescue SyntaxError => e
+ [e, t, nil]
+ else
+ [re.source, t, re =~ "a#{c}a"]
+ end
+ ]
+ }.transpose
+ assert_equal(expected, result)
+ end
+
+ def test_source_escaped_paren
+ bug7610 = '[ruby-core:51088] [Bug #7610]'
+ bug8133 = '[ruby-core:53578] [Bug #8133]'
+ [
+ ["(", ")", bug7610], ["[", "]", bug8133],
+ ["{", "}", bug8133], ["<", ">", bug8133],
+ ].each do |lparen, rparen, bug|
+ s = "\\#{lparen}a\\#{rparen}"
+ assert_equal(/#{s}/, eval("%r#{lparen}#{s}#{rparen}"), bug)
+ end
+ end
+
+ def test_source_unescaped
+ expected, result = "!\"#%&',-/:;=@_`~".each_char.map {|c|
+ [
+ ["#{c}", "\\#{c}", 1],
+ begin
+ re = eval("%r#{c}\\#{c}#{c}", nil, __FILE__, __LINE__)
+ t = eval("%r{\\#{c}}", nil, __FILE__, __LINE__).source
+ rescue SyntaxError => e
+ [e, t, nil]
+ else
+ [re.source, t, re =~ "a#{c}a"]
+ end
+ ]
+ }.transpose
+ assert_equal(expected, result)
+ end
+
+ def test_inspect
+ assert_equal('//', //.inspect)
+ assert_equal('//i', //i.inspect)
+ assert_equal('/\//i', /\//i.inspect)
+ assert_equal('/\//i', %r"#{'/'}"i.inspect)
+ assert_equal('/\/x/i', /\/x/i.inspect)
+ assert_equal('/\x00/i', /#{"\0"}/i.inspect)
+ assert_equal("/\n/i", /#{"\n"}/i.inspect)
+ s = [0xf1, 0xf2, 0xf3].pack("C*")
+ assert_equal('/\/\xF1\xF2\xF3/i', /\/#{s}/i.inspect)
+ end
+
+ def test_char_to_option
+ assert_equal("BAR", "FOOBARBAZ"[/b../i])
+ assert_equal("bar", "foobarbaz"[/ b . . /x])
+ assert_equal("bar\n", "foo\nbar\nbaz"[/b.../m])
+ assert_raise(SyntaxError) { eval('//z') }
+ end
+
+ def test_char_to_option_kcode
+ assert_equal("bar", "foobarbaz"[/b../s])
+ assert_equal("bar", "foobarbaz"[/b../e])
+ assert_equal("bar", "foobarbaz"[/b../u])
+ end
+
+ def test_to_s2
+ assert_equal('(?-mix:foo)', /(?:foo)/.to_s)
+ assert_equal('(?m-ix:foo)', /(?:foo)/m.to_s)
+ assert_equal('(?mi-x:foo)', /(?:foo)/mi.to_s)
+ assert_equal('(?mix:foo)', /(?:foo)/mix.to_s)
+ assert_equal('(?m-ix:foo)', /(?m-ix:foo)/.to_s)
+ assert_equal('(?mi-x:foo)', /(?mi-x:foo)/.to_s)
+ assert_equal('(?mix:foo)', /(?mix:foo)/.to_s)
+ assert_equal('(?mix:)', /(?mix)/.to_s)
+ assert_equal('(?-mix:(?mix:foo) )', /(?mix:foo) /.to_s)
+ end
+
+ def test_casefold_p
+ assert_equal(false, /a/.casefold?)
+ assert_equal(true, /a/i.casefold?)
+ assert_equal(false, /(?i:a)/.casefold?)
+ end
+
+ def test_options
+ assert_equal(Regexp::IGNORECASE, /a/i.options)
+ assert_equal(Regexp::EXTENDED, /a/x.options)
+ assert_equal(Regexp::MULTILINE, /a/m.options)
+ end
+
+ def test_match_init_copy
+ m = /foo/.match("foo")
+ assert_equal(/foo/, m.dup.regexp)
+ assert_raise(TypeError) do
+ m.instance_eval { initialize_copy(nil) }
+ end
+ assert_equal([0, 3], m.offset(0))
+ assert_equal(/foo/, m.dup.regexp)
+ end
+
+ def test_match_size
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ assert_equal(5, m.size)
+ end
+
+ def test_match_offset_begin_end
+ m = /(?<x>b..)/.match("foobarbaz")
+ assert_equal([3, 6], m.offset("x"))
+ assert_equal(3, m.begin("x"))
+ assert_equal(6, m.end("x"))
+ assert_raise(IndexError) { m.offset("y") }
+ assert_raise(IndexError) { m.offset(2) }
+ assert_raise(IndexError) { m.begin(2) }
+ assert_raise(IndexError) { m.end(2) }
+
+ m = /(?<x>q..)?/.match("foobarbaz")
+ assert_equal([nil, nil], m.offset("x"))
+ assert_equal(nil, m.begin("x"))
+ assert_equal(nil, m.end("x"))
+
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ assert_equal([1, 2], m.offset(1))
+ assert_equal([nil, nil], m.offset(2))
+ assert_equal([2, 3], m.offset(3))
+ end
+
+ def test_match_to_s
+ m = /(?<x>b..)/.match("foobarbaz")
+ assert_equal("bar", m.to_s)
+ end
+
+ def test_match_pre_post
+ m = /(?<x>b..)/.match("foobarbaz")
+ assert_equal("foo", m.pre_match)
+ assert_equal("baz", m.post_match)
+ end
+
+ def test_match_array
+ m = /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal(["foobarbaz", "foo", "bar", "baz", nil], m.to_a)
+ end
+
+ def test_match_captures
+ m = /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal(["foo", "bar", "baz", nil], m.captures)
+ end
+
+ def test_match_aref
+ m = /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal("foo", m[1])
+ assert_equal(["foo", "bar", "baz"], m[1..3])
+ assert_nil(m[5])
+ assert_raise(IndexError) { m[:foo] }
+ end
+
+ def test_match_values_at
+ m = /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal(["foo", "bar", "baz"], m.values_at(1, 2, 3))
+ end
+
+ def test_match_string
+ m = /(?<x>b..)/.match("foobarbaz")
+ assert_equal("foobarbaz", m.string)
+ end
+
+ def test_match_inspect
+ m = /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect)
+ end
+
+ def test_initialize
+ assert_raise(ArgumentError) { Regexp.new }
+ assert_equal(/foo/, Regexp.new(/foo/, Regexp::IGNORECASE))
+
+ assert_equal(Encoding.find("US-ASCII"), Regexp.new("b..", nil, "n").encoding)
+ assert_equal("bar", "foobarbaz"[Regexp.new("b..", nil, "n")])
+ assert_equal(//n, Regexp.new("", nil, "n"))
+
+ arg_encoding_none = 32 # ARG_ENCODING_NONE is implementation defined value
+ assert_equal(arg_encoding_none, Regexp.new("", nil, "n").options)
+ assert_equal(arg_encoding_none, Regexp.new("", nil, "N").options)
+
+ assert_raise(RegexpError) { Regexp.new(")(") }
+ end
+
+ def test_unescape
+ assert_raise(ArgumentError) { s = '\\'; /#{ s }/ }
+ assert_equal(/\xFF/n, /#{ s="\\xFF" }/n)
+ assert_equal(/\177/, (s = '\177'; /#{ s }/))
+ assert_raise(ArgumentError) { s = '\u'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u{ ffffffff }'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u{ ffffff }'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u{ ffff X }'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u{ }'; /#{ s }/ }
+ assert_equal("b", "abc"[(s = '\u{0062}'; /#{ s }/)])
+ assert_equal("b", "abc"[(s = '\u0062'; /#{ s }/)])
+ assert_raise(ArgumentError) { s = '\u0'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u000X'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = "\xff" + '\u3042'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\u3042' + [0xff].pack("C"); /#{ s }/ }
+ assert_raise(SyntaxError) { s = ''; eval(%q(/\u#{ s }/)) }
+
+ assert_equal(/a/, eval(%q(s="\u0061";/#{s}/n)))
+ assert_raise(RegexpError) { s = "\u3042"; eval(%q(/#{s}/n)) }
+ assert_raise(RegexpError) { s = "\u0061"; eval(%q(/\u3042#{s}/n)) }
+ assert_raise(RegexpError) { s1=[0xff].pack("C"); s2="\u3042"; eval(%q(/#{s1}#{s2}/)); [s1, s2] }
+
+ assert_raise(ArgumentError) { s = '\x'; /#{ s }/ }
+
+ assert_equal("\xe1", [0x00, 0xe1, 0xff].pack("C*")[/\M-a/])
+ assert_equal("\xdc", [0x00, 0xdc, 0xff].pack("C*")[/\M-\\/])
+ assert_equal("\x8a", [0x00, 0x8a, 0xff].pack("C*")[/\M-\n/])
+ assert_equal("\x89", [0x00, 0x89, 0xff].pack("C*")[/\M-\t/])
+ assert_equal("\x8d", [0x00, 0x8d, 0xff].pack("C*")[/\M-\r/])
+ assert_equal("\x8c", [0x00, 0x8c, 0xff].pack("C*")[/\M-\f/])
+ assert_equal("\x8b", [0x00, 0x8b, 0xff].pack("C*")[/\M-\v/])
+ assert_equal("\x87", [0x00, 0x87, 0xff].pack("C*")[/\M-\a/])
+ assert_equal("\x9b", [0x00, 0x9b, 0xff].pack("C*")[/\M-\e/])
+ assert_equal("\x01", [0x00, 0x01, 0xff].pack("C*")[/\C-a/])
+
+ assert_raise(ArgumentError) { s = '\M'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\M-\M-a'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\M-\\'; /#{ s }/ }
+
+ assert_raise(ArgumentError) { s = '\C'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\c'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\C-\C-a'; /#{ s }/ }
+
+ assert_raise(ArgumentError) { s = '\M-\z'; /#{ s }/ }
+ assert_raise(ArgumentError) { s = '\M-\777'; /#{ s }/ }
+
+ assert_equal("\u3042\u3042", "\u3042\u3042"[(s = "\u3042" + %q(\xe3\x81\x82); /#{s}/)])
+ assert_raise(ArgumentError) { s = "\u3042" + %q(\xe3); /#{s}/ }
+ assert_raise(ArgumentError) { s = "\u3042" + %q(\xe3\xe3); /#{s}/ }
+ assert_raise(ArgumentError) { s = '\u3042' + [0xff].pack("C"); /#{s}/ }
+
+ assert_raise(SyntaxError) { eval("/\u3042/n") }
+
+ s = ".........."
+ 5.times { s.sub!(".", "") }
+ assert_equal(".....", s)
+ end
+
+ def test_equal
+ bug5484 = '[ruby-core:40364]'
+ assert_equal(/abc/, /abc/)
+ assert_not_equal(/abc/, /abc/m)
+ assert_not_equal(/abc/, /abd/)
+ assert_equal(/\/foo/, Regexp.new('/foo'), bug5484)
+ end
+
+ def test_match
+ assert_nil(//.match(nil))
+ assert_equal("abc", /.../.match(:abc)[0])
+ assert_raise(TypeError) { /.../.match(Object.new)[0] }
+ assert_equal("bc", /../.match('abc', 1)[0])
+ assert_equal("bc", /../.match('abc', -2)[0])
+ assert_nil(/../.match("abc", -4))
+ assert_nil(/../.match("abc", 4))
+ assert_equal('\x', /../n.match("\u3042" + '\x', 1)[0])
+
+ r = nil
+ /.../.match("abc") {|m| r = m[0] }
+ assert_equal("abc", r)
+
+ $_ = "abc"; assert_equal(1, ~/bc/)
+ $_ = "abc"; assert_nil(~/d/)
+ $_ = nil; assert_nil(~/./)
+ end
+
+ def test_eqq
+ assert_equal(false, /../ === nil)
+ end
+
+ def test_quote
+ assert_equal("\xff", Regexp.quote([0xff].pack("C")))
+ assert_equal("\\ ", Regexp.quote("\ "))
+ assert_equal("\\t", Regexp.quote("\t"))
+ assert_equal("\\n", Regexp.quote("\n"))
+ assert_equal("\\r", Regexp.quote("\r"))
+ assert_equal("\\f", Regexp.quote("\f"))
+ assert_equal("\\v", Regexp.quote("\v"))
+ assert_equal("\u3042\\t", Regexp.quote("\u3042\t"))
+ assert_equal("\\t\xff", Regexp.quote("\t" + [0xff].pack("C")))
+ end
+
+ def test_try_convert
+ assert_equal(/re/, Regexp.try_convert(/re/))
+ assert_nil(Regexp.try_convert("re"))
+
+ o = Object.new
+ assert_nil(Regexp.try_convert(o))
+ def o.to_regexp() /foo/ end
+ assert_equal(/foo/, Regexp.try_convert(o))
+ end
+
+ def test_union2
+ assert_equal(/(?!)/, Regexp.union)
+ assert_equal(/foo/, Regexp.union(/foo/))
+ assert_equal(/foo/, Regexp.union([/foo/]))
+ assert_equal(/\t/, Regexp.union("\t"))
+ assert_equal(/(?-mix:\u3042)|(?-mix:\u3042)/, Regexp.union(/\u3042/, /\u3042/))
+ assert_equal("\u3041", "\u3041"[Regexp.union(/\u3042/, "\u3041")])
+ end
+
+ def test_dup
+ assert_equal(//, //.dup)
+ assert_raise(TypeError) { //.instance_eval { initialize_copy(nil) } }
+ end
+
+ def test_regsub
+ assert_equal("fooXXXbaz", "foobarbaz".sub!(/bar/, "XXX"))
+ s = [0xff].pack("C")
+ assert_equal(s, "X".sub!(/./, s))
+ assert_equal('\\' + s, "X".sub!(/./, '\\' + s))
+ assert_equal('\k', "foo".sub!(/.../, '\k'))
+ assert_raise(RuntimeError) { "foo".sub!(/(?<x>o)/, '\k<x') }
+ assert_equal('foo[bar]baz', "foobarbaz".sub!(/(b..)/, '[\0]'))
+ assert_equal('foo[foo]baz', "foobarbaz".sub!(/(b..)/, '[\`]'))
+ assert_equal('foo[baz]baz', "foobarbaz".sub!(/(b..)/, '[\\\']'))
+ assert_equal('foo[r]baz', "foobarbaz".sub!(/(b)(.)(.)/, '[\+]'))
+ assert_equal('foo[\\]baz', "foobarbaz".sub!(/(b..)/, '[\\\\]'))
+ assert_equal('foo[\z]baz', "foobarbaz".sub!(/(b..)/, '[\z]'))
+ end
+
+ def test_regsub_K
+ bug8856 = '[ruby-dev:47694] [Bug #8856]'
+ result = "foobarbazquux/foobarbazquux".gsub(/foo\Kbar/, "")
+ assert_equal('foobazquux/foobazquux', result, bug8856)
+ end
+
+ def test_KCODE
+ assert_nil($KCODE)
+ assert_nothing_raised { $KCODE = nil }
+ assert_equal(false, $=)
+ assert_nothing_raised { $= = nil }
+ end
+
+ def test_match_setter
+ /foo/ =~ "foo"
+ m = $~
+ /bar/ =~ "bar"
+ $~ = m
+ assert_equal("foo", $&)
+ end
+
+ def test_match_without_regexp
+ bug10877 = '[ruby-core:68209] [Bug #10877]'
+ "abc".sub("a", "")
+ assert_raise_with_message(IndexError, /foo/, bug10877) {$~["foo"]}
+ key = "\u{3042}"
+ [Encoding::UTF_8, Encoding::Shift_JIS, Encoding::EUC_JP].each do |enc|
+ idx = key.encode(enc)
+ EnvUtil.with_default_external(enc) do
+ assert_raise_with_message(IndexError, /#{idx}/, bug10877) {$~[idx]}
+ end
+ end
+ end
+
+ def test_last_match
+ /(...)(...)(...)(...)?/.match("foobarbaz")
+ assert_equal("foobarbaz", Regexp.last_match(0))
+ assert_equal("foo", Regexp.last_match(1))
+ assert_nil(Regexp.last_match(5))
+ assert_nil(Regexp.last_match(-1))
+ end
+
+ def test_getter
+ alias $__REGEXP_TEST_LASTMATCH__ $&
+ alias $__REGEXP_TEST_PREMATCH__ $`
+ alias $__REGEXP_TEST_POSTMATCH__ $'
+ alias $__REGEXP_TEST_LASTPARENMATCH__ $+
+ /(b)(.)(.)/.match("foobarbaz")
+ assert_equal("bar", $__REGEXP_TEST_LASTMATCH__)
+ assert_equal("foo", $__REGEXP_TEST_PREMATCH__)
+ assert_equal("baz", $__REGEXP_TEST_POSTMATCH__)
+ assert_equal("r", $__REGEXP_TEST_LASTPARENMATCH__)
+
+ /(...)(...)(...)/.match("foobarbaz")
+ assert_equal("baz", $+)
+ end
+
+ def test_rindex_regexp
+ assert_equal(3, "foobarbaz\u3042".rindex(/b../n, 5))
+ end
+
+ def test_taint
+ m = Thread.new do
+ "foo"[/foo/]
+ $SAFE = 3
+ /foo/.match("foo")
+ end.value
+ assert_predicate(m, :tainted?)
+ assert_nothing_raised('[ruby-core:26137]') {
+ m = proc {$SAFE = 3; %r"#{ }"o}.call
+ }
+ assert_predicate(m, :tainted?)
+ end
+
+ def assert_regexp(re, ss, fs = [], msg = nil)
+ re = Regexp.new(re) unless re.is_a?(Regexp)
+ ss = [ss] unless ss.is_a?(Array)
+ ss.each do |e, s|
+ s ||= e
+ assert_match(re, s, msg)
+ m = re.match(s)
+ assert_equal(e, m[0], msg)
+ end
+ fs = [fs] unless fs.is_a?(Array)
+ fs.each {|s| assert_no_match(re, s, msg) }
+ end
+ alias check assert_regexp
+
+ def assert_fail(re)
+ assert_raise(RegexpError) { %r"#{ re }" }
+ end
+ alias failcheck assert_fail
+
+ def test_parse
+ check(/\*\+\?\{\}\|\(\)\<\>\`\'/, "*+?{}|()<>`'")
+ check(/\A\w\W\z/, %w(a. b!), %w(.. ab))
+ check(/\A.\b.\b.\B.\B.\z/, %w(a.aaa .a...), %w(aaaaa .....))
+ check(/\A\s\S\z/, [' a', "\n."], [' ', "\n\n", 'a '])
+ check(/\A\d\D\z/, '0a', %w(00 aa))
+ check(/\A\h\H\z/, %w(0g ag BH), %w(a0 af GG))
+ check(/\Afoo\Z\s\z/, "foo\n", ["foo", "foo\nbar"])
+ assert_equal(%w(a b c), "abc def".scan(/\G\w/))
+ check(/\A\u3042\z/, "\u3042", ["", "\u3043", "a"])
+ check(/\A(..)\1\z/, %w(abab ....), %w(abba aba))
+ failcheck('\1')
+ check(/\A\80\z/, "80", ["\100", ""])
+ check(/\A\77\z/, "?")
+ check(/\A\78\z/, "\7" + '8', ["\100", ""])
+ check(eval('/\A\Qfoo\E\z/'), "QfooE")
+ check(/\Aa++\z/, "aaa")
+ check('\Ax]\z', "x]")
+ check(/x#foo/x, "x", "#foo")
+ check(/\Ax#foo#{ "\n" }x\z/x, "xx", ["x", "x#foo\nx"])
+ check(/\A\p{Alpha}\z/, ["a", "z"], [".", "", ".."])
+ check(/\A\p{^Alpha}\z/, [".", "!"], ["!a", ""])
+ check(/\A\n\z/, "\n")
+ check(/\A\t\z/, "\t")
+ check(/\A\r\z/, "\r")
+ check(/\A\f\z/, "\f")
+ check(/\A\a\z/, "\007")
+ check(/\A\e\z/, "\033")
+ check(/\A\v\z/, "\v")
+ failcheck('(')
+ failcheck('(?foo)')
+ failcheck('/\p{foobarbazqux}/')
+ failcheck('/\p{foobarbazqux' + 'a' * 1000 + '}/')
+ failcheck('/[1-\w]/')
+ end
+
+ def test_exec
+ check(/A*B/, %w(B AB AAB AAAB), %w(A))
+ check(/\w*!/, %w(! a! ab! abc!), %w(abc))
+ check(/\w*\W/, %w(! a" ab# abc$), %w(abc))
+ check(/\w*\w/, %w(z az abz abcz), %w(!))
+ check(/[a-z]*\w/, %w(z az abz abcz), %w(!))
+ check(/[a-z]*\W/, %w(! a" ab# abc$), %w(A))
+ check(/((a|bb|ccc|dddd)(1|22|333|4444))/i, %w(a1 bb1 a22), %w(a2 b1))
+ check(/\u0080/, (1..4).map {|i| ["\u0080", "\u0080" * i] }, ["\u0081"])
+ check(/\u0080\u0080/, (2..4).map {|i| ["\u0080" * 2, "\u0080" * i] }, ["\u0081"])
+ check(/\u0080\u0080\u0080/, (3..4).map {|i| ["\u0080" * 3, "\u0080" * i] }, ["\u0081"])
+ check(/\u0080\u0080\u0080\u0080/, (4..4).map {|i| ["\u0080" * 4, "\u0080" * i] }, ["\u0081"])
+ check(/[^\u3042\u3043\u3044]/, %W(a b \u0080 \u3041 \u3045), %W(\u3042 \u3043 \u3044))
+ check(/a.+/m, %W(a\u0080 a\u0080\u0080 a\u0080\u0080\u0080), %W(a))
+ check(/a.+z/m, %W(a\u0080z a\u0080\u0080z a\u0080\u0080\u0080z), %W(az))
+ check(/abc\B.\Bxyz/, %w(abcXxyz abc0xyz), %w(abc|xyz abc-xyz))
+ check(/\Bxyz/, [%w(xyz abcXxyz), %w(xyz abc0xyz)], %w(abc xyz abc-xyz))
+ check(/abc\B/, [%w(abc abcXxyz), %w(abc abc0xyz)], %w(abc xyz abc-xyz))
+ failcheck('(?<foo>abc)\1')
+ check(/^(A+|B+)(?>\g<1>)*[BC]$/, %w(AC BC ABC BAC AABBC), %w(AABB))
+ check(/^(A+|B(?>\g<1>)*)[AC]$/, %w(AAAC BBBAAAAC), %w(BBBAAA))
+ check(/^()(?>\g<1>)*$/, "", "a")
+ check(/^(?>(?=a)(#{ "a" * 1000 }|))++$/, ["a" * 1000, "a" * 2000, "a" * 3000], ["", "a" * 500, "b" * 1000])
+ check(eval('/^(?:a?)?$/'), ["", "a"], ["aa"])
+ check(eval('/^(?:a+)?$/'), ["", "a", "aa"], ["ab"])
+ check(/^(?:a?)+?$/, ["", "a", "aa"], ["ab"])
+ check(/^a??[ab]/, [["a", "a"], ["a", "aa"], ["b", "b"], ["a", "ab"]], ["c"])
+ check(/^(?:a*){3,5}$/, ["", "a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa"], ["b"])
+ check(/^(?:a+){3,5}$/, ["aaa", "aaaa", "aaaaa", "aaaaaa"], ["", "a", "aa", "b"])
+ end
+
+ def test_parse_look_behind
+ check(/(?<=A)B(?=C)/, [%w(B ABC)], %w(aBC ABc aBc))
+ check(/(?<!A)B(?!C)/, [%w(B aBc)], %w(ABC aBC ABc))
+ failcheck('(?<=.*)')
+ failcheck('(?<!.*)')
+ check(/(?<=A|B.)C/, [%w(C AC), %w(C BXC)], %w(C BC))
+ check(/(?<!A|B.)C/, [%w(C C), %w(C BC)], %w(AC BXC))
+
+ assert_not_match(/(?<!aa|b)c/i, "Aac")
+ assert_not_match(/(?<!b|aa)c/i, "Aac")
+ end
+
+ def test_parse_kg
+ check(/\A(.)(.)\k<1>(.)\z/, %w(abac abab ....), %w(abcd aaba xxx))
+ check(/\A(.)(.)\k<-1>(.)\z/, %w(abbc abba ....), %w(abcd aaba xxx))
+ check(/\A(?<n>.)(?<x>\g<n>){0}(?<y>\k<n+0>){0}\g<x>\g<y>\z/, "aba", "abb")
+ check(/\A(?<n>.)(?<x>\g<n>){0}(?<y>\k<n+1>){0}\g<x>\g<y>\z/, "abb", "aba")
+ check(/\A(?<x>..)\k<x>\z/, %w(abab ....), %w(abac abba xxx))
+ check(/\A(.)(..)\g<-1>\z/, "abcde", %w(.... ......))
+ failcheck('\k<x>')
+ failcheck('\k<')
+ failcheck('\k<>')
+ failcheck('\k<.>')
+ failcheck('\k<x.>')
+ failcheck('\k<1.>')
+ failcheck('\k<x')
+ failcheck('\k<x+')
+ failcheck('()\k<-2>')
+ failcheck('()\g<-2>')
+ check(/\A(?<x>.)(?<x>.)\k<x>\z/, %w(aba abb), %w(abc .. ....))
+ check(/\A(?<x>.)(?<x>.)\k<x>\z/i, %w(aba ABa abb ABb), %w(abc .. ....))
+ check('\k\g', "kg")
+ failcheck('(.\g<1>)')
+ failcheck('(.\g<2>)')
+ failcheck('(?=\g<1>)')
+ failcheck('((?=\g<1>))')
+ failcheck('(\g<1>|.)')
+ failcheck('(.|\g<1>)')
+ check(/(!)(?<=(a)|\g<1>)/, ["!"], %w(a))
+ check(/^(a|b\g<1>c)$/, %w(a bac bbacc bbbaccc), %w(bbac bacc))
+ check(/^(a|b\g<2>c)(B\g<1>C){0}$/, %w(a bBaCc bBbBaCcCc bBbBbBaCcCcCc), %w(bBbBaCcC BbBaCcCc))
+ check(/\A(?<n>.|X\g<n>)(?<x>\g<n>){0}(?<y>\k<n+0>){0}\g<x>\g<y>\z/, "XXaXbXXa", %w(XXabXa abb))
+ check(/\A(?<n>.|X\g<n>)(?<x>\g<n>){0}(?<y>\k<n+1>){0}\g<x>\g<y>\z/, "XaXXbXXb", %w(aXXbXb aba))
+ failcheck('(?<x>)(?<x>)(\g<x>)')
+ check(/^(?<x>foo)(bar)\k<x>/, %w(foobarfoo), %w(foobar barfoo))
+ check(/^(?<a>f)(?<a>o)(?<a>o)(?<a>b)(?<a>a)(?<a>r)(?<a>b)(?<a>a)(?<a>z)\k<a>{9}$/, %w(foobarbazfoobarbaz foobarbazbazbarfoo foobarbazzabraboof), %w(foobar barfoo))
+ end
+
+ def test_parse_curly_brace
+ check(/\A{/, ["{", ["{", "{x"]])
+ check(/\A{ /, ["{ ", ["{ ", "{ x"]])
+ check(/\A{,}\z/, "{,}")
+ check(/\A{}\z/, "{}")
+ check(/\Aa{0}+\z/, "", %w(a aa aab))
+ check(/\Aa{1}+\z/, %w(a aa), ["", "aab"])
+ check(/\Aa{1,2}b{1,2}\z/, %w(ab aab abb aabb), ["", "aaabb", "abbb"])
+ check(/(?!x){0,1}/, [ ['', 'ab'], ['', ''] ])
+ check(/c\z{0,1}/, [ ['c', 'abc'], ['c', 'cab']], ['abd'])
+ check(/\A{0,1}a/, [ ['a', 'abc'], ['a', '____abc']], ['bcd'])
+ failcheck('.{100001}')
+ failcheck('.{0,100001}')
+ failcheck('.{1,0}')
+ failcheck('{0}')
+ end
+
+ def test_parse_comment
+ check(/\A(?#foo\)bar)\z/, "", "a")
+ failcheck('(?#')
+ end
+
+ def test_char_type
+ check(/\u3042\d/, ["\u30421", "\u30422"])
+
+ # CClassTable cache test
+ assert_match(/\u3042\d/, "\u30421")
+ assert_match(/\u3042\d/, "\u30422")
+ end
+
+ def test_char_class
+ failcheck('[]')
+ failcheck('[x')
+ check('\A[]]\z', "]", "")
+ check('\A[]\.]+\z', %w(] . ]..]), ["", "["])
+ check(/\A[\u3042]\z/, "\u3042", "\u3042aa")
+ check(/\A[\u3042\x61]+\z/, ["aa\u3042aa", "\u3042\u3042", "a"], ["", "b"])
+ check(/\A[\u3042\x61\x62]+\z/, "abab\u3042abab\u3042")
+ check(/\A[abc]+\z/, "abcba", ["", "ada"])
+ check(/\A[\w][\W]\z/, %w(a. b!), %w(.. ab))
+ check(/\A[\s][\S]\z/, [' a', "\n."], [' ', "\n\n", 'a '])
+ check(/\A[\d][\D]\z/, '0a', %w(00 aa))
+ check(/\A[\h][\H]\z/, %w(0g ag BH), %w(a0 af GG))
+ check(/\A[\p{Alpha}]\z/, ["a", "z"], [".", "", ".."])
+ check(/\A[\p{^Alpha}]\z/, [".", "!"], ["!a", ""])
+ check(/\A[\xff]\z/, "\xff", ["", "\xfe"])
+ check(/\A[\80]+\z/, "8008", ["\\80", "\100", "\1000"])
+ check(/\A[\77]+\z/, "???")
+ check(/\A[\78]+\z/, "\788\7")
+ check(/\A[\0]\z/, "\0")
+ check(/\A[[:0]]\z/, [":", "0"], ["", ":0"])
+ check(/\A[0-]\z/, ["0", "-"], "0-")
+ check('\A[a-&&\w]\z', "a", "-")
+ check('\A[--0]\z', ["-", "/", "0"], ["", "1"])
+ check('\A[\'--0]\z', %w(* + \( \) 0 ,), ["", ".", "1"])
+ check(/\A[a-b-]\z/, %w(a b -), ["", "c"])
+ check('\A[a-b-&&\w]\z', %w(a b), ["", "-"])
+ check('\A[a-b-&&\W]\z', "-", ["", "a", "b"])
+ check('\A[a-c-e]\z', %w(a b c e -), %w(d))
+ check(/\A[a-f&&[^b-c]&&[^e]]\z/, %w(a d f), %w(b c e g 0))
+ check(/\A[[^b-c]&&[^e]&&a-f]\z/, %w(a d f), %w(b c e g 0))
+ check(/\A[\n\r\t]\z/, ["\n", "\r", "\t"])
+ failcheck('[9-1]')
+
+ assert_match(/\A\d+\z/, "0123456789")
+ assert_no_match(/\d/, "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19")
+ assert_match(/\A\w+\z/, "09azAZ_")
+ assert_no_match(/\w/, "\uff10\uff19\uff41\uff5a\uff21\uff3a")
+ assert_match(/\A\s+\z/, "\r\n\v\f\r\s")
+ assert_no_match(/\s/, "\u0085")
+ end
+
+ def test_posix_bracket
+ check(/\A[[:alpha:]0]\z/, %w(0 a), %w(1 .))
+ check(eval('/\A[[:^alpha:]0]\z/'), %w(0 1 .), "a")
+ check(eval('/\A[[:alpha\:]]\z/'), %w(a l p h a :), %w(b 0 1 .))
+ check(eval('/\A[[:alpha:foo]0]\z/'), %w(0 a), %w(1 .))
+ check(/\A[[:xdigit:]&&[:alpha:]]\z/, "a", %w(g 0))
+ check('\A[[:abcdefghijklmnopqrstu:]]+\z', "[]")
+ failcheck('[[:alpha')
+ failcheck('[[:alpha:')
+ failcheck('[[:alp:]]')
+
+ assert_match(/\A[[:digit:]]+\z/, "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19")
+ assert_match(/\A[[:alnum:]]+\z/, "\uff10\uff19\uff41\uff5a\uff21\uff3a")
+ assert_match(/\A[[:space:]]+\z/, "\r\n\v\f\r\s\u0085")
+ assert_match(/\A[[:ascii:]]+\z/, "\x00\x7F")
+ assert_no_match(/[[:ascii:]]/, "\x80\xFF")
+ end
+
+ def test_backward
+ assert_equal(3, "foobar".rindex(/b.r/i))
+ assert_equal(nil, "foovar".rindex(/b.r/i))
+ assert_equal(3, ("foo" + "bar" * 1000).rindex(/#{"bar"*1000}/))
+ assert_equal(4, ("foo\nbar\nbaz\n").rindex(/bar/i))
+ end
+
+ def test_uninitialized
+ assert_raise(TypeError) { Regexp.allocate.hash }
+ assert_raise(TypeError) { Regexp.allocate.eql? Regexp.allocate }
+ assert_raise(TypeError) { Regexp.allocate == Regexp.allocate }
+ assert_raise(TypeError) { Regexp.allocate =~ "" }
+ assert_equal(false, Regexp.allocate === Regexp.allocate)
+ assert_nil(~Regexp.allocate)
+ assert_raise(TypeError) { Regexp.allocate.match("") }
+ assert_raise(TypeError) { Regexp.allocate.to_s }
+ assert_match(/^#<Regexp:.*>$/, Regexp.allocate.inspect)
+ assert_raise(TypeError) { Regexp.allocate.source }
+ assert_raise(TypeError) { Regexp.allocate.casefold? }
+ assert_raise(TypeError) { Regexp.allocate.options }
+ assert_equal(Encoding.find("ASCII-8BIT"), Regexp.allocate.encoding)
+ assert_equal(false, Regexp.allocate.fixed_encoding?)
+ assert_raise(TypeError) { Regexp.allocate.names }
+ assert_raise(TypeError) { Regexp.allocate.named_captures }
+
+ assert_raise(TypeError) { MatchData.allocate.regexp }
+ assert_raise(TypeError) { MatchData.allocate.names }
+ assert_raise(TypeError) { MatchData.allocate.size }
+ assert_raise(TypeError) { MatchData.allocate.length }
+ assert_raise(TypeError) { MatchData.allocate.offset(0) }
+ assert_raise(TypeError) { MatchData.allocate.begin(0) }
+ assert_raise(TypeError) { MatchData.allocate.end(0) }
+ assert_raise(TypeError) { MatchData.allocate.to_a }
+ assert_raise(TypeError) { MatchData.allocate[:foo] }
+ assert_raise(TypeError) { MatchData.allocate.captures }
+ assert_raise(TypeError) { MatchData.allocate.values_at }
+ assert_raise(TypeError) { MatchData.allocate.pre_match }
+ assert_raise(TypeError) { MatchData.allocate.post_match }
+ assert_raise(TypeError) { MatchData.allocate.to_s }
+ assert_match(/^#<MatchData:.*>$/, MatchData.allocate.inspect)
+ assert_raise(TypeError) { MatchData.allocate.string }
+ $~ = MatchData.allocate
+ assert_raise(TypeError) { $& }
+ assert_raise(TypeError) { $` }
+ assert_raise(TypeError) { $' }
+ assert_raise(TypeError) { $+ }
+ end
+
+ def test_unicode
+ assert_match(/^\u3042{0}\p{Any}$/, "a")
+ assert_match(/^\u3042{0}\p{Any}$/, "\u3041")
+ assert_match(/^\u3042{0}\p{Any}$/, "\0")
+ assert_match(/^\p{Lo}{4}$/u, "\u3401\u4E01\u{20001}\u{2A701}")
+ assert_no_match(/^\u3042{0}\p{Any}$/, "\0\0")
+ assert_no_match(/^\u3042{0}\p{Any}$/, "")
+ assert_raise(SyntaxError) { eval('/^\u3042{0}\p{' + "\u3042" + '}$/') }
+ assert_raise(SyntaxError) { eval('/^\u3042{0}\p{' + 'a' * 1000 + '}$/') }
+ assert_raise(SyntaxError) { eval('/^\u3042{0}\p{foobarbazqux}$/') }
+ assert_match(/^(\uff21)(a)\1\2$/i, "\uff21A\uff41a")
+ assert_no_match(/^(\uff21)\1$/i, "\uff21A")
+ assert_no_match(/^(\uff41)\1$/i, "\uff41a")
+ assert_match(/^\u00df$/i, "\u00df")
+ assert_match(/^\u00df$/i, "ss")
+ #assert_match(/^(\u00df)\1$/i, "\u00dfss") # this must be bug...
+ assert_match(/^\u00df{2}$/i, "\u00dfss")
+ assert_match(/^\u00c5$/i, "\u00c5")
+ assert_match(/^\u00c5$/i, "\u00e5")
+ assert_match(/^\u00c5$/i, "\u212b")
+ assert_match(/^(\u00c5)\1\1$/i, "\u00c5\u00e5\u212b")
+ assert_match(/^\u0149$/i, "\u0149")
+ assert_match(/^\u0149$/i, "\u02bcn")
+ #assert_match(/^(\u0149)\1$/i, "\u0149\u02bcn") # this must be bug...
+ assert_match(/^\u0149{2}$/i, "\u0149\u02bcn")
+ assert_match(/^\u0390$/i, "\u0390")
+ assert_match(/^\u0390$/i, "\u03b9\u0308\u0301")
+ #assert_match(/^(\u0390)\1$/i, "\u0390\u03b9\u0308\u0301") # this must be bug...
+ assert_match(/^\u0390{2}$/i, "\u0390\u03b9\u0308\u0301")
+ assert_match(/^\ufb05$/i, "\ufb05")
+ assert_match(/^\ufb05$/i, "\ufb06")
+ assert_match(/^\ufb05$/i, "st")
+ #assert_match(/^(\ufb05)\1\1$/i, "\ufb05\ufb06st") # this must be bug...
+ assert_match(/^\ufb05{3}$/i, "\ufb05\ufb06st")
+ assert_match(/^\u03b9\u0308\u0301$/i, "\u0390")
+ end
+
+ def test_unicode_age
+ assert_match(/^\p{Age=6.0}$/u, "\u261c")
+ assert_match(/^\p{Age=1.1}$/u, "\u261c")
+ assert_no_match(/^\P{age=6.0}$/u, "\u261c")
+
+ assert_match(/^\p{age=6.0}$/u, "\u31f6")
+ assert_match(/^\p{age=3.2}$/u, "\u31f6")
+ assert_no_match(/^\p{age=3.1}$/u, "\u31f6")
+ assert_no_match(/^\p{age=3.0}$/u, "\u31f6")
+ assert_no_match(/^\p{age=1.1}$/u, "\u31f6")
+
+ assert_match(/^\p{age=6.0}$/u, "\u2754")
+ assert_no_match(/^\p{age=5.0}$/u, "\u2754")
+ assert_no_match(/^\p{age=4.0}$/u, "\u2754")
+ assert_no_match(/^\p{age=3.0}$/u, "\u2754")
+ assert_no_match(/^\p{age=2.0}$/u, "\u2754")
+ assert_no_match(/^\p{age=1.1}$/u, "\u2754")
+ end
+
+ MatchData_A = eval("class MatchData_\u{3042} < MatchData; self; end")
+
+ def test_matchdata
+ a = "haystack".match(/hay/)
+ b = "haystack".match(/hay/)
+ assert_equal(a, b, '[ruby-core:24748]')
+ h = {a => 42}
+ assert_equal(42, h[b], '[ruby-core:24748]')
+ assert_match(/#<TestRegexp::MatchData_\u{3042}:/, MatchData_A.allocate.inspect)
+ end
+
+ def test_regexp_poped
+ assert_nothing_raised { eval("a = 1; /\#{ a }/; a") }
+ assert_nothing_raised { eval("a = 1; /\#{ a }/o; a") }
+ end
+
+ def test_invalid_fragment
+ bug2547 = '[ruby-core:27374]'
+ assert_raise(SyntaxError, bug2547) {eval('/#{"\\\\"}y/')}
+ end
+
+ def test_dup_warn
+ assert_warning(/duplicated/) { Regexp.new('[\u3042\u3043\u3042]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u3042\u3043\u3043]') }
+ assert_warning(/\A\z/) { Regexp.new('[\u3042\u3044\u3043]') }
+ assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3043]') }
+ assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3044]') }
+ assert_warning(/\A\z/) { Regexp.new('[\u3042\u3045\u3043-\u3044]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u3042\u3045\u3042-\u3043]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u3042\u3045\u3044-\u3045]') }
+ assert_warning(/\A\z/) { Regexp.new('[\u3042\u3046\u3044]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u1000-\u2000\u3042-\u3046\u3044]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u3044\u3041-\u3047]') }
+ assert_warning(/duplicated/) { Regexp.new('[\u3042\u3044\u3046\u3041-\u3047]') }
+
+ bug7471 = '[ruby-core:50344]'
+ assert_warning('', bug7471) { Regexp.new('[\D]') =~ "\u3042" }
+
+ bug8151 = '[ruby-core:53649]'
+ assert_warning(/\A\z/, bug8151) { Regexp.new('(?:[\u{33}])').to_s }
+ end
+
+ def test_property_warn
+ assert_in_out_err('-w', 'x=/\p%s/', [], %r"warning: invalid Unicode Property \\p: /\\p%s/")
+ end
+
+ def test_invalid_escape_error
+ bug3539 = '[ruby-core:31048]'
+ error = assert_raise(SyntaxError) {eval('/\x/', nil, bug3539)}
+ assert_match(/invalid hex escape/, error.message)
+ assert_equal(1, error.message.scan(/.*invalid .*escape.*/i).size, bug3539)
+ end
+
+ def test_raw_hyphen_and_tk_char_type_after_range
+ bug6853 = '[ruby-core:47115]'
+ # use Regexp.new instead of literal to ignore a parser warning.
+ check(Regexp.new('[0-1-\\s]'), [' ', '-'], ['2', 'a'], bug6853)
+ end
+
+ def test_error_message_on_failed_conversion
+ bug7539 = '[ruby-core:50733]'
+ assert_equal false, /x/=== 42
+ assert_raise_with_message(TypeError, 'no implicit conversion of Fixnum into String', bug7539) {
+ Regexp.quote(42)
+ }
+ end
+
+ def test_conditional_expression
+ bug8583 = '[ruby-dev:47480] [Bug #8583]'
+
+ conds = {"xy"=>true, "yx"=>true, "xx"=>false, "yy"=>false}
+ assert_match_each(/\A((x)|(y))(?(2)y|x)\z/, conds, bug8583)
+ assert_match_each(/\A((?<x>x)|(?<y>y))(?(<x>)y|x)\z/, conds, bug8583)
+ end
+
+ def test_options_in_look_behind
+ assert_nothing_raised {
+ assert_match_at("(?<=(?i)ab)cd", "ABcd", [[2,4]])
+ assert_match_at("(?<=(?i:ab))cd", "ABcd", [[2,4]])
+ assert_match_at("(?<!(?i)ab)cd", "aacd", [[2,4]])
+ assert_match_at("(?<!(?i:ab))cd", "aacd", [[2,4]])
+
+ assert_not_match("(?<=(?i)ab)cd", "ABCD")
+ assert_not_match("(?<=(?i:ab))cd", "ABCD")
+ assert_not_match("(?<!(?i)ab)cd", "ABcd")
+ assert_not_match("(?<!(?i:ab))cd", "ABcd")
+ }
+ end
+
+ def test_once
+ pr1 = proc{|i| /#{i}/o}
+ assert_equal(/0/, pr1.call(0))
+ assert_equal(/0/, pr1.call(1))
+ assert_equal(/0/, pr1.call(2))
+ end
+
+ def test_once_recursive
+ pr2 = proc{|i|
+ if i > 0
+ /#{pr2.call(i-1).to_s}#{i}/
+ else
+ //
+ end
+ }
+ assert_equal(/(?-mix:(?-mix:(?-mix:)1)2)3/, pr2.call(3))
+ end
+
+ def test_once_multithread
+ m = Mutex.new
+ pr3 = proc{|i|
+ /#{m.unlock; sleep 0.5; i}/o
+ }
+ ary = []
+ n = 0
+ th1 = Thread.new{m.lock; ary << pr3.call(n+=1)}
+ th2 = Thread.new{m.lock; ary << pr3.call(n+=1)}
+ th1.join; th2.join
+ assert_equal([/1/, /1/], ary)
+ end
+
+ def test_once_escape
+ pr4 = proc{|i|
+ catch(:xyzzy){
+ /#{throw :xyzzy, i}/o =~ ""
+ :ng
+ }
+ }
+ assert_equal(0, pr4.call(0))
+ assert_equal(1, pr4.call(1))
+ end
+
+ def test_eq_tilde_can_be_overridden
+ assert_separately([], <<-RUBY)
+ class Regexp
+ undef =~
+ def =~(str)
+ "foo"
+ end
+ end
+
+ assert_equal("foo", // =~ "")
+ RUBY
+ end
+
+ # This assertion is for porting x2() tests in testpy.py of Onigmo.
+ def assert_match_at(re, str, positions, msg = nil)
+ re = Regexp.new(re) unless re.is_a?(Regexp)
+
+ match = re.match(str)
+
+ assert_not_nil match, message(msg) {
+ "Expected #{re.inspect} to match #{str.inspect}"
+ }
+
+ if match
+ actual_positions = (0...match.size).map { |i|
+ [match.begin(i), match.end(i)]
+ }
+
+ assert_equal positions, actual_positions, message(msg) {
+ "Expected #{re.inspect} to match #{str.inspect} at: #{positions.inspect}"
+ }
+ end
+ end
+
+ def assert_match_each(re, conds, msg = nil)
+ errs = conds.select {|str, match| match ^ (re =~ str)}
+ msg = message(msg) {
+ "Expected #{re.inspect} to\n" +
+ errs.map {|str, match| "\t#{'not ' unless match}match #{str.inspect}"}.join(",\n")
+ }
+ assert_empty(errs, msg)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_require.rb b/jni/ruby/test/ruby/test_require.rb
new file mode 100644
index 0000000..33aea60
--- /dev/null
+++ b/jni/ruby/test/ruby/test_require.rb
@@ -0,0 +1,704 @@
+require 'test/unit'
+
+require 'tempfile'
+require 'tmpdir'
+
+class TestRequire < Test::Unit::TestCase
+ def test_load_error_path
+ filename = "should_not_exist"
+ error = assert_raise(LoadError) do
+ require filename
+ end
+ assert_equal filename, error.path
+ end
+
+ def test_require_invalid_shared_object
+ Tempfile.create(["test_ruby_test_require", ".so"]) {|t|
+ t.puts "dummy"
+ t.close
+
+ assert_separately([], <<-INPUT)
+ $:.replace([IO::NULL])
+ assert_raise(LoadError) do
+ require \"#{ t.path }\"
+ end
+ INPUT
+ }
+ end
+
+ def test_require_too_long_filename
+ assert_separately(["RUBYOPT"=>nil], <<-INPUT)
+ $:.replace([IO::NULL])
+ assert_raise(LoadError) do
+ require '#{ "foo/" * 10000 }foo'
+ end
+ INPUT
+
+ begin
+ assert_in_out_err(["-S", "-w", "foo/" * 1024 + "foo"], "") do |r, e|
+ assert_equal([], r)
+ assert_operator(2, :<=, e.size)
+ assert_match(/warning: openpath: pathname too long \(ignored\)/, e.first)
+ assert_match(/\(LoadError\)/, e.last)
+ end
+ rescue Errno::EINVAL
+ # too long commandline may be blocked by OS.
+ end
+ end
+
+ def test_require_nonascii
+ bug3758 = '[ruby-core:31915]'
+ ["\u{221e}", "\x82\xa0".force_encoding("cp932")].each do |path|
+ assert_raise_with_message(LoadError, /#{path}\z/, bug3758) {require path}
+ end
+ end
+
+ def test_require_nonascii_path
+ bug8165 = '[ruby-core:53733] [Bug #8165]'
+ encoding = 'filesystem'
+ assert_require_nonascii_path(encoding, bug8165)
+ end
+
+ def test_require_nonascii_path_utf8
+ bug8676 = '[ruby-core:56136] [Bug #8676]'
+ encoding = Encoding::UTF_8
+ return if Encoding.find('filesystem') == encoding
+ assert_require_nonascii_path(encoding, bug8676)
+ end
+
+ def test_require_nonascii_path_shift_jis
+ bug8676 = '[ruby-core:56136] [Bug #8676]'
+ encoding = Encoding::Shift_JIS
+ return if Encoding.find('filesystem') == encoding
+ assert_require_nonascii_path(encoding, bug8676)
+ end
+
+ case RUBY_PLATFORM
+ when /cygwin/, /mswin/, /mingw/, /darwin/
+ def self.ospath_encoding(path)
+ Encoding::UTF_8
+ end
+ else
+ def self.ospath_encoding(path)
+ path.encoding
+ end
+ end
+
+ def assert_require_nonascii_path(encoding, bug)
+ Dir.mktmpdir {|tmp|
+ dir = "\u3042" * 5
+ begin
+ require_path = File.join(tmp, dir, 'foo.rb').encode(encoding)
+ rescue
+ skip "cannot convert path encoding to #{encoding}"
+ end
+ Dir.mkdir(File.dirname(require_path))
+ open(require_path, "wb") {|f| f.puts '$:.push __FILE__'}
+ begin
+ load_path = $:.dup
+ features = $".dup
+ # leave paths for require encoding objects
+ bug = "#{bug} require #{encoding} path"
+ require_path = "#{require_path}"
+ $:.clear
+ assert_nothing_raised(LoadError, bug) {
+ assert(require(require_path), bug)
+ assert_equal(self.class.ospath_encoding(require_path), $:.last.encoding, '[Bug #8753]')
+ assert(!require(require_path), bug)
+ }
+ ensure
+ $:.replace(load_path)
+ $".replace(features)
+ end
+ }
+ end
+
+ def test_require_path_home_1
+ env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"]
+ pathname_too_long = /pathname too long \(ignored\).*\(LoadError\)/m
+
+ ENV["RUBYPATH"] = "~"
+ ENV["HOME"] = "/foo" * 1024
+ assert_in_out_err(%w(-S -w test_ruby_test_require), "", [], pathname_too_long)
+
+ ensure
+ env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH")
+ env_home ? ENV["HOME"] = env_home : ENV.delete("HOME")
+ end
+
+ def test_require_path_home_2
+ env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"]
+ pathname_too_long = /pathname too long \(ignored\).*\(LoadError\)/m
+
+ ENV["RUBYPATH"] = "~" + "/foo" * 1024
+ ENV["HOME"] = "/foo"
+ assert_in_out_err(%w(-S -w test_ruby_test_require), "", [], pathname_too_long)
+
+ ensure
+ env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH")
+ env_home ? ENV["HOME"] = env_home : ENV.delete("HOME")
+ end
+
+ def test_require_path_home_3
+ env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"]
+
+ Tempfile.create(["test_ruby_test_require", ".rb"]) {|t|
+ t.puts "p :ok"
+ t.close
+
+ ENV["RUBYPATH"] = "~"
+ ENV["HOME"] = t.path
+ assert_in_out_err(%w(-S test_ruby_test_require), "", [], /\(LoadError\)/)
+
+ ENV["HOME"], name = File.split(t.path)
+ assert_in_out_err(["-S", name], "", %w(:ok), [])
+ }
+ ensure
+ env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH")
+ env_home ? ENV["HOME"] = env_home : ENV.delete("HOME")
+ end
+
+ def test_require_with_unc
+ ruby = File.expand_path(EnvUtil.rubybin).sub(/\A(\w):/, '//127.0.0.1/\1$/')
+ skip "local drive #$1: is not shared" unless File.exist?(ruby)
+ pid = nil
+ assert_nothing_raised {pid = spawn(ruby, "-rabbrev", "-e0")}
+ ret, status = Process.wait2(pid)
+ assert_equal(pid, ret)
+ assert_predicate(status, :success?)
+ end if /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_require_twice
+ Dir.mktmpdir do |tmp|
+ req = File.join(tmp, "very_long_file_name.rb")
+ File.write(req, "p :ok\n")
+ assert_file.exist?(req)
+ req[/.rb$/i] = ""
+ assert_in_out_err(['--disable-gems'], <<-INPUT, %w(:ok), [])
+ require "#{req}"
+ require "#{req}"
+ INPUT
+ end
+ end
+
+ def test_define_class
+ begin
+ require "socket"
+ rescue LoadError
+ return
+ end
+
+ assert_separately([], <<-INPUT)
+ BasicSocket = 1
+ assert_raise(TypeError) do
+ require 'socket'
+ end
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ class BasicSocket; end
+ assert_raise(TypeError) do
+ require 'socket'
+ end
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ class BasicSocket < IO; end
+ assert_nothing_raised do
+ require 'socket'
+ end
+ INPUT
+ end
+
+ def test_define_class_under
+ begin
+ require "zlib"
+ rescue LoadError
+ return
+ end
+
+ assert_separately([], <<-INPUT)
+ module Zlib; end
+ Zlib::Error = 1
+ assert_raise(TypeError) do
+ require 'zlib'
+ end
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ module Zlib; end
+ class Zlib::Error; end
+ assert_raise(NameError) do
+ require 'zlib'
+ end
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ module Zlib; end
+ class Zlib::Error < StandardError; end
+ assert_nothing_raised do
+ require 'zlib'
+ end
+ INPUT
+ end
+
+ def test_define_module
+ begin
+ require "zlib"
+ rescue LoadError
+ return
+ end
+
+ assert_separately([], <<-INPUT)
+ Zlib = 1
+ assert_raise(TypeError) do
+ require 'zlib'
+ end
+ INPUT
+ end
+
+ def test_define_module_under
+ begin
+ require "socket"
+ rescue LoadError
+ return
+ end
+
+ assert_separately([], <<-INPUT)
+ class BasicSocket < IO; end
+ class Socket < BasicSocket; end
+ Socket::Constants = 1
+ assert_raise(TypeError) do
+ require 'socket'
+ end
+ INPUT
+ end
+
+ def test_load
+ Tempfile.create(["test_ruby_test_require", ".rb"]) {|t|
+ t.puts "module Foo; end"
+ t.puts "at_exit { p :wrap_end }"
+ t.puts "at_exit { raise 'error in at_exit test' }"
+ t.puts "p :ok"
+ t.close
+
+ assert_in_out_err([], <<-INPUT, %w(:ok :end :wrap_end), /error in at_exit test/)
+ load(#{ t.path.dump }, true)
+ GC.start
+ p :end
+ INPUT
+
+ assert_raise(ArgumentError) { at_exit }
+ }
+ end
+
+ def test_load_scope
+ bug1982 = '[ruby-core:25039] [Bug #1982]'
+ Tempfile.create(["test_ruby_test_require", ".rb"]) {|t|
+ t.puts "Hello = 'hello'"
+ t.puts "class Foo"
+ t.puts " p Hello"
+ t.puts "end"
+ t.close
+
+ assert_in_out_err([], <<-INPUT, %w("hello"), [], bug1982)
+ load(#{ t.path.dump }, true)
+ INPUT
+ }
+ end
+
+ def test_load_ospath
+ bug = '[ruby-list:49994] path in ospath'
+ base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J)
+ path = nil
+ Tempfile.create([base, ".rb"]) do |t|
+ path = t.path
+
+ assert_raise_with_message(LoadError, /#{base}/) {
+ load(File.join(File.dirname(path), base))
+ }
+
+ t.puts "warn 'ok'"
+ t.close
+ assert_include(path, base)
+ assert_warn("ok\n", bug) {
+ assert_nothing_raised(LoadError, bug) {
+ load(path)
+ }
+ }
+ end
+ end
+
+ def test_tainted_loadpath
+ Tempfile.create(["test_ruby_test_require", ".rb"]) {|t|
+ abs_dir, file = File.split(t.path)
+ abs_dir = File.expand_path(abs_dir).untaint
+
+ assert_separately([], <<-INPUT)
+ abs_dir = "#{ abs_dir }"
+ $: << abs_dir
+ assert_nothing_raised {require "#{ file }"}
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ abs_dir = "#{ abs_dir }"
+ $: << abs_dir.taint
+ assert_nothing_raised {require "#{ file }"}
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ abs_dir = "#{ abs_dir }"
+ $: << abs_dir.taint
+ $SAFE = 1
+ assert_raise(SecurityError) {require "#{ file }"}
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ abs_dir = "#{ abs_dir }"
+ $: << abs_dir.taint
+ $SAFE = 1
+ assert_raise(SecurityError) {require "#{ file }"}
+ INPUT
+
+ assert_separately([], <<-INPUT)
+ abs_dir = "#{ abs_dir }"
+ $: << abs_dir << 'elsewhere'.taint
+ assert_nothing_raised {require "#{ file }"}
+ INPUT
+ }
+ end
+
+ def test_relative
+ load_path = $:.dup
+ $:.delete(".")
+ Dir.mktmpdir do |tmp|
+ Dir.chdir(tmp) do
+ Dir.mkdir('x')
+ File.open('x/t.rb', 'wb') {}
+ File.open('x/a.rb', 'wb') {|f| f.puts("require_relative('t.rb')")}
+ assert require('./x/t.rb')
+ assert !require(File.expand_path('x/t.rb'))
+ assert_nothing_raised(LoadError) {require('./x/a.rb')}
+ assert_raise(LoadError) {require('x/t.rb')}
+ File.unlink(*Dir.glob('x/*'))
+ Dir.rmdir("#{tmp}/x")
+ $:.replace(load_path)
+ load_path = nil
+ assert(!require('tmpdir'))
+ end
+ end
+ ensure
+ $:.replace(load_path) if load_path
+ end
+
+ def test_relative_symlink
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ Dir.mkdir "a"
+ Dir.mkdir "b"
+ File.open("a/lib.rb", "w") {|f| f.puts 'puts "a/lib.rb"' }
+ File.open("b/lib.rb", "w") {|f| f.puts 'puts "b/lib.rb"' }
+ File.open("a/tst.rb", "w") {|f| f.puts 'require_relative "lib"' }
+ begin
+ File.symlink("../a/tst.rb", "b/tst.rb")
+ result = IO.popen([EnvUtil.rubybin, "b/tst.rb"], &:read)
+ assert_equal("a/lib.rb\n", result, "[ruby-dev:40040]")
+ rescue NotImplementedError
+ skip "File.symlink is not implemented"
+ end
+ }
+ }
+ end
+
+ def test_frozen_loaded_features
+ bug3756 = '[ruby-core:31913]'
+ assert_in_out_err(['-e', '$LOADED_FEATURES.freeze; require "ostruct"'], "",
+ [], /\$LOADED_FEATURES is frozen; cannot append feature \(RuntimeError\)$/,
+ bug3756)
+ end
+
+ def test_race_exception
+ bug5754 = '[ruby-core:41618]'
+ path = nil
+ stderr = $stderr
+ verbose = $VERBOSE
+ Tempfile.create(%w"bug5754 .rb") {|tmp|
+ path = tmp.path
+ tmp.print %{\
+ th = Thread.current
+ t = th[:t]
+ scratch = th[:scratch]
+
+ if scratch.empty?
+ scratch << :pre
+ Thread.pass until t.stop?
+ raise RuntimeError
+ else
+ scratch << :post
+ end
+ }
+ tmp.close
+
+ class << (output = "")
+ alias write concat
+ end
+ $stderr = output
+
+ start = false
+
+ scratch = []
+ t1_res = nil
+ t2_res = nil
+
+ t1 = Thread.new do
+ Thread.pass until start
+ begin
+ require(path)
+ rescue RuntimeError
+ end
+
+ t1_res = require(path)
+ end
+
+ t2 = Thread.new do
+ Thread.pass until scratch[0]
+ t2_res = require(path)
+ end
+
+ t1[:scratch] = t2[:scratch] = scratch
+ t1[:t] = t2
+ t2[:t] = t1
+
+ $VERBOSE = true
+ start = true
+
+ assert_nothing_raised(ThreadError, bug5754) {t1.join}
+ assert_nothing_raised(ThreadError, bug5754) {t2.join}
+
+ $VERBOSE = false
+
+ assert_equal(true, (t1_res ^ t2_res), bug5754 + " t1:#{t1_res} t2:#{t2_res}")
+ assert_equal([:pre, :post], scratch, bug5754)
+
+ assert_match(/circular require/, output)
+ assert_match(/in #{__method__}'$/o, output)
+ }
+ ensure
+ $VERBOSE = verbose
+ $stderr = stderr
+ $".delete(path)
+ end
+
+ def test_loaded_features_encoding
+ bug6377 = '[ruby-core:44750]'
+ loadpath = $:.dup
+ features = $".dup
+ $".clear
+ $:.clear
+ Dir.mktmpdir {|tmp|
+ $: << tmp
+ open(File.join(tmp, "foo.rb"), "w") {}
+ require "foo"
+ assert_send([Encoding, :compatible?, tmp, $"[0]], bug6377)
+ }
+ ensure
+ $:.replace(loadpath)
+ $".replace(features)
+ end
+
+ def test_require_changed_current_dir
+ bug7158 = '[ruby-core:47970]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ Dir.mkdir("a")
+ Dir.mkdir("b")
+ open(File.join("a", "foo.rb"), "w") {}
+ open(File.join("b", "bar.rb"), "w") {|f|
+ f.puts "p :ok"
+ }
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158)
+ $:.replace([IO::NULL])
+ $: << "."
+ Dir.chdir("a")
+ require "foo"
+ Dir.chdir("../b")
+ p :ng unless require "bar"
+ Dir.chdir("..")
+ p :ng if require "b/bar"
+ INPUT
+ }
+ }
+ end
+
+ def test_require_not_modified_load_path
+ bug7158 = '[ruby-core:47970]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158)
+ $:.replace([IO::NULL])
+ a = Object.new
+ def a.to_str
+ "#{tmp}"
+ end
+ $: << a
+ require "foo"
+ last_path = $:.pop
+ p :ok if last_path == a && last_path.class == Object
+ INPUT
+ }
+ }
+ end
+
+ def test_require_changed_home
+ bug7158 = '[ruby-core:47970]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ Dir.mkdir("a")
+ open(File.join("a", "bar.rb"), "w") {}
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158)
+ $:.replace([IO::NULL])
+ $: << '~'
+ ENV['HOME'] = "#{tmp}"
+ require "foo"
+ ENV['HOME'] = "#{tmp}/a"
+ p :ok if require "bar"
+ INPUT
+ }
+ }
+ end
+
+ def test_require_to_path_redefined_in_load_path
+ bug7158 = '[ruby-core:47970]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158)
+ $:.replace([IO::NULL])
+ a = Object.new
+ def a.to_path
+ "bar"
+ end
+ $: << a
+ begin
+ require "foo"
+ p [:ng, $LOAD_PATH, ENV['RUBYLIB']]
+ rescue LoadError
+ end
+ def a.to_path
+ "#{tmp}"
+ end
+ p :ok if require "foo"
+ INPUT
+ }
+ }
+ end
+
+ def test_require_to_str_redefined_in_load_path
+ bug7158 = '[ruby-core:47970]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158)
+ $:.replace([IO::NULL])
+ a = Object.new
+ def a.to_str
+ "foo"
+ end
+ $: << a
+ begin
+ require "foo"
+ p [:ng, $LOAD_PATH, ENV['RUBYLIB']]
+ rescue LoadError
+ end
+ def a.to_str
+ "#{tmp}"
+ end
+ p :ok if require "foo"
+ INPUT
+ }
+ }
+ end
+
+ def assert_require_with_shared_array_modified(add, del)
+ bug7383 = '[ruby-core:49518]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ Dir.mkdir("a")
+ open(File.join("a", "bar.rb"), "w") {}
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7383)
+ $:.replace([IO::NULL])
+ $:.#{add} "#{tmp}"
+ $:.#{add} "#{tmp}/a"
+ require "foo"
+ $:.#{del}
+ # Expanded load path cache should be rebuilt.
+ begin
+ require "bar"
+ rescue LoadError
+ p :ok
+ end
+ INPUT
+ }
+ }
+ end
+
+ def test_require_with_array_pop
+ assert_require_with_shared_array_modified("push", "pop")
+ end
+
+ def test_require_with_array_shift
+ assert_require_with_shared_array_modified("unshift", "shift")
+ end
+
+ def test_require_local_var_on_toplevel
+ bug7536 = '[ruby-core:50701]'
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("bar.rb", "w") {|f| f.puts 'TOPLEVEL_BINDING.eval("lib = 2")' }
+ assert_in_out_err(%w[-r./bar.rb], <<-INPUT, %w([:lib] 2), [], bug7536)
+ puts TOPLEVEL_BINDING.eval("local_variables").inspect
+ puts TOPLEVEL_BINDING.eval("lib").inspect
+ INPUT
+ }
+ }
+ end
+
+ def test_require_with_loaded_features_pop
+ bug7530 = '[ruby-core:50645]'
+ Tempfile.create(%w'bug-7530- .rb') {|script|
+ script.close
+ assert_in_out_err([{"RUBYOPT" => nil}, "-", script.path], <<-INPUT, %w(:ok), [], bug7530)
+ PATH = ARGV.shift
+ THREADS = 2
+ ITERATIONS_PER_THREAD = 1000
+
+ THREADS.times.map {
+ Thread.new do
+ ITERATIONS_PER_THREAD.times do
+ require PATH
+ $".pop
+ end
+ end
+ }.each(&:join)
+ p :ok
+ INPUT
+ }
+ end
+
+ def test_loading_fifo_threading
+ Tempfile.create(%w'fifo .rb') {|f|
+ f.close
+ File.unlink(f.path)
+ File.mkfifo(f.path)
+ assert_separately(["-", f.path], <<-END, timeout: 3)
+ th = Thread.current
+ Thread.start {begin sleep(0.001) end until th.stop?; th.raise(IOError)}
+ assert_raise(IOError) {load(ARGV[0])}
+ END
+ }
+ rescue Errno::ENOENT
+ end unless /mswin|mingw/ =~ RUBY_PLATFORM
+end
diff --git a/jni/ruby/test/ruby/test_rubyoptions.rb b/jni/ruby/test/ruby/test_rubyoptions.rb
new file mode 100644
index 0000000..7cb1248
--- /dev/null
+++ b/jni/ruby/test/ruby/test_rubyoptions.rb
@@ -0,0 +1,796 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+
+require 'tmpdir'
+require 'tempfile'
+
+class TestRubyOptions < Test::Unit::TestCase
+ def write_file(filename, content)
+ File.open(filename, "w") {|f|
+ f << content
+ }
+ end
+
+ def with_tmpchdir
+ Dir.mktmpdir {|d|
+ d = File.realpath(d)
+ Dir.chdir(d) {
+ yield d
+ }
+ }
+ end
+
+ def test_source_file
+ assert_in_out_err([], "", [], [])
+ end
+
+ def test_usage
+ assert_in_out_err(%w(-h)) do |r, e|
+ assert_operator(r.size, :<=, 24)
+ longer = r[1..-1].select {|x| x.size > 80}
+ assert_equal([], longer)
+ assert_equal([], e)
+ end
+ end
+
+ def test_usage_long
+ assert_in_out_err(%w(--help)) do |r, e|
+ longer = r[1..-1].select {|x| x.size > 80}
+ assert_equal([], longer)
+ assert_equal([], e)
+ end
+ end
+
+ def test_option_variables
+ assert_in_out_err(["-e", 'p [$-p, $-l, $-a]']) do |r, e|
+ assert_equal(["[false, false, false]"], r)
+ assert_equal([], e)
+ end
+
+ assert_in_out_err(%w(-p -l -a -e) + ['p [$-p, $-l, $-a]'],
+ "foo\nbar\nbaz\n") do |r, e|
+ assert_equal(
+ [ '[true, true, true]', 'foo',
+ '[true, true, true]', 'bar',
+ '[true, true, true]', 'baz' ], r)
+ assert_equal([], e)
+ end
+ end
+
+ def test_warning
+ save_rubyopt = ENV['RUBYOPT']
+ ENV['RUBYOPT'] = nil
+ assert_in_out_err(%w(-W0 -e) + ['p $-W'], "", %w(0), [])
+ assert_in_out_err(%w(-W1 -e) + ['p $-W'], "", %w(1), [])
+ assert_in_out_err(%w(-Wx -e) + ['p $-W'], "", %w(1), [])
+ assert_in_out_err(%w(-W -e) + ['p $-W'], "", %w(2), [])
+ ensure
+ ENV['RUBYOPT'] = save_rubyopt
+ end
+
+ def test_safe_level
+ assert_in_out_err(%w(-T -e) + [""], "", [],
+ /no -e allowed in tainted mode \(SecurityError\)/)
+
+ assert_in_out_err(%w(-T4 -S foo.rb), "", [],
+ /no -S allowed in tainted mode \(SecurityError\)/)
+ end
+
+ def test_debug
+ assert_in_out_err(["--disable-gems", "-de", "p $DEBUG"], "", %w(true), [])
+
+ assert_in_out_err(["--disable-gems", "--debug", "-e", "p $DEBUG"],
+ "", %w(true), [])
+ end
+
+ def test_verbose
+ assert_in_out_err(["-vve", ""]) do |r, e|
+ assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev|rc).*? \[#{RUBY_PLATFORM}\]$/, r.join)
+ assert_equal RUBY_DESCRIPTION, r.join.chomp
+ assert_equal([], e)
+ end
+
+ assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), [])
+
+ assert_in_out_err(%w(--verbose), "", [], [])
+ end
+
+ def test_copyright
+ assert_in_out_err(%w(--copyright), "",
+ /^ruby - Copyright \(C\) 1993-\d+ Yukihiro Matsumoto$/, [])
+
+ assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), [])
+ end
+
+ def test_enable
+ assert_in_out_err(%w(--enable all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--enable-all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--enable=all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [],
+ /unknown argument for --enable: `foobarbazqux'/)
+ assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/)
+ end
+
+ def test_disable
+ assert_in_out_err(%w(--disable all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--disable-all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--disable=all -e) + [""], "", [], [])
+ assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [],
+ /unknown argument for --disable: `foobarbazqux'/)
+ assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/)
+ end
+
+ def test_kanji
+ assert_in_out_err(%w(-KU), "p '\u3042'") do |r, e|
+ assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
+ end
+ line = '-eputs"\xc2\xa1".encoding'
+ env = {'RUBYOPT' => nil}
+ assert_in_out_err([env, '-Ke', line], "", ["EUC-JP"], [])
+ assert_in_out_err([env, '-KE', line], "", ["EUC-JP"], [])
+ assert_in_out_err([env, '-Ks', line], "", ["Windows-31J"], [])
+ assert_in_out_err([env, '-KS', line], "", ["Windows-31J"], [])
+ assert_in_out_err([env, '-Ku', line], "", ["UTF-8"], [])
+ assert_in_out_err([env, '-KU', line], "", ["UTF-8"], [])
+ assert_in_out_err([env, '-Kn', line], "", ["ASCII-8BIT"], [])
+ assert_in_out_err([env, '-KN', line], "", ["ASCII-8BIT"], [])
+ assert_in_out_err([env, '-wKe', line], "", ["EUC-JP"], /-K/)
+ end
+
+ def test_version
+ assert_in_out_err(%w(--version)) do |r, e|
+ assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev|rc).*? \[#{RUBY_PLATFORM}\]$/, r.join)
+ assert_equal RUBY_DESCRIPTION, r.join.chomp
+ assert_equal([], e)
+ end
+ end
+
+ def test_eval
+ assert_in_out_err(%w(-e), "", [], /no code specified for -e \(RuntimeError\)/)
+ end
+
+ def test_require
+ require "pp"
+ assert_in_out_err(%w(-r pp -e) + ["pp 1"], "", %w(1), [])
+ assert_in_out_err(%w(-rpp -e) + ["pp 1"], "", %w(1), [])
+ assert_in_out_err(%w(-ep\ 1 -r), "", %w(1), [])
+ assert_in_out_err(%w(-r), "", [], [])
+ rescue LoadError
+ end
+
+ def test_include
+ d = Dir.tmpdir
+ assert_in_out_err(["-I" + d, "-e", ""], "", [], [])
+ assert_in_out_err(["-I", d, "-e", ""], "", [], [])
+ end
+
+ def test_separator
+ assert_in_out_err(%w(-000 -e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0baz), [])
+
+ assert_in_out_err(%w(-0141 -e) + ["print gets"], "foo\nbar\0baz", %w(foo ba), [])
+
+ assert_in_out_err(%w(-0e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0), [])
+ end
+
+ def test_autosplit
+ assert_in_out_err(%w(-an -F: -e) + ["p $F"], "foo:bar:baz\nqux:quux:quuux\n",
+ ['["foo", "bar", "baz\n"]', '["qux", "quux", "quuux\n"]'], [])
+ end
+
+ def test_chdir
+ assert_in_out_err(%w(-C), "", [], /Can't chdir/)
+
+ assert_in_out_err(%w(-C test_ruby_test_rubyoptions_foobarbazqux), "", [], /Can't chdir/)
+
+ d = Dir.tmpdir
+ assert_in_out_err(["-C", d, "-e", "puts Dir.pwd"]) do |r, e|
+ assert_file.identical?(r.join, d)
+ assert_equal([], e)
+ end
+ end
+
+ def test_yydebug
+ assert_in_out_err(["-ye", ""]) do |r, e|
+ assert_equal([], r)
+ assert_not_equal([], e)
+ end
+
+ assert_in_out_err(%w(--yydebug -e) + [""]) do |r, e|
+ assert_equal([], r)
+ assert_not_equal([], e)
+ end
+ end
+
+ def test_encoding
+ assert_in_out_err(%w(--encoding), "", [], /missing argument for --encoding/)
+
+ assert_in_out_err(%w(--encoding test_ruby_test_rubyoptions_foobarbazqux), "", [],
+ /unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/)
+
+ if /mswin|mingw|aix/ =~ RUBY_PLATFORM &&
+ (str = "\u3042".force_encoding(Encoding.find("locale"))).valid_encoding?
+ # This result depends on locale because LANG=C doesn't affect locale
+ # on Windows.
+ # On AIX, the source encoding of stdin with LANG=C is ISO-8859-1,
+ # which allows \u3042.
+ out, err = [str], []
+ else
+ out, err = [], /invalid multibyte char/
+ end
+ assert_in_out_err(%w(-Eutf-8), "puts '\u3042'", out, err)
+ assert_in_out_err(%w(--encoding utf-8), "puts '\u3042'", out, err)
+ end
+
+ def test_syntax_check
+ assert_in_out_err(%w(-c -e a=1+1 -e !a), "", ["Syntax OK"], [])
+ end
+
+ def test_invalid_option
+ assert_in_out_err(%w(--foobarbazqux), "", [], /invalid option --foobarbazqux/)
+
+ assert_in_out_err(%W(-\r -e) + [""], "", [], [])
+
+ assert_in_out_err(%W(-\rx), "", [], /invalid option -\\x0D \(-h will show valid options\) \(RuntimeError\)/)
+
+ assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/)
+
+ assert_in_out_err(%w(-Z), "", [], /invalid option -Z \(-h will show valid options\) \(RuntimeError\)/)
+ end
+
+ def test_rubyopt
+ rubyopt_orig = ENV['RUBYOPT']
+
+ ENV['RUBYOPT'] = ' - -'
+ assert_in_out_err([], "", [], [])
+
+ ENV['RUBYOPT'] = '-e "p 1"'
+ assert_in_out_err([], "", [], /invalid switch in RUBYOPT: -e \(RuntimeError\)/)
+
+ ENV['RUBYOPT'] = '-T1'
+ assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/)
+
+ ENV['RUBYOPT'] = '-T4'
+ assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/)
+
+ ENV['RUBYOPT'] = '-Eus-ascii -KN'
+ assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e|
+ assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
+ assert_equal([], e)
+ end
+
+ ensure
+ if rubyopt_orig
+ ENV['RUBYOPT'] = rubyopt_orig
+ else
+ ENV.delete('RUBYOPT')
+ end
+ end
+
+ def test_search
+ rubypath_orig = ENV['RUBYPATH']
+ path_orig = ENV['PATH']
+
+ Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
+ t.puts "p 1"
+ t.close
+
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+
+ ENV['PATH'] = File.dirname(t.path)
+
+ assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), [])
+
+ ENV['RUBYPATH'] = File.dirname(t.path)
+
+ assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), [])
+ }
+
+ ensure
+ if rubypath_orig
+ ENV['RUBYPATH'] = rubypath_orig
+ else
+ ENV.delete('RUBYPATH')
+ end
+ if path_orig
+ ENV['PATH'] = path_orig
+ else
+ ENV.delete('PATH')
+ end
+ $VERBOSE = @verbose
+ end
+
+ def test_shebang
+ assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux\r\np 1\r\n",
+ [], /: no Ruby script found in input/)
+
+ assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux -foo -bar\r\np 1\r\n",
+ [], /: no Ruby script found in input/)
+
+ assert_in_out_err([{'RUBYOPT' => nil}], "#!ruby -KU -Eutf-8\r\np \"\u3042\"\r\n") do |r, e|
+ assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
+ assert_equal([], e)
+ end
+
+ bug4118 = '[ruby-dev:42680]'
+ assert_in_out_err(%w[], "#!/bin/sh\n""#!shebang\n""#!ruby\n""puts __LINE__\n",
+ %w[4], [], bug4118)
+ assert_in_out_err(%w[-x], "#!/bin/sh\n""#!shebang\n""#!ruby\n""puts __LINE__\n",
+ %w[4], [], bug4118)
+ end
+
+ def test_sflag
+ assert_in_out_err(%w(- -abc -def=foo -ghi-jkl -- -xyz),
+ "#!ruby -s\np [$abc, $def, $ghi_jkl, defined?($xyz)]\n",
+ ['[true, "foo", true, nil]'], [])
+
+ assert_in_out_err(%w(- -#), "#!ruby -s\n", [],
+ /invalid name for global variable - -# \(NameError\)/)
+
+ assert_in_out_err(%w(- -#=foo), "#!ruby -s\n", [],
+ /invalid name for global variable - -# \(NameError\)/)
+ end
+
+ def test_assignment_in_conditional
+ Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
+ t.puts "if a = 1"
+ t.puts "end"
+ t.puts "0.times do"
+ t.puts " if b = 2"
+ t.puts " a += b"
+ t.puts " end"
+ t.puts "end"
+ t.flush
+ warning = ' warning: found = in conditional, should be =='
+ err = ["#{t.path}:1:#{warning}",
+ "#{t.path}:4:#{warning}",
+ ]
+ bug2136 = '[ruby-dev:39363]'
+ assert_in_out_err(["-w", t.path], "", [], err, bug2136)
+ assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err, bug2136)
+
+ t.rewind
+ t.truncate(0)
+ t.puts "if a = ''; end"
+ t.puts "if a = []; end"
+ t.puts "if a = [1]; end"
+ t.puts "if a = [a]; end"
+ t.puts "if a = {}; end"
+ t.puts "if a = {1=>2}; end"
+ t.puts "if a = {3=>a}; end"
+ t.flush
+ err = ["#{t.path}:1:#{warning}",
+ "#{t.path}:2:#{warning}",
+ "#{t.path}:3:#{warning}",
+ "#{t.path}:5:#{warning}",
+ "#{t.path}:6:#{warning}",
+ ]
+ feature4299 = '[ruby-dev:43083]'
+ assert_in_out_err(["-w", t.path], "", [], err, feature4299)
+ assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err, feature4299)
+ }
+ end
+
+ def test_indentation_check
+ Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
+ t.puts "begin"
+ t.puts " end"
+ t.flush
+ err = ["#{t.path}:2: warning: mismatched indentations at 'end' with 'begin' at 1"]
+ assert_in_out_err(["-w", t.path], "", [], err)
+ assert_in_out_err(["-wr", t.path, "-e", ""], "", [], err)
+
+ t.rewind
+ t.puts "# -*- warn-indent: false -*-"
+ t.puts "begin"
+ t.puts " end"
+ t.flush
+ assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]')
+
+ err = ["#{t.path}:4: warning: mismatched indentations at 'end' with 'begin' at 3"]
+ t.rewind
+ t.puts "# -*- warn-indent: false -*-"
+ t.puts "# -*- warn-indent: true -*-"
+ t.puts "begin"
+ t.puts " end"
+ t.flush
+ assert_in_out_err(["-w", t.path], "", [], err, '[ruby-core:25442]')
+
+ err = ["#{t.path}:4: warning: mismatched indentations at 'end' with 'begin' at 2"]
+ t.rewind
+ t.puts "# -*- warn-indent: true -*-"
+ t.puts "begin"
+ t.puts "# -*- warn-indent: false -*-"
+ t.puts " end"
+ t.flush
+ assert_in_out_err(["-w", t.path], "", [], [], '[ruby-core:25442]')
+ }
+ end
+
+ def test_notfound
+ notexist = "./notexist.rb"
+ rubybin = EnvUtil.rubybin.dup
+ rubybin.gsub!(%r(/), '\\') if /mswin|mingw/ =~ RUBY_PLATFORM
+ rubybin = Regexp.quote(rubybin)
+ pat = Regexp.quote(notexist)
+ bug1573 = '[ruby-core:23717]'
+ assert_file.not_exist?(notexist)
+ assert_in_out_err(["-r", notexist, "-ep"], "", [], /.* -- #{pat} \(LoadError\)/, bug1573)
+ assert_in_out_err([notexist], "", [], /#{rubybin}:.* -- #{pat} \(LoadError\)/, bug1573)
+ end
+
+ def test_program_name
+ ruby = EnvUtil.rubybin
+ IO.popen([ruby, '-e', 'print $0']) {|f|
+ assert_equal('-e', f.read)
+ }
+ IO.popen([ruby, '-'], 'r+') {|f|
+ f << 'print $0'
+ f.close_write
+ assert_equal('-', f.read)
+ }
+ Dir.mktmpdir {|d|
+ n1 = File.join(d, 't1')
+ open(n1, 'w') {|f| f << 'print $0' }
+ IO.popen([ruby, n1]) {|f|
+ assert_equal(n1, f.read)
+ }
+ if File.respond_to? :symlink
+ n2 = File.join(d, 't2')
+ File.symlink(n1, n2)
+ IO.popen([ruby, n2]) {|f|
+ assert_equal(n2, f.read)
+ }
+ end
+ Dir.chdir(d) {
+ n3 = '-e'
+ open(n3, 'w') {|f| f << 'print $0' }
+ IO.popen([ruby, '--', n3]) {|f|
+ assert_equal(n3, f.read)
+ }
+ n4 = '-'
+ IO.popen([ruby, '--', n4], 'r+') {|f|
+ f << 'print $0'
+ f.close_write
+ assert_equal(n4, f.read)
+ }
+ }
+ }
+ end
+
+ if /linux|freebsd|netbsd|openbsd|darwin/ =~ RUBY_PLATFORM
+ PSCMD = EnvUtil.find_executable("ps", "-o", "command", "-p", $$.to_s) {|out| /ruby/=~out}
+ PSCMD.pop if PSCMD
+ end
+
+ def test_set_program_name
+ skip "platform dependent feature" unless defined?(PSCMD) and PSCMD
+
+ with_tmpchdir do
+ write_file("test-script", "$0 = 'hello world'; /test-script/ =~ Process.argv0 or $0 = 'Process.argv0 changed!'; sleep 60")
+
+ pid = spawn(EnvUtil.rubybin, "test-script")
+ ps = nil
+ 10.times do
+ sleep 0.1
+ ps = `#{PSCMD.join(' ')} #{pid}`
+ break if /hello world/ =~ ps
+ end
+ assert_match(/hello world/, ps)
+ Process.kill :KILL, pid
+ Process.wait(pid)
+ end
+ end
+
+ def test_setproctitle
+ skip "platform dependent feature" unless defined?(PSCMD) and PSCMD
+
+ with_tmpchdir do
+ write_file("test-script", "$_0 = $0.dup; Process.setproctitle('hello world'); $0 == $_0 or Process.setproctitle('$0 changed!'); sleep 60")
+
+ pid = spawn(EnvUtil.rubybin, "test-script")
+ ps = nil
+ 10.times do
+ sleep 0.1
+ ps = `#{PSCMD.join(' ')} #{pid}`
+ break if /hello world/ =~ ps
+ end
+ assert_match(/hello world/, ps)
+ Process.kill :KILL, pid
+ Process.wait(pid)
+ end
+ end
+
+ module SEGVTest
+ opts = {}
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ additional = /[\s\w\.\']*/
+ else
+ opts[:rlimit_core] = 0
+ additional = nil
+ end
+ ExecOptions = opts.freeze
+
+ ExpectedStderrList = [
+ %r(
+ -e:(?:1:)?\s\[BUG\]\sSegmentation\sfault.*\n
+ )x,
+ %r(
+ #{ Regexp.quote(RUBY_DESCRIPTION) }\n\n
+ )x,
+ %r(
+ (?:--\s(?:.+\n)*\n)?
+ --\sControl\sframe\sinformation\s-+\n
+ (?:c:.*\n)*
+ )x,
+ %r(
+ (?:
+ --\sRuby\slevel\sbacktrace\sinformation\s----------------------------------------\n
+ -e:1:in\s\`<main>\'\n
+ -e:1:in\s\`kill\'\n
+ )?
+ )x,
+ %r(
+ (?:
+ --\sC\slevel\sbacktrace\sinformation\s-------------------------------------------\n
+ (?:(?:.*\s)?\[0x\h+\]\n)*\n
+ )?
+ )x,
+ :*,
+ %r(
+ \[NOTE\]\n
+ You\smay\shave\sencountered\sa\sbug\sin\sthe\sRuby\sinterpreter\sor\sextension\slibraries.\n
+ Bug\sreports\sare\swelcome.\n
+ (?:.*\n)?
+ For\sdetails:\shttp:\/\/.*\.ruby-lang\.org/.*\n
+ \n
+ )x,
+ ]
+ ExpectedStderrList << additional if additional
+ end
+
+ def assert_segv(args, message=nil)
+ test_stdin = ""
+ opt = SEGVTest::ExecOptions.dup
+
+ _, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, false, true, **opt)
+ stderr.force_encoding("ASCII-8BIT")
+
+ if signo = status.termsig
+ sleep 0.1
+ EnvUtil.diagnostic_reports(Signal.signame(signo), EnvUtil.rubybin, status.pid, Time.now)
+ end
+
+ assert_pattern_list(SEGVTest::ExpectedStderrList, stderr, message)
+
+ status
+ end
+
+ def test_segv_test
+ assert_segv(["--disable-gems", "-e", "Process.kill :SEGV, $$"])
+ end
+
+ def test_segv_loaded_features
+ opts = SEGVTest::ExecOptions.dup
+
+ bug7402 = '[ruby-core:49573]'
+
+ status = Dir.mktmpdir("segv_test") do |tmpdir|
+ assert_in_out_err(['-e', 'class Bogus; def to_str; exit true; end; end',
+ '-e', '$".clear',
+ '-e', '$".unshift Bogus.new',
+ '-e', '(p $"; abort) unless $".size == 1',
+ '-e', 'Process.kill :SEGV, $$',
+ '-C', tmpdir,
+ ],
+ "", [], //,
+ nil,
+ opts)
+ end
+ if signo = status.termsig
+ sleep 0.1
+ EnvUtil.diagnostic_reports(Signal.signame(signo), EnvUtil.rubybin, status.pid, Time.now)
+ end
+ assert_not_predicate(status, :success?, "segv but success #{bug7402}")
+ end
+
+ def test_segv_setproctitle
+ bug7597 = '[ruby-dev:46786]'
+ Tempfile.create(["test_ruby_test_bug7597", ".rb"]) {|t|
+ t.write "f" * 100
+ t.flush
+ assert_segv(["--disable-gems", "-e", "$0=ARGV[0]; Process.kill :SEGV, $$", t.path], bug7597)
+ }
+ end
+
+ def test_DATA
+ Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
+ t.puts "puts DATA.read.inspect"
+ t.puts "__END__"
+ t.puts "foo"
+ t.puts "bar"
+ t.puts "baz"
+ t.flush
+ assert_in_out_err([t.path], "", %w("foo\\nbar\\nbaz\\n"), [])
+ }
+ end
+
+ def test_unused_variable
+ feature3446 = '[ruby-dev:41620]'
+ assert_in_out_err(["-we", "a=1"], "", [], [], feature3446)
+ assert_in_out_err(["-we", "def foo\n a=1\nend"], "", [], ["-e:2: warning: assigned but unused variable - a"], feature3446)
+ assert_in_out_err(["-we", "def foo\n eval('a=1')\nend"], "", [], [], feature3446)
+ assert_in_out_err(["-we", "1.times do\n a=1\nend"], "", [], [], feature3446)
+ assert_in_out_err(["-we", "def foo\n 1.times do\n a=1\n end\nend"], "", [], ["-e:3: warning: assigned but unused variable - a"], feature3446)
+ assert_in_out_err(["-we", "def foo\n"" 1.times do |a| end\n""end"], "", [], [])
+ feature6693 = '[ruby-core:46160]'
+ assert_in_out_err(["-we", "def foo\n _a=1\nend"], "", [], [], feature6693)
+ bug7408 = '[ruby-core:49659]'
+ assert_in_out_err(["-we", "def foo\n a=1\n :a\nend"], "", [], ["-e:2: warning: assigned but unused variable - a"], bug7408)
+ feature7730 = '[ruby-core:51580]'
+ assert_in_out_err(["-w", "-"], "a=1", [], ["-:1: warning: assigned but unused variable - a"], feature7730)
+ assert_in_out_err(["-w", "-"], "eval('a=1')", [], [], feature7730)
+ end
+
+ def test_shadowing_variable
+ bug4130 = '[ruby-dev:42718]'
+ assert_in_out_err(["-we", "def foo\n"" a=1\n"" 1.times do |a| end\n"" a\n""end"],
+ "", [], ["-e:3: warning: shadowing outer local variable - a"], bug4130)
+ assert_in_out_err(["-we", "def foo\n"" a=1\n"" 1.times do |a| end\n""end"],
+ "", [],
+ ["-e:3: warning: shadowing outer local variable - a",
+ "-e:2: warning: assigned but unused variable - a",
+ ], bug4130)
+ feature6693 = '[ruby-core:46160]'
+ assert_in_out_err(["-we", "def foo\n"" _a=1\n"" 1.times do |_a| end\n""end"],
+ "", [], [], feature6693)
+ end
+
+ def test_script_from_stdin
+ begin
+ require 'pty'
+ require 'io/console'
+ rescue LoadError
+ return
+ end
+ require 'timeout'
+ result = nil
+ IO.pipe {|r, w|
+ begin
+ PTY.open {|m, s|
+ s.echo = false
+ m.print("\C-d")
+ pid = spawn(EnvUtil.rubybin, :in => s, :out => w)
+ w.close
+ assert_nothing_raised('[ruby-dev:37798]') do
+ result = Timeout.timeout(3) {r.read}
+ end
+ Process.wait pid
+ }
+ rescue RuntimeError
+ skip $!
+ end
+ }
+ assert_equal("", result, '[ruby-dev:37798]')
+ IO.pipe {|r, w|
+ PTY.open {|m, s|
+ s.echo = false
+ pid = spawn(EnvUtil.rubybin, :in => s, :out => w)
+ w.close
+ m.print("$stdin.read; p $stdin.gets\n\C-d")
+ m.print("abc\n\C-d")
+ m.print("zzz\n")
+ result = r.read
+ Process.wait pid
+ }
+ }
+ assert_equal("\"zzz\\n\"\n", result, '[ruby-core:30910]')
+ end
+
+ def test_unmatching_glob
+ bug3851 = '[ruby-core:32478]'
+ a = "a[foo"
+ Dir.mktmpdir do |dir|
+ open(File.join(dir, a), "w") {|f| f.puts("p 42")}
+ assert_in_out_err(["-C", dir, a], "", ["42"], [], bug3851)
+ File.unlink(File.join(dir, a))
+ assert_in_out_err(["-C", dir, a], "", [], /LoadError/, bug3851)
+ end
+ end
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ def test_command_line_glob_nonascii
+ bug10555 = '[ruby-dev:48752] [Bug #10555]'
+ name = "\u{3042}.txt"
+ expected = name.encode("locale") rescue "?.txt"
+ with_tmpchdir do |dir|
+ open(name, "w") {}
+ assert_in_out_err(["-e", "puts ARGV", "?.txt"], "", [expected], [],
+ bug10555, encoding: "locale")
+ end
+ end
+
+ def test_command_line_progname_nonascii
+ bug10555 = '[ruby-dev:48752] [Bug #10555]'
+ name = "\u{3042}.rb"
+ expected = name.encode("locale") rescue "?.rb"
+ with_tmpchdir do |dir|
+ open(name, "w") {|f| f.puts "puts File.basename($0)"}
+ assert_in_out_err([name], "", [expected], [],
+ bug10555, encoding: "locale")
+ end
+ end
+
+ def test_command_line_glob_with_dir
+ bug10941 = '[ruby-core:68430] [Bug #10941]'
+ with_tmpchdir do |dir|
+ Dir.mkdir('test')
+ assert_in_out_err(["-e", "", "test/*"], "", [], [], bug10941)
+ end
+ end
+ end
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ Ougai = %W[\u{68ee}O\u{5916}.txt \u{68ee 9d0e 5916}.txt \u{68ee 9dd7 5916}.txt]
+ def test_command_line_glob_noncodepage
+ with_tmpchdir do |dir|
+ Ougai.each {|f| open(f, "w") {}}
+ assert_in_out_err(["-Eutf-8", "-e", "puts ARGV", "*"], "", Ougai, encoding: "utf-8")
+ ougai = Ougai.map {|f| f.encode("locale", replace: "?")}
+ assert_in_out_err(["-e", "puts ARGV", "*.txt"], "", ougai)
+ end
+ end
+ end
+
+ def test_script_is_directory
+ feature2408 = '[ruby-core:26925]'
+ assert_in_out_err(%w[.], "", [], /Is a directory -- \./, feature2408)
+ end
+
+ def test_pflag_gsub
+ bug7157 = '[ruby-core:47967]'
+ assert_in_out_err(['-p', '-e', 'gsub(/t.*/){"TEST"}'], %[test], %w[TEST], [], bug7157)
+ end
+
+ def test_pflag_sub
+ bug7157 = '[ruby-core:47967]'
+ assert_in_out_err(['-p', '-e', 'sub(/t.*/){"TEST"}'], %[test], %w[TEST], [], bug7157)
+ end
+
+ def assert_norun_with_rflag(opt)
+ bug10435 = "[ruby-dev:48712] [Bug #10435]: should not run with #{opt} option"
+ stderr = []
+ Tempfile.create(%w"bug10435- .rb") do |script|
+ dir, base = File.split(script.path)
+ script.puts "abort ':run'"
+ script.close
+ opts = ['-C', dir, '-r', "./#{base}", opt]
+ assert_in_out_err([*opts, '-ep']) do |_, e|
+ stderr.concat(e)
+ end
+ stderr << "---"
+ assert_in_out_err([*opts, base]) do |_, e|
+ stderr.concat(e)
+ end
+ end
+ assert_not_include(stderr, ":run", bug10435)
+ end
+
+ def test_dump_syntax_with_rflag
+ assert_norun_with_rflag('-c')
+ assert_norun_with_rflag('--dump=syntax')
+ end
+
+ def test_dump_yydebug_with_rflag
+ assert_norun_with_rflag('-y')
+ assert_norun_with_rflag('--dump=yydebug')
+ end
+
+ def test_dump_parsetree_with_rflag
+ assert_norun_with_rflag('--dump=parsetree')
+ end
+
+ def test_dump_insns_with_rflag
+ assert_norun_with_rflag('--dump=insns')
+ end
+end
diff --git a/jni/ruby/test/ruby/test_rubyvm.rb b/jni/ruby/test/ruby/test_rubyvm.rb
new file mode 100644
index 0000000..580f3be
--- /dev/null
+++ b/jni/ruby/test/ruby/test_rubyvm.rb
@@ -0,0 +1,17 @@
+require 'test/unit'
+
+class TestRubyVM < Test::Unit::TestCase
+ def test_stat
+ assert_kind_of Hash, RubyVM.stat
+ assert_kind_of Fixnum, RubyVM.stat[:global_method_state]
+
+ RubyVM.stat(stat = {})
+ assert_not_empty stat
+ assert_equal stat[:global_method_state], RubyVM.stat(:global_method_state)
+ end
+
+ def test_stat_unknown
+ assert_raise(ArgumentError){ RubyVM.stat(:unknown) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {RubyVM.stat(:"\u{30eb 30d3 30fc}")}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_settracefunc.rb b/jni/ruby/test/ruby/test_settracefunc.rb
new file mode 100644
index 0000000..1dcd2cc
--- /dev/null
+++ b/jni/ruby/test/ruby/test_settracefunc.rb
@@ -0,0 +1,1355 @@
+require 'test/unit'
+
+class TestSetTraceFunc < Test::Unit::TestCase
+ def setup
+ @original_compile_option = RubyVM::InstructionSequence.compile_option
+ RubyVM::InstructionSequence.compile_option = {
+ :trace_instruction => true,
+ :specialized_instruction => false
+ }
+ @target_thread = Thread.current
+ end
+
+ def teardown
+ set_trace_func(nil)
+ RubyVM::InstructionSequence.compile_option = @original_compile_option
+ @target_thread = nil
+ end
+
+ def target_thread?
+ Thread.current == @target_thread
+ end
+
+ def test_c_call
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: x = 1 + 1
+ 5: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 4, :+, Fixnum],
+ events.shift)
+ assert_equal(["c-return", 4, :+, Fixnum],
+ events.shift)
+ assert_equal(["line", 5, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 5, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_call
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: def add(x, y)
+ 5: x + y
+ 6: end
+ 7: x = add(1, 1)
+ 8: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["c-return", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["line", 7, __method__, self.class],
+ events.shift)
+ assert_equal(["call", 4, :add, self.class],
+ events.shift)
+ assert_equal(["line", 5, :add, self.class],
+ events.shift)
+ assert_equal(["c-call", 5, :+, Fixnum],
+ events.shift)
+ assert_equal(["c-return", 5, :+, Fixnum],
+ events.shift)
+ assert_equal(["return", 6, :add, self.class],
+ events.shift)
+ assert_equal(["line", 8, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 8, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_class
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: class Foo
+ 5: def bar
+ 6: end
+ 7: end
+ 8: x = Foo.new.bar
+ 9: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 4, :inherited, Class],
+ events.shift)
+ assert_equal(["c-return", 4, :inherited, Class],
+ events.shift)
+ assert_equal(["class", 4, nil, nil],
+ events.shift)
+ assert_equal(["line", 5, nil, nil],
+ events.shift)
+ assert_equal(["c-call", 5, :method_added, Module],
+ events.shift)
+ assert_equal(["c-return", 5, :method_added, Module],
+ events.shift)
+ assert_equal(["end", 7, nil, nil],
+ events.shift)
+ assert_equal(["line", 8, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 8, :new, Class],
+ events.shift)
+ assert_equal(["c-call", 8, :initialize, BasicObject],
+ events.shift)
+ assert_equal(["c-return", 8, :initialize, BasicObject],
+ events.shift)
+ assert_equal(["c-return", 8, :new, Class],
+ events.shift)
+ assert_equal(["call", 5, :bar, Foo],
+ events.shift)
+ assert_equal(["return", 6, :bar, Foo],
+ events.shift)
+ assert_equal(["line", 9, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 9, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_return # [ruby-dev:38701]
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: def meth_return(a)
+ 5: return if a
+ 6: return
+ 7: end
+ 8: meth_return(true)
+ 9: meth_return(false)
+ 10: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["c-return", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["line", 8, __method__, self.class],
+ events.shift)
+ assert_equal(["call", 4, :meth_return, self.class],
+ events.shift)
+ assert_equal(["line", 5, :meth_return, self.class],
+ events.shift)
+ assert_equal(["return", 5, :meth_return, self.class],
+ events.shift)
+ assert_equal(["line", 9, :test_return, self.class],
+ events.shift)
+ assert_equal(["call", 4, :meth_return, self.class],
+ events.shift)
+ assert_equal(["line", 5, :meth_return, self.class],
+ events.shift)
+ assert_equal(["return", 7, :meth_return, self.class],
+ events.shift)
+ assert_equal(["line", 10, :test_return, self.class],
+ events.shift)
+ assert_equal(["c-call", 10, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_return2 # [ruby-core:24463]
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: def meth_return2
+ 5: a = 5
+ 6: return a
+ 7: end
+ 8: meth_return2
+ 9: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["c-return", 4, :method_added, self.class],
+ events.shift)
+ assert_equal(["line", 8, __method__, self.class],
+ events.shift)
+ assert_equal(["call", 4, :meth_return2, self.class],
+ events.shift)
+ assert_equal(["line", 5, :meth_return2, self.class],
+ events.shift)
+ assert_equal(["line", 6, :meth_return2, self.class],
+ events.shift)
+ assert_equal(["return", 7, :meth_return2, self.class],
+ events.shift)
+ assert_equal(["line", 9, :test_return2, self.class],
+ events.shift)
+ assert_equal(["c-call", 9, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_raise
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: begin
+ 5: raise TypeError, "error"
+ 6: rescue TypeError
+ 7: end
+ 8: set_trace_func(nil)
+ EOF
+ assert_equal(["c-return", 1, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal(["line", 4, __method__, self.class],
+ events.shift)
+ assert_equal(["line", 5, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 5, :raise, Kernel],
+ events.shift)
+ assert_equal(["c-call", 5, :exception, Exception],
+ events.shift)
+ assert_equal(["c-call", 5, :initialize, Exception],
+ events.shift)
+ assert_equal(["c-return", 5, :initialize, Exception],
+ events.shift)
+ assert_equal(["c-return", 5, :exception, Exception],
+ events.shift)
+ assert_equal(["c-return", 5, :raise, Kernel],
+ events.shift)
+ assert_equal(["c-call", 5, :backtrace, Exception],
+ events.shift)
+ assert_equal(["c-return", 5, :backtrace, Exception],
+ events.shift)
+ assert_equal(["raise", 5, :test_raise, TestSetTraceFunc],
+ events.shift)
+ assert_equal(["c-call", 6, :===, Module],
+ events.shift)
+ assert_equal(["c-return", 6, :===, Module],
+ events.shift)
+ assert_equal(["line", 8, __method__, self.class],
+ events.shift)
+ assert_equal(["c-call", 8, :set_trace_func, Kernel],
+ events.shift)
+ assert_equal([], events)
+ end
+
+ def test_break # [ruby-core:27606] [Bug #2610]
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 2: events << [event, lineno, mid, klass] if file == name
+ 3: })
+ 4: [1,2,3].any? {|n| n}
+ 8: set_trace_func(nil)
+ EOF
+
+ [["c-return", 1, :set_trace_func, Kernel],
+ ["line", 4, __method__, self.class],
+ ["c-call", 4, :any?, Array],
+ ["line", 4, __method__, self.class],
+ ["c-return", 4, :any?, Array],
+ ["line", 5, __method__, self.class],
+ ["c-call", 5, :set_trace_func, Kernel]].each{|e|
+ assert_equal(e, events.shift)
+ }
+ end
+
+ def test_invalid_proc
+ assert_raise(TypeError) { set_trace_func(1) }
+ end
+
+ def test_raise_in_trace
+ set_trace_func proc {raise rescue nil}
+ assert_equal(42, (raise rescue 42), '[ruby-core:24118]')
+ end
+
+ def test_thread_trace
+ events = {:set => [], :add => []}
+ prc = Proc.new { |event, file, lineno, mid, binding, klass|
+ events[:set] << [event, lineno, mid, klass, :set]
+ }
+ prc = prc # suppress warning
+ prc2 = Proc.new { |event, file, lineno, mid, binding, klass|
+ events[:add] << [event, lineno, mid, klass, :add]
+ }
+ prc2 = prc2 # suppress warning
+
+ th = Thread.new do
+ th = Thread.current
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: th.set_trace_func(prc)
+ 2: th.add_trace_func(prc2)
+ 3: class ThreadTraceInnerClass
+ 4: def foo
+ 5: _x = 1 + 1
+ 6: end
+ 7: end
+ 8: ThreadTraceInnerClass.new.foo
+ 9: th.set_trace_func(nil)
+ EOF
+ end
+ th.join
+
+ [["c-return", 1, :set_trace_func, Thread, :set],
+ ["line", 2, __method__, self.class, :set],
+ ["c-call", 2, :add_trace_func, Thread, :set]].each do |e|
+ assert_equal(e, events[:set].shift)
+ end
+
+ [["c-return", 2, :add_trace_func, Thread],
+ ["line", 3, __method__, self.class],
+ ["c-call", 3, :inherited, Class],
+ ["c-return", 3, :inherited, Class],
+ ["class", 3, nil, nil],
+ ["line", 4, nil, nil],
+ ["c-call", 4, :method_added, Module],
+ ["c-return", 4, :method_added, Module],
+ ["end", 7, nil, nil],
+ ["line", 8, __method__, self.class],
+ ["c-call", 8, :new, Class],
+ ["c-call", 8, :initialize, BasicObject],
+ ["c-return", 8, :initialize, BasicObject],
+ ["c-return", 8, :new, Class],
+ ["call", 4, :foo, ThreadTraceInnerClass],
+ ["line", 5, :foo, ThreadTraceInnerClass],
+ ["c-call", 5, :+, Fixnum],
+ ["c-return", 5, :+, Fixnum],
+ ["return", 6, :foo, ThreadTraceInnerClass],
+ ["line", 9, __method__, self.class],
+ ["c-call", 9, :set_trace_func, Thread]].each do |e|
+ [:set, :add].each do |type|
+ assert_equal(e + [type], events[type].shift)
+ end
+ end
+ assert_equal([], events[:set])
+ assert_equal([], events[:add])
+ end
+
+ def test_trace_defined_method
+ events = []
+ name = "#{self.class}\##{__method__}"
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, name
+ 1: class FooBar; define_method(:foobar){}; end
+ 2: fb = FooBar.new
+ 3: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
+ 4: events << [event, lineno, mid, klass] if file == name
+ 5: })
+ 6: fb.foobar
+ 7: set_trace_func(nil)
+ EOF
+
+ [["c-return", 3, :set_trace_func, Kernel],
+ ["line", 6, __method__, self.class],
+ ["call", 1, :foobar, FooBar],
+ ["return", 6, :foobar, FooBar],
+ ["line", 7, __method__, self.class],
+ ["c-call", 7, :set_trace_func, Kernel]].each{|e|
+ assert_equal(e, events.shift)
+ }
+ end
+
+ def test_remove_in_trace
+ bug3921 = '[ruby-dev:42350]'
+ ok = false
+ func = lambda{|e, f, l, i, b, k|
+ set_trace_func(nil)
+ ok = eval("self", b)
+ }
+
+ set_trace_func(func)
+ assert_equal(self, ok, bug3921)
+ end
+
+ class << self
+ define_method(:method_added, Module.method(:method_added))
+ end
+
+ def trace_by_tracepoint *trace_events
+ events = []
+ trace = nil
+ xyzzy = nil
+ _local_var = :outer
+ raised_exc = nil
+ method = :trace_by_tracepoint
+ _get_data = lambda{|tp|
+ case tp.event
+ when :return, :c_return
+ tp.return_value
+ when :raise
+ tp.raised_exception
+ else
+ :nothing
+ end
+ }
+ _defined_class = lambda{|tp|
+ klass = tp.defined_class
+ begin
+ # If it is singleton method, then return original class
+ # to make compatible with set_trace_func().
+ # This is very ad-hoc hack. I hope I can make more clean test on it.
+ case klass.inspect
+ when /Class:TracePoint/; return TracePoint
+ when /Class:Exception/; return Exception
+ else klass
+ end
+ rescue Exception => e
+ e
+ end if klass
+ }
+
+ trace = nil
+ begin
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy'
+ 1: trace = TracePoint.trace(*trace_events){|tp| next if !target_thread?
+ 2: events << [tp.event, tp.lineno, tp.path, _defined_class.(tp), tp.method_id, tp.self, tp.binding.eval("_local_var"), _get_data.(tp)] if tp.path == 'xyzzy'
+ 3: }
+ 4: 1.times{|;_local_var| _local_var = :inner
+ 5: tap{}
+ 6: }
+ 7: class XYZZY
+ 8: _local_var = :XYZZY_outer
+ 9: def foo
+ 10: _local_var = :XYZZY_foo
+ 11: bar
+ 12: end
+ 13: def bar
+ 14: _local_var = :XYZZY_bar
+ 15: tap{}
+ 16: end
+ 17: end
+ 18: xyzzy = XYZZY.new
+ 19: xyzzy.foo
+ 20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end
+ 21: trace.disable
+ EOF
+ self.class.class_eval{remove_const(:XYZZY)}
+ ensure
+ trace.disable if trace && trace.enabled?
+ end
+
+ answer_events = [
+ #
+ [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, :outer, trace],
+ [:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing],
+ [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing],
+ [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing],
+ [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
+ [:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing],
+ [:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self],
+ [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1],
+ [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
+ [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing],
+ [:c_return, 7, "xyzzy", Class, :inherited, Object, :outer, nil],
+ [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
+ [:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
+ [:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],
+ [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing],
+ [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil],
+ [:line, 13, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],
+ [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing],
+ [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil],
+ [:end, 17, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],
+ [:line, 18, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
+ [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, :outer, :nothing],
+ [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, :nothing],
+ [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, nil],
+ [:c_return,18, "xyzzy", Class, :new, xyzzy.class, :outer, xyzzy],
+ [:line, 19, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
+ [:call, 9, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing],
+ [:line, 10, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing],
+ [:line, 11, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, :nothing],
+ [:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
+ [:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
+ [:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing],
+ [:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing],
+ [:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy],
+ [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy],
+ [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy],
+ [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
+ [:c_call, 20, "xyzzy", Kernel, :raise, self, :outer, :nothing],
+ [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, :outer, :nothing],
+ [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, :outer, :nothing],
+ [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, :outer, raised_exc],
+ [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, :outer, raised_exc],
+ [:c_return,20, "xyzzy", Kernel, :raise, self, :outer, nil],
+ [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, :outer, :nothing],
+ [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, :outer, nil],
+ [:raise, 20, "xyzzy", TestSetTraceFunc, :trace_by_tracepoint, self, :outer, raised_exc],
+ [:c_call, 20, "xyzzy", Module, :===, RuntimeError,:outer, :nothing],
+ [:c_return,20, "xyzzy", Module, :===, RuntimeError,:outer, true],
+ [:line, 21, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
+ [:c_call, 21, "xyzzy", TracePoint, :disable, trace, :outer, :nothing],
+ ]
+
+ return events, answer_events
+ end
+
+ def trace_by_set_trace_func
+ events = []
+ trace = nil
+ trace = trace
+ xyzzy = nil
+ xyzzy = xyzzy
+ _local_var = :outer
+ eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy'
+ 1: set_trace_func(lambda{|event, file, line, id, binding, klass|
+ 2: events << [event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")] if file == 'xyzzy'
+ 3: })
+ 4: 1.times{|;_local_var| _local_var = :inner
+ 5: tap{}
+ 6: }
+ 7: class XYZZY
+ 8: _local_var = :XYZZY_outer
+ 9: def foo
+ 10: _local_var = :XYZZY_foo
+ 11: bar
+ 12: end
+ 13: def bar
+ 14: _local_var = :XYZZY_bar
+ 15: tap{}
+ 16: end
+ 17: end
+ 18: xyzzy = XYZZY.new
+ 19: xyzzy.foo
+ 20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end
+ 21: set_trace_func(nil)
+ EOF
+ self.class.class_eval{remove_const(:XYZZY)}
+ return events
+ end
+
+ def test_tracepoint
+ events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise)
+
+ ms = [events1, answer_events].map{|evs|
+ evs.map{|e|
+ "#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
+ }
+ }
+
+ mesg = ms[0].zip(ms[1]).map{|a, b|
+ if a != b
+ "#{a} <-> #{b}"
+ end
+ }.compact.join("\n")
+
+ answer_events.zip(events1){|answer, event|
+ assert_equal answer, event, mesg
+ }
+
+ events2 = trace_by_set_trace_func
+ events1.zip(events2){|ev1, ev2|
+ ev2[0] = ev2[0].sub('-', '_').to_sym
+ assert_equal ev1[0..2], ev2[0..2], ev1.inspect
+
+ # event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")
+ assert_equal ev1[3].nil?, ev2[3].nil? # klass
+ assert_equal ev1[4].nil?, ev2[4].nil? # id
+ assert_equal ev1[6], ev2[6] # _local_var
+ }
+
+ [:line, :class, :end, :call, :return, :c_call, :c_return, :raise].each{|event|
+ events1, answer_events = *trace_by_tracepoint(event)
+ answer_events.find_all{|e| e[0] == event}.zip(events1){|answer_line, event_line|
+ assert_equal answer_line, event_line
+ }
+ }
+ end
+
+ def test_tracepoint_object_id
+ tps = []
+ trace = TracePoint.trace(){|tp|
+ next if !target_thread?
+ tps << tp
+ }
+ tap{}
+ tap{}
+ tap{}
+ trace.disable
+
+ # passed tp is unique, `trace' object which is generated by TracePoint.trace
+ tps.each{|tp|
+ assert_equal trace, tp
+ }
+ end
+
+ def test_tracepoint_access_from_outside
+ tp_store = nil
+ trace = TracePoint.trace(){|tp|
+ next if !target_thread?
+ tp_store = tp
+ }
+ tap{}
+ trace.disable
+
+ assert_raise(RuntimeError){tp_store.lineno}
+ assert_raise(RuntimeError){tp_store.event}
+ assert_raise(RuntimeError){tp_store.path}
+ assert_raise(RuntimeError){tp_store.method_id}
+ assert_raise(RuntimeError){tp_store.defined_class}
+ assert_raise(RuntimeError){tp_store.binding}
+ assert_raise(RuntimeError){tp_store.self}
+ assert_raise(RuntimeError){tp_store.return_value}
+ assert_raise(RuntimeError){tp_store.raised_exception}
+ end
+
+ def foo
+ end
+
+ def test_tracepoint_enable
+ ary = []
+ trace = TracePoint.new(:call){|tp|
+ next if !target_thread?
+ ary << tp.method_id
+ }
+ foo
+ trace.enable{
+ foo
+ }
+ foo
+ assert_equal([:foo], ary)
+
+ trace = TracePoint.new{}
+ begin
+ assert_equal(false, trace.enable)
+ assert_equal(true, trace.enable)
+ trace.enable{}
+ assert_equal(true, trace.enable)
+ ensure
+ trace.disable
+ end
+ end
+
+ def test_tracepoint_disable
+ ary = []
+ trace = TracePoint.trace(:call){|tp|
+ next if !target_thread?
+ ary << tp.method_id
+ }
+ foo
+ trace.disable{
+ foo
+ }
+ foo
+ trace.disable
+ assert_equal([:foo, :foo], ary)
+
+ trace = TracePoint.new{}
+ trace.enable{
+ assert_equal(true, trace.disable)
+ assert_equal(false, trace.disable)
+ trace.disable{}
+ assert_equal(false, trace.disable)
+ }
+ end
+
+ def test_tracepoint_enabled
+ trace = TracePoint.trace(:call){|tp|
+ #
+ }
+ assert_equal(true, trace.enabled?)
+ trace.disable{
+ assert_equal(false, trace.enabled?)
+ trace.enable{
+ assert_equal(true, trace.enabled?)
+ }
+ }
+ trace.disable
+ assert_equal(false, trace.enabled?)
+ end
+
+ def method_test_tracepoint_return_value obj
+ obj
+ end
+
+ def test_tracepoint_return_value
+ trace = TracePoint.new(:call, :return){|tp|
+ next if !target_thread?
+ next if tp.path != __FILE__
+ case tp.event
+ when :call
+ assert_raise(RuntimeError) {tp.return_value}
+ when :return
+ assert_equal("xyzzy", tp.return_value)
+ end
+ }
+ trace.enable{
+ method_test_tracepoint_return_value "xyzzy"
+ }
+ end
+
+ class XYZZYException < Exception; end
+ def method_test_tracepoint_raised_exception err
+ raise err
+ end
+
+ def test_tracepoint_raised_exception
+ trace = TracePoint.new(:call, :return){|tp|
+ next if !target_thread?
+ case tp.event
+ when :call, :return
+ assert_raise(RuntimeError) { tp.raised_exception }
+ when :raise
+ assert_equal(XYZZYError, tp.raised_exception)
+ end
+ }
+ trace.enable{
+ begin
+ method_test_tracepoint_raised_exception XYZZYException
+ rescue XYZZYException
+ # ok
+ else
+ raise
+ end
+ }
+ end
+
+ def method_for_test_tracepoint_block
+ yield
+ end
+
+ def test_tracepoint_block
+ events = []
+ TracePoint.new(:call, :return, :c_call, :b_call, :c_return, :b_return){|tp|
+ next if !target_thread?
+ events << [
+ tp.event, tp.method_id, tp.defined_class, tp.self.class,
+ /return/ =~ tp.event ? tp.return_value : nil
+ ]
+ }.enable{
+ 1.times{
+ 3
+ }
+ method_for_test_tracepoint_block{
+ 4
+ }
+ }
+ # pp events
+ # expected_events =
+ [[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:c_call, :times, Integer, Fixnum, nil],
+ [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3],
+ [:c_return, :times, Integer, Fixnum, 1],
+ [:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
+ [:return, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4]
+ ].zip(events){|expected, actual|
+ assert_equal(expected, actual)
+ }
+ end
+
+ def test_tracepoint_thread
+ events = []
+ thread_self = nil
+ created_thread = nil
+ TracePoint.new(:thread_begin, :thread_end){|tp|
+ events << [Thread.current,
+ tp.event,
+ tp.lineno, #=> 0
+ tp.path, #=> nil
+ tp.binding, #=> nil
+ tp.defined_class, #=> nil,
+ tp.self.class # tp.self return creating/ending thread
+ ]
+ }.enable{
+ created_thread = Thread.new{thread_self = self}
+ created_thread.join
+ }
+ events.reject!{|i| i[0] != created_thread}
+ assert_equal(self, thread_self)
+ assert_equal([created_thread, :thread_begin, 0, nil, nil, nil, Thread], events[0])
+ assert_equal([created_thread, :thread_end, 0, nil, nil, nil, Thread], events[1])
+ assert_equal(2, events.size)
+ end
+
+ def test_tracepoint_inspect
+ events = []
+ trace = TracePoint.new{|tp|
+ next if !target_thread?
+ events << [tp.event, tp.inspect]
+ }
+ assert_equal("#<TracePoint:disabled>", trace.inspect)
+ trace.enable{
+ assert_equal("#<TracePoint:enabled>", trace.inspect)
+ Thread.new{}.join
+ }
+ assert_equal("#<TracePoint:disabled>", trace.inspect)
+ events.each{|(ev, str)|
+ case ev
+ when :line
+ assert_match(/ in /, str)
+ when :call, :c_call
+ assert_match(/call \`/, str) # #<TracePoint:c_call `inherited'@../trunk/test.rb:11>
+ when :return, :c_return
+ assert_match(/return \`/, str) # #<TracePoint:return `m'@../trunk/test.rb:3>
+ when /thread/
+ assert_match(/\#<Thread:/, str) # #<TracePoint:thread_end of #<Thread:0x87076c0>>
+ else
+ assert_match(/\#<TracePoint:/, str)
+ end
+ }
+ end
+
+ def test_tracepoint_exception_at_line
+ assert_raise(RuntimeError) do
+ TracePoint.new(:line) {
+ next if !target_thread?
+ raise
+ }.enable {
+ 1
+ }
+ end
+ end
+
+ def test_tracepoint_exception_at_return
+ assert_nothing_raised(Timeout::Error, 'infinite trace') do
+ assert_normal_exit('def m; end; TracePoint.new(:return) {raise}.enable {m}', '', timeout: 3)
+ end
+ end
+
+ def test_tracepoint_with_multithreads
+ assert_nothing_raised do
+ TracePoint.new{
+ 10.times{
+ Thread.pass
+ }
+ }.enable do
+ (1..10).map{
+ Thread.new{
+ 1000.times{
+ }
+ }
+ }.each{|th|
+ th.join
+ }
+ end
+ end
+ end
+
+ class FOO_ERROR < RuntimeError; end
+ class BAR_ERROR < RuntimeError; end
+ def m1_test_trace_point_at_return_when_exception
+ m2_test_trace_point_at_return_when_exception
+ end
+ def m2_test_trace_point_at_return_when_exception
+ raise BAR_ERROR
+ end
+
+ def test_trace_point_at_return_when_exception
+ bug_7624 = '[ruby-core:51128] [ruby-trunk - Bug #7624]'
+ TracePoint.new{|tp|
+ next if !target_thread?
+ if tp.event == :return &&
+ tp.method_id == :m2_test_trace_point_at_return_when_exception
+ raise FOO_ERROR
+ end
+ }.enable do
+ assert_raise(FOO_ERROR, bug_7624) do
+ m1_test_trace_point_at_return_when_exception
+ end
+ end
+
+ bug_7668 = '[Bug #7668]'
+ ary = []
+ trace = TracePoint.new{|tp|
+ next if !target_thread?
+ ary << tp.event
+ raise
+ }
+ begin
+ trace.enable{
+ 1.times{
+ raise
+ }
+ }
+ rescue
+ assert_equal([:b_call, :b_return], ary, bug_7668)
+ end
+ end
+
+ def m1_for_test_trace_point_binding_in_ifunc(arg)
+ arg + nil
+ rescue
+ end
+
+ def m2_for_test_trace_point_binding_in_ifunc(arg)
+ arg.inject(:+)
+ rescue
+ end
+
+ def test_trace_point_binding_in_ifunc
+ bug7774 = '[ruby-dev:46908]'
+ src = %q{
+ tp = TracePoint.new(:raise) do |tp|
+ tp.binding
+ end
+ tp.enable do
+ obj = Object.new
+ class << obj
+ include Enumerable
+ def each
+ yield 1
+ end
+ end
+ %s
+ end
+ }
+ assert_normal_exit src % %q{obj.zip({}) {}}, bug7774
+ assert_normal_exit src % %q{
+ require 'continuation'
+ begin
+ c = nil
+ obj.sort_by {|x| callcc {|c2| c ||= c2 }; x }
+ c.call
+ rescue RuntimeError
+ end
+ }, bug7774
+
+ # TracePoint
+ tp_b = nil
+ TracePoint.new(:raise) do |tp|
+ next if !target_thread?
+ tp_b = tp.binding
+ end.enable do
+ m1_for_test_trace_point_binding_in_ifunc(0)
+ assert_equal(self, eval('self', tp_b), '[ruby-dev:46960]')
+
+ m2_for_test_trace_point_binding_in_ifunc([0, nil])
+ assert_equal(self, eval('self', tp_b), '[ruby-dev:46960]')
+ end
+
+ # set_trace_func
+ stf_b = nil
+ set_trace_func ->(event, file, line, id, binding, klass) do
+ stf_b = binding if event == 'raise'
+ end
+ begin
+ m1_for_test_trace_point_binding_in_ifunc(0)
+ assert_equal(self, eval('self', stf_b), '[ruby-dev:46960]')
+
+ m2_for_test_trace_point_binding_in_ifunc([0, nil])
+ assert_equal(self, eval('self', stf_b), '[ruby-dev:46960]')
+ ensure
+ set_trace_func(nil)
+ end
+ end
+
+ def test_trace_point_binding_after_break
+ bug10689 = '[ruby-dev:48797]'
+ assert_in_out_err([], <<-INPUT, [], [], bug10689)
+ class Bug
+ include Enumerable
+
+ def each
+ [0].each do
+ yield
+ end
+ end
+ end
+
+ TracePoint.trace(:c_return) do |tp|
+ tp.binding
+ end
+
+ Bug.new.all? { false }
+ INPUT
+ end
+
+ def test_tracepoint_b_return_with_next
+ n = 0
+ TracePoint.new(:b_return){
+ next if !target_thread?
+ n += 1
+ }.enable{
+ 3.times{
+ next
+ } # 3 times b_retun
+ } # 1 time b_return
+
+ assert_equal 4, n
+ end
+
+ def test_tracepoint_b_return_with_lambda
+ n = 0
+ TracePoint.new(:b_return){
+ next if !target_thread?
+ n+=1
+ }.enable{
+ lambda{
+ return
+ }.call # n += 1 #=> 1
+ 3.times{
+ lambda{
+ return # n += 3 #=> 4
+ }.call
+ } # n += 3 #=> 7
+ begin
+ lambda{
+ raise
+ }.call # n += 1 #=> 8
+ rescue
+ # ignore
+ end # n += 1 #=> 9
+ }
+
+ assert_equal 9, n
+ end
+
+ def test_isolated_raise_in_trace
+ bug9088 = '[ruby-dev:47793] [Bug #9088]'
+ assert_ruby_status([], <<-END, bug9088)
+ set_trace_func proc {raise rescue nil}
+ 1.times {break}
+ END
+ end
+
+ def test_a_call
+ events = []
+ TracePoint.new(:a_call){|tp|
+ next if !target_thread?
+ events << tp.event
+ }.enable{
+ 1.times{
+ 3
+ }
+ method_for_test_tracepoint_block{
+ 4
+ }
+ }
+ assert_equal([
+ :b_call,
+ :c_call,
+ :b_call,
+ :call,
+ :b_call,
+ ], events)
+ end
+
+ def test_a_return
+ events = []
+ TracePoint.new(:a_return){|tp|
+ next if !target_thread?
+ events << tp.event
+ }.enable{
+ 1.times{
+ 3
+ }
+ method_for_test_tracepoint_block{
+ 4
+ }
+ }
+ assert_equal([
+ :b_return,
+ :c_return,
+ :b_return,
+ :return,
+ :b_return
+ ], events)
+ end
+
+ def test_const_missing
+ bug59398 = '[ruby-core:59398]'
+ events = []
+ assert !defined?(MISSING_CONSTANT_59398)
+ TracePoint.new(:c_call, :c_return, :call, :return){|tp|
+ next if !target_thread?
+ next unless tp.defined_class == Module
+ # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name
+ # but this only happens when running the full test suite
+ events << [tp.event,tp.method_id] if tp.method_id == :const_missing || tp.method_id == :rake_original_const_missing
+ }.enable{
+ MISSING_CONSTANT_59398 rescue nil
+ }
+ if events.map{|e|e[1]}.include?(:rake_original_const_missing)
+ assert_equal([
+ [:call, :const_missing],
+ [:c_call, :rake_original_const_missing],
+ [:c_return, :rake_original_const_missing],
+ [:return, :const_missing],
+ ], events, bug59398)
+ else
+ assert_equal([
+ [:c_call, :const_missing],
+ [:c_return, :const_missing]
+ ], events, bug59398)
+ end
+ end
+
+ class AliasedRubyMethod
+ def foo; 1; end;
+ alias bar foo
+ end
+ def test_aliased_ruby_method
+ events = []
+ aliased = AliasedRubyMethod.new
+ TracePoint.new(:call, :return){|tp|
+ next if !target_thread?
+ events << [tp.event, tp.method_id]
+ }.enable{
+ aliased.bar
+ }
+ assert_equal([
+ [:call, :foo],
+ [:return, :foo]
+ ], events, "should use original method name for tracing ruby methods")
+ end
+ class AliasedCMethod < Hash
+ alias original_size size
+ def size; original_size; end
+ end
+
+ def test_aliased_c_method
+ events = []
+ aliased = AliasedCMethod.new
+ TracePoint.new(:call, :return, :c_call, :c_return){|tp|
+ next if !target_thread?
+ events << [tp.event, tp.method_id]
+ }.enable{
+ aliased.size
+ }
+ assert_equal([
+ [:call, :size],
+ [:c_call, :original_size],
+ [:c_return, :original_size],
+ [:return, :size]
+ ], events, "should use alias method name for tracing c methods")
+ end
+
+ def test_method_missing
+ bug59398 = '[ruby-core:59398]'
+ events = []
+ assert !respond_to?(:missing_method_59398)
+ TracePoint.new(:c_call, :c_return, :call, :return){|tp|
+ next if !target_thread?
+ next unless tp.defined_class == BasicObject
+ # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name
+ # but this only happens when running the full test suite
+ events << [tp.event,tp.method_id] if tp.method_id == :method_missing
+ }.enable{
+ missing_method_59398 rescue nil
+ }
+ assert_equal([
+ [:c_call, :method_missing],
+ [:c_return, :method_missing]
+ ], events, bug59398)
+ end
+
+ class C9759
+ define_method(:foo){
+ raise
+ }
+ end
+
+ def test_define_method_on_exception
+ events = []
+ obj = C9759.new
+ TracePoint.new(:call, :return){|tp|
+ next unless target_thread?
+ events << [tp.event, tp.method_id]
+ }.enable{
+ obj.foo rescue nil
+ }
+ assert_equal([[:call, :foo], [:return, :foo]], events, 'Bug #9759')
+
+ events = []
+ begin
+ set_trace_func(lambda{|event, file, lineno, mid, binding, klass|
+ next unless target_thread?
+ case event
+ when 'call', 'return'
+ events << [event, mid]
+ end
+ })
+ obj.foo rescue nil
+ set_trace_func(nil)
+
+ assert_equal([['call', :foo], ['return', :foo]], events, 'Bug #9759')
+ ensure
+ end
+ end
+
+ def test_recursive
+ assert_ruby_status [], %q{
+ stack = []
+ TracePoint.new(:c_call){|tp|
+ p 2
+ stack << tp.method_id
+ }.enable{
+ p 1
+ }
+ raise if stack != [:p, :hash, :inspect]
+ }, '[Bug #9940]'
+ end
+
+ def method_prefix event
+ case event
+ when :call, :return
+ :n
+ when :c_call, :c_return
+ :c
+ when :b_call, :b_return
+ :b
+ end
+ end
+
+ def method_label tp
+ "#{method_prefix(tp.event)}##{tp.method_id}"
+ end
+
+ def assert_consistent_call_return message='', check_events: nil
+ check_events ||= %i(a_call a_return)
+ call_stack = []
+
+ TracePoint.new(*check_events){|tp|
+ next unless target_thread?
+
+ case tp.event.to_s
+ when /call/
+ call_stack << method_label(tp)
+ when /return/
+ frame = call_stack.pop
+ assert_equal(frame, method_label(tp))
+ end
+ }.enable do
+ yield
+ end
+
+ assert_equal true, call_stack.empty?
+ end
+
+ def method_test_rescue_should_not_cause_b_return
+ begin
+ raise
+ rescue
+ return
+ end
+ end
+
+ def method_test_ensure_should_not_cause_b_return
+ begin
+ raise
+ ensure
+ return
+ end
+ end
+
+ def test_rescue_and_ensure_should_not_cause_b_return
+ assert_consistent_call_return '[Bug #9957]' do
+ method_test_rescue_should_not_cause_b_return
+ begin
+ method_test_ensure_should_not_cause_b_return
+ rescue
+ # ignore
+ end
+ end
+ end
+
+ define_method(:method_test_argument_error_on_bmethod){|correct_key: 1|}
+
+ def test_argument_error_on_bmethod
+ assert_consistent_call_return '[Bug #9959]' do
+ begin
+ method_test_argument_error_on_bmethod(wrong_key: 2)
+ rescue => e
+ # ignore
+ end
+ end
+ end
+
+ def test_rb_rescue
+ assert_consistent_call_return '[Bug #9961]' do
+ begin
+ -Numeric.new
+ rescue => e
+ # ignore
+ end
+ end
+ end
+
+ def test_b_call_with_redo
+ assert_consistent_call_return '[Bug #9964]' do
+ i = 0
+ 1.times{
+ break if (i+=1) > 10
+ redo
+ }
+ end
+ end
+
+ def test_no_duplicate_line_events
+ lines = []
+ dummy = []
+
+ TracePoint.new(:line){|tp|
+ next unless target_thread?
+ lines << tp.lineno
+ }.enable{
+ dummy << (1) + (2)
+ dummy << (1) + (2)
+ }
+ assert_equal [__LINE__ - 3, __LINE__ - 2], lines, 'Bug #10449'
+ end
+
+ class Bug10724
+ def initialize
+ loop{return}
+ end
+ end
+
+ def test_throwing_return_with_finish_frame
+ target_th = Thread.current
+ evs = []
+
+ TracePoint.new(:call, :return){|tp|
+ return if Thread.current != target_th
+ evs << tp.event
+ }.enable{
+ a = Bug10724.new
+ }
+
+ assert_equal([:call, :return], evs)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_signal.rb b/jni/ruby/test/ruby/test_signal.rb
new file mode 100644
index 0000000..4a59aa6
--- /dev/null
+++ b/jni/ruby/test/ruby/test_signal.rb
@@ -0,0 +1,294 @@
+require 'test/unit'
+require 'timeout'
+require 'tempfile'
+
+class TestSignal < Test::Unit::TestCase
+ def test_signal
+ begin
+ x = 0
+ oldtrap = Signal.trap(:INT) {|sig| x = 2 }
+ Process.kill :INT, Process.pid
+ 10.times do
+ break if 2 == x
+ sleep 0.1
+ end
+ assert_equal 2, x
+
+ Signal.trap(:INT) { raise "Interrupt" }
+ assert_raise_with_message(RuntimeError, /Interrupt/) {
+ Process.kill :INT, Process.pid
+ sleep 0.1
+ }
+ ensure
+ Signal.trap :INT, oldtrap if oldtrap
+ end
+ end if Process.respond_to?(:kill)
+
+ def test_signal_process_group
+ bug4362 = '[ruby-dev:43169]'
+ assert_nothing_raised(bug4362) do
+ pid = Process.spawn(EnvUtil.rubybin, '-e', 'sleep 10', :pgroup => true)
+ Process.kill(:"-TERM", pid)
+ Process.waitpid(pid)
+ assert_equal(true, $?.signaled?)
+ assert_equal(Signal.list["TERM"], $?.termsig)
+ end
+ end if Process.respond_to?(:kill) and
+ Process.respond_to?(:pgroup) # for mswin32
+
+ def test_exit_action
+ if Signal.list[sig = "USR1"]
+ term = :TERM
+ else
+ sig = "INT"
+ term = :KILL
+ end
+ IO.popen([EnvUtil.rubybin, '-e', <<-"End"], 'r+') do |io|
+ Signal.trap(:#{sig}, "EXIT")
+ STDOUT.syswrite("a")
+ Thread.start { sleep(2) }
+ STDIN.sysread(4096)
+ End
+ pid = io.pid
+ io.sysread(1)
+ sleep 0.1
+ assert_nothing_raised("[ruby-dev:26128]") {
+ Process.kill(term, pid)
+ begin
+ Timeout.timeout(3) {
+ Process.waitpid pid
+ }
+ rescue Timeout::Error
+ if term
+ Process.kill(term, pid)
+ term = (:KILL if term != :KILL)
+ retry
+ end
+ raise
+ end
+ }
+ end
+ end if Process.respond_to?(:kill)
+
+ def test_invalid_signal_name
+ assert_raise(ArgumentError) { Process.kill(:XXXXXXXXXX, $$) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.kill("\u{30eb 30d3 30fc}", $$) }
+ end if Process.respond_to?(:kill)
+
+ def test_signal_exception
+ assert_raise(ArgumentError) { SignalException.new }
+ assert_raise(ArgumentError) { SignalException.new(-1) }
+ assert_raise(ArgumentError) { SignalException.new(:XXXXXXXXXX) }
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { SignalException.new("\u{30eb 30d3 30fc}") }
+ Signal.list.each do |signm, signo|
+ next if signm == "EXIT"
+ assert_equal(SignalException.new(signm).signo, signo)
+ assert_equal(SignalException.new(signm.to_sym).signo, signo)
+ assert_equal(SignalException.new(signo).signo, signo)
+ end
+ end
+
+ def test_interrupt
+ assert_raise(Interrupt) { raise Interrupt.new }
+ end
+
+ def test_signal2
+ begin
+ x = false
+ oldtrap = Signal.trap(:INT) {|sig| x = true }
+ GC.start
+
+ assert_raise(ArgumentError) { Process.kill }
+
+ Timeout.timeout(10) do
+ x = false
+ Process.kill(SignalException.new(:INT).signo, $$)
+ sleep(0.01) until x
+
+ x = false
+ Process.kill("INT", $$)
+ sleep(0.01) until x
+
+ x = false
+ Process.kill("SIGINT", $$)
+ sleep(0.01) until x
+
+ x = false
+ o = Object.new
+ def o.to_str; "SIGINT"; end
+ Process.kill(o, $$)
+ sleep(0.01) until x
+ end
+
+ assert_raise(ArgumentError) { Process.kill(Object.new, $$) }
+
+ ensure
+ Signal.trap(:INT, oldtrap) if oldtrap
+ end
+ end if Process.respond_to?(:kill)
+
+ def test_trap
+ begin
+ oldtrap = Signal.trap(:INT) {|sig| }
+
+ assert_raise(ArgumentError) { Signal.trap }
+
+ assert_raise(SecurityError) do
+ s = proc {}.taint
+ Signal.trap(:INT, s)
+ end
+
+ # FIXME!
+ Signal.trap(:INT, nil)
+ Signal.trap(:INT, "")
+ Signal.trap(:INT, "SIG_IGN")
+ Signal.trap(:INT, "IGNORE")
+
+ Signal.trap(:INT, "SIG_DFL")
+ Signal.trap(:INT, "SYSTEM_DEFAULT")
+
+ Signal.trap(:INT, "EXIT")
+
+ Signal.trap(:INT, "xxxxxx")
+ Signal.trap(:INT, "xxxx")
+
+ Signal.trap(SignalException.new(:INT).signo, "SIG_DFL")
+
+ assert_raise(ArgumentError) { Signal.trap(-1, "xxxx") }
+
+ o = Object.new
+ def o.to_str; "SIGINT"; end
+ Signal.trap(o, "SIG_DFL")
+
+ assert_raise(ArgumentError) { Signal.trap("XXXXXXXXXX", "SIG_DFL") }
+
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Signal.trap("\u{30eb 30d3 30fc}", "SIG_DFL") }
+ ensure
+ Signal.trap(:INT, oldtrap) if oldtrap
+ end
+ end if Process.respond_to?(:kill)
+
+ %w"KILL STOP".each do |sig|
+ if Signal.list.key?(sig)
+ define_method("test_trap_uncatchable_#{sig}") do
+ assert_raise(Errno::EINVAL, "SIG#{sig} is not allowed to be caught") { Signal.trap(sig) {} }
+ end
+ end
+ end
+
+ def test_sigexit
+ assert_in_out_err([], 'Signal.trap(:EXIT) {print "OK"}', ["OK"])
+ assert_in_out_err([], 'Signal.trap("EXIT") {print "OK"}', ["OK"])
+ assert_in_out_err([], 'Signal.trap(:SIGEXIT) {print "OK"}', ["OK"])
+ assert_in_out_err([], 'Signal.trap("SIGEXIT") {print "OK"}', ["OK"])
+ assert_in_out_err([], 'Signal.trap(0) {print "OK"}', ["OK"])
+ end
+
+ def test_kill_immediately_before_termination
+ Signal.list[sig = "USR1"] or sig = "INT"
+ assert_in_out_err(["-e", <<-"end;"], "", %w"foo")
+ Signal.trap(:#{sig}) { STDOUT.syswrite("foo") }
+ Process.kill :#{sig}, $$
+ end;
+ end if Process.respond_to?(:kill)
+
+ def test_trap_system_default
+ assert_separately([], <<-End)
+ trap(:QUIT, "SYSTEM_DEFAULT")
+ assert_equal("SYSTEM_DEFAULT", trap(:QUIT, "DEFAULT"))
+ End
+ end if Signal.list.key?('QUIT')
+
+ def test_reserved_signal
+ assert_raise(ArgumentError) {
+ Signal.trap(:SEGV) {}
+ }
+ assert_raise(ArgumentError) {
+ Signal.trap(:BUS) {}
+ }
+ assert_raise(ArgumentError) {
+ Signal.trap(:ILL) {}
+ }
+ assert_raise(ArgumentError) {
+ Signal.trap(:FPE) {}
+ }
+ assert_raise(ArgumentError) {
+ Signal.trap(:VTALRM) {}
+ }
+ end
+
+ def test_signame
+ 10.times do
+ IO.popen([EnvUtil.rubybin, "-e", <<EOS, :err => File::NULL]) do |child|
+ Signal.trap("INT") do |signo|
+ signame = Signal.signame(signo)
+ Marshal.dump(signame, STDOUT)
+ STDOUT.flush
+ exit 0
+ end
+ Process.kill("INT", $$)
+ sleep 1 # wait signal deliver
+EOS
+
+ signame = Marshal.load(child)
+ assert_equal(signame, "INT")
+ end
+ end
+ end if Process.respond_to?(:kill)
+
+ def test_trap_puts
+ assert_in_out_err([], <<-INPUT, ["a"*10000], [])
+ Signal.trap(:INT) {
+ # for enable internal io mutex
+ STDOUT.sync = false
+ # larger than internal io buffer
+ print "a"*10000
+ }
+ Process.kill :INT, $$
+ sleep 0.1
+ INPUT
+ end if Process.respond_to?(:kill)
+
+ def test_hup_me
+ # [Bug #7951] [ruby-core:52864]
+ # This is MRI specific spec. ruby has no guarantee
+ # that signal will be deliverd synchronously.
+ # This ugly workaround was introduced to don't break
+ # compatibility against silly example codes.
+ assert_separately([], <<-RUBY)
+ trap(:HUP, "DEFAULT")
+ assert_raise(SignalException) {
+ Process.kill('HUP', Process.pid)
+ }
+ RUBY
+ bug8137 = '[ruby-dev:47182] [Bug #8137]'
+ assert_nothing_raised(bug8137) {
+ Timeout.timeout(1) {
+ Process.kill(0, Process.pid)
+ }
+ }
+ end if Process.respond_to?(:kill) and Signal.list.key?('HUP')
+
+ def test_ignored_interrupt
+ bug9820 = '[ruby-dev:48203] [Bug #9820]'
+ assert_separately(['-', bug9820], <<-'end;') # begin
+ bug = ARGV.shift
+ trap(:INT, "IGNORE")
+ assert_nothing_raised(SignalException, bug) do
+ Process.kill(:INT, $$)
+ end
+ end;
+
+ if trap = Signal.list['TRAP']
+ bug9820 = '[ruby-dev:48592] [Bug #9820]'
+ status = assert_in_out_err(['-e', 'Process.kill(:TRAP, $$)'])
+ assert_predicate(status, :signaled?, bug9820)
+ assert_equal(trap, status.termsig, bug9820)
+ end
+
+ if Signal.list['CONT']
+ bug9820 = '[ruby-dev:48606] [Bug #9820]'
+ assert_ruby_status(['-e', 'Process.kill(:CONT, $$)'])
+ end
+ end if Process.respond_to?(:kill)
+end
diff --git a/jni/ruby/test/ruby/test_sleep.rb b/jni/ruby/test/ruby/test_sleep.rb
new file mode 100644
index 0000000..29490a7
--- /dev/null
+++ b/jni/ruby/test/ruby/test_sleep.rb
@@ -0,0 +1,16 @@
+require 'test/unit'
+require 'etc'
+
+class TestSleep < Test::Unit::TestCase
+ def test_sleep_5sec
+ GC.disable
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ sleep 5
+ slept = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
+ bottom = 5.0
+ assert_operator(slept, :>=, bottom)
+ assert_operator(slept, :<=, 6.0, "[ruby-core:18015]: longer than expected")
+ ensure
+ GC.enable
+ end
+end
diff --git a/jni/ruby/test/ruby/test_sprintf.rb b/jni/ruby/test/ruby/test_sprintf.rb
new file mode 100644
index 0000000..15c809c
--- /dev/null
+++ b/jni/ruby/test/ruby/test_sprintf.rb
@@ -0,0 +1,412 @@
+require 'test/unit'
+
+class TestSprintf < Test::Unit::TestCase
+ def test_positional
+ assert_equal(" 00001", sprintf("%*1$.*2$3$d", 10, 5, 1))
+ end
+
+ def test_binary
+ assert_equal("0", sprintf("%b", 0))
+ assert_equal("1", sprintf("%b", 1))
+ assert_equal("10", sprintf("%b", 2))
+ assert_equal("..1", sprintf("%b", -1))
+
+ assert_equal(" 0", sprintf("%4b", 0))
+ assert_equal(" 1", sprintf("%4b", 1))
+ assert_equal(" 10", sprintf("%4b", 2))
+ assert_equal(" ..1", sprintf("%4b", -1))
+
+ assert_equal("0000", sprintf("%04b", 0))
+ assert_equal("0001", sprintf("%04b", 1))
+ assert_equal("0010", sprintf("%04b", 2))
+ assert_equal("..11", sprintf("%04b", -1))
+
+ assert_equal("0000", sprintf("%.4b", 0))
+ assert_equal("0001", sprintf("%.4b", 1))
+ assert_equal("0010", sprintf("%.4b", 2))
+ assert_equal("..11", sprintf("%.4b", -1))
+
+ assert_equal(" 0000", sprintf("%6.4b", 0))
+ assert_equal(" 0001", sprintf("%6.4b", 1))
+ assert_equal(" 0010", sprintf("%6.4b", 2))
+ assert_equal(" ..11", sprintf("%6.4b", -1))
+
+ assert_equal(" 0", sprintf("%#4b", 0))
+ assert_equal(" 0b1", sprintf("%#4b", 1))
+ assert_equal("0b10", sprintf("%#4b", 2))
+ assert_equal("0b..1", sprintf("%#4b", -1))
+
+ assert_equal("0000", sprintf("%#04b", 0))
+ assert_equal("0b01", sprintf("%#04b", 1))
+ assert_equal("0b10", sprintf("%#04b", 2))
+ assert_equal("0b..1", sprintf("%#04b", -1))
+
+ assert_equal("0000", sprintf("%#.4b", 0))
+ assert_equal("0b0001", sprintf("%#.4b", 1))
+ assert_equal("0b0010", sprintf("%#.4b", 2))
+ assert_equal("0b..11", sprintf("%#.4b", -1))
+
+ assert_equal(" 0000", sprintf("%#6.4b", 0))
+ assert_equal("0b0001", sprintf("%#6.4b", 1))
+ assert_equal("0b0010", sprintf("%#6.4b", 2))
+ assert_equal("0b..11", sprintf("%#6.4b", -1))
+
+ assert_equal("+0", sprintf("%+b", 0))
+ assert_equal("+1", sprintf("%+b", 1))
+ assert_equal("+10", sprintf("%+b", 2))
+ assert_equal("-1", sprintf("%+b", -1))
+
+ assert_equal(" +0", sprintf("%+4b", 0))
+ assert_equal(" +1", sprintf("%+4b", 1))
+ assert_equal(" +10", sprintf("%+4b", 2))
+ assert_equal(" -1", sprintf("%+4b", -1))
+
+ assert_equal("+000", sprintf("%+04b", 0))
+ assert_equal("+001", sprintf("%+04b", 1))
+ assert_equal("+010", sprintf("%+04b", 2))
+ assert_equal("-001", sprintf("%+04b", -1))
+
+ assert_equal("+0000", sprintf("%+.4b", 0))
+ assert_equal("+0001", sprintf("%+.4b", 1))
+ assert_equal("+0010", sprintf("%+.4b", 2))
+ assert_equal("-0001", sprintf("%+.4b", -1))
+
+ assert_equal(" +0000", sprintf("%+6.4b", 0))
+ assert_equal(" +0001", sprintf("%+6.4b", 1))
+ assert_equal(" +0010", sprintf("%+6.4b", 2))
+ assert_equal(" -0001", sprintf("%+6.4b", -1))
+ end
+
+ def test_nan
+ nan = 0.0 / 0.0
+ assert_equal("NaN", sprintf("%f", nan))
+ assert_equal("NaN", sprintf("%-f", nan))
+ assert_equal("+NaN", sprintf("%+f", nan))
+
+ assert_equal(" NaN", sprintf("%8f", nan))
+ assert_equal("NaN ", sprintf("%-8f", nan))
+ assert_equal(" +NaN", sprintf("%+8f", nan))
+
+ assert_equal(" NaN", sprintf("%08f", nan))
+ assert_equal("NaN ", sprintf("%-08f", nan))
+ assert_equal(" +NaN", sprintf("%+08f", nan))
+
+ assert_equal(" NaN", sprintf("% 8f", nan))
+ assert_equal(" NaN ", sprintf("%- 8f", nan))
+ assert_equal(" +NaN", sprintf("%+ 8f", nan))
+
+ assert_equal(" NaN", sprintf("% 08f", nan))
+ assert_equal(" NaN ", sprintf("%- 08f", nan))
+ assert_equal(" +NaN", sprintf("%+ 08f", nan))
+ end
+
+ def test_inf
+ inf = 1.0 / 0.0
+ assert_equal("Inf", sprintf("%f", inf))
+ assert_equal("Inf", sprintf("%-f", inf))
+ assert_equal("+Inf", sprintf("%+f", inf))
+
+ assert_equal(" Inf", sprintf("%8f", inf))
+ assert_equal("Inf ", sprintf("%-8f", inf))
+ assert_equal(" +Inf", sprintf("%+8f", inf))
+
+ assert_equal(" Inf", sprintf("%08f", inf))
+ assert_equal("Inf ", sprintf("%-08f", inf))
+ assert_equal(" +Inf", sprintf("%+08f", inf))
+
+ assert_equal(" Inf", sprintf("% 8f", inf))
+ assert_equal(" Inf ", sprintf("%- 8f", inf))
+ assert_equal(" +Inf", sprintf("%+ 8f", inf))
+
+ assert_equal(" Inf", sprintf("% 08f", inf))
+ assert_equal(" Inf ", sprintf("%- 08f", inf))
+ assert_equal(" +Inf", sprintf("%+ 08f", inf))
+
+ assert_equal("-Inf", sprintf("%f", -inf))
+ assert_equal("-Inf", sprintf("%-f", -inf))
+ assert_equal("-Inf", sprintf("%+f", -inf))
+
+ assert_equal(" -Inf", sprintf("%8f", -inf))
+ assert_equal("-Inf ", sprintf("%-8f", -inf))
+ assert_equal(" -Inf", sprintf("%+8f", -inf))
+
+ assert_equal(" -Inf", sprintf("%08f", -inf))
+ assert_equal("-Inf ", sprintf("%-08f", -inf))
+ assert_equal(" -Inf", sprintf("%+08f", -inf))
+
+ assert_equal(" -Inf", sprintf("% 8f", -inf))
+ assert_equal("-Inf ", sprintf("%- 8f", -inf))
+ assert_equal(" -Inf", sprintf("%+ 8f", -inf))
+
+ assert_equal(" -Inf", sprintf("% 08f", -inf))
+ assert_equal("-Inf ", sprintf("%- 08f", -inf))
+ assert_equal(" -Inf", sprintf("%+ 08f", -inf))
+ assert_equal('..f00000000',
+ sprintf("%x", -2**32), '[ruby-dev:32351]')
+ assert_equal("..101111111111111111111111111111111",
+ sprintf("%b", -2147483649), '[ruby-dev:32365]')
+ assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]')
+ end
+
+ def test_rational
+ assert_match(/\A0\.10+\z/, sprintf("%.60f", 0.1r))
+ assert_match(/\A0\.010+\z/, sprintf("%.60f", 0.01r))
+ assert_match(/\A0\.0010+\z/, sprintf("%.60f", 0.001r))
+ assert_match(/\A0\.3+\z/, sprintf("%.60f", 1/3r))
+ assert_match(/\A1\.20+\z/, sprintf("%.60f", 1.2r))
+
+ 0.upto(9) do |len|
+ -1.upto(9) do |prec|
+ ['', '+', '-', ' ', '0', '+0', '-0', ' 0', '+ ', '- ', '+ 0', '- 0'].each do |flags|
+ fmt = "%#{flags}#{len > 0 ? len : ''}#{prec >= 0 ? ".#{prec}" : ''}f"
+ [0, 0.1, 0.01, 0.001, 1.001, 100.0, 100.001, 10000000000.0, 0.00000000001, 1/3r, 2/3r, 1.2r, 10r].each do |num|
+ assert_equal(sprintf(fmt, num.to_f), sprintf(fmt, num.to_r), "sprintf(#{fmt.inspect}, #{num.inspect}.to_r)")
+ assert_equal(sprintf(fmt, -num.to_f), sprintf(fmt, -num.to_r), "sprintf(#{fmt.inspect}, #{(-num).inspect}.to_r)") if num > 0
+ end
+ end
+ end
+ end
+ end
+
+ def test_hash
+ options = {:capture=>/\d+/}
+ assert_equal("with options {:capture=>/\\d+/}", sprintf("with options %p" % options))
+ end
+
+ def test_invalid
+ # Star precision before star width:
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.**d", 5, 10, 1)}
+
+ # Precision before flags and width:
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.5+05d", 5)}
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%.5 5d", 5)}
+
+ # Overriding a star width with a numeric one:
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%*1s", 5, 1)}
+
+ # Width before flags:
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%5+0d", 1)}
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%5 0d", 1)}
+
+ # Specifying width multiple times:
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%50+30+20+10+5d", 5)}
+ assert_raise(ArgumentError, "[ruby-core:11569]") {sprintf("%50 30 20 10 5d", 5)}
+
+ # Specifying the precision multiple times with negative star arguments:
+ assert_raise(ArgumentError, "[ruby-core:11570]") {sprintf("%.*.*.*.*f", -1, -1, -1, 5, 1)}
+
+ # Null bytes after percent signs are removed:
+ assert_equal("%\0x hello", sprintf("%\0x hello"), "[ruby-core:11571]")
+
+ assert_raise(ArgumentError, "[ruby-core:11573]") {sprintf("%.25555555555555555555555555555555555555s", "hello")}
+
+ assert_raise(ArgumentError) { sprintf("%\1", 1) }
+ assert_raise(ArgumentError) { sprintf("%!", 1) }
+ assert_raise(ArgumentError) { sprintf("%1$1$d", 1) }
+ assert_raise(ArgumentError) { sprintf("%0%") }
+
+ assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$*d", 3) }
+ assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$.*d", 3) }
+
+ verbose, $VERBOSE = $VERBOSE, nil
+ assert_nothing_raised { sprintf("", 1) }
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def test_float
+ assert_equal("36893488147419111424",
+ sprintf("%20.0f", 36893488147419107329.0))
+ assert_equal(" Inf", sprintf("% 0e", 1.0/0.0), "moved from btest/knownbug")
+ assert_equal(" -0.", sprintf("%#10.0f", -0.5), "[ruby-dev:42552]")
+ # out of spec
+ #assert_equal("0x1p+2", sprintf('%.0a', Float('0x1.fp+1')), "[ruby-dev:42551]")
+ #assert_equal("-0x1.0p+2", sprintf('%.1a', Float('-0x1.ffp+1')), "[ruby-dev:42551]")
+ end
+
+ def test_float_hex
+ assert_equal("-0x0p+0", sprintf("%a", -0.0))
+ assert_equal("0x0p+0", sprintf("%a", 0.0))
+ assert_equal("0x1p-1", sprintf("%a", 0.5))
+ assert_equal("0x1p+0", sprintf("%a", 1.0))
+ assert_equal("0x1p+1", sprintf("%a", 2.0))
+ assert_equal("0x1p+10", sprintf("%a", 1024))
+ assert_equal("0x1.23456p+789", sprintf("%a", 3.704450999893983e+237))
+ assert_equal("0x1p-1074", sprintf("%a", 4.9e-324))
+ assert_equal("Inf", sprintf("%e", Float::INFINITY))
+ assert_equal("Inf", sprintf("%E", Float::INFINITY))
+ assert_equal("NaN", sprintf("%e", Float::NAN))
+ assert_equal("NaN", sprintf("%E", Float::NAN))
+
+ assert_equal(" -0x1p+0", sprintf("%10a", -1))
+ assert_equal(" -0x1.8p+0", sprintf("%10a", -1.5))
+ assert_equal(" -0x1.4p+0", sprintf("%10a", -1.25))
+ assert_equal(" -0x1.2p+0", sprintf("%10a", -1.125))
+ assert_equal(" -0x1.1p+0", sprintf("%10a", -1.0625))
+ assert_equal("-0x1.08p+0", sprintf("%10a", -1.03125))
+
+ bug3962 = '[ruby-core:32841]'
+ assert_equal("-0x0001p+0", sprintf("%010a", -1), bug3962)
+ assert_equal("-0x01.8p+0", sprintf("%010a", -1.5), bug3962)
+ assert_equal("-0x01.4p+0", sprintf("%010a", -1.25), bug3962)
+ assert_equal("-0x01.2p+0", sprintf("%010a", -1.125), bug3962)
+ assert_equal("-0x01.1p+0", sprintf("%010a", -1.0625), bug3962)
+ assert_equal("-0x1.08p+0", sprintf("%010a", -1.03125), bug3962)
+
+ bug3964 = '[ruby-core:32848]'
+ assert_equal("0x000000000000000p+0", sprintf("%020a", 0), bug3964)
+ assert_equal("0x000000000000001p+0", sprintf("%020a", 1), bug3964)
+ assert_equal("-0x00000000000001p+0", sprintf("%020a", -1), bug3964)
+ assert_equal("0x00000000000000.p+0", sprintf("%#020a", 0), bug3964)
+
+ bug3965 = '[ruby-dev:42431]'
+ assert_equal("0x1.p+0", sprintf("%#.0a", 1), bug3965)
+ assert_equal("0x00000000000000.p+0", sprintf("%#020a", 0), bug3965)
+ assert_equal("0x0000.0000000000p+0", sprintf("%#020.10a", 0), bug3965)
+
+ bug3979 = '[ruby-dev:42453]'
+ assert_equal(" 0x0.000p+0", sprintf("%20.3a", 0), bug3979)
+ assert_equal(" 0x1.000p+0", sprintf("%20.3a", 1), bug3979)
+ end
+
+ BSIZ = 120
+
+ def test_skip
+ assert_equal(" " * BSIZ + "1", sprintf(" " * BSIZ + "%d", 1))
+ end
+
+ def test_char
+ assert_equal("a", sprintf("%c", 97))
+ assert_equal("a", sprintf("%c", ?a))
+ assert_raise(ArgumentError) { sprintf("%c", sprintf("%c%c", ?a, ?a)) }
+ assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%c", ?a))
+ assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%-1c", ?a))
+ assert_equal(" " * BSIZ + "a", sprintf("%#{ BSIZ + 1 }c", ?a))
+ assert_equal("a" + " " * BSIZ, sprintf("%-#{ BSIZ + 1 }c", ?a))
+ end
+
+ def test_string
+ assert_equal("foo", sprintf("%s", "foo"))
+ assert_equal("fo", sprintf("%.2s", "foo"))
+ assert_equal(" " * BSIZ, sprintf("%s", " " * BSIZ))
+ assert_equal(" " * (BSIZ - 1) + "foo", sprintf("%#{ BSIZ - 1 + 3 }s", "foo"))
+ assert_equal(" " * BSIZ + "foo", sprintf("%#{ BSIZ + 3 }s", "foo"))
+ assert_equal("foo" + " " * BSIZ, sprintf("%-#{ BSIZ + 3 }s", "foo"))
+ end
+
+ def test_integer
+ assert_equal("01", sprintf("%#o", 1))
+ assert_equal("0x1", sprintf("%#x", 1))
+ assert_equal("0X1", sprintf("%#X", 1))
+ assert_equal("0b1", sprintf("%#b", 1))
+ assert_equal("0B1", sprintf("%#B", 1))
+ assert_equal("1", sprintf("%d", 1.0))
+ assert_equal("4294967296", sprintf("%d", (2**32).to_f))
+ assert_equal("-2147483648", sprintf("%d", -(2**31).to_f))
+ assert_equal("18446744073709551616", sprintf("%d", (2**64).to_f))
+ assert_equal("-9223372036854775808", sprintf("%d", -(2**63).to_f))
+ assert_equal("1", sprintf("%d", "1"))
+ o = Object.new; def o.to_int; 1; end
+ assert_equal("1", sprintf("%d", o))
+ assert_equal("+1", sprintf("%+d", 1))
+ assert_equal(" 1", sprintf("% d", 1))
+ assert_equal("..f", sprintf("%x", -1))
+ assert_equal("..7", sprintf("%o", -1))
+ one = (2**32).coerce(1).first
+ mone = (2**32).coerce(-1).first
+ assert_equal("+1", sprintf("%+d", one))
+ assert_equal(" 1", sprintf("% d", one))
+ assert_equal("..f", sprintf("%x", mone))
+ assert_equal("..7", sprintf("%o", mone))
+ assert_equal(" " * BSIZ + "1", sprintf("%#{ BSIZ + 1 }d", one))
+ assert_equal(" " * (BSIZ - 1) + "1", sprintf(" " * (BSIZ - 1) + "%d", 1))
+ end
+
+ def test_float2
+ inf = 1.0 / 0.0
+ assert_equal(" " * BSIZ + "Inf", sprintf("%#{ BSIZ + 3 }.1f", inf))
+ assert_equal("+Inf", sprintf("%+-f", inf))
+ assert_equal(" " * BSIZ + "1.0", sprintf("%#{ BSIZ + 3 }.1f", 1.0))
+ end
+
+ class T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+ end
+
+ def test_star
+ assert_equal("-1 ", sprintf("%*d", -3, -1))
+ assert_raise_with_message(ArgumentError, /width too big/) {
+ sprintf("%*999999999999999999999999999999999999999999999999999999999999$d", 1)
+ }
+ assert_raise_with_message(ArgumentError, /prec too big/) {
+ sprintf("%.*999999999999999999999999999999999999999999999999999999999999$d", 1)
+ }
+ end
+
+ def test_escape
+ assert_equal("%" * BSIZ, sprintf("%%" * BSIZ))
+ end
+
+ def test_rb_sprintf
+ assert_match(/^#<TestSprintf::T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789:0x[0-9a-f]+>$/,
+ T012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.new.inspect)
+ end
+
+ def test_negative_hex
+ s1 = sprintf("%0x", -0x40000000)
+ s2 = sprintf("%0x", -0x40000001)
+ b1 = (/\.\./ =~ s1) != nil
+ b2 = (/\.\./ =~ s2) != nil
+ assert_equal(b1, b2, "[ruby-dev:33224]")
+ end
+
+ def test_named_untyped
+ assert_equal("value", sprintf("%<key>s", :key => "value"))
+ assert_raise_with_message(ArgumentError, "named<key2> after numbered") {sprintf("%1$<key2>s", :key => "value")}
+ assert_raise_with_message(ArgumentError, "named<key2> after unnumbered(2)") {sprintf("%s%s%<key2>s", "foo", "bar", :key => "value")}
+ assert_raise_with_message(ArgumentError, "named<key2> after <key>") {sprintf("%<key><key2>s", :key => "value")}
+ assert_raise_with_message(KeyError, "key<key> not found") {sprintf("%<key>s", {})}
+ end
+
+ def test_named_untyped_enc
+ key = "\u{3012}"
+ [Encoding::UTF_8, Encoding::EUC_JP].each do |enc|
+ k = key.encode(enc)
+ e = assert_raise_with_message(ArgumentError, "named<#{k}> after numbered") {sprintf("%1$<#{k}>s", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named<#{k}> after unnumbered(2)") {sprintf("%s%s%<#{k}>s", "foo", "bar", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named<#{k}> after <key>") {sprintf("%<key><#{k}>s", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named<key> after <#{k}>") {sprintf("%<#{k}><key>s", k.to_sym => "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(KeyError, "key<#{k}> not found") {sprintf("%<#{k}>s", {})}
+ assert_equal(enc, e.message.encoding)
+ end
+ end
+
+ def test_named_typed
+ assert_equal("value", sprintf("%{key}", :key => "value"))
+ assert_raise_with_message(ArgumentError, "named{key2} after numbered") {sprintf("%1${key2}", :key => "value")}
+ assert_raise_with_message(ArgumentError, "named{key2} after unnumbered(2)") {sprintf("%s%s%{key2}", "foo", "bar", :key => "value")}
+ assert_raise_with_message(ArgumentError, "named{key2} after <key>") {sprintf("%<key>{key2}", :key => "value")}
+ assert_equal("value{key2}", sprintf("%{key}{key2}", :key => "value"))
+ assert_raise_with_message(KeyError, "key{key} not found") {sprintf("%{key}", {})}
+ end
+
+ def test_named_typed_enc
+ key = "\u{3012}"
+ [Encoding::UTF_8, Encoding::EUC_JP].each do |enc|
+ k = key.encode(enc)
+ e = assert_raise_with_message(ArgumentError, "named{#{k}} after numbered") {sprintf("%1${#{k}}s", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named{#{k}} after unnumbered(2)") {sprintf("%s%s%{#{k}}s", "foo", "bar", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named{#{k}} after <key>") {sprintf("%<key>{#{k}}s", key: "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(ArgumentError, "named{key} after <#{k}>") {sprintf("%<#{k}>{key}s", k.to_sym => "value")}
+ assert_equal(enc, e.message.encoding)
+ e = assert_raise_with_message(KeyError, "key{#{k}} not found") {sprintf("%{#{k}}", {})}
+ assert_equal(enc, e.message.encoding)
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_sprintf_comb.rb b/jni/ruby/test/ruby/test_sprintf_comb.rb
new file mode 100644
index 0000000..c58ddf4
--- /dev/null
+++ b/jni/ruby/test/ruby/test_sprintf_comb.rb
@@ -0,0 +1,553 @@
+require 'test/unit'
+require_relative 'allpairs'
+
+class TestSprintfComb < Test::Unit::TestCase
+ VS = [
+ #-0x1000000000000000000000000000000000000000000000002,
+ #-0x1000000000000000000000000000000000000000000000001,
+ #-0x1000000000000000000000000000000000000000000000000,
+ #-0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ #-0x1000000000000000000000002,
+ #-0x1000000000000000000000001,
+ #-0x1000000000000000000000000,
+ #-0xffffffffffffffffffffffff,
+ -0x10000000000000002,
+ -0x10000000000000001,
+ -0x10000000000000000,
+ -0xffffffffffffffff,
+ -0x4000000000000002,
+ -0x4000000000000001,
+ -0x4000000000000000,
+ -0x3fffffffffffffff,
+ -0x100000002,
+ -0x100000001,
+ -0x100000000,
+ -0xffffffff,
+ #-0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001
+ -0x80000002,
+ -0x80000001,
+ -0x80000000,
+ -0x7fffffff,
+ #-0x524b2245,
+ -0x40000002,
+ -0x40000001,
+ -0x40000000,
+ -0x3fffffff,
+ #-0x10002,
+ #-0x10001,
+ #-0x10000,
+ #-0xffff,
+ #-0x8101, # 0x8101 * 0x7f01 = 0x40000001
+ #-0x8002,
+ #-0x8001,
+ #-0x8000,
+ #-0x7fff,
+ #-0x7f01,
+ #-65,
+ #-64,
+ #-63,
+ #-62,
+ #-33,
+ #-32,
+ #-31,
+ #-30,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ #30,
+ #31,
+ #32,
+ #33,
+ #62,
+ #63,
+ #64,
+ #65,
+ #0x7f01,
+ #0x7ffe,
+ #0x7fff,
+ #0x8000,
+ #0x8001,
+ #0x8101,
+ #0xfffe,
+ #0xffff,
+ #0x10000,
+ #0x10001,
+ 0x3ffffffe,
+ 0x3fffffff,
+ 0x40000000,
+ 0x40000001,
+ #0x524b2245,
+ 0x7ffffffe,
+ 0x7fffffff,
+ 0x80000000,
+ 0x80000001,
+ #0xc717a08d,
+ 0xfffffffe,
+ 0xffffffff,
+ 0x100000000,
+ 0x100000001,
+ 0x3ffffffffffffffe,
+ 0x3fffffffffffffff,
+ 0x4000000000000000,
+ 0x4000000000000001,
+ 0xfffffffffffffffe,
+ 0xffffffffffffffff,
+ 0x10000000000000000,
+ 0x10000000000000001,
+ #0xffffffffffffffffffffffff,
+ #0x1000000000000000000000000,
+ #0x1000000000000000000000001,
+ #0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ #0x1000000000000000000000000000000000000000000000000,
+ #0x1000000000000000000000000000000000000000000000001
+ ]
+ VS.reverse!
+
+ FLAGS = [['', ' '], ['', '#'], ['', '+'], ['', '-'], ['', '0']]
+
+ def self.combination(*args, &b)
+ #AllPairs.exhaustive_each(*args, &b)
+ AllPairs.each(*args, &b)
+ end
+
+ def emu_int(format, v)
+ /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
+ sp = $1
+ hs = $2
+ pl = $3
+ mi = $4
+ zr = $5
+ width = $6
+ precision = $7
+ type = $8
+ width = width.to_i if width
+ precision = precision.to_i if precision
+ prefix = ''
+
+ zr = nil if precision
+
+ zr = nil if mi && zr
+
+ case type
+ when 'B'
+ radix = 2
+ digitmap = {0 => '0', 1 => '1'}
+ complement = !pl && !sp
+ prefix = '0B' if hs && v != 0
+ when 'b'
+ radix = 2
+ digitmap = {0 => '0', 1 => '1'}
+ complement = !pl && !sp
+ prefix = '0b' if hs && v != 0
+ when 'd'
+ radix = 10
+ digitmap = {}
+ 10.times {|i| digitmap[i] = i.to_s }
+ complement = false
+ when 'o'
+ radix = 8
+ digitmap = {}
+ 8.times {|i| digitmap[i] = i.to_s }
+ complement = !pl && !sp
+ when 'X'
+ radix = 16
+ digitmap = {}
+ 16.times {|i| digitmap[i] = i.to_s(16).upcase }
+ complement = !pl && !sp
+ prefix = '0X' if hs && v != 0
+ when 'x'
+ radix = 16
+ digitmap = {}
+ 16.times {|i| digitmap[i] = i.to_s(16) }
+ complement = !pl && !sp
+ prefix = '0x' if hs && v != 0
+ else
+ raise "unexpected type: #{type.inspect}"
+ end
+
+ digits = []
+ abs = v.abs
+ sign = ''
+ while 0 < abs
+ digits << (abs % radix)
+ abs /= radix
+ end
+
+ if v < 0
+ if complement
+ digits.map! {|d| radix-1 - d }
+ carry = 1
+ digits.each_index {|i|
+ digits[i] += carry
+ carry = 0
+ if radix <= digits[i]
+ digits[i] -= radix
+ carry = 1
+ end
+ }
+ if digits.last != radix-1
+ digits << (radix-1)
+ end
+ sign = '..'
+ else
+ sign = '-'
+ end
+ else
+ if pl
+ sign = '+'
+ elsif sp
+ sign = ' '
+ end
+ end
+
+ dlen = digits.length
+ dlen += 2 if sign == '..'
+
+ if v < 0 && complement
+ d = radix - 1
+ else
+ d = 0
+ end
+ if precision
+ if dlen < precision
+ (precision - dlen).times {
+ digits << d
+ }
+ end
+ else
+ if dlen == 0
+ digits << d
+ end
+ end
+ if type == 'o' && hs
+ if digits.empty? || digits.last != d
+ digits << d
+ end
+ end
+
+ digits.reverse!
+
+ str = digits.map {|digit| digitmap[digit] }.join
+
+ pad = ''
+ nlen = prefix.length + sign.length + str.length
+ if width && nlen < width
+ len = width - nlen
+ if zr
+ if complement && v < 0
+ pad = digitmap[radix-1] * len
+ else
+ pad = '0' * len
+ end
+ else
+ pad = ' ' * len
+ end
+ end
+
+ if / / =~ pad
+ if sign == '..'
+ str = prefix + sign + str
+ else
+ str = sign + prefix + str
+ end
+ if mi
+ str = str + pad
+ else
+ str = pad + str
+ end
+ else
+ if sign == '..'
+ str = prefix + sign + pad + str
+ else
+ str = sign + prefix + pad + str
+ end
+ end
+
+ str
+ end
+
+ def self.assertions_format_integer(format)
+ proc {
+ VS.each {|v|
+ r = sprintf format, v
+ e = emu_int format, v
+ if true
+ assert_equal(e, r, "sprintf(#{format.dump}, #{v})")
+ else
+ if e != r
+ puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{v})"
+ end
+ end
+ }
+ }
+ end
+
+ combination(%w[B b d o X x],
+ [nil, 0, 5, 20],
+ ["", ".", ".0", ".8", ".20"],
+ *FLAGS) {|type, width, precision, sp, hs, pl, mi, zr|
+ format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
+ define_method("test_format_integer(#{format})", assertions_format_integer(format))
+ }
+
+ FLOAT_VALUES = [
+ -1e100,
+ -123456789.0,
+ -1.0,
+ -0.0,
+ 0.0,
+ 0.01,
+ 1/3.0,
+ 2/3.0,
+ 1.0,
+ 2.0,
+ 9.99999999,
+ 123456789.0,
+ 1e100,
+ Float::MAX,
+ Float::MIN,
+ Float::EPSILON,
+ 1+Float::EPSILON,
+ #1-Float::EPSILON/2,
+ 10 + Float::EPSILON*10,
+ 10 - Float::EPSILON*5,
+ 1.0/0.0,
+ -1.0/0.0,
+ 0.0/0.0,
+ ]
+
+ def split_float10(v)
+ if v == 0
+ if 1/v < 0
+ sign = -1
+ v = -v
+ else
+ sign = 1
+ end
+ else
+ if v < 0
+ sign = -1
+ v = -v
+ else
+ sign = 1
+ end
+ end
+ exp = 0
+ int = v.floor
+ v -= int
+ while v != 0
+ v *= 2
+ int *= 2
+ i = v.floor
+ v -= i
+ int += i
+ exp -= 1
+ end
+ int *= 5 ** (-exp)
+ [sign, int, exp]
+ end
+
+ def emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
+ precision = 6 unless precision
+ if int == 0
+ if precision == 0 && !hs
+ result = "0#{type}+00"
+ else
+ result = "0." + "0" * precision + "#{type}+00"
+ end
+ else
+ if int < 10**precision
+ int *= 10**precision
+ exp -= precision
+ end
+ digits = int.to_s.length
+ discard = digits - (precision+1)
+ if discard != 0
+ q, r = int.divmod(10**discard)
+ if r < 10**discard / 2
+ int = q
+ exp += discard
+ elsif (q+1).to_s.length == q.to_s.length
+ int = q+1
+ exp += discard
+ else
+ discard += 1
+ q, r = int.divmod(10**discard)
+ int = q+1
+ exp += discard
+ end
+ end
+ ints = int.to_s
+ frac = ints[1..-1]
+ result = ints[0,1]
+ e = exp + frac.length
+ if precision != 0 || hs
+ result << "."
+ if precision != 0
+ result << frac
+ end
+ end
+ result << type
+ if e == 0
+ if v.abs < 1
+ result << '-00' # glibc 2.7 causes '+00'
+ else
+ result << '+00'
+ end
+ else
+ result << sprintf("%+03d", e)
+ end
+ result
+ end
+ result
+ end
+
+ def emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
+ precision = 6 unless precision
+ if int == 0
+ if precision == 0 && !hs
+ result = '0'
+ else
+ result = '0.' + '0' * precision
+ end
+ else
+ if -precision < exp
+ int *= 10 ** (precision+exp)
+ exp = -precision
+ end
+ if exp < -precision
+ discard = -exp - precision
+ q, r = int.divmod(10**discard)
+ if 10**discard / 2 <= r
+ q += 1
+ end
+ int = q
+ exp += discard
+ end
+ result = int.to_s
+ if result.length <= precision
+ result = '0' * (precision+1 - result.length) + result
+ end
+ if precision != 0 || hs
+ if precision == 0
+ result << '.'
+ else
+ result[-precision,0] = '.'
+ end
+ end
+ end
+ result
+ end
+
+ def emu_float(format, v)
+ /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
+ sp = $1
+ hs = $2
+ pl = $3
+ mi = $4
+ zr = $5
+ width = $6
+ precision = $7
+ type = $8
+ width = width.to_i if width
+ precision = precision.to_i if precision
+
+ zr = nil if mi && zr
+
+ if v.infinite?
+ sign = v < 0 ? -1 : 1
+ int = :inf
+ hs = zr = nil
+ elsif v.nan?
+ sign = 1
+ int = :nan
+ hs = zr = nil
+ else
+ sign, int, exp = split_float10(v)
+ end
+
+ if sign < 0
+ sign = '-'
+ elsif sign == 0
+ sign = ''
+ elsif pl
+ sign = '+'
+ elsif sp
+ sign = ' '
+ else
+ sign = ''
+ end
+
+ if v.nan?
+ result = 'NaN'
+ elsif v.infinite?
+ result = 'Inf'
+ else
+ case type
+ when /[eE]/
+ result = emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
+ when /f/
+ result = emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
+ when /[gG]/
+ precision = 6 unless precision
+ precision = 1 if precision == 0
+ r = emu_e(sp, hs, pl, mi, zr, width, precision-1, type.tr('gG', 'eE'), v, sign, int, exp)
+ /[eE]([+-]\d+)/ =~ r
+ e = $1.to_i
+ if e < -4 || precision <= e
+ result = r
+ else
+ result = emu_f(sp, hs, pl, mi, zr, width, precision-1-e, type, sign, int, exp)
+ end
+ result.sub!(/\.[0-9]*/) { $&.sub(/\.?0*\z/, '') } if !hs
+ else
+ raise "unexpected type: #{type}"
+ end
+ end
+
+ pad = ''
+ if width && sign.length + result.length < width
+ if zr
+ pad = '0' * (width - sign.length - result.length)
+ else
+ pad = ' ' * (width - sign.length - result.length)
+ end
+ end
+ if mi
+ sign + result + pad
+ elsif zr
+ sign + pad + result
+ else
+ pad + sign + result
+ end
+
+ end
+
+ def self.assertions_format_float(format)
+ proc {
+ FLOAT_VALUES.each {|v|
+ r = sprintf format, v
+ e = emu_float format, v
+ if true
+ assert_equal(e, r, "sprintf(#{format.dump}, #{'%.20g' % v})")
+ else
+ if e != r
+ puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{'%.20g' % v})"
+ end
+ end
+ }
+ }
+ end
+
+ combination(%w[e E f g G],
+ [nil, 0, 5, 20],
+ ["", ".", ".0", ".8", ".20", ".200", ".9999"],
+ *FLAGS) {|type, width, precision, sp, hs, pl, mi, zr|
+ format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
+ define_method("test_format_float(#{format})", assertions_format_float(format))
+ }
+end
diff --git a/jni/ruby/test/ruby/test_string.rb b/jni/ruby/test/ruby/test_string.rb
new file mode 100644
index 0000000..4cd6afd
--- /dev/null
+++ b/jni/ruby/test/ruby/test_string.rb
@@ -0,0 +1,2314 @@
+require 'test/unit'
+
+# use of $= is deprecated after 1.7.1
+def pre_1_7_1
+end
+
+class TestString < Test::Unit::TestCase
+ ENUMERATOR_WANTARRAY = RUBY_VERSION >= "3.0.0"
+
+ def initialize(*args)
+ @cls = String
+ @aref_re_nth = true
+ @aref_re_silent = false
+ @aref_slicebang_silent = true
+ super
+ end
+
+ def S(str)
+ @cls.new(str)
+ end
+
+ def test_s_new
+ assert_equal("RUBY", S("RUBY"))
+ end
+
+ def test_AREF # '[]'
+ assert_equal("A", S("AooBar")[0])
+ assert_equal("B", S("FooBaB")[-1])
+ assert_equal(nil, S("FooBar")[6])
+ assert_equal(nil, S("FooBar")[-7])
+
+ assert_equal(S("Foo"), S("FooBar")[0,3])
+ assert_equal(S("Bar"), S("FooBar")[-3,3])
+ assert_equal(S(""), S("FooBar")[6,2])
+ assert_equal(nil, S("FooBar")[-7,10])
+
+ assert_equal(S("Foo"), S("FooBar")[0..2])
+ assert_equal(S("Foo"), S("FooBar")[0...3])
+ assert_equal(S("Bar"), S("FooBar")[-3..-1])
+ assert_equal(S(""), S("FooBar")[6..2])
+ assert_equal(nil, S("FooBar")[-10..-7])
+
+ assert_equal(S("Foo"), S("FooBar")[/^F../])
+ assert_equal(S("Bar"), S("FooBar")[/..r$/])
+ assert_equal(nil, S("FooBar")[/xyzzy/])
+ assert_equal(nil, S("FooBar")[/plugh/])
+
+ assert_equal(S("Foo"), S("FooBar")[S("Foo")])
+ assert_equal(S("Bar"), S("FooBar")[S("Bar")])
+ assert_equal(nil, S("FooBar")[S("xyzzy")])
+ assert_equal(nil, S("FooBar")[S("plugh")])
+
+ if @aref_re_nth
+ assert_equal(S("Foo"), S("FooBar")[/([A-Z]..)([A-Z]..)/, 1])
+ assert_equal(S("Bar"), S("FooBar")[/([A-Z]..)([A-Z]..)/, 2])
+ assert_equal(nil, S("FooBar")[/([A-Z]..)([A-Z]..)/, 3])
+ assert_equal(S("Bar"), S("FooBar")[/([A-Z]..)([A-Z]..)/, -1])
+ assert_equal(S("Foo"), S("FooBar")[/([A-Z]..)([A-Z]..)/, -2])
+ assert_equal(nil, S("FooBar")[/([A-Z]..)([A-Z]..)/, -3])
+ end
+
+ o = Object.new
+ def o.to_int; 2; end
+ assert_equal("o", "foo"[o])
+
+ assert_raise(ArgumentError) { "foo"[] }
+ end
+
+ def test_ASET # '[]='
+ s = S("FooBar")
+ s[0] = S('A')
+ assert_equal(S("AooBar"), s)
+
+ s[-1]= S('B')
+ assert_equal(S("AooBaB"), s)
+ assert_raise(IndexError) { s[-7] = S("xyz") }
+ assert_equal(S("AooBaB"), s)
+ s[0] = S("ABC")
+ assert_equal(S("ABCooBaB"), s)
+
+ s = S("FooBar")
+ s[0,3] = S("A")
+ assert_equal(S("ABar"),s)
+ s[0] = S("Foo")
+ assert_equal(S("FooBar"), s)
+ s[-3,3] = S("Foo")
+ assert_equal(S("FooFoo"), s)
+ assert_raise(IndexError) { s[7,3] = S("Bar") }
+ assert_raise(IndexError) { s[-7,3] = S("Bar") }
+
+ s = S("FooBar")
+ s[0..2] = S("A")
+ assert_equal(S("ABar"), s)
+ s[1..3] = S("Foo")
+ assert_equal(S("AFoo"), s)
+ s[-4..-4] = S("Foo")
+ assert_equal(S("FooFoo"), s)
+ assert_raise(RangeError) { s[7..10] = S("Bar") }
+ assert_raise(RangeError) { s[-7..-10] = S("Bar") }
+
+ s = S("FooBar")
+ s[/^F../]= S("Bar")
+ assert_equal(S("BarBar"), s)
+ s[/..r$/] = S("Foo")
+ assert_equal(S("BarFoo"), s)
+ if @aref_re_silent
+ s[/xyzzy/] = S("None")
+ assert_equal(S("BarFoo"), s)
+ else
+ assert_raise(IndexError) { s[/xyzzy/] = S("None") }
+ end
+ if @aref_re_nth
+ s[/([A-Z]..)([A-Z]..)/, 1] = S("Foo")
+ assert_equal(S("FooFoo"), s)
+ s[/([A-Z]..)([A-Z]..)/, 2] = S("Bar")
+ assert_equal(S("FooBar"), s)
+ assert_raise(IndexError) { s[/([A-Z]..)([A-Z]..)/, 3] = "None" }
+ s[/([A-Z]..)([A-Z]..)/, -1] = S("Foo")
+ assert_equal(S("FooFoo"), s)
+ s[/([A-Z]..)([A-Z]..)/, -2] = S("Bar")
+ assert_equal(S("BarFoo"), s)
+ assert_raise(IndexError) { s[/([A-Z]..)([A-Z]..)/, -3] = "None" }
+ end
+
+ s = S("FooBar")
+ s[S("Foo")] = S("Bar")
+ assert_equal(S("BarBar"), s)
+
+ pre_1_7_1 do
+ s = S("FooBar")
+ s[S("Foo")] = S("xyz")
+ assert_equal(S("xyzBar"), s)
+
+ $= = true
+ s = S("FooBar")
+ s[S("FOO")] = S("Bar")
+ assert_equal(S("BarBar"), s)
+ s[S("FOO")] = S("xyz")
+ assert_equal(S("BarBar"), s)
+ $= = false
+ end
+
+ s = S("a string")
+ s[0..s.size] = S("another string")
+ assert_equal(S("another string"), s)
+
+ o = Object.new
+ def o.to_int; 2; end
+ s = "foo"
+ s[o] = "bar"
+ assert_equal("fobar", s)
+
+ assert_raise(ArgumentError) { "foo"[1, 2, 3] = "" }
+ end
+
+ def test_CMP # '<=>'
+ assert_equal(1, S("abcdef") <=> S("abcde"))
+ assert_equal(0, S("abcdef") <=> S("abcdef"))
+ assert_equal(-1, S("abcde") <=> S("abcdef"))
+
+ assert_equal(-1, S("ABCDEF") <=> S("abcdef"))
+
+ pre_1_7_1 do
+ $= = true
+ assert_equal(0, S("ABCDEF") <=> S("abcdef"))
+ $= = false
+ end
+
+ assert_nil("foo" <=> Object.new)
+
+ o = Object.new
+ def o.to_str; "bar"; end
+ assert_equal(1, "foo" <=> o)
+
+ class << o;remove_method :to_str;end
+ def o.<=>(x); nil; end
+ assert_nil("foo" <=> o)
+
+ class << o;remove_method :<=>;end
+ def o.<=>(x); 1; end
+ assert_equal(-1, "foo" <=> o)
+
+ class << o;remove_method :<=>;end
+ def o.<=>(x); 2**100; end
+ assert_equal(-1, "foo" <=> o)
+ end
+
+ def test_EQUAL # '=='
+ assert_not_equal(:foo, S("foo"))
+ assert_equal(S("abcdef"), S("abcdef"))
+
+ pre_1_7_1 do
+ $= = true
+ assert_equal(S("CAT"), S('cat'))
+ assert_equal(S("CaT"), S('cAt'))
+ $= = false
+ end
+
+ assert_not_equal(S("CAT"), S('cat'))
+ assert_not_equal(S("CaT"), S('cAt'))
+
+ o = Object.new
+ def o.to_str; end
+ def o.==(x); false; end
+ assert_equal(false, "foo" == o)
+ class << o;remove_method :==;end
+ def o.==(x); true; end
+ assert_equal(true, "foo" == o)
+ end
+
+ def test_LSHIFT # '<<'
+ assert_equal(S("world!"), S("world") << 33)
+ assert_equal(S("world!"), S("world") << S("!"))
+
+ s = "a"
+ 10.times {|i|
+ s << s
+ assert_equal("a" * (2 << i), s)
+ }
+
+ s = ["foo"].pack("p")
+ l = s.size
+ s << "bar"
+ assert_equal(l + 3, s.size)
+
+ bug = '[ruby-core:27583]'
+ assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -3}
+ assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -2}
+ assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -1}
+ assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << 0x81308130}
+ assert_nothing_raised {S("a".force_encoding(Encoding::GB18030)) << 0x81308130}
+ end
+
+ def test_MATCH # '=~'
+ assert_equal(10, S("FeeFieFoo-Fum") =~ /Fum$/)
+ assert_equal(nil, S("FeeFieFoo-Fum") =~ /FUM$/)
+
+ pre_1_7_1 do
+ $= = true
+ assert_equal(10, S("FeeFieFoo-Fum") =~ /FUM$/)
+ $= = false
+ end
+
+ o = Object.new
+ def o.=~(x); x + "bar"; end
+ assert_equal("foobar", S("foo") =~ o)
+
+ assert_raise(TypeError) { S("foo") =~ "foo" }
+ end
+
+ def test_MOD # '%'
+ assert_equal(S("00123"), S("%05d") % 123)
+ assert_equal(S("123 |00000001"), S("%-5s|%08x") % [123, 1])
+ x = S("%3s %-4s%%foo %.0s%5d %#x%c%3.1f %b %x %X %#b %#x %#X") %
+ [S("hi"),
+ 123,
+ S("never seen"),
+ 456,
+ 0,
+ ?A,
+ 3.0999,
+ 11,
+ 171,
+ 171,
+ 11,
+ 171,
+ 171]
+
+ assert_equal(S(' hi 123 %foo 456 0A3.1 1011 ab AB 0b1011 0xab 0XAB'), x)
+ end
+
+ def test_MUL # '*'
+ assert_equal(S("XXX"), S("X") * 3)
+ assert_equal(S("HOHO"), S("HO") * 2)
+ end
+
+ def test_PLUS # '+'
+ assert_equal(S("Yodel"), S("Yo") + S("del"))
+ end
+
+ def casetest(a, b, rev=false)
+ msg = proc {"#{a} should#{' not' if rev} match #{b}"}
+ case a
+ when b
+ assert(!rev, msg)
+ else
+ assert(rev, msg)
+ end
+ end
+
+ def test_VERY_EQUAL # '==='
+ # assert_equal(true, S("foo") === :foo)
+ casetest(S("abcdef"), S("abcdef"))
+
+ pre_1_7_1 do
+ $= = true
+ casetest(S("CAT"), S('cat'))
+ casetest(S("CaT"), S('cAt'))
+ $= = false
+ end
+
+ casetest(S("CAT"), S('cat'), true) # Reverse the test - we don't want to
+ casetest(S("CaT"), S('cAt'), true) # find these in the case.
+ end
+
+ def test_capitalize
+ assert_equal(S("Hello"), S("hello").capitalize)
+ assert_equal(S("Hello"), S("hELLO").capitalize)
+ assert_equal(S("123abc"), S("123ABC").capitalize)
+ end
+
+ def test_capitalize!
+ a = S("hello"); a.capitalize!
+ assert_equal(S("Hello"), a)
+
+ a = S("hELLO"); a.capitalize!
+ assert_equal(S("Hello"), a)
+
+ a = S("123ABC"); a.capitalize!
+ assert_equal(S("123abc"), a)
+
+ assert_equal(nil, S("123abc").capitalize!)
+ assert_equal(S("123abc"), S("123ABC").capitalize!)
+ assert_equal(S("Abc"), S("ABC").capitalize!)
+ assert_equal(S("Abc"), S("abc").capitalize!)
+ assert_equal(nil, S("Abc").capitalize!)
+
+ a = S("hello")
+ b = a.dup
+ assert_equal(S("Hello"), a.capitalize!)
+ assert_equal(S("hello"), b)
+
+ end
+
+ Bug2463 = '[ruby-dev:39856]'
+ def test_center
+ assert_equal(S("hello"), S("hello").center(4))
+ assert_equal(S(" hello "), S("hello").center(11))
+ assert_equal(S("ababaababa"), S("").center(10, "ab"), Bug2463)
+ assert_equal(S("ababaababab"), S("").center(11, "ab"), Bug2463)
+ end
+
+ def test_chomp
+ assert_equal(S("hello"), S("hello").chomp("\n"))
+ assert_equal(S("hello"), S("hello\n").chomp("\n"))
+ save = $/
+
+ $/ = "\n"
+
+ assert_equal(S("hello"), S("hello").chomp)
+ assert_equal(S("hello"), S("hello\n").chomp)
+
+ $/ = "!"
+ assert_equal(S("hello"), S("hello").chomp)
+ assert_equal(S("hello"), S("hello!").chomp)
+ $/ = save
+
+ assert_equal(S("a").hash, S("a\u0101").chomp(S("\u0101")).hash, '[ruby-core:22414]')
+ end
+
+ def test_chomp!
+ a = S("hello")
+ a.chomp!(S("\n"))
+
+ assert_equal(S("hello"), a)
+ assert_equal(nil, a.chomp!(S("\n")))
+
+ a = S("hello\n")
+ a.chomp!(S("\n"))
+ assert_equal(S("hello"), a)
+ save = $/
+
+ $/ = "\n"
+ a = S("hello")
+ a.chomp!
+ assert_equal(S("hello"), a)
+
+ a = S("hello\n")
+ a.chomp!
+ assert_equal(S("hello"), a)
+
+ $/ = "!"
+ a = S("hello")
+ a.chomp!
+ assert_equal(S("hello"), a)
+
+ a="hello!"
+ a.chomp!
+ assert_equal(S("hello"), a)
+
+ $/ = save
+
+ a = S("hello\n")
+ b = a.dup
+ assert_equal(S("hello"), a.chomp!)
+ assert_equal(S("hello\n"), b)
+
+ s = "foo\r\n"
+ s.chomp!
+ assert_equal("foo", s)
+
+ s = "foo\r"
+ s.chomp!
+ assert_equal("foo", s)
+
+ s = "foo\r\n"
+ s.chomp!("")
+ assert_equal("foo", s)
+
+ s = "foo\r"
+ s.chomp!("")
+ assert_equal("foo\r", s)
+
+ assert_equal(S("a").hash, S("a\u0101").chomp!(S("\u0101")).hash, '[ruby-core:22414]')
+ end
+
+ def test_chop
+ assert_equal(S("hell"), S("hello").chop)
+ assert_equal(S("hello"), S("hello\r\n").chop)
+ assert_equal(S("hello\n"), S("hello\n\r").chop)
+ assert_equal(S(""), S("\r\n").chop)
+ assert_equal(S(""), S("").chop)
+ assert_equal(S("a").hash, S("a\u00d8").chop.hash)
+ end
+
+ def test_chop!
+ a = S("hello").chop!
+ assert_equal(S("hell"), a)
+
+ a = S("hello\r\n").chop!
+ assert_equal(S("hello"), a)
+
+ a = S("hello\n\r").chop!
+ assert_equal(S("hello\n"), a)
+
+ a = S("\r\n").chop!
+ assert_equal(S(""), a)
+
+ a = S("").chop!
+ assert_nil(a)
+
+ a = S("a\u00d8")
+ a.chop!
+ assert_equal(S("a").hash, a.hash)
+
+ a = S("hello\n")
+ b = a.dup
+ assert_equal(S("hello"), a.chop!)
+ assert_equal(S("hello\n"), b)
+ end
+
+ def test_clone
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = S("Cool")
+ a.taint if taint
+ a.freeze if frozen
+ b = a.clone
+
+ assert_equal(a, b)
+ assert_not_same(a, b)
+ assert_equal(a.frozen?, b.frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+
+ null = File.exist?("/dev/null") ? "/dev/null" : "NUL" # maybe DOSISH
+ assert_equal("", File.read(null).clone, '[ruby-dev:32819] reported by Kazuhiro NISHIYAMA')
+ end
+
+ def test_concat
+ assert_equal(S("world!"), S("world").concat(33))
+ assert_equal(S("world!"), S("world").concat(S('!')))
+
+ bug7090 = '[ruby-core:47751]'
+ result = S("").force_encoding(Encoding::UTF_16LE)
+ result << 0x0300
+ expected = S("\u0300".encode(Encoding::UTF_16LE))
+ assert_equal(expected, result, bug7090)
+ assert_raise(TypeError) { 'foo' << :foo }
+ end
+
+ def test_count
+ a = S("hello world")
+ assert_equal(5, a.count(S("lo")))
+ assert_equal(2, a.count(S("lo"), S("o")))
+ assert_equal(4, a.count(S("hello"), S("^l")))
+ assert_equal(4, a.count(S("ej-m")))
+ assert_equal(0, S("y").count(S("a\\-z")))
+ assert_equal(5, "abc\u{3042 3044 3046}".count("^a"))
+ assert_equal(1, "abc\u{3042 3044 3046}".count("\u3042"))
+ assert_equal(5, "abc\u{3042 3044 3046}".count("^\u3042"))
+ assert_equal(2, "abc\u{3042 3044 3046}".count("a-z", "^a"))
+ assert_equal(0, "abc\u{3042 3044 3046}".count("a", "\u3042"))
+ assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "a"))
+ assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "\u3044"))
+ assert_equal(4, "abc\u{3042 3044 3046}".count("^a", "^\u3044"))
+ assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3044", "^a"))
+ assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3042", "^\u3044"))
+
+ assert_raise(ArgumentError) { "foo".count }
+ end
+
+ def test_crypt
+ assert_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("aa")))
+ assert_not_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("ab")))
+ assert_raise(ArgumentError) {S("mypassword").crypt(S(""))}
+ assert_raise(ArgumentError) {S("mypassword").crypt(S("\0a"))}
+ assert_raise(ArgumentError) {S("mypassword").crypt(S("a\0"))}
+ [Encoding::UTF_16BE, Encoding::UTF_16LE,
+ Encoding::UTF_32BE, Encoding::UTF_32LE].each do |enc|
+ assert_raise(ArgumentError) {S("mypassword").crypt(S("aa".encode(enc)))}
+ assert_raise(ArgumentError) {S("mypassword".encode(enc)).crypt(S("aa"))}
+ end
+ end
+
+ def test_delete
+ assert_equal(S("heo"), S("hello").delete(S("l"), S("lo")))
+ assert_equal(S("he"), S("hello").delete(S("lo")))
+ assert_equal(S("hell"), S("hello").delete(S("aeiou"), S("^e")))
+ assert_equal(S("ho"), S("hello").delete(S("ej-m")))
+
+ assert_equal("a".hash, "a\u0101".delete("\u0101").hash, '[ruby-talk:329267]')
+ assert_equal(true, "a\u0101".delete("\u0101").ascii_only?)
+ assert_equal(true, "a\u3041".delete("\u3041").ascii_only?)
+ assert_equal(false, "a\u3041\u3042".tr("\u3041", "a").ascii_only?)
+
+ assert_equal("a", "abc\u{3042 3044 3046}".delete("^a"))
+ assert_equal("bc\u{3042 3044 3046}", "abc\u{3042 3044 3046}".delete("a"))
+ assert_equal("\u3042", "abc\u{3042 3044 3046}".delete("^\u3042"))
+
+ bug6160 = '[ruby-dev:45374]'
+ assert_equal("", '\\'.delete('\\'), bug6160)
+ end
+
+ def test_delete!
+ a = S("hello")
+ a.delete!(S("l"), S("lo"))
+ assert_equal(S("heo"), a)
+
+ a = S("hello")
+ a.delete!(S("lo"))
+ assert_equal(S("he"), a)
+
+ a = S("hello")
+ a.delete!(S("aeiou"), S("^e"))
+ assert_equal(S("hell"), a)
+
+ a = S("hello")
+ a.delete!(S("ej-m"))
+ assert_equal(S("ho"), a)
+
+ a = S("hello")
+ assert_nil(a.delete!(S("z")))
+
+ a = S("hello")
+ b = a.dup
+ a.delete!(S("lo"))
+ assert_equal(S("he"), a)
+ assert_equal(S("hello"), b)
+
+ a = S("hello")
+ a.delete!(S("^el"))
+ assert_equal(S("ell"), a)
+
+ assert_raise(ArgumentError) { S("foo").delete! }
+ end
+
+
+ def test_downcase
+ assert_equal(S("hello"), S("helLO").downcase)
+ assert_equal(S("hello"), S("hello").downcase)
+ assert_equal(S("hello"), S("HELLO").downcase)
+ assert_equal(S("abc hello 123"), S("abc HELLO 123").downcase)
+ end
+
+ def test_downcase!
+ a = S("helLO")
+ b = a.dup
+ assert_equal(S("hello"), a.downcase!)
+ assert_equal(S("hello"), a)
+ assert_equal(S("helLO"), b)
+
+ a=S("hello")
+ assert_nil(a.downcase!)
+ assert_equal(S("hello"), a)
+ end
+
+ def test_dump
+ a= S("Test") << 1 << 2 << 3 << 9 << 13 << 10
+ assert_equal(S('"Test\\x01\\x02\\x03\\t\\r\\n"'), a.dump)
+ end
+
+ def test_dup
+ for taint in [ false, true ]
+ for frozen in [ false, true ]
+ a = S("hello")
+ a.taint if taint
+ a.freeze if frozen
+ b = a.dup
+
+ assert_equal(a, b)
+ assert_not_same(a, b)
+ assert_not_predicate(b, :frozen?)
+ assert_equal(a.tainted?, b.tainted?)
+ end
+ end
+ end
+
+ def test_each
+ save = $/
+ $/ = "\n"
+ res=[]
+ S("hello\nworld").lines.each {|x| res << x}
+ assert_equal(S("hello\n"), res[0])
+ assert_equal(S("world"), res[1])
+
+ res=[]
+ S("hello\n\n\nworld").lines(S('')).each {|x| res << x}
+ assert_equal(S("hello\n\n\n"), res[0])
+ assert_equal(S("world"), res[1])
+
+ $/ = "!"
+ res=[]
+ S("hello!world").lines.each {|x| res << x}
+ assert_equal(S("hello!"), res[0])
+ assert_equal(S("world"), res[1])
+ $/ = save
+ end
+
+ def test_each_byte
+ s = S("ABC")
+
+ res = []
+ assert_equal s.object_id, s.each_byte {|x| res << x }.object_id
+ assert_equal(65, res[0])
+ assert_equal(66, res[1])
+ assert_equal(67, res[2])
+
+ assert_equal 65, s.each_byte.next
+ end
+
+ def test_bytes
+ s = S("ABC")
+ assert_equal [65, 66, 67], s.bytes
+
+ if ENUMERATOR_WANTARRAY
+ assert_warn(/block not used/) {
+ assert_equal [65, 66, 67], s.bytes {}
+ }
+ else
+ assert_warning(/deprecated/) {
+ res = []
+ assert_equal s.object_id, s.bytes {|x| res << x }.object_id
+ assert_equal(65, res[0])
+ assert_equal(66, res[1])
+ assert_equal(67, res[2])
+ }
+ end
+ end
+
+ def test_each_codepoint
+ # Single byte optimization
+ assert_equal 65, S("ABC").each_codepoint.next
+
+ s = S("\u3042\u3044\u3046")
+
+ res = []
+ assert_equal s.object_id, s.each_codepoint {|x| res << x }.object_id
+ assert_equal(0x3042, res[0])
+ assert_equal(0x3044, res[1])
+ assert_equal(0x3046, res[2])
+
+ assert_equal 0x3042, s.each_codepoint.next
+ end
+
+ def test_codepoints
+ # Single byte optimization
+ assert_equal [65, 66, 67], S("ABC").codepoints
+
+ s = S("\u3042\u3044\u3046")
+ assert_equal [0x3042, 0x3044, 0x3046], s.codepoints
+
+ if ENUMERATOR_WANTARRAY
+ assert_warn(/block not used/) {
+ assert_equal [0x3042, 0x3044, 0x3046], s.codepoints {}
+ }
+ else
+ assert_warning(/deprecated/) {
+ res = []
+ assert_equal s.object_id, s.codepoints {|x| res << x }.object_id
+ assert_equal(0x3042, res[0])
+ assert_equal(0x3044, res[1])
+ assert_equal(0x3046, res[2])
+ }
+ end
+ end
+
+ def test_each_char
+ s = S("ABC")
+
+ res = []
+ assert_equal s.object_id, s.each_char {|x| res << x }.object_id
+ assert_equal("A", res[0])
+ assert_equal("B", res[1])
+ assert_equal("C", res[2])
+
+ assert_equal "A", S("ABC").each_char.next
+ end
+
+ def test_chars
+ s = S("ABC")
+ assert_equal ["A", "B", "C"], s.chars
+
+ if ENUMERATOR_WANTARRAY
+ assert_warn(/block not used/) {
+ assert_equal ["A", "B", "C"], s.chars {}
+ }
+ else
+ assert_warning(/deprecated/) {
+ res = []
+ assert_equal s.object_id, s.chars {|x| res << x }.object_id
+ assert_equal("A", res[0])
+ assert_equal("B", res[1])
+ assert_equal("C", res[2])
+ }
+ end
+ end
+
+ def test_each_line
+ save = $/
+ $/ = "\n"
+ res=[]
+ S("hello\nworld").each_line {|x| res << x}
+ assert_equal(S("hello\n"), res[0])
+ assert_equal(S("world"), res[1])
+
+ res=[]
+ S("hello\n\n\nworld").each_line(S('')) {|x| res << x}
+ assert_equal(S("hello\n\n\n"), res[0])
+ assert_equal(S("world"), res[1])
+
+ $/ = "!"
+
+ res=[]
+ S("hello!world").each_line {|x| res << x}
+ assert_equal(S("hello!"), res[0])
+ assert_equal(S("world"), res[1])
+
+ $/ = "ab"
+
+ res=[]
+ S("a").lines.each {|x| res << x}
+ assert_equal(1, res.size)
+ assert_equal(S("a"), res[0])
+
+ $/ = save
+
+ s = nil
+ "foo\nbar".each_line(nil) {|s2| s = s2 }
+ assert_equal("foo\nbar", s)
+
+ assert_equal "hello\n", S("hello\nworld").each_line.next
+ assert_equal "hello\nworld", S("hello\nworld").each_line(nil).next
+
+ bug7646 = "[ruby-dev:46827]"
+ assert_nothing_raised(bug7646) do
+ "\n\u0100".each_line("\n") {}
+ end
+ end
+
+ def test_lines
+ s = S("hello\nworld")
+ assert_equal ["hello\n", "world"], s.lines
+ assert_equal ["hello\nworld"], s.lines(nil)
+
+ if ENUMERATOR_WANTARRAY
+ assert_warn(/block not used/) {
+ assert_equal ["hello\n", "world"], s.lines {}
+ }
+ else
+ assert_warning(/deprecated/) {
+ res = []
+ assert_equal s.object_id, s.lines {|x| res << x }.object_id
+ assert_equal(S("hello\n"), res[0])
+ assert_equal(S("world"), res[1])
+ }
+ end
+ end
+
+ def test_empty?
+ assert_empty(S(""))
+ assert_not_empty(S("not"))
+ end
+
+ def test_end_with?
+ assert_send([S("hello"), :end_with?, S("llo")])
+ assert_not_send([S("hello"), :end_with?, S("ll")])
+ assert_send([S("hello"), :end_with?, S("el"), S("lo")])
+
+ bug5536 = '[ruby-core:40623]'
+ assert_raise(TypeError, bug5536) {S("str").end_with? :not_convertible_to_string}
+ end
+
+ def test_eql?
+ a = S("hello")
+ assert_operator(a, :eql?, S("hello"))
+ assert_operator(a, :eql?, a)
+ end
+
+ def test_gsub
+ assert_equal(S("h*ll*"), S("hello").gsub(/[aeiou]/, S('*')))
+ assert_equal(S("h<e>ll<o>"), S("hello").gsub(/([aeiou])/, S('<\1>')))
+ assert_equal(S("h e l l o "),
+ S("hello").gsub(/./) { |s| s[0].to_s + S(' ')})
+ assert_equal(S("HELL-o"),
+ S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 })
+ assert_equal(S("<>h<>e<>l<>l<>o<>"), S("hello").gsub(S(''), S('<\0>')))
+
+ a = S("hello")
+ a.taint
+ assert_predicate(a.gsub(/./, S('X')), :tainted?)
+
+ assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug")
+
+ assert_raise(ArgumentError) { "foo".gsub }
+ end
+
+ def test_gsub_encoding
+ a = S("hello world")
+ a.force_encoding Encoding::UTF_8
+
+ b = S("hi")
+ b.force_encoding Encoding::US_ASCII
+
+ assert_equal Encoding::UTF_8, a.gsub(/hello/, b).encoding
+
+ c = S("everybody")
+ c.force_encoding Encoding::US_ASCII
+
+ assert_equal Encoding::UTF_8, a.gsub(/world/, c).encoding
+
+ assert_equal S("a\u{e9}apos&lt;"), S("a\u{e9}'&lt;").gsub("'", "apos")
+
+ bug9849 = '[ruby-core:62669] [Bug #9849]'
+ assert_equal S("\u{3042 3042 3042}!foo!"), S("\u{3042 3042 3042}/foo/").gsub("/", "!"), bug9849
+ end
+
+ def test_gsub!
+ a = S("hello")
+ b = a.dup
+ a.gsub!(/[aeiou]/, S('*'))
+ assert_equal(S("h*ll*"), a)
+ assert_equal(S("hello"), b)
+
+ a = S("hello")
+ a.gsub!(/([aeiou])/, S('<\1>'))
+ assert_equal(S("h<e>ll<o>"), a)
+
+ a = S("hello")
+ a.gsub!(/./) { |s| s[0].to_s + S(' ')}
+ assert_equal(S("h e l l o "), a)
+
+ a = S("hello")
+ a.gsub!(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 }
+ assert_equal(S("HELL-o"), a)
+
+ r = S('X')
+ r.taint
+ a.gsub!(/./, r)
+ assert_predicate(a, :tainted?)
+
+ a = S("hello")
+ assert_nil(a.sub!(S('X'), S('Y')))
+ end
+
+ def test_sub_hash
+ assert_equal('azc', 'abc'.sub(/b/, "b" => "z"))
+ assert_equal('ac', 'abc'.sub(/b/, {}))
+ assert_equal('a1c', 'abc'.sub(/b/, "b" => 1))
+ assert_equal('aBc', 'abc'.sub(/b/, Hash.new {|h, k| k.upcase }))
+ assert_equal('a[\&]c', 'abc'.sub(/b/, "b" => '[\&]'))
+ assert_equal('aBcabc', 'abcabc'.sub(/b/, Hash.new {|h, k| h[k] = k.upcase }))
+ assert_equal('aBcdef', 'abcdef'.sub(/de|b/, "b" => "B", "de" => "DE"))
+ end
+
+ def test_gsub_hash
+ assert_equal('azc', 'abc'.gsub(/b/, "b" => "z"))
+ assert_equal('ac', 'abc'.gsub(/b/, {}))
+ assert_equal('a1c', 'abc'.gsub(/b/, "b" => 1))
+ assert_equal('aBc', 'abc'.gsub(/b/, Hash.new {|h, k| k.upcase }))
+ assert_equal('a[\&]c', 'abc'.gsub(/b/, "b" => '[\&]'))
+ assert_equal('aBcaBc', 'abcabc'.gsub(/b/, Hash.new {|h, k| h[k] = k.upcase }))
+ assert_equal('aBcDEf', 'abcdef'.gsub(/de|b/, "b" => "B", "de" => "DE"))
+ end
+
+ def test_hash
+ assert_equal(S("hello").hash, S("hello").hash)
+ assert_not_equal(S("hello").hash, S("helLO").hash)
+ bug4104 = '[ruby-core:33500]'
+ assert_not_equal(S("a").hash, S("a\0").hash, bug4104)
+ bug9172 = '[ruby-core:58658] [Bug #9172]'
+ assert_not_equal(S("sub-setter").hash, S("discover").hash, bug9172)
+ end
+
+ def test_hash_random
+ str = 'abc'
+ a = [str.hash.to_s]
+ 3.times {
+ assert_in_out_err(["-e", "print #{str.dump}.hash"], "") do |r, e|
+ a += r
+ assert_equal([], e)
+ end
+ }
+ assert_not_equal([str.hash.to_s], a.uniq)
+ end
+
+ def test_hex
+ assert_equal(255, S("0xff").hex)
+ assert_equal(-255, S("-0xff").hex)
+ assert_equal(255, S("ff").hex)
+ assert_equal(-255, S("-ff").hex)
+ assert_equal(0, S("-ralph").hex)
+ assert_equal(-15, S("-fred").hex)
+ assert_equal(15, S("fred").hex)
+ end
+
+ def test_include?
+ assert_include(S("foobar"), ?f)
+ assert_include(S("foobar"), S("foo"))
+ assert_not_include(S("foobar"), S("baz"))
+ assert_not_include(S("foobar"), ?z)
+ end
+
+ def test_index
+ assert_equal(0, S("hello").index(?h))
+ assert_equal(1, S("hello").index(S("ell")))
+ assert_equal(2, S("hello").index(/ll./))
+
+ assert_equal(3, S("hello").index(?l, 3))
+ assert_equal(3, S("hello").index(S("l"), 3))
+ assert_equal(3, S("hello").index(/l./, 3))
+
+ assert_nil(S("hello").index(?z, 3))
+ assert_nil(S("hello").index(S("z"), 3))
+ assert_nil(S("hello").index(/z./, 3))
+
+ assert_nil(S("hello").index(?z))
+ assert_nil(S("hello").index(S("z")))
+ assert_nil(S("hello").index(/z./))
+
+ assert_equal(0, S("").index(S("")))
+ assert_equal(0, S("").index(//))
+ assert_nil(S("").index(S("hello")))
+ assert_nil(S("").index(/hello/))
+ assert_equal(0, S("hello").index(S("")))
+ assert_equal(0, S("hello").index(//))
+
+ s = S("long") * 1000 << "x"
+ assert_nil(s.index(S("y")))
+ assert_equal(4 * 1000, s.index(S("x")))
+ s << "yx"
+ assert_equal(4 * 1000, s.index(S("x")))
+ assert_equal(4 * 1000, s.index(S("xyx")))
+
+ o = Object.new
+ def o.to_str; "bar"; end
+ assert_equal(3, "foobarbarbaz".index(o))
+ assert_raise(TypeError) { "foo".index(Object.new) }
+
+ assert_nil("foo".index(//, -100))
+ assert_nil($~)
+ end
+
+ def test_intern
+ assert_equal(:koala, S("koala").intern)
+ assert_not_equal(:koala, S("Koala").intern)
+ end
+
+ def test_length
+ assert_equal(0, S("").length)
+ assert_equal(4, S("1234").length)
+ assert_equal(6, S("1234\r\n").length)
+ assert_equal(7, S("\0011234\r\n").length)
+ end
+
+ def test_ljust
+ assert_equal(S("hello"), S("hello").ljust(4))
+ assert_equal(S("hello "), S("hello").ljust(11))
+ assert_equal(S("ababababab"), S("").ljust(10, "ab"), Bug2463)
+ assert_equal(S("abababababa"), S("").ljust(11, "ab"), Bug2463)
+ end
+
+ def test_next
+ assert_equal(S("abd"), S("abc").next)
+ assert_equal(S("z"), S("y").next)
+ assert_equal(S("aaa"), S("zz").next)
+
+ assert_equal(S("124"), S("123").next)
+ assert_equal(S("1000"), S("999").next)
+
+ assert_equal(S("2000aaa"), S("1999zzz").next)
+ assert_equal(S("AAAAA000"), S("ZZZZ999").next)
+
+ assert_equal(S("*+"), S("**").next)
+ end
+
+ def test_next!
+ a = S("abc")
+ b = a.dup
+ assert_equal(S("abd"), a.next!)
+ assert_equal(S("abd"), a)
+ assert_equal(S("abc"), b)
+
+ a = S("y")
+ assert_equal(S("z"), a.next!)
+ assert_equal(S("z"), a)
+
+ a = S("zz")
+ assert_equal(S("aaa"), a.next!)
+ assert_equal(S("aaa"), a)
+
+ a = S("123")
+ assert_equal(S("124"), a.next!)
+ assert_equal(S("124"), a)
+
+ a = S("999")
+ assert_equal(S("1000"), a.next!)
+ assert_equal(S("1000"), a)
+
+ a = S("1999zzz")
+ assert_equal(S("2000aaa"), a.next!)
+ assert_equal(S("2000aaa"), a)
+
+ a = S("ZZZZ999")
+ assert_equal(S("AAAAA000"), a.next!)
+ assert_equal(S("AAAAA000"), a)
+
+ a = S("**")
+ assert_equal(S("*+"), a.next!)
+ assert_equal(S("*+"), a)
+ end
+
+ def test_oct
+ assert_equal(255, S("0377").oct)
+ assert_equal(255, S("377").oct)
+ assert_equal(-255, S("-0377").oct)
+ assert_equal(-255, S("-377").oct)
+ assert_equal(0, S("OO").oct)
+ assert_equal(24, S("030OO").oct)
+ end
+
+ def test_replace
+ a = S("foo")
+ assert_equal(S("f"), a.replace(S("f")))
+
+ a = S("foo")
+ assert_equal(S("foobar"), a.replace(S("foobar")))
+
+ a = S("foo")
+ a.taint
+ b = a.replace(S("xyz"))
+ assert_equal(S("xyz"), b)
+ assert_predicate(b, :tainted?)
+
+ s = "foo" * 100
+ s2 = ("bar" * 100).dup
+ s.replace(s2)
+ assert_equal(s2, s)
+
+ s2 = ["foo"].pack("p")
+ s.replace(s2)
+ assert_equal(s2, s)
+
+ fs = "".freeze
+ assert_raise(RuntimeError) { fs.replace("a") }
+ assert_raise(RuntimeError) { fs.replace(fs) }
+ assert_raise(ArgumentError) { fs.replace() }
+ assert_raise(RuntimeError) { fs.replace(42) }
+ end
+
+ def test_reverse
+ assert_equal(S("beta"), S("ateb").reverse)
+ assert_equal(S("madamImadam"), S("madamImadam").reverse)
+
+ a=S("beta")
+ assert_equal(S("ateb"), a.reverse)
+ assert_equal(S("beta"), a)
+ end
+
+ def test_reverse!
+ a = S("beta")
+ b = a.dup
+ assert_equal(S("ateb"), a.reverse!)
+ assert_equal(S("ateb"), a)
+ assert_equal(S("beta"), b)
+
+ assert_equal(S("madamImadam"), S("madamImadam").reverse!)
+
+ a = S("madamImadam")
+ assert_equal(S("madamImadam"), a.reverse!) # ??
+ assert_equal(S("madamImadam"), a)
+ end
+
+ def test_rindex
+ assert_equal(3, S("hello").rindex(?l))
+ assert_equal(6, S("ell, hello").rindex(S("ell")))
+ assert_equal(7, S("ell, hello").rindex(/ll./))
+
+ assert_equal(3, S("hello,lo").rindex(?l, 3))
+ assert_equal(3, S("hello,lo").rindex(S("l"), 3))
+ assert_equal(3, S("hello,lo").rindex(/l./, 3))
+
+ assert_nil(S("hello").rindex(?z, 3))
+ assert_nil(S("hello").rindex(S("z"), 3))
+ assert_nil(S("hello").rindex(/z./, 3))
+
+ assert_nil(S("hello").rindex(?z))
+ assert_nil(S("hello").rindex(S("z")))
+ assert_nil(S("hello").rindex(/z./))
+
+ o = Object.new
+ def o.to_str; "bar"; end
+ assert_equal(6, "foobarbarbaz".rindex(o))
+ assert_raise(TypeError) { "foo".rindex(Object.new) }
+
+ assert_nil("foo".rindex(//, -100))
+ assert_nil($~)
+ end
+
+ def test_rjust
+ assert_equal(S("hello"), S("hello").rjust(4))
+ assert_equal(S(" hello"), S("hello").rjust(11))
+ assert_equal(S("ababababab"), S("").rjust(10, "ab"), Bug2463)
+ assert_equal(S("abababababa"), S("").rjust(11, "ab"), Bug2463)
+ end
+
+ def test_scan
+ a = S("cruel world")
+ assert_equal([S("cruel"), S("world")],a.scan(/\w+/))
+ assert_equal([S("cru"), S("el "), S("wor")],a.scan(/.../))
+ assert_equal([[S("cru")], [S("el ")], [S("wor")]],a.scan(/(...)/))
+
+ res = []
+ a.scan(/\w+/) { |w| res << w }
+ assert_equal([S("cruel"), S("world") ],res)
+
+ res = []
+ a.scan(/.../) { |w| res << w }
+ assert_equal([S("cru"), S("el "), S("wor")],res)
+
+ res = []
+ a.scan(/(...)/) { |w| res << w }
+ assert_equal([[S("cru")], [S("el ")], [S("wor")]],res)
+
+ a = S("hello")
+ a.taint
+ res = []
+ a.scan(/./) { |w| res << w }
+ assert_predicate(res[0], :tainted?, '[ruby-core:33338] #4087')
+
+ /h/ =~ a
+ a.scan(/x/)
+ assert_nil($~)
+
+ /h/ =~ a
+ a.scan('x')
+ assert_nil($~)
+
+ assert_equal(3, S("hello hello hello").scan("hello".taint).count(&:tainted?))
+ end
+
+ def test_size
+ assert_equal(0, S("").size)
+ assert_equal(4, S("1234").size)
+ assert_equal(6, S("1234\r\n").size)
+ assert_equal(7, S("\0011234\r\n").size)
+ end
+
+ def test_slice
+ assert_equal(?A, S("AooBar").slice(0))
+ assert_equal(?B, S("FooBaB").slice(-1))
+ assert_nil(S("FooBar").slice(6))
+ assert_nil(S("FooBar").slice(-7))
+
+ assert_equal(S("Foo"), S("FooBar").slice(0,3))
+ assert_equal(S(S("Bar")), S("FooBar").slice(-3,3))
+ assert_nil(S("FooBar").slice(7,2)) # Maybe should be six?
+ assert_nil(S("FooBar").slice(-7,10))
+
+ assert_equal(S("Foo"), S("FooBar").slice(0..2))
+ assert_equal(S("Bar"), S("FooBar").slice(-3..-1))
+ assert_equal(S(""), S("FooBar").slice(6..2))
+ assert_nil(S("FooBar").slice(-10..-7))
+
+ assert_equal(S("Foo"), S("FooBar").slice(/^F../))
+ assert_equal(S("Bar"), S("FooBar").slice(/..r$/))
+ assert_nil(S("FooBar").slice(/xyzzy/))
+ assert_nil(S("FooBar").slice(/plugh/))
+
+ assert_equal(S("Foo"), S("FooBar").slice(S("Foo")))
+ assert_equal(S("Bar"), S("FooBar").slice(S("Bar")))
+ assert_nil(S("FooBar").slice(S("xyzzy")))
+ assert_nil(S("FooBar").slice(S("plugh")))
+
+ bug9882 = '[ruby-core:62842] [Bug #9882]'
+ substr = S("\u{30c6 30b9 30c8 2019}#{bug9882}").slice(4..-1)
+ assert_equal(S(bug9882).hash, substr.hash, bug9882)
+ assert_predicate(substr, :ascii_only?, bug9882)
+ end
+
+ def test_slice!
+ a = S("AooBar")
+ b = a.dup
+ assert_equal(?A, a.slice!(0))
+ assert_equal(S("ooBar"), a)
+ assert_equal(S("AooBar"), b)
+
+ a = S("FooBar")
+ assert_equal(?r,a.slice!(-1))
+ assert_equal(S("FooBa"), a)
+
+ a = S("FooBar")
+ if @aref_slicebang_silent
+ assert_nil( a.slice!(6) )
+ else
+ assert_raise(IndexError) { a.slice!(6) }
+ end
+ assert_equal(S("FooBar"), a)
+
+ if @aref_slicebang_silent
+ assert_nil( a.slice!(-7) )
+ else
+ assert_raise(IndexError) { a.slice!(-7) }
+ end
+ assert_equal(S("FooBar"), a)
+
+ a = S("FooBar")
+ assert_equal(S("Foo"), a.slice!(0,3))
+ assert_equal(S("Bar"), a)
+
+ a = S("FooBar")
+ assert_equal(S("Bar"), a.slice!(-3,3))
+ assert_equal(S("Foo"), a)
+
+ a=S("FooBar")
+ if @aref_slicebang_silent
+ assert_nil(a.slice!(7,2)) # Maybe should be six?
+ else
+ assert_raise(IndexError) {a.slice!(7,2)} # Maybe should be six?
+ end
+ assert_equal(S("FooBar"), a)
+ if @aref_slicebang_silent
+ assert_nil(a.slice!(-7,10))
+ else
+ assert_raise(IndexError) {a.slice!(-7,10)}
+ end
+ assert_equal(S("FooBar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Foo"), a.slice!(0..2))
+ assert_equal(S("Bar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Bar"), a.slice!(-3..-1))
+ assert_equal(S("Foo"), a)
+
+ a=S("FooBar")
+ if @aref_slicebang_silent
+ assert_equal(S(""), a.slice!(6..2))
+ else
+ assert_raise(RangeError) {a.slice!(6..2)}
+ end
+ assert_equal(S("FooBar"), a)
+ if @aref_slicebang_silent
+ assert_nil(a.slice!(-10..-7))
+ else
+ assert_raise(RangeError) {a.slice!(-10..-7)}
+ end
+ assert_equal(S("FooBar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Foo"), a.slice!(/^F../))
+ assert_equal(S("Bar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Bar"), a.slice!(/..r$/))
+ assert_equal(S("Foo"), a)
+
+ a=S("FooBar")
+ if @aref_slicebang_silent
+ assert_nil(a.slice!(/xyzzy/))
+ else
+ assert_raise(IndexError) {a.slice!(/xyzzy/)}
+ end
+ assert_equal(S("FooBar"), a)
+ if @aref_slicebang_silent
+ assert_nil(a.slice!(/plugh/))
+ else
+ assert_raise(IndexError) {a.slice!(/plugh/)}
+ end
+ assert_equal(S("FooBar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Foo"), a.slice!(S("Foo")))
+ assert_equal(S("Bar"), a)
+
+ a=S("FooBar")
+ assert_equal(S("Bar"), a.slice!(S("Bar")))
+ assert_equal(S("Foo"), a)
+
+ pre_1_7_1 do
+ a=S("FooBar")
+ assert_nil(a.slice!(S("xyzzy")))
+ assert_equal(S("FooBar"), a)
+ assert_nil(a.slice!(S("plugh")))
+ assert_equal(S("FooBar"), a)
+ end
+
+ assert_raise(ArgumentError) { "foo".slice! }
+ end
+
+ def test_split
+ assert_nil($;)
+ assert_equal([S("a"), S("b"), S("c")], S(" a b\t c ").split)
+ assert_equal([S("a"), S("b"), S("c")], S(" a b\t c ").split(S(" ")))
+
+ assert_equal([S(" a "), S(" b "), S(" c ")], S(" a | b | c ").split(S("|")))
+
+ assert_equal([S("a"), S("b"), S("c")], S("aXXbXXcXX").split(/X./))
+
+ assert_equal([S("a"), S("b"), S("c")], S("abc").split(//))
+
+ assert_equal([S("a|b|c")], S("a|b|c").split(S('|'), 1))
+
+ assert_equal([S("a"), S("b|c")], S("a|b|c").split(S('|'), 2))
+ assert_equal([S("a"), S("b"), S("c")], S("a|b|c").split(S('|'), 3))
+
+ assert_equal([S("a"), S("b"), S("c"), S("")], S("a|b|c|").split(S('|'), -1))
+ assert_equal([S("a"), S("b"), S("c"), S(""), S("")], S("a|b|c||").split(S('|'), -1))
+
+ assert_equal([S("a"), S(""), S("b"), S("c")], S("a||b|c|").split(S('|')))
+ assert_equal([S("a"), S(""), S("b"), S("c"), S("")], S("a||b|c|").split(S('|'), -1))
+
+ assert_equal([], "".split(//, 1))
+
+ assert_equal("[2, 3]", [1,2,3].slice!(1,10000).inspect, "moved from btest/knownbug")
+ end
+
+ def test_split_encoding
+ bug6206 = '[ruby-dev:45441]'
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ s = S("a:".force_encoding(enc))
+ assert_equal([enc]*2, s.split(":", 2).map(&:encoding), bug6206)
+ end
+ end
+
+ def test_split_wchar
+ bug8642 = '[ruby-core:56036] [Bug #8642]'
+ [
+ Encoding::UTF_16BE, Encoding::UTF_16LE,
+ Encoding::UTF_32BE, Encoding::UTF_32LE,
+ ].each do |enc|
+ s = S("abc,def".encode(enc))
+ assert_equal(["abc", "def"].map {|c| c.encode(enc)},
+ s.split(",".encode(enc)),
+ "#{bug8642} in #{enc.name}")
+ end
+ end
+
+ def test_split_invalid_sequence
+ bug10886 = '[ruby-core:68229] [Bug #10886]'
+ broken = S("\xa1".force_encoding("utf-8"))
+ assert_raise(ArgumentError, bug10886) {
+ S("a,b").split(broken)
+ }
+ end
+
+ def test_split_invalid_argument
+ assert_raise(TypeError) {
+ S("a,b").split(BasicObject.new)
+ }
+ end
+
+ def test_squeeze
+ assert_equal(S("abc"), S("aaabbbbccc").squeeze)
+ assert_equal(S("aa bb cc"), S("aa bb cc").squeeze(S(" ")))
+ assert_equal(S("BxTyWz"), S("BxxxTyyyWzzzzz").squeeze(S("a-z")))
+ end
+
+ def test_squeeze!
+ a = S("aaabbbbccc")
+ b = a.dup
+ assert_equal(S("abc"), a.squeeze!)
+ assert_equal(S("abc"), a)
+ assert_equal(S("aaabbbbccc"), b)
+
+ a = S("aa bb cc")
+ assert_equal(S("aa bb cc"), a.squeeze!(S(" ")))
+ assert_equal(S("aa bb cc"), a)
+
+ a = S("BxxxTyyyWzzzzz")
+ assert_equal(S("BxTyWz"), a.squeeze!(S("a-z")))
+ assert_equal(S("BxTyWz"), a)
+
+ a=S("The quick brown fox")
+ assert_nil(a.squeeze!)
+ end
+
+ def test_start_with?
+ assert_send([S("hello"), :start_with?, S("hel")])
+ assert_not_send([S("hello"), :start_with?, S("el")])
+ assert_send([S("hello"), :start_with?, S("el"), S("he")])
+
+ bug5536 = '[ruby-core:40623]'
+ assert_raise(TypeError, bug5536) {S("str").start_with? :not_convertible_to_string}
+ end
+
+ def test_strip
+ assert_equal(S("x"), S(" x ").strip)
+ assert_equal(S("x"), S(" \n\r\t x \t\r\n\n ").strip)
+
+ assert_equal("0b0 ".force_encoding("UTF-16BE"),
+ "\x00 0b0 ".force_encoding("UTF-16BE").strip)
+ assert_equal("0\x000b0 ".force_encoding("UTF-16BE"),
+ "0\x000b0 ".force_encoding("UTF-16BE").strip)
+ end
+
+ def test_strip!
+ a = S(" x ")
+ b = a.dup
+ assert_equal(S("x") ,a.strip!)
+ assert_equal(S("x") ,a)
+ assert_equal(S(" x "), b)
+
+ a = S(" \n\r\t x \t\r\n\n ")
+ assert_equal(S("x"), a.strip!)
+ assert_equal(S("x"), a)
+
+ a = S("x")
+ assert_nil(a.strip!)
+ assert_equal(S("x") ,a)
+ end
+
+ def test_sub
+ assert_equal(S("h*llo"), S("hello").sub(/[aeiou]/, S('*')))
+ assert_equal(S("h<e>llo"), S("hello").sub(/([aeiou])/, S('<\1>')))
+ assert_equal(S("h ello"), S("hello").sub(/./) {
+ |s| s[0].to_s + S(' ')})
+ assert_equal(S("HELL-o"), S("hello").sub(/(hell)(.)/) {
+ |s| $1.upcase + S('-') + $2
+ })
+ assert_equal(S("h<e>llo"), S("hello").sub('e', S('<\0>')))
+
+ assert_equal(S("a\\aba"), S("ababa").sub(/b/, '\\'))
+ assert_equal(S("ab\\aba"), S("ababa").sub(/(b)/, '\1\\'))
+ assert_equal(S("ababa"), S("ababa").sub(/(b)/, '\1'))
+ assert_equal(S("ababa"), S("ababa").sub(/(b)/, '\\1'))
+ assert_equal(S("a\\1aba"), S("ababa").sub(/(b)/, '\\\1'))
+ assert_equal(S("a\\1aba"), S("ababa").sub(/(b)/, '\\\\1'))
+ assert_equal(S("a\\baba"), S("ababa").sub(/(b)/, '\\\\\1'))
+
+ assert_equal(S("a--ababababababababab"),
+ S("abababababababababab").sub(/(b)/, '-\9-'))
+ assert_equal(S("1-b-0"),
+ S("1b2b3b4b5b6b7b8b9b0").
+ sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\9-'))
+ assert_equal(S("1-b-0"),
+ S("1b2b3b4b5b6b7b8b9b0").
+ sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\\9-'))
+ assert_equal(S("1-\\9-0"),
+ S("1b2b3b4b5b6b7b8b9b0").
+ sub(/(b).(b).(b).(b).(b).(b).(b).(b).(b)/, '-\\\9-'))
+ assert_equal(S("k"),
+ S("1a2b3c4d5e6f7g8h9iAjBk").
+ sub(/.(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.)/, '\+'))
+
+ assert_equal(S("ab\\aba"), S("ababa").sub(/b/, '\&\\'))
+ assert_equal(S("ababa"), S("ababa").sub(/b/, '\&'))
+ assert_equal(S("ababa"), S("ababa").sub(/b/, '\\&'))
+ assert_equal(S("a\\&aba"), S("ababa").sub(/b/, '\\\&'))
+ assert_equal(S("a\\&aba"), S("ababa").sub(/b/, '\\\\&'))
+ assert_equal(S("a\\baba"), S("ababa").sub(/b/, '\\\\\&'))
+
+ a = S("hello")
+ a.taint
+ x = a.sub(/./, S('X'))
+ assert_predicate(x, :tainted?)
+
+ o = Object.new
+ def o.to_str; "bar"; end
+ assert_equal("fooBARbaz", "foobarbaz".sub(o, "BAR"))
+
+ assert_raise(TypeError) { "foo".sub(Object.new, "") }
+
+ assert_raise(ArgumentError) { "foo".sub }
+
+ assert_raise(IndexError) { "foo"[/(?:(o$)|(x))/, 2] = 'bar' }
+
+ o = Object.new
+ def o.to_s; self; end
+ assert_match(/^foo#<Object:0x.*>baz$/, "foobarbaz".sub("bar") { o })
+
+ assert_equal(S("Abc"), S("abc").sub("a", "A"))
+ m = nil
+ assert_equal(S("Abc"), S("abc").sub("a") {m = $~; "A"})
+ assert_equal(S("a"), m[0])
+ assert_equal(/a/, m.regexp)
+ end
+
+ def test_sub!
+ a = S("hello")
+ b = a.dup
+ a.sub!(/[aeiou]/, S('*'))
+ assert_equal(S("h*llo"), a)
+ assert_equal(S("hello"), b)
+
+ a = S("hello")
+ a.sub!(/([aeiou])/, S('<\1>'))
+ assert_equal(S("h<e>llo"), a)
+
+ a = S("hello")
+ a.sub!(/./) { |s| s[0].to_s + S(' ')}
+ assert_equal(S("h ello"), a)
+
+ a = S("hello")
+ a.sub!(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 }
+ assert_equal(S("HELL-o"), a)
+
+ a=S("hello")
+ assert_nil(a.sub!(/X/, S('Y')))
+
+ r = S('X')
+ r.taint
+ a.sub!(/./, r)
+ assert_predicate(a, :tainted?)
+ end
+
+ def test_succ
+ assert_equal(S("abd"), S("abc").succ)
+ assert_equal(S("z"), S("y").succ)
+ assert_equal(S("aaa"), S("zz").succ)
+
+ assert_equal(S("124"), S("123").succ)
+ assert_equal(S("1000"), S("999").succ)
+ assert_equal(S("2.000"), S("1.999").succ)
+
+ assert_equal(S("No.10"), S("No.9").succ)
+ assert_equal(S("2000aaa"), S("1999zzz").succ)
+ assert_equal(S("AAAAA000"), S("ZZZZ999").succ)
+ assert_equal(S("*+"), S("**").succ)
+
+ assert_equal("abce", "abcd".succ)
+ assert_equal("THX1139", "THX1138".succ)
+ assert_equal("<\<koalb>>", "<\<koala>>".succ)
+ assert_equal("2000aaa", "1999zzz".succ)
+ assert_equal("AAAA0000", "ZZZ9999".succ)
+ assert_equal("**+", "***".succ)
+ end
+
+ def test_succ!
+ a = S("abc")
+ b = a.dup
+ assert_equal(S("abd"), a.succ!)
+ assert_equal(S("abd"), a)
+ assert_equal(S("abc"), b)
+
+ a = S("y")
+ assert_equal(S("z"), a.succ!)
+ assert_equal(S("z"), a)
+
+ a = S("zz")
+ assert_equal(S("aaa"), a.succ!)
+ assert_equal(S("aaa"), a)
+
+ a = S("123")
+ assert_equal(S("124"), a.succ!)
+ assert_equal(S("124"), a)
+
+ a = S("999")
+ assert_equal(S("1000"), a.succ!)
+ assert_equal(S("1000"), a)
+
+ a = S("1999zzz")
+ assert_equal(S("2000aaa"), a.succ!)
+ assert_equal(S("2000aaa"), a)
+
+ a = S("ZZZZ999")
+ assert_equal(S("AAAAA000"), a.succ!)
+ assert_equal(S("AAAAA000"), a)
+
+ a = S("**")
+ assert_equal(S("*+"), a.succ!)
+ assert_equal(S("*+"), a)
+
+ a = S("No.9")
+ assert_equal(S("No.10"), a.succ!)
+ assert_equal(S("No.10"), a)
+
+ assert_equal("aaaaaaaaaaaa", "zzzzzzzzzzz".succ!)
+ assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", "zzzzzzzzzzzzzzzzzzzzzzz".succ!)
+ end
+
+ def test_sum
+ n = S("\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001")
+ assert_equal(15, n.sum)
+ n += S("\001")
+ assert_equal(16, n.sum(17))
+ n[0] = 2.chr
+ assert_not_equal(15, n.sum)
+ assert_equal(17, n.sum(0))
+ assert_equal(17, n.sum(-1))
+ end
+
+ def check_sum(str, bits=16)
+ sum = 0
+ str.each_byte {|c| sum += c}
+ sum = sum & ((1 << bits) - 1) if bits != 0
+ assert_equal(sum, str.sum(bits))
+ end
+
+ def test_sum_2
+ assert_equal(0, "".sum)
+ assert_equal(294, "abc".sum)
+ check_sum("abc")
+ check_sum("\x80")
+ -3.upto(70) {|bits|
+ check_sum("xyz", bits)
+ }
+ end
+
+ def test_sum_long
+ s8421505 = "\xff" * 8421505
+ assert_equal(127, s8421505.sum(31))
+ assert_equal(2147483775, s8421505.sum(0))
+ s16843010 = ("\xff" * 16843010)
+ assert_equal(254, s16843010.sum(32))
+ assert_equal(4294967550, s16843010.sum(0))
+ end
+
+ def test_swapcase
+ assert_equal(S("hi&LOW"), S("HI&low").swapcase)
+ end
+
+ def test_swapcase!
+ a = S("hi&LOW")
+ b = a.dup
+ assert_equal(S("HI&low"), a.swapcase!)
+ assert_equal(S("HI&low"), a)
+ assert_equal(S("hi&LOW"), b)
+
+ a = S("$^#^%$#!!")
+ assert_nil(a.swapcase!)
+ assert_equal(S("$^#^%$#!!"), a)
+ end
+
+ def test_to_f
+ assert_equal(344.3, S("344.3").to_f)
+ assert_equal(5.9742e24, S("5.9742e24").to_f)
+ assert_equal(98.6, S("98.6 degrees").to_f)
+ assert_equal(0.0, S("degrees 100.0").to_f)
+ assert_equal([ 0.0].pack('G'), [S(" 0.0").to_f].pack('G'))
+ assert_equal([-0.0].pack('G'), [S("-0.0").to_f].pack('G'))
+ end
+
+ def test_to_i
+ assert_equal(1480, S("1480ft/sec").to_i)
+ assert_equal(0, S("speed of sound in water @20C = 1480ft/sec)").to_i)
+ assert_equal(0, " 0".to_i)
+ assert_equal(0, "+0".to_i)
+ assert_equal(0, "-0".to_i)
+ assert_equal(0, "--0".to_i)
+ assert_equal(16, "0x10".to_i(0))
+ assert_equal(16, "0X10".to_i(0))
+ assert_equal(2, "0b10".to_i(0))
+ assert_equal(2, "0B10".to_i(0))
+ assert_equal(8, "0o10".to_i(0))
+ assert_equal(8, "0O10".to_i(0))
+ assert_equal(10, "0d10".to_i(0))
+ assert_equal(10, "0D10".to_i(0))
+ assert_equal(8, "010".to_i(0))
+ assert_raise(ArgumentError) { "010".to_i(-10) }
+ 2.upto(36) {|radix|
+ assert_equal(radix, "10".to_i(radix))
+ assert_equal(radix**2, "100".to_i(radix))
+ }
+ assert_raise(ArgumentError) { "0".to_i(1) }
+ assert_raise(ArgumentError) { "0".to_i(37) }
+ assert_equal(0, "z".to_i(10))
+ assert_equal(12, "1_2".to_i(10))
+ assert_equal(0x40000000, "1073741824".to_i(10))
+ assert_equal(0x4000000000000000, "4611686018427387904".to_i(10))
+ assert_equal(1, "1__2".to_i(10))
+ assert_equal(1, "1_z".to_i(10))
+
+ bug6192 = '[ruby-core:43566]'
+ assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16be").to_i}
+ assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16le").to_i}
+ assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32be").to_i}
+ assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32le").to_i}
+ assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("iso-2022-jp").to_i}
+ end
+
+ def test_to_s
+ a = S("me")
+ assert_equal("me", a.to_s)
+ assert_equal(a.__id__, a.to_s.__id__) if @cls == String
+ end
+
+ def test_to_str
+ a = S("me")
+ assert_equal("me", a.to_s)
+ assert_equal(a.__id__, a.to_s.__id__) if @cls == String
+
+ o = Object.new
+ def o.to_str
+ "at"
+ end
+ assert_equal("meat", a.concat(o))
+
+ o = Object.new
+ def o.to_str
+ foo_bar()
+ end
+ assert_match(/foo_bar/, assert_raise(NoMethodError) {a.concat(o)}.message)
+ end
+
+ def test_tr
+ assert_equal(S("hippo"), S("hello").tr(S("el"), S("ip")))
+ assert_equal(S("*e**o"), S("hello").tr(S("^aeiou"), S("*")))
+ assert_equal(S("hal"), S("ibm").tr(S("b-z"), S("a-z")))
+
+ a = "abc".force_encoding(Encoding::US_ASCII)
+ assert_equal(Encoding::US_ASCII, a.tr(S("z"), S("\u0101")).encoding, '[ruby-core:22326]')
+
+ assert_equal("a".hash, "a".tr("a", "\u0101").tr("\u0101", "a").hash, '[ruby-core:22328]')
+ assert_equal(true, "\u0101".tr("\u0101", "a").ascii_only?)
+ assert_equal(true, "\u3041".tr("\u3041", "a").ascii_only?)
+ assert_equal(false, "\u3041\u3042".tr("\u3041", "a").ascii_only?)
+
+ bug6156 = '[ruby-core:43335]'
+ str, range, star = %w[b a-z *].map{|s|s.encode("utf-16le")}
+ assert_equal(star, str.tr(range, star), bug6156)
+ end
+
+ def test_tr!
+ a = S("hello")
+ b = a.dup
+ assert_equal(S("hippo"), a.tr!(S("el"), S("ip")))
+ assert_equal(S("hippo"), a)
+ assert_equal(S("hello"),b)
+
+ a = S("hello")
+ assert_equal(S("*e**o"), a.tr!(S("^aeiou"), S("*")))
+ assert_equal(S("*e**o"), a)
+
+ a = S("IBM")
+ assert_equal(S("HAL"), a.tr!(S("B-Z"), S("A-Z")))
+ assert_equal(S("HAL"), a)
+
+ a = S("ibm")
+ assert_nil(a.tr!(S("B-Z"), S("A-Z")))
+ assert_equal(S("ibm"), a)
+
+ a = "abc".force_encoding(Encoding::US_ASCII)
+ assert_nil(a.tr!(S("z"), S("\u0101")), '[ruby-core:22326]')
+ assert_equal(Encoding::US_ASCII, a.encoding, '[ruby-core:22326]')
+ end
+
+ def test_tr_s
+ assert_equal(S("hypo"), S("hello").tr_s(S("el"), S("yp")))
+ assert_equal(S("h*o"), S("hello").tr_s(S("el"), S("*")))
+ assert_equal("a".hash, "\u0101\u0101".tr_s("\u0101", "a").hash)
+ assert_equal(true, "\u3041\u3041".tr("\u3041", "a").ascii_only?)
+ end
+
+ def test_tr_s!
+ a = S("hello")
+ b = a.dup
+ assert_equal(S("hypo"), a.tr_s!(S("el"), S("yp")))
+ assert_equal(S("hypo"), a)
+ assert_equal(S("hello"), b)
+
+ a = S("hello")
+ assert_equal(S("h*o"), a.tr_s!(S("el"), S("*")))
+ assert_equal(S("h*o"), a)
+ end
+
+ def test_unpack
+ a = [S("cat"), S("wom"), S("x"), S("yy")]
+ assert_equal(a, S("catwomx yy ").unpack(S("A3A3A3A3")))
+
+ assert_equal([S("cat")], S("cat \000\000").unpack(S("A*")))
+ assert_equal([S("cwx"), S("wx"), S("x"), S("yy")],
+ S("cwx yy ").unpack(S("A3@1A3@2A3A3")))
+ assert_equal([S("cat"), S("wom"), S("x\000\000"), S("yy\000")],
+ S("catwomx\000\000yy\000").unpack(S("a3a3a3a3")))
+ assert_equal([S("cat \000\000")], S("cat \000\000").unpack(S("a*")))
+ assert_equal([S("ca")], S("catdog").unpack(S("a2")))
+
+ assert_equal([S("cat\000\000")],
+ S("cat\000\000\000\000\000dog").unpack(S("a5")))
+
+ assert_equal([S("01100001")], S("\x61").unpack(S("B8")))
+ assert_equal([S("01100001")], S("\x61").unpack(S("B*")))
+ assert_equal([S("0110000100110111")], S("\x61\x37").unpack(S("B16")))
+ assert_equal([S("01100001"), S("00110111")], S("\x61\x37").unpack(S("B8B8")))
+ assert_equal([S("0110")], S("\x60").unpack(S("B4")))
+
+ assert_equal([S("01")], S("\x40").unpack(S("B2")))
+
+ assert_equal([S("01100001")], S("\x86").unpack(S("b8")))
+ assert_equal([S("01100001")], S("\x86").unpack(S("b*")))
+
+ assert_equal([S("0110000100110111")], S("\x86\xec").unpack(S("b16")))
+ assert_equal([S("01100001"), S("00110111")], S("\x86\xec").unpack(S("b8b8")))
+
+ assert_equal([S("0110")], S("\x06").unpack(S("b4")))
+ assert_equal([S("01")], S("\x02").unpack(S("b2")))
+
+ assert_equal([ 65, 66, 67 ], S("ABC").unpack(S("C3")))
+ assert_equal([ 255, 66, 67 ], S("\377BC").unpack("C*"))
+ assert_equal([ 65, 66, 67 ], S("ABC").unpack("c3"))
+ assert_equal([ -1, 66, 67 ], S("\377BC").unpack("c*"))
+
+
+ assert_equal([S("4142"), S("0a"), S("1")], S("AB\n\x10").unpack(S("H4H2H1")))
+ assert_equal([S("1424"), S("a0"), S("2")], S("AB\n\x02").unpack(S("h4h2h1")))
+
+ assert_equal([S("abc\002defcat\001"), S(""), S("")],
+ S("abc=02def=\ncat=\n=01=\n").unpack(S("M9M3M4")))
+
+ assert_equal([S("hello\n")], S("aGVsbG8K\n").unpack(S("m")))
+
+ assert_equal([S("hello\nhello\n")], S(",:&5L;&\\*:&5L;&\\*\n").unpack(S("u")))
+
+ assert_equal([0xa9, 0x42, 0x2260], S("\xc2\xa9B\xe2\x89\xa0").unpack(S("U*")))
+
+=begin
+ skipping "Not tested:
+ D,d & double-precision float, native format\\
+ E & double-precision float, little-endian byte order\\
+ e & single-precision float, little-endian byte order\\
+ F,f & single-precision float, native format\\
+ G & double-precision float, network (big-endian) byte order\\
+ g & single-precision float, network (big-endian) byte order\\
+ I & unsigned integer\\
+ i & integer\\
+ L & unsigned long\\
+ l & long\\
+
+ m & string encoded in base64 (uuencoded)\\
+ N & long, network (big-endian) byte order\\
+ n & short, network (big-endian) byte-order\\
+ P & pointer to a structure (fixed-length string)\\
+ p & pointer to a null-terminated string\\
+ S & unsigned short\\
+ s & short\\
+ V & long, little-endian byte order\\
+ v & short, little-endian byte order\\
+ X & back up a byte\\
+ x & null byte\\
+ Z & ASCII string (null padded, count is width)\\
+"
+=end
+ end
+
+ def test_upcase
+ assert_equal(S("HELLO"), S("hello").upcase)
+ assert_equal(S("HELLO"), S("hello").upcase)
+ assert_equal(S("HELLO"), S("HELLO").upcase)
+ assert_equal(S("ABC HELLO 123"), S("abc HELLO 123").upcase)
+ end
+
+ def test_upcase!
+ a = S("hello")
+ b = a.dup
+ assert_equal(S("HELLO"), a.upcase!)
+ assert_equal(S("HELLO"), a)
+ assert_equal(S("hello"), b)
+
+ a = S("HELLO")
+ assert_nil(a.upcase!)
+ assert_equal(S("HELLO"), a)
+ end
+
+ def test_upto
+ a = S("aa")
+ start = S("aa")
+ count = 0
+ assert_equal(S("aa"), a.upto(S("zz")) {|s|
+ assert_equal(start, s)
+ start.succ!
+ count += 1
+ })
+ assert_equal(676, count)
+ end
+
+ def test_upto_numeric
+ a = S("00")
+ start = S("00")
+ count = 0
+ assert_equal(S("00"), a.upto(S("23")) {|s|
+ assert_equal(start, s, "[ruby-dev:39361]")
+ assert_equal(Encoding::US_ASCII, s.encoding)
+ start.succ!
+ count += 1
+ })
+ assert_equal(24, count, "[ruby-dev:39361]")
+ end
+
+ def test_upto_nonalnum
+ first = S("\u3041")
+ last = S("\u3093")
+ count = 0
+ assert_equal(first, first.upto(last) {|s|
+ count += 1
+ s.replace(last)
+ })
+ assert_equal(83, count, "[ruby-dev:39626]")
+ end
+
+ def test_mod_check
+ assert_raise(RuntimeError) {
+ s = ""
+ s.sub!(/\A/) { s.replace "z" * 2000; "zzz" }
+ }
+ end
+
+ def test_frozen_check
+ assert_raise(RuntimeError) {
+ s = ""
+ s.sub!(/\A/) { s.freeze; "zzz" }
+ }
+ end
+
+ class S2 < String
+ end
+ def test_str_new4
+ s = (0..54).to_a.join # length = 100
+ s2 = S2.new(s[10,90])
+ s3 = s2[10,80]
+ assert_equal((10..54).to_a.to_a.join, s2)
+ assert_equal((15..54).to_a.to_a.join, s3)
+ end
+
+ def test_rb_str_new4
+ s = "a" * 100
+ s2 = s[10,90]
+ assert_equal("a" * 90, s2)
+ s3 = s2[10,80]
+ assert_equal("a" * 80, s3)
+ end
+
+ class StringLike
+ def initialize(str)
+ @str = str
+ end
+
+ def to_str
+ @str
+ end
+ end
+
+ def test_rb_str_to_str
+ assert_equal("ab", "a" + StringLike.new("b"))
+ end
+
+ def test_rb_str_shared_replace
+ s = "a" * 100
+ s.succ!
+ assert_equal("a" * 99 + "b", s)
+ s = ""
+ s.succ!
+ assert_equal("", s)
+ end
+
+ def test_times
+ assert_raise(ArgumentError) { "a" * (-1) }
+ end
+
+ def test_splice!
+ l = S("1234\n234\n34\n4\n")
+ assert_equal(S("1234\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]")
+ assert_equal(S("234\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]")
+ assert_equal(S("34\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]")
+ assert_equal(S("4\n"), l.slice!(/\A.*\n/), "[ruby-dev:31665]")
+ assert_nil(l.slice!(/\A.*\n/), "[ruby-dev:31665]")
+ end
+
+ def test_times2
+ s1 = ''
+ 100.times {|n|
+ s2 = "a" * n
+ assert_equal(s1, s2)
+ s1 << 'a'
+ }
+
+ assert_raise(ArgumentError) { "foo" * (-1) }
+ end
+
+ def test_respond_to
+ o = Object.new
+ def o.respond_to?(arg) [:to_str].include?(arg) ? nil : super end
+ def o.to_str() "" end
+ def o.==(other) "" == other end
+ assert_equal(false, "" == o)
+ end
+
+ def test_match_method
+ assert_equal("bar", "foobarbaz".match(/bar/).to_s)
+
+ o = Regexp.new('foo')
+ def o.match(x, y, z); x + y + z; end
+ assert_equal("foobarbaz", "foo".match(o, "bar", "baz"))
+ x = nil
+ "foo".match(o, "bar", "baz") {|y| x = y }
+ assert_equal("foobarbaz", x)
+
+ assert_raise(ArgumentError) { "foo".match }
+ end
+
+ def test_clear
+ s = "foo" * 100
+ s.clear
+ assert_equal("", s)
+ end
+
+ def test_to_s_2
+ c = Class.new(String)
+ s = c.new
+ s.replace("foo")
+ assert_equal("foo", s.to_s)
+ assert_instance_of(String, s.to_s)
+ end
+
+ def test_inspect_nul
+ bug8290 = '[ruby-core:54458]'
+ s = "\0" + "12"
+ assert_equal '"\u000012"', s.inspect, bug8290
+ s = "\0".b + "12"
+ assert_equal '"\x0012"', s.inspect, bug8290
+ end
+
+ def test_partition
+ assert_equal(%w(he l lo), "hello".partition(/l/))
+ assert_equal(%w(he l lo), "hello".partition("l"))
+ assert_raise(TypeError) { "hello".partition(1) }
+ def (hyphen = Object.new).to_str; "-"; end
+ assert_equal(%w(foo - bar), "foo-bar".partition(hyphen), '[ruby-core:23540]')
+
+ bug6206 = '[ruby-dev:45441]'
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ s = S("a:".force_encoding(enc))
+ assert_equal([enc]*3, s.partition("|").map(&:encoding), bug6206)
+ end
+
+ assert_equal(["\u30E6\u30FC\u30B6", "@", "\u30C9\u30E1.\u30A4\u30F3"],
+ "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".partition(/[@.]/))
+ end
+
+ def test_rpartition
+ assert_equal(%w(hel l o), "hello".rpartition(/l/))
+ assert_equal(%w(hel l o), "hello".rpartition("l"))
+ assert_raise(TypeError) { "hello".rpartition(1) }
+ def (hyphen = Object.new).to_str; "-"; end
+ assert_equal(%w(foo - bar), "foo-bar".rpartition(hyphen), '[ruby-core:23540]')
+
+ bug6206 = '[ruby-dev:45441]'
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ s = S("a:".force_encoding(enc))
+ assert_equal([enc]*3, s.rpartition("|").map(&:encoding), bug6206)
+ end
+
+ bug8138 = '[ruby-dev:47183]'
+ assert_equal(["\u30E6\u30FC\u30B6@\u30C9\u30E1", ".", "\u30A4\u30F3"],
+ "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".rpartition(/[@.]/), bug8138)
+ end
+
+ def test_setter
+ assert_raise(TypeError) { $/ = 1 }
+ name = "\u{5206 884c}"
+ assert_separately([], <<-"end;") # do
+ alias $#{name} $/
+ assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 }
+ end;
+ end
+
+ def test_to_id
+ c = Class.new
+ c.class_eval do
+ def initialize
+ @foo = :foo
+ end
+ end
+
+ assert_raise(TypeError) do
+ c.class_eval { attr 1 }
+ end
+
+ o = Object.new
+ def o.to_str; :foo; end
+ assert_raise(TypeError) do
+ c.class_eval { attr 1 }
+ end
+
+ class << o;remove_method :to_str;end
+ def o.to_str; "foo"; end
+ assert_nothing_raised do
+ c.class_eval { attr o }
+ end
+ assert_equal(:foo, c.new.foo)
+ end
+
+ def test_gsub_enumerator
+ assert_normal_exit %q{"abc".gsub(/./).next}, "[ruby-dev:34828]"
+ end
+
+ def test_clear_nonasciicompat
+ assert_equal("", "\u3042".encode("ISO-2022-JP").clear)
+ end
+
+ def test_try_convert
+ assert_equal(nil, String.try_convert(1))
+ assert_equal("foo", String.try_convert("foo"))
+ end
+
+ def test_substr_negative_begin
+ assert_equal("\u3042", ("\u3042" * 100)[-1])
+ end
+
+=begin
+ def test_compare_different_encoding_string
+ s1 = "\xff".force_encoding("UTF-8")
+ s2 = "\xff".force_encoding("ISO-2022-JP")
+ assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort)
+ end
+=end
+
+ def test_casecmp
+ assert_equal(1, "\u3042B".casecmp("\u3042a"))
+ end
+
+ def test_upcase2
+ assert_equal("\u3042AB", "\u3042aB".upcase)
+ end
+
+ def test_downcase2
+ assert_equal("\u3042ab", "\u3042aB".downcase)
+ end
+
+ def test_rstrip
+ assert_equal("\u3042", "\u3042 ".rstrip)
+ assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip }
+ end
+
+=begin
+ def test_symbol_table_overflow
+ assert_in_out_err([], <<-INPUT, [], /symbol table overflow \(symbol [a-z]{8}\) \(RuntimeError\)/)
+ ("aaaaaaaa".."zzzzzzzz").each {|s| s.to_sym }
+ INPUT
+ end
+=end
+
+ def test_shared_force_encoding
+ s = "\u{3066}\u{3059}\u{3068}".gsub(//, '')
+ h = {}
+ h[s] = nil
+ k = h.keys[0]
+ assert_equal(s, k, '[ruby-dev:39068]')
+ assert_equal(Encoding::UTF_8, k.encoding, '[ruby-dev:39068]')
+ s.dup.force_encoding(Encoding::ASCII_8BIT).gsub(//, '')
+ k = h.keys[0]
+ assert_equal(s, k, '[ruby-dev:39068]')
+ assert_equal(Encoding::UTF_8, k.encoding, '[ruby-dev:39068]')
+ end
+
+ def test_ascii_incomat_inspect
+ bug4081 = '[ruby-core:33283]'
+ [Encoding::UTF_16LE, Encoding::UTF_16BE,
+ Encoding::UTF_32LE, Encoding::UTF_32BE].each do |e|
+ assert_equal('"abc"', "abc".encode(e).inspect)
+ assert_equal('"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).inspect)
+ assert_equal('"ab\\"c"', "ab\"c".encode(e).inspect, bug4081)
+ end
+ begin
+ verbose, $VERBOSE = $VERBOSE, nil
+ ext = Encoding.default_external
+ Encoding.default_external = "us-ascii"
+ $VERBOSE = verbose
+ i = "abc\"\\".force_encoding("utf-8").inspect
+ ensure
+ $VERBOSE = nil
+ Encoding.default_external = ext
+ $VERBOSE = verbose
+ end
+ assert_equal('"abc\\"\\\\"', i, bug4081)
+ end
+
+ def test_dummy_inspect
+ assert_equal('"\e\x24\x42\x22\x4C\x22\x68\e\x28\x42"',
+ "\u{ffe2}\u{2235}".encode("cp50220").inspect)
+ end
+
+ def test_prepend
+ assert_equal(S("hello world!"), "world!".prepend("hello "))
+
+ foo = Object.new
+ def foo.to_str
+ "b"
+ end
+ assert_equal(S("ba"), "a".prepend(foo))
+
+ a = S("world")
+ b = S("hello ")
+ a.prepend(b)
+ assert_equal(S("hello world"), a)
+ assert_equal(S("hello "), b)
+ end
+
+ def u(str)
+ str.force_encoding(Encoding::UTF_8)
+ end
+
+ def test_byteslice
+ assert_equal("h", "hello".byteslice(0))
+ assert_equal(nil, "hello".byteslice(5))
+ assert_equal("o", "hello".byteslice(-1))
+ assert_equal(nil, "hello".byteslice(-6))
+
+ assert_equal("", "hello".byteslice(0, 0))
+ assert_equal("hello", "hello".byteslice(0, 6))
+ assert_equal("hello", "hello".byteslice(0, 6))
+ assert_equal("", "hello".byteslice(5, 1))
+ assert_equal("o", "hello".byteslice(-1, 6))
+ assert_equal(nil, "hello".byteslice(-6, 1))
+ assert_equal(nil, "hello".byteslice(0, -1))
+
+ assert_equal("h", "hello".byteslice(0..0))
+ assert_equal("", "hello".byteslice(5..0))
+ assert_equal("o", "hello".byteslice(4..5))
+ assert_equal(nil, "hello".byteslice(6..0))
+ assert_equal("", "hello".byteslice(-1..0))
+ assert_equal("llo", "hello".byteslice(-3..5))
+
+ assert_equal(u("\x81"), "\u3042".byteslice(1))
+ assert_equal(u("\x81\x82"), "\u3042".byteslice(1, 2))
+ assert_equal(u("\x81\x82"), "\u3042".byteslice(1..2))
+
+ assert_equal(u("\x82")+("\u3042"*9), ("\u3042"*10).byteslice(2, 28))
+
+ bug7954 = '[ruby-dev:47108]'
+ assert_equal(false, "\u3042".byteslice(0, 2).valid_encoding?, bug7954)
+ assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954)
+ end
+
+ def test_unknown_string_option
+ str = nil
+ assert_nothing_raised(SyntaxError) do
+ eval(%{
+ str = begin"hello"end
+ })
+ end
+ assert_equal "hello", str
+ end
+
+ def test_eq_tilde_can_be_overridden
+ assert_separately([], <<-RUBY)
+ class String
+ undef =~
+ def =~(str)
+ "foo"
+ end
+ end
+
+ assert_equal("foo", "" =~ //)
+ RUBY
+ end
+
+ class Bug9581 < String
+ def =~ re; :foo end
+ end
+
+ def test_regexp_match_subclass
+ s = Bug9581.new("abc")
+ r = /abc/
+ assert_equal(:foo, s =~ r)
+ assert_equal(:foo, s.send(:=~, r))
+ assert_equal(:foo, s.send(:=~, /abc/))
+ assert_equal(:foo, s =~ /abc/, "should not use optimized instruction")
+ end
+
+ def test_LSHIFT_neary_long_max
+ return unless @cls == String
+ assert_ruby_status([], <<-'end;', '[ruby-core:61886] [Bug #9709]', timeout: 20)
+ begin
+ a = "a" * 0x4000_0000
+ a << "a" * 0x1_0000
+ rescue NoMemoryError
+ end
+ end;
+ end if [0].pack("l!").bytesize < [nil].pack("p").bytesize
+ # enable only when string size range is smaller than memory space
+end
+
+class TestString2 < TestString
+ def initialize(*args)
+ super
+ @cls = S2
+ end
+end
diff --git a/jni/ruby/test/ruby/test_stringchar.rb b/jni/ruby/test/ruby/test_stringchar.rb
new file mode 100644
index 0000000..7f7342c
--- /dev/null
+++ b/jni/ruby/test/ruby/test_stringchar.rb
@@ -0,0 +1,181 @@
+require 'test/unit'
+
+class TestStringchar < Test::Unit::TestCase
+ def test_string
+ assert_equal("abcd", "abcd")
+ assert_match(/abcd/, "abcd")
+ assert_operator("abcd", :===, "abcd")
+ # compile time string concatenation
+ assert_equal("abcd", "ab" "cd")
+ assert_equal("22aacd44", "#{22}aa" "cd#{44}")
+ assert_equal("22aacd445566", "#{22}aa" "cd#{44}" "55" "#{66}")
+ assert_operator("abc", :!~, /^$/)
+ assert_operator("abc\n", :!~, /^$/)
+ assert_operator("abc", :!~, /^d*$/)
+ assert_equal(3, ("abc" =~ /d*$/))
+ assert("" =~ /^$/)
+ assert("\n" =~ /^$/)
+ assert("a\n\n" =~ /^$/)
+ assert("abcabc" =~ /.*a/); assert_equal("abca", $&)
+ assert("abcabc" =~ /.*c/); assert_equal("abcabc", $&)
+ assert("abcabc" =~ /.*?a/); assert_equal("a", $&)
+ assert("abcabc" =~ /.*?c/); assert_equal("abc", $&)
+ assert(/(.|\n)*?\n(b|\n)/ =~ "a\nb\n\n"); assert_equal("a\nb", $&)
+
+ assert(/^(ab+)+b/ =~ "ababb"); assert_equal("ababb", $&)
+ assert(/^(?:ab+)+b/ =~ "ababb"); assert_equal("ababb", $&)
+ assert(/^(ab+)+/ =~ "ababb"); assert_equal("ababb", $&)
+ assert(/^(?:ab+)+/ =~ "ababb"); assert_equal("ababb", $&)
+
+ assert(/(\s+\d+){2}/ =~ " 1 2"); assert_equal(" 1 2", $&)
+ assert(/(?:\s+\d+){2}/ =~ " 1 2"); assert_equal(" 1 2", $&)
+
+ x = <<END;
+ABCD
+ABCD
+END
+ x.gsub!(/((.|\n)*?)B((.|\n)*?)D/m ,'\1\3')
+ assert_equal("AC\nAC\n", x)
+
+ assert_match(/foo(?=(bar)|(baz))/, "foobar")
+ assert_match(/foo(?=(bar)|(baz))/, "foobaz")
+
+ $foo = "abc"
+ assert_equal("abc = abc", "#$foo = abc")
+ assert_equal("abc = abc", "#{$foo} = abc")
+
+ foo = "abc"
+ assert_equal("abc = abc", "#{foo} = abc")
+
+ assert_equal('-----', '-' * 5)
+ assert_equal('-', '-' * 1)
+ assert_equal('', '-' * 0)
+
+ foo = '-'
+ assert_equal('-----', foo * 5)
+ assert_equal('-', foo * 1)
+ assert_equal('', foo * 0)
+
+ x = "a.gif"
+ assert_equal("gif", x.sub(/.*\.([^\.]+)$/, '\1'))
+ assert_equal("b.gif", x.sub(/.*\.([^\.]+)$/, 'b.\1'))
+ assert_equal("", x.sub(/.*\.([^\.]+)$/, '\2'))
+ assert_equal("ab", x.sub(/.*\.([^\.]+)$/, 'a\2b'))
+ assert_equal("<a.gif>", x.sub(/.*\.([^\.]+)$/, '<\&>'))
+ end
+
+ def test_char
+ # character constants(assumes ASCII)
+ assert_equal(?a, "a"[0])
+ assert_equal(?a, ?a)
+ assert_equal("\1", ?\C-a)
+ assert_equal("\341", ?\M-a)
+ assert_equal("\201", ?\M-\C-a)
+ assert_equal(?A, "a".upcase![0])
+ assert_equal(?a, "A".downcase![0])
+ assert_equal("ABC", "abc".tr!("a-z", "A-Z"))
+ assert_equal("ABC", "aabbcccc".tr_s!("a-z", "A-Z"))
+ assert_equal("abc", "abcc".squeeze!("a-z"))
+ assert_equal("ad", "abcd".delete!("bc"))
+
+ x = "abcdef"
+ y = [ ?a, ?b, ?c, ?d, ?e, ?f ]
+ bad = false
+ x.each_byte {|i|
+ if i.chr != y.shift
+ bad = true
+ break
+ end
+ }
+ assert(!bad)
+
+ s = "a string"
+ s[0..s.size]="another string"
+ assert_equal("another string", s)
+
+ s = <<EOS
+#{
+[1,2,3].join(",")
+}
+EOS
+ assert_equal("1,2,3\n", s)
+ assert_equal(926381, "Just".to_i(36))
+ assert_equal(-23200231779, "-another".to_i(36))
+ assert_equal("ruby", 1299022.to_s(36))
+ assert_equal("-hacker", -1045307475.to_s(36))
+ assert_equal(265419172580680477752431643787347, "Just_another_Ruby_hacker".to_i(36))
+ assert_equal("-justanotherrubyhacker", -265419172580680477752431643787347.to_s(36))
+
+ a = []
+ (0..255).each {|n|
+ ch = [n].pack("C")
+ a.push ch if /a#{Regexp.quote ch}b/x =~ "ab"
+ }
+ assert_equal(0, a.size)
+ end
+
+ def test_bang
+ s = "aBc"
+ s.upcase
+ assert_equal("aBc", s)
+ s.upcase!
+ assert_equal("ABC", s)
+
+ s = "aBc"
+ s.downcase
+ assert_equal("aBc", s)
+ s.downcase!
+ assert_equal("abc", s)
+
+ s = "aBc"
+ s.swapcase
+ assert_equal("aBc", s)
+ s.swapcase!
+ assert_equal("AbC", s)
+
+ s = "aBc"
+ s.capitalize
+ assert_equal("aBc", s)
+ s.capitalize!
+ assert_equal("Abc", s)
+
+ s = "aBc"
+ s.tr("a-z", "A-Z")
+ assert_equal("aBc", s)
+ s.tr!("a-z", "A-Z")
+ assert_equal("ABC", s)
+
+ s = "aaBBcc"
+ s.tr_s("a-z", "A-Z")
+ assert_equal("aaBBcc", s)
+ s.tr_s!("a-z", "A-Z")
+ assert_equal("ABBC", s)
+
+ s = "aaBBcc"
+ s.squeeze("a-z")
+ assert_equal("aaBBcc", s)
+ s.squeeze!("a-z")
+ assert_equal("aBBc", s)
+
+ s = "aaBBcc"
+ s.delete("a-z")
+ assert_equal("aaBBcc", s)
+ s.delete!("a-z")
+ assert_equal("BB", s)
+ end
+
+ def test_dump
+ bug3996 = '[ruby-core:32935]'
+ Encoding.list.find_all {|enc| enc.ascii_compatible?}.each do |enc|
+ (0..256).map do |c|
+ begin
+ s = c.chr(enc)
+ rescue RangeError, ArgumentError
+ break
+ else
+ assert_not_match(/\0/, s.dump, bug3996)
+ end
+ end
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_struct.rb b/jni/ruby/test/ruby/test_struct.rb
new file mode 100644
index 0000000..df859f7
--- /dev/null
+++ b/jni/ruby/test/ruby/test_struct.rb
@@ -0,0 +1,374 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+require 'timeout'
+
+module TestStruct
+ def test_struct
+ struct_test = @Struct.new("Test", :foo, :bar)
+ assert_equal(@Struct::Test, struct_test)
+
+ test = struct_test.new(1, 2)
+ assert_equal(1, test.foo)
+ assert_equal(2, test.bar)
+ assert_equal(1, test[0])
+ assert_equal(2, test[1])
+
+ a, b = test.to_a
+ assert_equal(1, a)
+ assert_equal(2, b)
+
+ test[0] = 22
+ assert_equal(22, test.foo)
+
+ test.bar = 47
+ assert_equal(47, test.bar)
+ end
+
+ # [ruby-dev:26247] more than 10 struct members causes segmentation fault
+ def test_morethan10members
+ list = %w( a b c d e f g h i j k l m n o p )
+ until list.empty?
+ c = @Struct.new(* list.map {|ch| ch.intern }).new
+ list.each do |ch|
+ c.__send__(ch)
+ end
+ list.pop
+ end
+ end
+
+ def test_small_structs
+ names = [:a, :b, :c, :d]
+ 1.upto(4) {|n|
+ fields = names[0, n]
+ klass = @Struct.new(*fields)
+ o = klass.new(*(0...n).to_a)
+ fields.each_with_index {|name, i|
+ assert_equal(i, o[name])
+ }
+ o = klass.new(*(0...n).to_a.reverse)
+ fields.each_with_index {|name, i|
+ assert_equal(n-i-1, o[name])
+ }
+ }
+ end
+
+ def test_inherit
+ klass = @Struct.new(:a)
+ klass2 = Class.new(klass)
+ o = klass2.new(1)
+ assert_equal(1, o.a)
+ end
+
+ def test_members
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal([:a], klass.members)
+ assert_equal([:a], o.members)
+ end
+
+ def test_ref
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal(1, o[:a])
+ assert_raise(NameError) { o[:b] }
+ end
+
+ def test_set
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ o[:a] = 2
+ assert_equal(2, o[:a])
+ assert_raise(NameError) { o[:b] = 3 }
+ end
+
+ def test_struct_new
+ assert_raise(NameError) { @Struct.new("foo") }
+ assert_nothing_raised { @Struct.new("Foo") }
+ @Struct.instance_eval { remove_const(:Foo) }
+ assert_nothing_raised { @Struct.new(:a) { } }
+ assert_raise(RuntimeError) { @Struct.new(:a) { raise } }
+
+ assert_equal([:utime, :stime, :cutime, :cstime], Process.times.members)
+ end
+
+ def test_initialize
+ klass = @Struct.new(:a)
+ assert_raise(ArgumentError) { klass.new(1, 2) }
+ end
+
+ def test_each
+ klass = @Struct.new(:a, :b)
+ o = klass.new(1, 2)
+ assert_equal([1, 2], o.each.to_a)
+ end
+
+ def test_each_pair
+ klass = @Struct.new(:a, :b)
+ o = klass.new(1, 2)
+ assert_equal([[:a, 1], [:b, 2]], o.each_pair.to_a)
+ bug7382 = '[ruby-dev:46533]'
+ a = []
+ o.each_pair {|x| a << x}
+ assert_equal([[:a, 1], [:b, 2]], a, bug7382)
+ end
+
+ def test_inspect
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal("#<struct a=1>", o.inspect)
+ o.a = o
+ assert_match(/^#<struct a=#<struct #<.*?>:...>>$/, o.inspect)
+
+ @Struct.new("Foo", :a)
+ o = @Struct::Foo.new(1)
+ assert_equal("#<struct #@Struct::Foo a=1>", o.inspect)
+ @Struct.instance_eval { remove_const(:Foo) }
+
+ klass = @Struct.new(:a, :b)
+ o = klass.new(1, 2)
+ assert_equal("#<struct a=1, b=2>", o.inspect)
+
+ klass = @Struct.new(:@a)
+ o = klass.new(1)
+ assert_equal(1, o.__send__(:@a))
+ assert_equal("#<struct :@a=1>", o.inspect)
+ o.__send__(:"@a=", 2)
+ assert_equal(2, o.__send__(:@a))
+ assert_equal("#<struct :@a=2>", o.inspect)
+ o.__send__("@a=", 3)
+ assert_equal(3, o.__send__(:@a))
+ assert_equal("#<struct :@a=3>", o.inspect)
+
+ methods = klass.instance_methods(false)
+ assert_equal([:@a, :"@a="].inspect, methods.inspect, '[Bug #8756]')
+ assert_include(methods, :@a)
+ assert_include(methods, :"@a=")
+ end
+
+ def test_init_copy
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal(o, o.dup)
+ end
+
+ def test_aref
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal(1, o[0])
+ assert_raise(IndexError) { o[-2] }
+ assert_raise(IndexError) { o[1] }
+ assert_raise_with_message(NameError, /foo/) {o["foo"]}
+ assert_raise_with_message(NameError, /foo/) {o[:foo]}
+ end
+
+ def test_aset
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ o[0] = 2
+ assert_equal(2, o[:a])
+ assert_raise(IndexError) { o[-2] = 3 }
+ assert_raise(IndexError) { o[1] = 3 }
+ assert_raise_with_message(NameError, /foo/) {o["foo"] = 3}
+ assert_raise_with_message(NameError, /foo/) {o[:foo] = 3}
+ end
+
+ def test_values_at
+ klass = @Struct.new(:a, :b, :c, :d, :e, :f)
+ o = klass.new(1, 2, 3, 4, 5, 6)
+ assert_equal([2, 4, 6], o.values_at(1, 3, 5))
+ assert_equal([2, 3, 4, 3, 4, 5], o.values_at(1..3, 2...5))
+ end
+
+ def test_select
+ klass = @Struct.new(:a, :b, :c, :d, :e, :f)
+ o = klass.new(1, 2, 3, 4, 5, 6)
+ assert_equal([1, 3, 5], o.select {|v| v % 2 != 0 })
+ assert_raise(ArgumentError) { o.select(1) }
+ end
+
+ def test_big_struct
+ klass1 = @Struct.new(*('a'..'z').map(&:to_sym))
+ o = klass1.new
+ assert_nil o.z
+ assert_equal(:foo, o.z = :foo)
+ assert_equal(:foo, o.z)
+ assert_equal(:foo, o[25])
+ end
+
+ def test_overridden_aset
+ bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by []= method'
+
+ struct = Class.new(Struct.new(*(:a..:z), :result)) do
+ def []=(*args)
+ raise args.inspect
+ end
+ end
+
+ obj = struct.new
+ assert_nothing_raised(RuntimeError, bug10601) do
+ obj.result = 42
+ end
+ assert_equal(42, obj.result, bug10601)
+ end
+
+ def test_overridden_aref
+ bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by [] method'
+
+ struct = Class.new(Struct.new(*(:a..:z), :result)) do
+ def [](*args)
+ raise args.inspect
+ end
+ end
+
+ obj = struct.new
+ obj.result = 42
+ result = assert_nothing_raised(RuntimeError, bug10601) do
+ break obj.result
+ end
+ assert_equal(42, result, bug10601)
+ end
+
+ def test_equal
+ klass1 = @Struct.new(:a)
+ klass2 = @Struct.new(:a, :b)
+ o1 = klass1.new(1)
+ o2 = klass1.new(1)
+ o3 = klass2.new(1)
+ assert_equal(o1, o2)
+ assert_not_equal(o1, o3)
+ end
+
+ def test_hash
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_kind_of(Fixnum, o.hash)
+ end
+
+ def test_eql
+ klass1 = @Struct.new(:a)
+ klass2 = @Struct.new(:a, :b)
+ o1 = klass1.new(1)
+ o2 = klass1.new(1)
+ o3 = klass2.new(1)
+ assert_operator(o1, :eql?, o2)
+ assert_not_operator(o1, :eql?, o3)
+ end
+
+ def test_size
+ klass = @Struct.new(:a)
+ o = klass.new(1)
+ assert_equal(1, o.size)
+ end
+
+ def test_error
+ assert_raise(TypeError){
+ @Struct.new(0)
+ }
+ end
+
+ def test_redefinition_warning
+ @Struct.new("RedefinitionWarning")
+ e = EnvUtil.verbose_warning do
+ @Struct.new("RedefinitionWarning")
+ end
+ assert_match(/redefining constant #@Struct::RedefinitionWarning/, e)
+ end
+
+ def test_nonascii
+ struct_test = @Struct.new("R\u{e9}sum\u{e9}", :"r\u{e9}sum\u{e9}")
+ assert_equal(@Struct.const_get("R\u{e9}sum\u{e9}"), struct_test, '[ruby-core:24849]')
+ a = struct_test.new(42)
+ assert_equal("#<struct #@Struct::R\u{e9}sum\u{e9} r\u{e9}sum\u{e9}=42>", a.inspect, '[ruby-core:24849]')
+ e = EnvUtil.verbose_warning do
+ @Struct.new("R\u{e9}sum\u{e9}", :"r\u{e9}sum\u{e9}")
+ end
+ assert_nothing_raised(Encoding::CompatibilityError) do
+ assert_match(/redefining constant #@Struct::R\u{e9}sum\u{e9}/, e)
+ end
+ end
+
+ def test_junk
+ struct_test = @Struct.new("Foo", "a\000")
+ o = struct_test.new(1)
+ assert_equal(1, o.send("a\000"))
+ @Struct.instance_eval { remove_const(:Foo) }
+ end
+
+ def test_comparison_when_recursive
+ klass1 = @Struct.new(:a, :b, :c)
+
+ x = klass1.new(1, 2, nil); x.c = x
+ y = klass1.new(1, 2, nil); y.c = y
+ Timeout.timeout(1) {
+ assert_equal x, y
+ assert_operator x, :eql?, y
+ }
+
+ z = klass1.new(:something, :other, nil); z.c = z
+ Timeout.timeout(1) {
+ assert_not_equal x, z
+ assert_not_operator x, :eql?, z
+ }
+
+ x.c = y; y.c = x
+ Timeout.timeout(1) {
+ assert_equal x, y
+ assert_operator x, :eql?, y
+ }
+
+ x.c = z; z.c = x
+ Timeout.timeout(1) {
+ assert_not_equal x, z
+ assert_not_operator x, :eql?, z
+ }
+ end
+
+ def test_to_h
+ klass = @Struct.new(:a, :b, :c, :d, :e, :f)
+ o = klass.new(1, 2, 3, 4, 5, 6)
+ assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h)
+ end
+
+ def test_question_mark_in_member
+ klass = @Struct.new(:a, :b?)
+ x = Object.new
+ o = klass.new("test", x)
+ assert_same(x, o.b?)
+ o.send("b?=", 42)
+ assert_equal(42, o.b?)
+ end
+
+ def test_bang_mark_in_member
+ klass = @Struct.new(:a, :b!)
+ x = Object.new
+ o = klass.new("test", x)
+ assert_same(x, o.b!)
+ o.send("b!=", 42)
+ assert_equal(42, o.b!)
+ end
+
+ def test_setter_method_returns_value
+ klass = @Struct.new(:a)
+ x = klass.new
+ assert_equal "[Bug #9353]", x.send(:a=, "[Bug #9353]")
+ end
+
+ class TopStruct < Test::Unit::TestCase
+ include TestStruct
+
+ def initialize(*)
+ super
+ @Struct = Struct
+ end
+ end
+
+ class SubStruct < Test::Unit::TestCase
+ include TestStruct
+ SubStruct = Class.new(Struct)
+
+ def initialize(*)
+ super
+ @Struct = SubStruct
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_super.rb b/jni/ruby/test/ruby/test_super.rb
new file mode 100644
index 0000000..7d4048b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_super.rb
@@ -0,0 +1,528 @@
+require 'test/unit'
+
+class TestSuper < Test::Unit::TestCase
+ class Base
+ def single(a) a end
+ def double(a, b) [a,b] end
+ def array(*a) a end
+ def optional(a = 0) a end
+ def keyword(**a) a end
+ end
+ class Single1 < Base
+ def single(*) super end
+ end
+ class Single2 < Base
+ def single(a,*) super end
+ end
+ class Double1 < Base
+ def double(*) super end
+ end
+ class Double2 < Base
+ def double(a,*) super end
+ end
+ class Double3 < Base
+ def double(a,b,*) super end
+ end
+ class Array1 < Base
+ def array(*) super end
+ end
+ class Array2 < Base
+ def array(a,*) super end
+ end
+ class Array3 < Base
+ def array(a,b,*) super end
+ end
+ class Array4 < Base
+ def array(a,b,c,*) super end
+ end
+ class Optional1 < Base
+ def optional(a = 1) super end
+ end
+ class Optional2 < Base
+ def optional(a, b = 1) super end
+ end
+ class Optional3 < Base
+ def single(a = 1) super end
+ end
+ class Optional4 < Base
+ def array(a = 1, *) super end
+ end
+ class Optional5 < Base
+ def array(a = 1, b = 2, *) super end
+ end
+ class Keyword1 < Base
+ def keyword(foo: "keyword1") super end
+ end
+ class Keyword2 < Base
+ def keyword(foo: "keyword2")
+ foo = "changed1"
+ x = super
+ foo = "changed2"
+ y = super
+ [x, y]
+ end
+ end
+
+ def test_single1
+ assert_equal(1, Single1.new.single(1))
+ end
+ def test_single2
+ assert_equal(1, Single2.new.single(1))
+ end
+ def test_double1
+ assert_equal([1, 2], Double1.new.double(1, 2))
+ end
+ def test_double2
+ assert_equal([1, 2], Double2.new.double(1, 2))
+ end
+ def test_double3
+ assert_equal([1, 2], Double3.new.double(1, 2))
+ end
+ def test_array1
+ assert_equal([], Array1.new.array())
+ assert_equal([1], Array1.new.array(1))
+ end
+ def test_array2
+ assert_equal([1], Array2.new.array(1))
+ assert_equal([1,2], Array2.new.array(1, 2))
+ end
+ def test_array3
+ assert_equal([1,2], Array3.new.array(1, 2))
+ assert_equal([1,2,3], Array3.new.array(1, 2, 3))
+ end
+ def test_array4
+ assert_equal([1,2,3], Array4.new.array(1, 2, 3))
+ assert_equal([1,2,3,4], Array4.new.array(1, 2, 3, 4))
+ end
+ def test_optional1
+ assert_equal(9, Optional1.new.optional(9))
+ assert_equal(1, Optional1.new.optional)
+ end
+ def test_optional2
+ assert_raise(ArgumentError) do
+ # call Base#optional with 2 arguments; the 2nd arg is supplied
+ assert_equal(9, Optional2.new.optional(9))
+ end
+ assert_raise(ArgumentError) do
+ # call Base#optional with 2 arguments
+ assert_equal(9, Optional2.new.optional(9, 2))
+ end
+ end
+ def test_optional3
+ assert_equal(9, Optional3.new.single(9))
+ # call Base#single with 1 argument; the arg is supplied
+ assert_equal(1, Optional3.new.single)
+ end
+ def test_optional4
+ assert_equal([1], Optional4.new.array)
+ assert_equal([9], Optional4.new.array(9))
+ assert_equal([9, 8], Optional4.new.array(9, 8))
+ end
+ def test_optional5
+ assert_equal([1, 2], Optional5.new.array)
+ assert_equal([9, 2], Optional5.new.array(9))
+ assert_equal([9, 8], Optional5.new.array(9, 8))
+ assert_equal([9, 8, 7], Optional5.new.array(9, 8, 7))
+ end
+ def test_keyword1
+ assert_equal({foo: "keyword1"}, Keyword1.new.keyword)
+ bug8008 = '[ruby-core:53114] [Bug #8008]'
+ assert_equal({foo: bug8008}, Keyword1.new.keyword(foo: bug8008))
+ end
+ def test_keyword2
+ assert_equal([{foo: "changed1"}, {foo: "changed2"}], Keyword2.new.keyword)
+ end
+
+ class A
+ def tt(aa)
+ "A#tt"
+ end
+
+ def uu(a)
+ class << self
+ define_method(:tt) do |sym|
+ super(sym)
+ end
+ end
+ end
+ end
+
+ def test_define_method
+ a = A.new
+ a.uu(12)
+ assert_equal("A#tt", a.tt(12), "[ruby-core:3856]")
+ assert_raise_with_message(RuntimeError, /implicit argument passing of super from method defined by define_method/, "[ruby-core:24244]") {
+ lambda {
+ Class.new {
+ define_method(:a) {super}
+ }.new.a
+ }.call
+ }
+ end
+
+ class SubSeq
+ def initialize
+ @first=11
+ @first or fail
+ end
+
+ def subseq
+ @first or fail
+ end
+ end
+
+ class Indexed
+ def subseq
+ SubSeq.new
+ end
+ end
+
+ Overlaid = proc do
+ class << self
+ def subseq
+ super.instance_eval(& Overlaid)
+ end
+ end
+ end
+
+ def test_overlaid
+ assert_nothing_raised('[ruby-dev:40959]') do
+ overlaid = proc do |obj|
+ def obj.reverse
+ super
+ end
+ end
+ overlaid.call(str = "123")
+ overlaid.call([1,2,3])
+ str.reverse
+ end
+
+ assert_nothing_raised('[ruby-core:27230]') do
+ mid=Indexed.new
+ mid.instance_eval(&Overlaid)
+ mid.subseq
+ mid.subseq
+ end
+ end
+
+ module DoubleInclude
+ class Base
+ def foo
+ [:Base]
+ end
+ end
+
+ module Override
+ def foo
+ super << :Override
+ end
+ end
+
+ class A < Base
+ end
+
+ class B < A
+ end
+
+ B.send(:include, Override)
+ A.send(:include, Override)
+ end
+
+ # [Bug #3351]
+ def test_double_include
+ assert_equal([:Base, :Override], DoubleInclude::B.new.foo)
+ # should be changed as follows?
+ # assert_equal([:Base, :Override, :Override], DoubleInclude::B.new.foo)
+ end
+
+ module DoubleInclude2
+ class Base
+ def foo
+ [:Base]
+ end
+ end
+
+ module Override
+ def foo
+ super << :Override
+ end
+ end
+
+ class A < Base
+ def foo
+ super << :A
+ end
+ end
+
+ class B < A
+ def foo
+ super << :B
+ end
+ end
+
+ B.send(:include, Override)
+ A.send(:include, Override)
+ end
+
+ def test_double_include2
+ assert_equal([:Base, :Override, :A, :Override, :B],
+ DoubleInclude2::B.new.foo)
+ end
+
+ def test_super_in_instance_eval
+ super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
+ def foo
+ return [:super, self]
+ end
+ }
+ sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) {
+ def foo
+ x = Object.new
+ x.instance_eval do
+ super()
+ end
+ end
+ }
+ obj = sub_class.new
+ assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do
+ obj.foo
+ end
+ end
+
+ def test_super_in_instance_eval_with_define_method
+ super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
+ def foo
+ return [:super, self]
+ end
+ }
+ sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) {
+ define_method(:foo) do
+ x = Object.new
+ x.instance_eval do
+ super()
+ end
+ end
+ }
+ obj = sub_class.new
+ assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do
+ obj.foo
+ end
+ end
+
+ def test_super_in_orphan_block
+ super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
+ def foo
+ return [:super, self]
+ end
+ }
+ sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) {
+ def foo
+ lambda { super() }
+ end
+ }
+ obj = sub_class.new
+ assert_equal([:super, obj], obj.foo.call)
+ end
+
+ def test_super_in_orphan_block_with_instance_eval
+ super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
+ def foo
+ return [:super, self]
+ end
+ }
+ sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) {
+ def foo
+ x = Object.new
+ x.instance_eval do
+ lambda { super() }
+ end
+ end
+ }
+ obj = sub_class.new
+ assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do
+ obj.foo.call
+ end
+ end
+
+ def test_yielding_super
+ a = Class.new { def yielder; yield; end }
+ x = Class.new { define_singleton_method(:hello) { 'hi' } }
+ y = Class.new(x) {
+ define_singleton_method(:hello) {
+ m = a.new
+ m.yielder { super() }
+ }
+ }
+ assert_equal 'hi', y.hello
+ end
+
+ def test_super_in_thread
+ hoge = Class.new {
+ def bar; 'hoge'; end
+ }
+ foo = Class.new(hoge) {
+ def bar; Thread.new { super }.join.value; end
+ }
+
+ assert_equal 'hoge', foo.new.bar
+ end
+
+ def assert_super_in_block(type)
+ bug7064 = '[ruby-core:47680]'
+ assert_normal_exit "#{type} {super}", bug7064
+ end
+
+ def test_super_in_at_exit
+ assert_super_in_block("at_exit")
+ end
+ def test_super_in_END
+ assert_super_in_block("END")
+ end
+
+ def test_super_in_BEGIN
+ assert_super_in_block("BEGIN")
+ end
+
+ class X
+ def foo(*args)
+ args
+ end
+ end
+
+ class Y < X
+ define_method(:foo) do |*args|
+ super(*args)
+ end
+ end
+
+ def test_super_splat
+ # [ruby-list:49575]
+ y = Y.new
+ assert_equal([1, 2], y.foo(1, 2))
+ assert_equal([1, false], y.foo(1, false))
+ assert_equal([1, 2, 3, 4, 5], y.foo(1, 2, 3, 4, 5))
+ assert_equal([false, true], y.foo(false, true))
+ assert_equal([false, false], y.foo(false, false))
+ assert_equal([1, 2, 3, false, 5], y.foo(1, 2, 3, false, 5))
+ end
+
+ def test_missing_super_in_method_module
+ bug9315 = '[ruby-core:59358] [Bug #9315]'
+ a = Module.new do
+ def foo
+ super
+ end
+ end
+ b = Class.new do
+ include a
+ end
+ assert_raise(NoMethodError, bug9315) do
+ b.new.method(:foo).call
+ end
+ end
+
+ def test_module_super_in_method_module
+ bug9315 = '[ruby-core:59589] [Bug #9315]'
+ a = Module.new do
+ def foo
+ super
+ end
+ end
+ c = Class.new do
+ def foo
+ :ok
+ end
+ end
+ o = c.new.extend(a)
+ assert_nothing_raised(NoMethodError, bug9315) do
+ assert_equal(:ok, o.method(:foo).call, bug9315)
+ end
+ end
+
+ def test_missing_super_in_module_unbound_method
+ bug9377 = '[ruby-core:59619] [Bug #9377]'
+
+ a = Module.new do
+ def foo; super end
+ end
+
+ m = a.instance_method(:foo).bind(Object.new)
+ assert_raise(NoMethodError, bug9377) do
+ m.call
+ end
+ end
+
+ def test_super_in_module_unbound_method
+ bug9721 = '[ruby-core:61936] [Bug #9721]'
+
+ a = Module.new do
+ def foo(result)
+ result << "A"
+ end
+ end
+
+ b = Module.new do
+ def foo(result)
+ result << "B"
+ super
+ end
+ end
+
+ um = b.instance_method(:foo)
+
+ m = um.bind(Object.new.extend(a))
+ result = []
+ assert_nothing_raised(NoMethodError, bug9721) do
+ m.call(result)
+ end
+ assert_equal(%w[B A], result, bug9721)
+
+ bug9740 = '[ruby-core:62017] [Bug #9740]'
+
+ b.module_eval do
+ define_method(:foo) do |result|
+ um.bind(self).call(result)
+ end
+ end
+
+ result.clear
+ o = Object.new.extend(a).extend(b)
+ assert_nothing_raised(NoMethodError, SystemStackError, bug9740) do
+ o.foo(result)
+ end
+ assert_equal(%w[B A], result, bug9721)
+ end
+
+ def test_from_eval
+ bug10263 = '[ruby-core:65122] [Bug #10263a]'
+ a = Class.new do
+ def foo
+ "A"
+ end
+ end
+ b = Class.new(a) do
+ def foo
+ binding.eval("super")
+ end
+ end
+ assert_equal("A", b.new.foo, bug10263)
+ end
+
+ def test_super_with_block
+ a = Class.new do
+ def foo
+ yield
+ end
+ end
+
+ b = Class.new(a) do
+ def foo
+ super{
+ "b"
+ }
+ end
+ end
+
+ assert_equal "b", b.new.foo{"c"}
+ end
+end
diff --git a/jni/ruby/test/ruby/test_symbol.rb b/jni/ruby/test/ruby/test_symbol.rb
new file mode 100644
index 0000000..ee29cd5
--- /dev/null
+++ b/jni/ruby/test/ruby/test_symbol.rb
@@ -0,0 +1,289 @@
+require 'test/unit'
+
+class TestSymbol < Test::Unit::TestCase
+ # [ruby-core:3573]
+
+ def assert_eval_inspected(sym, valid = true)
+ n = sym.inspect
+ if valid
+ bug5136 = '[ruby-dev:44314]'
+ assert_not_match(/\A:"/, n, bug5136)
+ end
+ assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(n))}
+ end
+
+ def test_inspect_invalid
+ # 2) Symbol#inspect sometimes returns invalid symbol representations:
+ assert_eval_inspected(:"!")
+ assert_eval_inspected(:"=", false)
+ assert_eval_inspected(:"0", false)
+ assert_eval_inspected(:"$1")
+ assert_eval_inspected(:"@1", false)
+ assert_eval_inspected(:"@@1", false)
+ assert_eval_inspected(:"@", false)
+ assert_eval_inspected(:"@@", false)
+ end
+
+ def assert_inspect_evaled(n)
+ assert_nothing_raised(SyntaxError) {assert_equal(n, eval(n).inspect)}
+ end
+
+ def test_inspect_suboptimal
+ # 3) Symbol#inspect sometimes returns suboptimal symbol representations:
+ assert_inspect_evaled(':foo')
+ assert_inspect_evaled(':foo!')
+ assert_inspect_evaled(':bar?')
+ assert_inspect_evaled(":<<")
+ assert_inspect_evaled(':>>')
+ assert_inspect_evaled(':<=')
+ assert_inspect_evaled(':>=')
+ assert_inspect_evaled(':=~')
+ assert_inspect_evaled(':==')
+ assert_inspect_evaled(':===')
+ assert_raise(SyntaxError) {eval ':='}
+ assert_inspect_evaled(':*')
+ assert_inspect_evaled(':**')
+ assert_raise(SyntaxError) {eval ':***'}
+ assert_inspect_evaled(':+')
+ assert_inspect_evaled(':-')
+ assert_inspect_evaled(':+@')
+ assert_inspect_evaled(':-@')
+ assert_inspect_evaled(':|')
+ assert_inspect_evaled(':^')
+ assert_inspect_evaled(':&')
+ assert_inspect_evaled(':/')
+ assert_inspect_evaled(':%')
+ assert_inspect_evaled(':~')
+ assert_inspect_evaled(':`')
+ assert_inspect_evaled(':[]')
+ assert_inspect_evaled(':[]=')
+ assert_raise(SyntaxError) {eval ':||'}
+ assert_raise(SyntaxError) {eval ':&&'}
+ assert_raise(SyntaxError) {eval ':['}
+ end
+
+ def test_inspect_dollar
+ # 4) :$- always treats next character literally:
+ assert_raise(SyntaxError) {eval ':$-'}
+ assert_raise(SyntaxError) {eval ":$-\n"}
+ assert_raise(SyntaxError) {eval ":$- "}
+ assert_raise(SyntaxError) {eval ":$-#"}
+ assert_raise(SyntaxError) {eval ':$-('}
+ end
+
+ def test_inspect_number
+ # 5) Inconsistency between :$0 and :$1? The first one is valid, but the
+ # latter isn't.
+ assert_inspect_evaled(':$0')
+ assert_inspect_evaled(':$1')
+ end
+
+ def test_inspect
+ valid = %W{$a @a @@a < << <= <=> > >> >= =~ == === * ** + +@ - -@
+ | ^ & / % ~ \` [] []= ! != !~ a a? a! a= A A? A! A=}
+ valid.each do |sym|
+ assert_equal(':' + sym, sym.intern.inspect)
+ end
+
+ invalid = %w{$a? $a! $a= @a? @a! @a= @@a? @@a! @@a= =}
+ invalid.each do |sym|
+ assert_equal(':"' + sym + '"', sym.intern.inspect)
+ end
+ end
+
+ def test_to_proc
+ assert_equal %w(1 2 3), (1..3).map(&:to_s)
+ [
+ [],
+ [1],
+ [1, 2],
+ [1, [2, 3]],
+ ].each do |ary|
+ ary_id = ary.object_id
+ assert_equal ary_id, :object_id.to_proc.call(ary)
+ ary_ids = ary.collect{|x| x.object_id }
+ assert_equal ary_ids, ary.collect(&:object_id)
+ end
+ end
+
+ def test_call
+ o = Object.new
+ def o.foo(x, y); x + y; end
+
+ assert_equal(3, :foo.to_proc.call(o, 1, 2))
+ assert_raise(ArgumentError) { :foo.to_proc.call }
+ end
+
+ def m_block_given?
+ block_given?
+ end
+
+ def m2_block_given?(m = nil)
+ if m
+ [block_given?, m.call(self)]
+ else
+ block_given?
+ end
+ end
+
+ def test_block_given_to_proc
+ bug8531 = '[Bug #8531]'
+ m = :m_block_given?.to_proc
+ assert(!m.call(self), "#{bug8531} without block")
+ assert(m.call(self) {}, "#{bug8531} with block")
+ assert(!m.call(self), "#{bug8531} without block second")
+ end
+
+ def test_block_persist_between_calls
+ bug8531 = '[Bug #8531]'
+ m2 = :m2_block_given?.to_proc
+ assert_equal([true, false], m2.call(self, m2) {}, "#{bug8531} nested with block")
+ assert_equal([false, false], m2.call(self, m2), "#{bug8531} nested without block")
+ end
+
+ def test_succ
+ assert_equal(:fop, :foo.succ)
+ end
+
+ def test_cmp
+ assert_equal(0, :FoO <=> :FoO)
+ assert_equal(-1, :FoO <=> :fOO)
+ assert_equal(1, :fOO <=> :FoO)
+ assert_nil(:foo <=> "foo")
+ end
+
+ def test_casecmp
+ assert_equal(0, :FoO.casecmp(:fOO))
+ assert_equal(1, :FoO.casecmp(:BaR))
+ assert_equal(-1, :baR.casecmp(:FoO))
+ assert_nil(:foo.casecmp("foo"))
+ end
+
+ def test_length
+ assert_equal(3, :FoO.length)
+ assert_equal(3, :FoO.size)
+ end
+
+ def test_empty
+ assert_equal(false, :FoO.empty?)
+ assert_equal(true, :"".empty?)
+ end
+
+ def test_case
+ assert_equal(:FOO, :FoO.upcase)
+ assert_equal(:foo, :FoO.downcase)
+ assert_equal(:Foo, :foo.capitalize)
+ assert_equal(:fOo, :FoO.swapcase)
+ end
+
+ def test_symbol_poped
+ assert_nothing_raised { eval('a = 1; :"#{ a }"; 1') }
+ end
+
+ def test_ascii_incomat_inspect
+ [Encoding::UTF_16LE, Encoding::UTF_16BE,
+ Encoding::UTF_32LE, Encoding::UTF_32BE].each do |e|
+ assert_equal(':"abc"', "abc".encode(e).to_sym.inspect)
+ assert_equal(':"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).to_sym.inspect)
+ end
+ end
+
+ def test_symbol_encoding
+ assert_equal(Encoding::US_ASCII, "$-A".force_encoding("iso-8859-15").intern.encoding)
+ assert_equal(Encoding::US_ASCII, "foobar~!".force_encoding("iso-8859-15").intern.encoding)
+ assert_equal(Encoding::UTF_8, "\u{2192}".intern.encoding)
+ assert_raise(EncodingError) {"\xb0a".force_encoding("utf-8").intern}
+ end
+
+ def test_singleton_method
+ assert_raise(TypeError) { a = :foo; def a.foo; end }
+ end
+
+ SymbolsForEval = [
+ :foo,
+ "dynsym_#{Random.rand(10000)}_#{Time.now}".to_sym
+ ]
+
+ def test_instance_eval
+ bug11086 = '[ruby-core:68961] [Bug #11086]'
+ SymbolsForEval.each do |sym|
+ assert_nothing_raised(TypeError, sym, bug11086) {
+ sym.instance_eval {}
+ }
+ assert_raise(TypeError, sym, bug11086) {
+ sym.instance_eval {def foo; end}
+ }
+ end
+ end
+
+ def test_instance_exec
+ bug11086 = '[ruby-core:68961] [Bug #11086]'
+ SymbolsForEval.each do |sym|
+ assert_nothing_raised(TypeError, sym, bug11086) {
+ sym.instance_exec {}
+ }
+ assert_raise(TypeError, sym, bug11086) {
+ sym.instance_exec {def foo; end}
+ }
+ end
+ end
+
+ def test_frozen_symbol
+ assert_equal(true, :foo.frozen?)
+ assert_equal(true, :each.frozen?)
+ assert_equal(true, :+.frozen?)
+ assert_equal(true, "foo#{Time.now.to_i}".to_sym.frozen?)
+ assert_equal(true, :foo.to_sym.frozen?)
+ end
+
+ def test_symbol_gc_1
+ assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;".".intern]',
+ '',
+ child_env: '--disable-gems')
+ assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;:"."]',
+ '',
+ child_env: '--disable-gems')
+ assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;%i"."]',
+ '',
+ child_env: '--disable-gems')
+ assert_normal_exit('tap{".".intern};GC.start(immediate_sweep:false);' +
+ 'eval %[syms=Symbol.all_symbols;GC.start;syms.each(&:to_sym)]',
+ '',
+ child_env: '--disable-gems')
+ end
+
+ def test_dynamic_attrset_id
+ bug10259 = '[ruby-dev:48559] [Bug #10259]'
+ class << (obj = Object.new)
+ attr_writer :unagi
+ end
+ assert_nothing_raised(NoMethodError, bug10259) {obj.send("unagi=".intern, 1)}
+ end
+
+ def test_symbol_fstr_leak
+ bug10686 = '[ruby-core:67268] [Bug #10686]'
+ x = 0
+ assert_no_memory_leak([], '', <<-"end;", bug10686, limit: 1.65)
+ 200_000.times { |i| i.to_s.to_sym }
+ end;
+ end
+
+ def test_hash_redefinition
+ assert_separately([], <<-'end;')
+ bug11035 = '[ruby-core:68767] [Bug #11035]'
+ class Symbol
+ def hash
+ raise
+ end
+ end
+
+ h = {}
+ assert_nothing_raised(RuntimeError, bug11035) {
+ h[:foo] = 1
+ }
+ assert_nothing_raised(RuntimeError, bug11035) {
+ h['bar'.to_sym] = 2
+ }
+ end;
+ end
+end
diff --git a/jni/ruby/test/ruby/test_syntax.rb b/jni/ruby/test/ruby/test_syntax.rb
new file mode 100644
index 0000000..8df641d
--- /dev/null
+++ b/jni/ruby/test/ruby/test_syntax.rb
@@ -0,0 +1,622 @@
+require 'test/unit'
+
+class TestSyntax < Test::Unit::TestCase
+ def assert_syntax_files(test)
+ srcdir = File.expand_path("../../..", __FILE__)
+ srcdir = File.join(srcdir, test)
+ assert_separately(%W[--disable-gem - #{srcdir}],
+ __FILE__, __LINE__, <<-'eom', timeout: Float::INFINITY)
+ dir = ARGV.shift
+ for script in Dir["#{dir}/**/*.rb"].sort
+ assert_valid_syntax(IO::read(script), script)
+ end
+ eom
+ end
+
+ def test_syntax_lib; assert_syntax_files("lib"); end
+ def test_syntax_sample; assert_syntax_files("sample"); end
+ def test_syntax_ext; assert_syntax_files("ext"); end
+ def test_syntax_test; assert_syntax_files("test"); end
+
+ def test_defined_empty_argument
+ bug8220 = '[ruby-core:53999] [Bug #8220]'
+ assert_ruby_status(%w[--disable-gem], 'puts defined? ()', bug8220)
+ end
+
+ def test_must_ascii_compatible
+ require 'tempfile'
+ f = Tempfile.new("must_ac_")
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ make_tmpsrc(f, "# -*- coding: #{enc.name} -*-")
+ assert_nothing_raised(ArgumentError, enc.name) {load(f.path)}
+ end
+ Encoding.list.each do |enc|
+ next if enc.ascii_compatible?
+ make_tmpsrc(f, "# -*- coding: #{enc.name} -*-")
+ assert_raise(ArgumentError, enc.name) {load(f.path)}
+ end
+ ensure
+ f.close! if f
+ end
+
+ def test_script_lines
+ require 'tempfile'
+ f = Tempfile.new("bug4361_")
+ bug4361 = '[ruby-dev:43168]'
+ with_script_lines do |debug_lines|
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ make_tmpsrc(f, "# -*- coding: #{enc.name} -*-\n#----------------")
+ load(f.path)
+ assert_equal([f.path], debug_lines.keys)
+ assert_equal([enc, enc], debug_lines[f.path].map(&:encoding), bug4361)
+ end
+ end
+ ensure
+ f.close! if f
+ end
+
+ def test_newline_in_block_parameters
+ bug = '[ruby-dev:45292]'
+ ["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params|
+ params = ["|", *params, "|"].join("\n")
+ assert_valid_syntax("1.times{#{params}}", __FILE__, "#{bug} #{params.inspect}")
+ end
+ end
+
+ tap do |_,
+ bug6115 = '[ruby-dev:45308]',
+ blockcall = '["elem"].each_with_object [] do end',
+ methods = [['map', 'no'], ['inject([])', 'with']],
+ blocks = [['do end', 'do'], ['{}', 'brace']],
+ *|
+ [%w'. dot', %w':: colon'].product(methods, blocks) do |(c, n1), (m, n2), (b, n3)|
+ m = m.tr_s('()', ' ').strip if n2 == 'do'
+ name = "test_#{n3}_block_after_blockcall_#{n1}_#{n2}_arg"
+ code = "#{blockcall}#{c}#{m} #{b}"
+ define_method(name) {assert_valid_syntax(code, bug6115)}
+ end
+ end
+
+ def test_do_block_in_cmdarg
+ bug9726 = '[ruby-core:61950] [Bug #9726]'
+ assert_valid_syntax("tap (proc do end)", __FILE__, bug9726)
+ end
+
+ def test_keyword_rest
+ bug5989 = '[ruby-core:42455]'
+ assert_valid_syntax("def kwrest_test(**a) a; end", __FILE__, bug5989)
+ assert_valid_syntax("def kwrest_test2(**a, &b) end", __FILE__, bug5989)
+ o = Object.new
+ def o.kw(**a) a end
+ assert_equal({}, o.kw, bug5989)
+ assert_equal({foo: 1}, o.kw(foo: 1), bug5989)
+ assert_equal({foo: 1, bar: 2}, o.kw(foo: 1, bar: 2), bug5989)
+ EnvUtil.under_gc_stress do
+ eval("def o.m(k: 0) k end")
+ end
+ assert_equal(42, o.m(k: 42), '[ruby-core:45744]')
+ bug7922 = '[ruby-core:52744] [Bug #7922]'
+ def o.bug7922(**) end
+ assert_nothing_raised(ArgumentError, bug7922) {o.bug7922(foo: 42)}
+ end
+
+ def test_keyword_splat
+ assert_valid_syntax("foo(**h)", __FILE__)
+ o = Object.new
+ def o.kw(k1: 1, k2: 2) [k1, k2] end
+ h = {k1: 11, k2: 12}
+ assert_equal([11, 12], o.kw(**h))
+ assert_equal([11, 12], o.kw(k2: 22, **h))
+ assert_equal([11, 22], o.kw(**h, **{k2: 22}))
+ assert_equal([11, 12], o.kw(**{k2: 22}, **h))
+
+ bug10315 = '[ruby-core:65368] [Bug #10315]'
+ assert_equal([23, 2], o.kw(**{k1: 22}, **{k1: 23}), bug10315)
+
+ h = {k3: 31}
+ assert_raise(ArgumentError) {o.kw(**h)}
+ h = {"k1"=>11, k2: 12}
+ assert_raise(TypeError) {o.kw(**h)}
+
+ bug10315 = '[ruby-core:65625] [Bug #10315]'
+ a = []
+ def a.add(x) push(x); x; end
+ def a.f(k:) k; end
+ a.clear
+ r = nil
+ assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), k: a.add(2))")}
+ assert_equal(2, r)
+ assert_equal([1, 2], a, bug10315)
+ a.clear
+ r = nil
+ assert_warn(/duplicated/) {r = eval("a.f({k: a.add(1), k: a.add(2)})")}
+ assert_equal(2, r)
+ assert_equal([1, 2], a, bug10315)
+ end
+
+ def test_keyword_empty_splat
+ assert_separately([], <<-'end;')
+ bug10719 = '[ruby-core:67446] [Bug #10719]'
+ assert_valid_syntax("foo(a: 1, **{})", bug10719)
+ end;
+ end
+
+ def test_keyword_self_reference
+ bug9593 = '[ruby-core:61299] [Bug #9593]'
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var: defined?(var)) var end")
+ end
+ assert_equal(42, o.foo(var: 42))
+ assert_equal("local-variable", o.foo, bug9593)
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var: var) var end")
+ end
+ assert_nil(o.foo, bug9593)
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var: bar(var)) var end")
+ end
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var: bar {var}) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("def foo(var: bar {|var| var}) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("def foo(var: def bar(var) var; end) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("proc {|var: 1| var}")
+ end
+ end
+
+ def test_optional_self_reference
+ bug9593 = '[ruby-core:61299] [Bug #9593]'
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = defined?(var)) var end")
+ end
+ assert_equal(42, o.foo(42))
+ assert_equal("local-variable", o.foo, bug9593)
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = var) var end")
+ end
+ assert_nil(o.foo, bug9593)
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = bar(var)) var end")
+ end
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = bar {var}) var end")
+ end
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = (def bar;end; var)) var end")
+ end
+
+ o = Object.new
+ assert_warn(/circular argument reference - var/) do
+ o.instance_eval("def foo(var = (def self.bar;end; var)) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("def foo(var = bar {|var| var}) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("def foo(var = def bar(var) var; end) var end")
+ end
+
+ o = Object.new
+ assert_warn("") do
+ o.instance_eval("proc {|var = 1| var}")
+ end
+ end
+
+ def test_warn_grouped_expression
+ bug5214 = '[ruby-core:39050]'
+ assert_warning("", bug5214) do
+ assert_valid_syntax("foo \\\n(\n true)", "test", verbose: true)
+ end
+ end
+
+ def test_warn_unreachable
+ assert_warning("test:3: warning: statement not reached\n") do
+ code = "loop do\n" "break\n" "foo\n" "end"
+ assert_valid_syntax(code, "test", verbose: true)
+ end
+ end
+
+ def test_warn_balanced
+ warning = <<WARN
+test:1: warning: `%s' after local variable or literal is interpreted as binary operator
+test:1: warning: even though it seems like %s
+WARN
+ [
+ [:**, "argument prefix"],
+ [:*, "argument prefix"],
+ [:<<, "here document"],
+ [:&, "argument prefix"],
+ [:+, "unary operator"],
+ [:-, "unary operator"],
+ [:/, "regexp literal"],
+ [:%, "string literal"],
+ ].each do |op, syn|
+ assert_warning(warning % [op, syn]) do
+ assert_valid_syntax("puts 1 #{op}0", "test", verbose: true)
+ end
+ end
+ end
+
+ def test_cmd_symbol_after_keyword
+ bug6347 = '[ruby-dev:45563]'
+ assert_not_label(:foo, 'if true then not_label:foo end', bug6347)
+ assert_not_label(:foo, 'if false; else not_label:foo end', bug6347)
+ assert_not_label(:foo, 'begin not_label:foo end', bug6347)
+ assert_not_label(:foo, 'begin ensure not_label:foo end', bug6347)
+ end
+
+ def test_cmd_symbol_in_string
+ bug6347 = '[ruby-dev:45563]'
+ assert_not_label(:foo, '"#{not_label:foo}"', bug6347)
+ end
+
+ def test_cmd_symbol_singleton_class
+ bug6347 = '[ruby-dev:45563]'
+ @not_label = self
+ assert_not_label(:foo, 'class << not_label:foo; end', bug6347)
+ end
+
+ def test_cmd_symbol_superclass
+ bug6347 = '[ruby-dev:45563]'
+ @not_label = Object
+ assert_not_label(:foo, 'class Foo < not_label:foo; end', bug6347)
+ end
+
+ def test_duplicated_arg
+ assert_syntax_error("def foo(a, a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_, _) end }
+ end
+
+ def test_duplicated_rest
+ assert_syntax_error("def foo(a, *a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_, *_) end }
+ end
+
+ def test_duplicated_opt
+ assert_syntax_error("def foo(a, a=1) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_, _=1) end }
+ end
+
+ def test_duplicated_opt_rest
+ assert_syntax_error("def foo(a=1, *a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_=1, *_) end }
+ end
+
+ def test_duplicated_rest_opt
+ assert_syntax_error("def foo(*a, a=1) end", /duplicated argument name/)
+ end
+
+ def test_duplicated_rest_post
+ assert_syntax_error("def foo(*a, a) end", /duplicated argument name/)
+ end
+
+ def test_duplicated_opt_post
+ assert_syntax_error("def foo(a=1, a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_=1, _) end }
+ end
+
+ def test_duplicated_kw
+ assert_syntax_error("def foo(a, a: 1) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_, _: 1) end }
+ end
+
+ def test_duplicated_rest_kw
+ assert_syntax_error("def foo(*a, a: 1) end", /duplicated argument name/)
+ assert_nothing_raised {def foo(*_, _: 1) end}
+ end
+
+ def test_duplicated_opt_kw
+ assert_syntax_error("def foo(a=1, a: 1) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_=1, _: 1) end }
+ end
+
+ def test_duplicated_kw_kwrest
+ assert_syntax_error("def foo(a: 1, **a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_: 1, **_) end }
+ end
+
+ def test_duplicated_rest_kwrest
+ assert_syntax_error("def foo(*a, **a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(*_, **_) end }
+ end
+
+ def test_duplicated_opt_kwrest
+ assert_syntax_error("def foo(a=1, **a) end", /duplicated argument name/)
+ assert_nothing_raised { def foo(_=1, **_) end }
+ end
+
+ def test_duplicated_when
+ w = 'warning: duplicated when clause is ignored'
+ assert_warning(/3: #{w}.+4: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ eval %q{
+ case 1
+ when 1, 1
+ when 1, 1
+ when 1, 1
+ end
+ }
+ }
+ assert_warning(/#{w}/){#/3: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ a = 1
+ eval %q{
+ case 1
+ when 1, 1
+ when 1, a
+ when 1, 1
+ end
+ }
+ }
+ end
+
+ def test_invalid_next
+ assert_syntax_error("def m; next; end", /Invalid next/)
+ end
+
+ def test_lambda_with_space
+ feature6390 = '[ruby-dev:45605]'
+ assert_valid_syntax("-> (x, y) {}", __FILE__, feature6390)
+ end
+
+ def test_do_block_in_cmdarg_begin
+ bug6419 = '[ruby-dev:45631]'
+ assert_valid_syntax("p begin 1.times do 1 end end", __FILE__, bug6419)
+ end
+
+ def test_do_block_in_call_args
+ bug9308 = '[ruby-core:59342] [Bug #9308]'
+ assert_valid_syntax("bar def foo; self.each do end end", bug9308)
+ end
+
+ def test_do_block_in_lambda
+ bug11107 = '[ruby-core:69017] [Bug #11107]'
+ assert_valid_syntax('p ->() do a() do end end', bug11107)
+ end
+
+ def test_do_block_after_lambda
+ bug11380 = '[ruby-core:70067] [Bug #11380]'
+ assert_valid_syntax('p -> { :hello }, a: 1 do end', bug11380)
+ end
+
+ def test_reserved_method_no_args
+ bug6403 = '[ruby-dev:45626]'
+ assert_valid_syntax("def self; :foo; end", __FILE__, bug6403)
+ end
+
+ def test_unassignable
+ gvar = global_variables
+ %w[self nil true false __FILE__ __LINE__ __ENCODING__].each do |kwd|
+ assert_raise(SyntaxError) {eval("#{kwd} = nil")}
+ assert_equal(gvar, global_variables)
+ end
+ end
+
+ Bug7559 = '[ruby-dev:46737]'
+
+ def test_lineno_command_call_quote
+ expected = __LINE__ + 1
+ actual = caller_lineno "a
+b
+c
+d
+e"
+ assert_equal(expected, actual, "#{Bug7559}: ")
+ end
+
+ def test_lineno_after_heredoc
+ bug7559 = '[ruby-dev:46737]'
+ expected, _, actual = __LINE__, <<eom, __LINE__
+ a
+ b
+ c
+ d
+eom
+ assert_equal(expected, actual, bug7559)
+ end
+
+ def test_lineno_operation_brace_block
+ expected = __LINE__ + 1
+ actual = caller_lineno\
+ {}
+ assert_equal(expected, actual)
+ end
+
+ def assert_constant_reassignment_nested(preset, op, expected, err = [], bug = '[Bug #5449]')
+ [
+ ["p ", ""], # no-pop
+ ["", "p Foo::Bar"], # pop
+ ].each do |p1, p2|
+ src = <<-EOM.gsub(/^\s*\n/, '')
+ class Foo
+ #{"Bar = " + preset if preset}
+ end
+ #{p1}Foo::Bar #{op}= 42
+ #{p2}
+ EOM
+ msg = "\# #{bug}\n#{src}"
+ assert_valid_syntax(src, caller_locations(1, 1)[0].path, msg)
+ assert_in_out_err([], src, expected, err, msg)
+ end
+ end
+
+ def test_constant_reassignment_nested
+ already = /already initialized constant Foo::Bar/
+ uninitialized = /uninitialized constant Foo::Bar/
+ assert_constant_reassignment_nested(nil, "||", %w[42])
+ assert_constant_reassignment_nested("false", "||", %w[42], already)
+ assert_constant_reassignment_nested("true", "||", %w[true])
+ assert_constant_reassignment_nested(nil, "&&", [], uninitialized)
+ assert_constant_reassignment_nested("false", "&&", %w[false])
+ assert_constant_reassignment_nested("true", "&&", %w[42], already)
+ assert_constant_reassignment_nested(nil, "+", [], uninitialized)
+ assert_constant_reassignment_nested("false", "+", [], /undefined method/)
+ assert_constant_reassignment_nested("11", "+", %w[53], already)
+ end
+
+ def assert_constant_reassignment_toplevel(preset, op, expected, err = [], bug = '[Bug #5449]')
+ [
+ ["p ", ""], # no-pop
+ ["", "p ::Bar"], # pop
+ ].each do |p1, p2|
+ src = <<-EOM.gsub(/^\s*\n/, '')
+ #{"Bar = " + preset if preset}
+ class Foo
+ #{p1}::Bar #{op}= 42
+ #{p2}
+ end
+ EOM
+ msg = "\# #{bug}\n#{src}"
+ assert_valid_syntax(src, caller_locations(1, 1)[0].path, msg)
+ assert_in_out_err([], src, expected, err, msg)
+ end
+ end
+
+ def test_constant_reassignment_toplevel
+ already = /already initialized constant Bar/
+ uninitialized = /uninitialized constant Bar/
+ assert_constant_reassignment_toplevel(nil, "||", %w[42])
+ assert_constant_reassignment_toplevel("false", "||", %w[42], already)
+ assert_constant_reassignment_toplevel("true", "||", %w[true])
+ assert_constant_reassignment_toplevel(nil, "&&", [], uninitialized)
+ assert_constant_reassignment_toplevel("false", "&&", %w[false])
+ assert_constant_reassignment_toplevel("true", "&&", %w[42], already)
+ assert_constant_reassignment_toplevel(nil, "+", [], uninitialized)
+ assert_constant_reassignment_toplevel("false", "+", [], /undefined method/)
+ assert_constant_reassignment_toplevel("11", "+", %w[53], already)
+ end
+
+ def test_integer_suffix
+ ["1if true", "begin 1end"].each do |src|
+ assert_valid_syntax(src)
+ assert_equal(1, eval(src), src)
+ end
+ end
+
+ def test_value_of_def
+ assert_separately [], <<-EOS
+ assert_equal(:foo, (def foo; end))
+ assert_equal(:foo, (def (Object.new).foo; end))
+ EOS
+ end
+
+ def test_heredoc_cr
+ assert_syntax_error("puts <<""EOS\n""ng\n""EOS\r""NO\n", /can't find string "EOS" anywhere before EOF/)
+ end
+
+ def test__END___cr
+ assert_syntax_error("__END__\r<<<<<\n", /unexpected <</)
+ end
+
+ def test_warning_for_cr
+ feature8699 = '[ruby-core:56240] [Feature #8699]'
+ assert_warning(/encountered \\r/, feature8699) do
+ eval("\r""__id__\r")
+ end
+ end
+
+ def test_unexpected_fraction
+ msg = /unexpected fraction/
+ assert_syntax_error("0x0.0", msg)
+ assert_syntax_error("0b0.0", msg)
+ assert_syntax_error("0d0.0", msg)
+ assert_syntax_error("0o0.0", msg)
+ assert_syntax_error("0.0.0", msg)
+ end
+
+ def test_error_message_encoding
+ bug10114 = '[ruby-core:64228] [Bug #10114]'
+ code = "# -*- coding: utf-8 -*-\n" "def n \"\u{2208}\"; end"
+ assert_syntax_error(code, /def n "\u{2208}"; end/, bug10114)
+ end
+
+ def test_bad_kwarg
+ bug10545 = '[ruby-dev:48742] [Bug #10545]'
+ src = 'def foo(A: a) end'
+ assert_syntax_error(src, /formal argument/, bug10545)
+ end
+
+ def test_null_range_cmdarg
+ bug10957 = '[ruby-core:68477] [Bug #10957]'
+ assert_ruby_status(['-c', '-e', 'p ()..0'], "", bug10957)
+ assert_ruby_status(['-c', '-e', 'p ()...0'], "", bug10957)
+ assert_syntax_error('0..%w.', /unterminated string/, bug10957)
+ assert_syntax_error('0...%w.', /unterminated string/, bug10957)
+ end
+
+ def test_too_big_nth_ref
+ bug11192 = '[ruby-core:69393] [Bug #11192]'
+ assert_warn(/too big/, bug11192) do
+ eval('$99999999999999999')
+ end
+ end
+
+ private
+
+ def not_label(x) @result = x; @not_label ||= nil end
+ def assert_not_label(expected, src, message = nil)
+ @result = nil
+ assert_nothing_raised(SyntaxError, message) {eval(src)}
+ assert_equal(expected, @result, message)
+ end
+
+ def make_tmpsrc(f, src)
+ f.open
+ f.truncate(0)
+ f.puts(src)
+ f.close
+ end
+
+ def with_script_lines
+ script_lines = nil
+ debug_lines = {}
+ Object.class_eval do
+ if defined?(SCRIPT_LINES__)
+ script_lines = SCRIPT_LINES__
+ remove_const :SCRIPT_LINES__
+ end
+ const_set(:SCRIPT_LINES__, debug_lines)
+ end
+ yield debug_lines
+ ensure
+ Object.class_eval do
+ remove_const :SCRIPT_LINES__
+ const_set(:SCRIPT_LINES__, script_lines) if script_lines
+ end
+ end
+
+ def caller_lineno(*)
+ caller_locations(1, 1)[0].lineno
+ end
+end
diff --git a/jni/ruby/test/ruby/test_system.rb b/jni/ruby/test/ruby/test_system.rb
new file mode 100644
index 0000000..b328cbc
--- /dev/null
+++ b/jni/ruby/test/ruby/test_system.rb
@@ -0,0 +1,162 @@
+require 'test/unit'
+require 'tmpdir'
+
+class TestSystem < Test::Unit::TestCase
+ def test_system
+ ruby = EnvUtil.rubybin
+ assert_equal("foobar\n", `echo foobar`)
+ assert_equal('foobar', `#{ruby} -e 'print "foobar"'`)
+
+ Dir.mktmpdir("ruby_script_tmp") {|tmpdir|
+ tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}"
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "print $zzz\n";
+ tmp.close
+
+ assert_equal('true', `#{ruby} -s #{tmpfilename} -zzz`)
+ assert_equal('555', `#{ruby} -s #{tmpfilename} -zzz=555`)
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "#! /usr/local/bin/ruby -s\n";
+ tmp.print "print $zzz\n";
+ tmp.close
+
+ assert_equal('678', `#{ruby} #{tmpfilename} -zzz=678`)
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "this is a leading junk\n";
+ tmp.print "#! /usr/local/bin/ruby -s\n";
+ tmp.print "print $zzz if defined? $zzz\n";
+ tmp.print "__END__\n";
+ tmp.print "this is a trailing junk\n";
+ tmp.close
+
+ assert_equal('', `#{ruby} -x #{tmpfilename}`)
+ assert_equal('555', `#{ruby} -x #{tmpfilename} -zzz=555`)
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "#! /non/exist\\interpreter?/./to|be:ignored\n";
+ tmp.print "this is a leading junk\n";
+ tmp.print "#! /usr/local/bin/ruby -s\n";
+ tmp.print "print $zzz if defined? $zzz\n";
+ tmp.print "__END__\n";
+ tmp.print "this is a trailing junk\n";
+ tmp.close
+
+ assert_equal('', `#{ruby} #{tmpfilename}`)
+ assert_equal('555', `#{ruby} #{tmpfilename} -zzz=555`)
+
+ tmp = open(tmpfilename, "w")
+ for i in 1..5
+ tmp.print i, "\n"
+ end
+ tmp.close
+
+ `#{ruby} -i.bak -pe '$_.sub!(/^[0-9]+$/){$&.to_i * 5}' #{tmpfilename}`
+ tmp = open(tmpfilename, "r")
+ while tmp.gets
+ assert_equal(0, $_.to_i % 5)
+ end
+ tmp.close
+
+ File.unlink tmpfilename or `/bin/rm -f "#{tmpfilename}"`
+ File.unlink "#{tmpfilename}.bak" or `/bin/rm -f "#{tmpfilename}.bak"`
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ testname = '[ruby-dev:38588]'
+ batch = "batch_tmp.#{$$}"
+ tmpfilename = "#{tmpdir}/#{batch}.bat"
+ open(tmpfilename, "wb") {|f| f.print "\r\n"}
+ assert(system(tmpfilename), testname)
+ assert(system("#{tmpdir}/#{batch}"), testname)
+ assert(system(tmpfilename, "1"), testname)
+ assert(system("#{tmpdir}/#{batch}", "1"), testname)
+ begin
+ path = ENV["PATH"]
+ ENV["PATH"] = "#{tmpdir.tr(File::SEPARATOR, File::ALT_SEPARATOR)}#{File::PATH_SEPARATOR + path if path}"
+ assert(system("#{batch}.bat"), testname)
+ assert(system(batch), testname)
+ assert(system("#{batch}.bat", "1"), testname)
+ assert(system(batch, "1"), testname)
+ ensure
+ ENV["PATH"] = path
+ end
+ File.unlink tmpfilename
+
+ testname = '[ruby-core:44505]'
+ assert_match(/Windows/, `ver`, testname)
+ assert_equal 0, $?.to_i, testname
+ end
+ }
+ end
+
+ def test_system_at
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ bug4393 = '[ruby-core:35218]'
+
+ # @ + builtin command
+ assert_equal("foo\n", `@echo foo`, bug4393);
+ assert_equal("foo\n", `@@echo foo`, bug4393);
+ assert_equal("@@foo\n", `@@echo @@foo`, bug4393);
+
+ # @ + non builtin command
+ Dir.mktmpdir("ruby_script_tmp") {|tmpdir|
+ tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}"
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "foo\nbar\nbaz\n@foo";
+ tmp.close
+
+ assert_match(/\Abar\nbaz\n?\z/, `@@findstr "ba" #{tmpfilename.gsub("/", "\\")}`, bug4393);
+ }
+ end
+ end
+
+ def test_system_redirect_win
+ if /mswin|mingw/ !~ RUBY_PLATFORM
+ return
+ end
+
+ Dir.mktmpdir("ruby_script_tmp") do |tmpdir|
+ cmd = nil
+ message = proc do
+ [
+ '[ruby-talk:258939]',
+ "out.txt:",
+ *File.readlines("out.txt").map{|s|" "+s.inspect},
+ "err.txt:",
+ *File.readlines("err.txt").map{|s|" "+s.inspect},
+ "system(#{cmd.inspect})"
+ ].join("\n")
+ end
+ class << message
+ alias to_s call
+ end
+ Dir.chdir(tmpdir) do
+ open("input.txt", "w") {|f| f.puts "BFI3CHL671"}
+ cmd = "%WINDIR%/system32/find.exe \"BFI3CHL671\" input.txt > out.txt 2>err.txt"
+ assert_equal(true, system(cmd), message)
+ cmd = "\"%WINDIR%/system32/find.exe\" \"BFI3CHL671\" input.txt > out.txt 2>err.txt"
+ assert_equal(true, system(cmd), message)
+ cmd = "\"%WINDIR%/system32/find.exe BFI3CHL671\" input.txt > out.txt 2>err.txt"
+ assert_equal(false, system(cmd), message)
+ end
+ end
+ end
+
+ def test_empty_evstr
+ assert_equal("", eval('"#{}"', nil, __FILE__, __LINE__), "[ruby-dev:25113]")
+ end
+
+ def test_fallback_to_sh
+ Dir.mktmpdir("ruby_script_tmp") {|tmpdir|
+ tmpfilename = "#{tmpdir}/ruby_script_tmp.#{$$}"
+ open(tmpfilename, "w") {|f|
+ f.puts ": ;"
+ f.chmod(0755)
+ }
+ assert_equal(true, system(tmpfilename), '[ruby-core:32745]')
+ }
+ end if File.executable?("/bin/sh")
+end
diff --git a/jni/ruby/test/ruby/test_thread.rb b/jni/ruby/test/ruby/test_thread.rb
new file mode 100644
index 0000000..87d5f0f
--- /dev/null
+++ b/jni/ruby/test/ruby/test_thread.rb
@@ -0,0 +1,1036 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+require 'thread'
+
+class TestThread < Test::Unit::TestCase
+ class Thread < ::Thread
+ Threads = []
+ def self.new(*)
+ th = super
+ Threads << th
+ th
+ end
+ end
+
+ def setup
+ Thread::Threads.clear
+ end
+
+ def teardown
+ Thread::Threads.each do |t|
+ t.kill if t.alive?
+ begin
+ t.join
+ rescue Exception
+ end
+ end
+ end
+
+ def test_inspect
+ th = Module.new {break module_eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")}.start{}
+ assert_match(/::C\u{30b9 30ec 30c3 30c9}:/, th.inspect)
+ ensure
+ th.join
+ end
+
+ def test_main_thread_variable_in_enumerator
+ assert_equal Thread.main, Thread.current
+
+ Thread.current.thread_variable_set :foo, "bar"
+
+ thread, value = Fiber.new {
+ Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
+ }.resume
+
+ assert_equal Thread.current, thread
+ assert_equal Thread.current.thread_variable_get(:foo), value
+ end
+
+ def test_thread_variable_in_enumerator
+ Thread.new {
+ Thread.current.thread_variable_set :foo, "bar"
+
+ thread, value = Fiber.new {
+ Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
+ }.resume
+
+ assert_equal Thread.current, thread
+ assert_equal Thread.current.thread_variable_get(:foo), value
+ }.join
+ end
+
+ def test_thread_variables
+ assert_equal [], Thread.new { Thread.current.thread_variables }.join.value
+
+ t = Thread.new {
+ Thread.current.thread_variable_set(:foo, "bar")
+ Thread.current.thread_variables
+ }
+ assert_equal [:foo], t.join.value
+ end
+
+ def test_thread_variable?
+ Thread.new { assert_not_send([Thread.current, :thread_variable?, "foo"]) }.value
+ t = Thread.new {
+ Thread.current.thread_variable_set("foo", "bar")
+ }.join
+
+ assert_send([t, :thread_variable?, "foo"])
+ assert_send([t, :thread_variable?, :foo])
+ assert_not_send([t, :thread_variable?, :bar])
+ end
+
+ def test_thread_variable_strings_and_symbols_are_the_same_key
+ t = Thread.new {}.join
+ t.thread_variable_set("foo", "bar")
+ assert_equal "bar", t.thread_variable_get(:foo)
+ end
+
+ def test_thread_variable_frozen
+ t = Thread.new { }.join
+ t.freeze
+ assert_raise(RuntimeError) do
+ t.thread_variable_set(:foo, "bar")
+ end
+ end
+
+ def test_mutex_synchronize
+ m = Mutex.new
+ r = 0
+ max = 10
+ (1..max).map{
+ Thread.new{
+ i=0
+ while i<max*max
+ i+=1
+ m.synchronize{
+ r += 1
+ }
+ end
+ }
+ }.each{|e|
+ e.join
+ }
+ assert_equal(max * max * max, r)
+ end
+
+ def test_mutex_synchronize_yields_no_block_params
+ bug8097 = '[ruby-core:53424] [Bug #8097]'
+ assert_empty(Mutex.new.synchronize {|*params| break params}, bug8097)
+ end
+
+ def test_local_barrier
+ dir = File.dirname(__FILE__)
+ lbtest = File.join(dir, "lbtest.rb")
+ $:.unshift File.join(File.dirname(dir), 'ruby')
+ $:.shift
+ 3.times {
+ `#{EnvUtil.rubybin} #{lbtest}`
+ assert_not_predicate($?, :coredump?, '[ruby-dev:30653]')
+ }
+ end
+
+ def test_priority
+ c1 = c2 = 0
+ run = true
+ t1 = Thread.new { c1 += 1 while run }
+ t1.priority = 3
+ t2 = Thread.new { c2 += 1 while run }
+ t2.priority = -3
+ assert_equal(3, t1.priority)
+ assert_equal(-3, t2.priority)
+ sleep 0.5
+ 5.times do
+ assert_not_predicate(t1, :stop?)
+ assert_not_predicate(t2, :stop?)
+ break if c1 > c2
+ sleep 0.1
+ end
+ run = false
+ t1.kill
+ t2.kill
+ assert_operator(c1, :>, c2, "[ruby-dev:33124]") # not guaranteed
+ end
+
+ def test_new
+ assert_raise(ThreadError) do
+ Thread.new
+ end
+
+ t1 = Thread.new { sleep }
+ assert_raise(ThreadError) do
+ t1.instance_eval { initialize { } }
+ end
+
+ t2 = Thread.new(&method(:sleep).to_proc)
+ assert_raise(ThreadError) do
+ t2.instance_eval { initialize { } }
+ end
+
+ ensure
+ t1.kill if t1
+ t2.kill if t2
+ end
+
+ def test_join
+ t = Thread.new { sleep }
+ assert_nil(t.join(0.05))
+
+ ensure
+ t.kill if t
+ end
+
+ def test_join2
+ ok = false
+ t1 = Thread.new { ok = true; sleep }
+ Thread.pass until ok
+ Thread.pass until t1.stop?
+ t2 = Thread.new do
+ Thread.pass while ok
+ t1.join(0.01)
+ end
+ t3 = Thread.new do
+ ok = false
+ t1.join
+ end
+ assert_nil(t2.value)
+ t1.wakeup
+ assert_equal(t1, t3.value)
+
+ ensure
+ t1.kill if t1
+ t2.kill if t2
+ t3.kill if t3
+ end
+
+ def test_kill_main_thread
+ assert_in_out_err([], <<-INPUT, %w(1), [])
+ p 1
+ Thread.kill Thread.current
+ p 2
+ INPUT
+ end
+
+ def test_kill_wrong_argument
+ bug4367 = '[ruby-core:35086]'
+ assert_raise(TypeError, bug4367) {
+ Thread.kill(nil)
+ }
+ o = Object.new
+ assert_raise(TypeError, bug4367) {
+ Thread.kill(o)
+ }
+ end
+
+ def test_kill_thread_subclass
+ c = Class.new(Thread)
+ t = c.new { sleep 10 }
+ assert_nothing_raised { Thread.kill(t) }
+ assert_equal(nil, t.value)
+ end
+
+ def test_exit
+ s = 0
+ Thread.new do
+ s += 1
+ Thread.exit
+ s += 2
+ end.join
+ assert_equal(1, s)
+ end
+
+ def test_wakeup
+ s = 0
+ t = Thread.new do
+ s += 1
+ Thread.stop
+ s += 1
+ end
+ Thread.pass until t.stop?
+ assert_equal(1, s)
+ t.wakeup
+ Thread.pass while t.alive?
+ assert_equal(2, s)
+ assert_raise(ThreadError) { t.wakeup }
+
+ ensure
+ t.kill if t
+ end
+
+ def test_stop
+ assert_in_out_err([], <<-INPUT, %w(2), [])
+ begin
+ Thread.stop
+ p 1
+ rescue ThreadError
+ p 2
+ end
+ INPUT
+ end
+
+ def test_list
+ assert_in_out_err([], <<-INPUT) do |r, e|
+ t1 = Thread.new { sleep }
+ Thread.pass
+ t2 = Thread.new { loop { Thread.pass } }
+ Thread.new { }.join
+ p [Thread.current, t1, t2].map{|t| t.object_id }.sort
+ p Thread.list.map{|t| t.object_id }.sort
+ INPUT
+ assert_equal(r.first, r.last)
+ assert_equal([], e)
+ end
+ end
+
+ def test_main
+ assert_in_out_err([], <<-INPUT, %w(true false), [])
+ p Thread.main == Thread.current
+ Thread.new { p Thread.main == Thread.current }.join
+ INPUT
+ end
+
+ def test_abort_on_exception
+ assert_in_out_err([], <<-INPUT, %w(false 1), [])
+ p Thread.abort_on_exception
+ begin
+ t = Thread.new { raise }
+ Thread.pass until t.stop?
+ p 1
+ rescue
+ p 2
+ end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, %w(true 2), [])
+ Thread.abort_on_exception = true
+ p Thread.abort_on_exception
+ begin
+ Thread.new { raise }
+ sleep 0.5
+ p 1
+ rescue
+ p 2
+ end
+ INPUT
+
+ assert_in_out_err(%w(--disable-gems -d), <<-INPUT, %w(false 2), %r".+")
+ p Thread.abort_on_exception
+ begin
+ t = Thread.new { raise }
+ Thread.pass until t.stop?
+ p 1
+ rescue
+ p 2
+ end
+ INPUT
+
+ assert_in_out_err([], <<-INPUT, %w(false true 2), [])
+ p Thread.abort_on_exception
+ begin
+ ok = false
+ t = Thread.new { Thread.pass until ok; raise }
+ t.abort_on_exception = true
+ p t.abort_on_exception
+ ok = 1
+ sleep 1
+ p 1
+ rescue
+ p 2
+ end
+ INPUT
+ end
+
+ def test_status_and_stop_p
+ a = ::Thread.new { raise("die now") }
+ b = Thread.new { Thread.stop }
+ c = Thread.new { Thread.exit }
+ e = Thread.current
+ Thread.pass while a.alive? or !b.stop? or c.alive?
+
+ assert_equal(nil, a.status)
+ assert_predicate(a, :stop?)
+
+ assert_equal("sleep", b.status)
+ assert_predicate(b, :stop?)
+
+ assert_equal(false, c.status)
+ assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect)
+ assert_predicate(c, :stop?)
+
+ es1 = e.status
+ es2 = e.stop?
+ assert_equal(["run", false], [es1, es2])
+
+ ensure
+ a.kill if a
+ b.kill if b
+ c.kill if c
+ end
+
+ def test_switch_while_busy_loop
+ bug1402 = "[ruby-dev:38319] [Bug #1402]"
+ flag = true
+ th = Thread.current
+ waiter = Thread.start {
+ sleep 0.1
+ flag = false
+ sleep 1
+ th.raise(bug1402)
+ }
+ assert_nothing_raised(RuntimeError, bug1402) do
+ nil while flag
+ end
+ assert(!flag, bug1402)
+ ensure
+ waiter.kill.join
+ end
+
+ def test_safe_level
+ ok = false
+ t = Thread.new do
+ EnvUtil.suppress_warning do
+ $SAFE = 3
+ end
+ ok = true
+ sleep
+ end
+ Thread.pass until ok
+ assert_equal(0, Thread.current.safe_level)
+ assert_equal(3, t.safe_level)
+
+ ensure
+ t.kill if t
+ end
+
+ def test_thread_local
+ t = Thread.new { sleep }
+
+ assert_equal(false, t.key?(:foo))
+
+ t["foo"] = "foo"
+ t["bar"] = "bar"
+ t["baz"] = "baz"
+
+ assert_equal(true, t.key?(:foo))
+ assert_equal(true, t.key?("foo"))
+ assert_equal(false, t.key?(:qux))
+ assert_equal(false, t.key?("qux"))
+
+ assert_equal([:foo, :bar, :baz], t.keys)
+
+ ensure
+ t.kill if t
+ end
+
+ def test_thread_local_security
+ assert_raise(RuntimeError) do
+ Thread.new do
+ Thread.current[:foo] = :bar
+ Thread.current.freeze
+ Thread.current[:foo] = :baz
+ end.join
+ end
+ end
+
+ def test_thread_local_dynamic_symbol
+ bug10667 = '[ruby-core:67185] [Bug #10667]'
+ t = Thread.new {}.join
+ key_str = "foo#{rand}"
+ key_sym = key_str.to_sym
+ t.thread_variable_set(key_str, "bar")
+ assert_equal("bar", t.thread_variable_get(key_str), "#{bug10667}: string key")
+ assert_equal("bar", t.thread_variable_get(key_sym), "#{bug10667}: symbol key")
+ end
+
+ def test_select_wait
+ assert_nil(IO.select(nil, nil, nil, 0.001))
+ t = Thread.new do
+ IO.select(nil, nil, nil, nil)
+ end
+ Thread.pass until t.stop?
+ assert_predicate(t, :alive?)
+ t.kill
+ end
+
+ def test_mutex_deadlock
+ m = Mutex.new
+ m.synchronize do
+ assert_raise(ThreadError) do
+ m.synchronize do
+ assert(false)
+ end
+ end
+ end
+ end
+
+ def test_mutex_interrupt
+ m = Mutex.new
+ m.lock
+ t = Thread.new do
+ m.lock
+ :foo
+ end
+ Thread.pass until t.stop?
+ t.kill
+ assert_nil(t.value)
+ end
+
+ def test_mutex_illegal_unlock
+ m = Mutex.new
+ m.lock
+ assert_raise(ThreadError) do
+ Thread.new do
+ m.unlock
+ end.join
+ end
+ end
+
+ def test_mutex_fifo_like_lock
+ m1 = Mutex.new
+ m2 = Mutex.new
+ m1.lock
+ m2.lock
+ m1.unlock
+ m2.unlock
+ assert_equal(false, m1.locked?)
+ assert_equal(false, m2.locked?)
+
+ m3 = Mutex.new
+ m1.lock
+ m2.lock
+ m3.lock
+ m1.unlock
+ m2.unlock
+ m3.unlock
+ assert_equal(false, m1.locked?)
+ assert_equal(false, m2.locked?)
+ assert_equal(false, m3.locked?)
+ end
+
+ def test_mutex_trylock
+ m = Mutex.new
+ assert_equal(true, m.try_lock)
+ assert_equal(false, m.try_lock, '[ruby-core:20943]')
+
+ Thread.new{
+ assert_equal(false, m.try_lock)
+ }.join
+
+ m.unlock
+ end
+
+ def test_recursive_outer
+ arr = []
+ obj = Struct.new(:foo, :visited).new(arr, false)
+ arr << obj
+ def obj.hash
+ self[:visited] = true
+ super
+ raise "recursive_outer should short circuit intermediate calls"
+ end
+ assert_nothing_raised {arr.hash}
+ assert(obj[:visited], "obj.hash was not called")
+ end
+
+ def test_thread_instance_variable
+ bug4389 = '[ruby-core:35192]'
+ assert_in_out_err([], <<-INPUT, %w(), [], bug4389)
+ class << Thread.current
+ @data = :data
+ end
+ INPUT
+ end
+
+ def test_no_valid_cfp
+ skip 'with win32ole, cannot run this testcase because win32ole redefines Thread#intialize' if defined?(WIN32OLE)
+ bug5083 = '[ruby-dev:44208]'
+ assert_equal([], Thread.new(&Module.method(:nesting)).value, bug5083)
+ assert_instance_of(Thread, Thread.new(:to_s, &Class.new.method(:undef_method)).join, bug5083)
+ end
+
+ def make_handle_interrupt_test_thread1 flag
+ r = []
+ ready_p = false
+ done = false
+ th = Thread.new{
+ begin
+ Thread.handle_interrupt(RuntimeError => flag){
+ begin
+ ready_p = true
+ sleep 0.01 until done
+ rescue
+ r << :c1
+ end
+ }
+ rescue
+ r << :c2
+ end
+ }
+ Thread.pass until ready_p
+ th.raise
+ begin
+ done = true
+ th.join
+ rescue
+ r << :c3
+ end
+ r
+ end
+
+ def test_handle_interrupt
+ [[:never, :c2],
+ [:immediate, :c1],
+ [:on_blocking, :c1]].each{|(flag, c)|
+ assert_equal([flag, c], [flag] + make_handle_interrupt_test_thread1(flag))
+ }
+ # TODO: complex cases are needed.
+ end
+
+ def test_handle_interrupt_invalid_argument
+ assert_raise(ArgumentError) {
+ Thread.handle_interrupt(RuntimeError => :immediate) # no block
+ }
+ assert_raise(ArgumentError) {
+ Thread.handle_interrupt(RuntimeError => :xyzzy) {}
+ }
+ assert_raise(TypeError) {
+ Thread.handle_interrupt([]) {} # array
+ }
+ end
+
+ def for_test_handle_interrupt_with_return
+ Thread.handle_interrupt(Object => :never){
+ Thread.current.raise RuntimeError.new("have to be rescured")
+ return
+ }
+ rescue
+ end
+
+ def test_handle_interrupt_with_return
+ assert_nothing_raised do
+ for_test_handle_interrupt_with_return
+ _dummy_for_check_ints=nil
+ end
+ end
+
+ def test_handle_interrupt_with_break
+ assert_nothing_raised do
+ begin
+ Thread.handle_interrupt(Object => :never){
+ Thread.current.raise RuntimeError.new("have to be rescured")
+ break
+ }
+ rescue
+ end
+ _dummy_for_check_ints=nil
+ end
+ end
+
+ def test_handle_interrupt_blocking
+ r=:ng
+ e=Class.new(Exception)
+ th_s = Thread.current
+ begin
+ th = Thread.start{
+ Thread.handle_interrupt(Object => :on_blocking){
+ begin
+ Thread.current.raise RuntimeError
+ r=:ok
+ sleep
+ ensure
+ th_s.raise e
+ end
+ }
+ }
+ sleep 1
+ r=:ng
+ th.raise RuntimeError
+ th.join
+ rescue e
+ end
+ assert_equal(:ok,r)
+ end
+
+ def test_handle_interrupt_and_io
+ assert_in_out_err([], <<-INPUT, %w(ok), [])
+ th_waiting = true
+
+ t = Thread.new {
+ Thread.handle_interrupt(RuntimeError => :on_blocking) {
+ nil while th_waiting
+ # async interrupt should be raised _before_ writing puts arguments
+ puts "ng"
+ }
+ }
+
+ Thread.pass while t.stop?
+ t.raise RuntimeError
+ th_waiting = false
+ t.join rescue nil
+ puts "ok"
+ INPUT
+ end
+
+ def test_handle_interrupt_and_p
+ assert_in_out_err([], <<-INPUT, %w(:ok :ok), [])
+ th_waiting = false
+
+ t = Thread.new {
+ Thread.handle_interrupt(RuntimeError => :on_blocking) {
+ th_waiting = true
+ nil while th_waiting
+ # p shouldn't provide interruptible point
+ p :ok
+ p :ok
+ }
+ }
+
+ Thread.pass until th_waiting
+ t.raise RuntimeError
+ th_waiting = false
+ t.join rescue nil
+ INPUT
+ end
+
+ def test_handle_interrupted?
+ q = Queue.new
+ Thread.handle_interrupt(RuntimeError => :never){
+ done = false
+ th = Thread.new{
+ q.push :e
+ begin
+ begin
+ Thread.pass until done
+ rescue => e
+ q.push :ng1
+ end
+ begin
+ Thread.handle_interrupt(Object => :immediate){} if Thread.pending_interrupt?
+ rescue RuntimeError => e
+ q.push :ok
+ end
+ rescue => e
+ q.push :ng2
+ ensure
+ q.push :ng3
+ end
+ }
+ q.pop
+ th.raise
+ done = true
+ th.join
+ assert_equal(:ok, q.pop)
+ }
+ end
+
+ def test_thread_timer_and_ensure
+ assert_normal_exit(<<_eom, 'r36492', timeout: 3)
+ flag = false
+ t = Thread.new do
+ begin
+ sleep
+ ensure
+ 1 until flag
+ end
+ end
+
+ Thread.pass until t.status == "sleep"
+
+ t.kill
+ t.alive? == true
+ flag = true
+ t.join
+_eom
+ end
+
+ def test_uninitialized
+ c = Class.new(Thread)
+ c.class_eval { def initialize; end }
+ assert_raise(ThreadError) { c.new.start }
+ end
+
+ def test_backtrace
+ Thread.new{
+ assert_equal(Array, Thread.main.backtrace.class)
+ }.join
+
+ t = Thread.new{}
+ t.join
+ assert_equal(nil, t.backtrace)
+ end
+
+ def test_thread_timer_and_interrupt
+ bug5757 = '[ruby-dev:44985]'
+ t0 = Time.now.to_f
+ pid = nil
+ cmd = 'Signal.trap(:INT, "DEFAULT"); r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read'
+ opt = {}
+ opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM
+ s, _err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, opt) do |in_p, out_p, err_p, cpid|
+ out_p.gets
+ pid = cpid
+ Process.kill(:SIGINT, pid)
+ Process.wait(pid)
+ [$?, err_p.read]
+ end
+ t1 = Time.now.to_f
+ assert_equal(pid, s.pid, bug5757)
+ assert_equal([false, true, false, Signal.list["INT"]],
+ [s.exited?, s.signaled?, s.stopped?, s.termsig],
+ "[s.exited?, s.signaled?, s.stopped?, s.termsig]")
+ assert_in_delta(t1 - t0, 1, 1, bug5757)
+ end
+
+ def test_thread_join_in_trap
+ assert_separately [], <<-'EOS'
+ Signal.trap(:INT, "DEFAULT")
+ t0 = Thread.current
+ assert_nothing_raised{
+ t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$)}
+
+ Signal.trap :INT do
+ t.join
+ end
+
+ t.join
+ }
+ EOS
+ end
+
+ def test_thread_value_in_trap
+ assert_separately [], <<-'EOS'
+ Signal.trap(:INT, "DEFAULT")
+ t0 = Thread.current
+ t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$); :normal_end}
+
+ Signal.trap :INT do
+ t.value
+ end
+ assert_equal(:normal_end, t.value)
+ EOS
+ end
+
+ def test_thread_join_current
+ assert_raise(ThreadError) do
+ Thread.current.join
+ end
+ end
+
+ def test_thread_join_main_thread
+ assert_raise(ThreadError) do
+ Thread.new(Thread.current) {|t|
+ t.join
+ }.join
+ end
+ end
+
+ def test_main_thread_status_at_exit
+ assert_in_out_err([], <<-'INPUT', ["false false aborting"], [])
+require 'thread'
+q = Queue.new
+Thread.new(Thread.current) {|mth|
+ begin
+ q.push nil
+ mth.run
+ Thread.pass until mth.stop?
+ p :mth_stopped # don't run if killed by rb_thread_terminate_all
+ ensure
+ puts "#{mth.alive?} #{mth.status} #{Thread.current.status}"
+ end
+}
+q.pop
+ INPUT
+ end
+
+ def test_thread_status_in_trap
+ # when running trap handler, Thread#status must show "run"
+ # Even though interrupted from sleeping function
+ assert_in_out_err([], <<-INPUT, %w(sleep run), [])
+ Signal.trap(:INT) {
+ puts Thread.current.status
+ exit
+ }
+ t = Thread.current
+
+ Thread.new(Thread.current) {|mth|
+ Thread.pass until t.stop?
+ puts mth.status
+ Process.kill(:INT, $$)
+ }
+ sleep 0.1
+ INPUT
+ end
+
+ # Bug #7450
+ def test_thread_status_raise_after_kill
+ ary = []
+
+ t = Thread.new {
+ begin
+ ary << Thread.current.status
+ sleep #1
+ ensure
+ begin
+ ary << Thread.current.status
+ sleep #2
+ ensure
+ ary << Thread.current.status
+ end
+ end
+ }
+
+ begin
+ Thread.pass until ary.size >= 1
+ Thread.pass until t.stop?
+ t.kill # wake up sleep #1
+ Thread.pass until ary.size >= 2
+ Thread.pass until t.stop?
+ t.raise "wakeup" # wake up sleep #2
+ Thread.pass while t.alive?
+ assert_equal(ary, ["run", "aborting", "aborting"])
+ ensure
+ t.join rescue nil
+ end
+ end
+
+ def test_mutex_owned
+ mutex = Mutex.new
+
+ assert_equal(mutex.owned?, false)
+ mutex.synchronize {
+ # Now, I have the mutex
+ assert_equal(mutex.owned?, true)
+ }
+ assert_equal(mutex.owned?, false)
+ end
+
+ def test_mutex_owned2
+ begin
+ mutex = Mutex.new
+ th = Thread.new {
+ # lock forever
+ mutex.lock
+ sleep
+ }
+
+ Thread.pass until th.status == "sleep"
+ # acquired another thread.
+ assert_equal(mutex.locked?, true)
+ assert_equal(mutex.owned?, false)
+ ensure
+ th.kill if th
+ end
+ end
+
+ def test_mutex_unlock_on_trap
+ assert_in_out_err([], <<-INPUT, %w(locked unlocked false), [])
+ m = Mutex.new
+
+ trapped = false
+ Signal.trap("INT") { |signo|
+ m.unlock
+ trapped = true
+ puts "unlocked"
+ }
+
+ m.lock
+ puts "locked"
+ Process.kill("INT", $$)
+ Thread.pass until trapped
+ puts m.locked?
+ INPUT
+ end
+
+ def invoke_rec script, vm_stack_size, machine_stack_size, use_length = true
+ env = {}
+ env['RUBY_THREAD_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size
+ env['RUBY_THREAD_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size
+ out, = EnvUtil.invoke_ruby([env, '-e', script], '', true, true)
+ use_length ? out.length : out
+ end
+
+ def test_stack_size
+ h_default = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', nil, nil, false))
+ h_0 = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 0, 0, false))
+ h_large = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 1024 * 1024 * 10, 1024 * 1024 * 10, false))
+
+ assert_operator(h_default[:thread_vm_stack_size], :>, h_0[:thread_vm_stack_size],
+ "0 thread_vm_stack_size")
+ assert_operator(h_default[:thread_vm_stack_size], :<, h_large[:thread_vm_stack_size],
+ "large thread_vm_stack_size")
+ assert_operator(h_default[:thread_machine_stack_size], :>=, h_0[:thread_machine_stack_size],
+ "0 thread_machine_stack_size")
+ assert_operator(h_default[:thread_machine_stack_size], :<=, h_large[:thread_machine_stack_size],
+ "large thread_machine_stack_size")
+ end
+
+ def test_vm_machine_stack_size
+ script = 'def rec; print "."; STDOUT.flush; rec; end; rec'
+ size_default = invoke_rec script, nil, nil
+ assert_operator(size_default, :>, 0, "default size")
+ size_0 = invoke_rec script, 0, nil
+ assert_operator(size_default, :>, size_0, "0 size")
+ size_large = invoke_rec script, 1024 * 1024 * 10, nil
+ assert_operator(size_default, :<, size_large, "large size")
+ end
+
+ def test_machine_stack_size
+ # check machine stack size
+ # Note that machine stack size may not change size (depend on OSs)
+ script = 'def rec; print "."; STDOUT.flush; 1.times{1.times{1.times{rec}}}; end; Thread.new{rec}.join'
+ vm_stack_size = 1024 * 1024
+ size_default = invoke_rec script, vm_stack_size, nil
+ size_0 = invoke_rec script, vm_stack_size, 0
+ assert_operator(size_default, :>=, size_0, "0 size")
+ size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10
+ assert_operator(size_default, :<=, size_large, "large size")
+ end unless /mswin|mingw/ =~ RUBY_PLATFORM
+
+ def test_blocking_mutex_unlocked_on_fork
+ bug8433 = '[ruby-core:55102] [Bug #8433]'
+
+ mutex = Mutex.new
+ flag = false
+ mutex.lock
+
+ th = Thread.new do
+ mutex.synchronize do
+ flag = true
+ sleep
+ end
+ end
+
+ Thread.pass until th.stop?
+ mutex.unlock
+
+ pid = Process.fork do
+ exit(mutex.locked?)
+ end
+
+ th.kill
+
+ pid, status = Process.waitpid2(pid)
+ assert_equal(false, status.success?, bug8433)
+ end if Process.respond_to?(:fork)
+
+ def test_fork_in_thread
+ bug9751 = '[ruby-core:62070] [Bug #9751]'
+ f = nil
+ th = Thread.start do
+ unless f = IO.popen("-")
+ STDERR.reopen(STDOUT)
+ exit
+ end
+ Process.wait2(f.pid)
+ end
+ unless th.join(3)
+ Process.kill(:QUIT, f.pid)
+ Process.kill(:KILL, f.pid) unless th.join(1)
+ end
+ _, status = th.value
+ output = f.read
+ f.close
+ assert_not_predicate(status, :signaled?, FailDesc[status, bug9751, output])
+ assert_predicate(status, :success?, bug9751)
+ end if Process.respond_to?(:fork)
+end
diff --git a/jni/ruby/test/ruby/test_threadgroup.rb b/jni/ruby/test/ruby/test_threadgroup.rb
new file mode 100644
index 0000000..e158f5a
--- /dev/null
+++ b/jni/ruby/test/ruby/test_threadgroup.rb
@@ -0,0 +1,57 @@
+require 'test/unit'
+require 'thread'
+
+class TestThreadGroup < Test::Unit::TestCase
+ def test_thread_init
+ thgrp = ThreadGroup.new
+ th = Thread.new{
+ thgrp.add(Thread.current)
+ Thread.new{sleep 1}
+ }.value
+ assert_equal(thgrp, th.group)
+ ensure
+ th.join
+ end
+
+ def test_frozen_thgroup
+ thgrp = ThreadGroup.new
+
+ t = Thread.new{1}
+ Thread.new{
+ thgrp.add(Thread.current)
+ thgrp.freeze
+ assert_raise(ThreadError) do
+ Thread.new{1}.join
+ end
+ assert_raise(ThreadError) do
+ thgrp.add(t)
+ end
+ assert_raise(ThreadError) do
+ ThreadGroup.new.add Thread.current
+ end
+ }.join
+ t.join
+ end
+
+ def test_enclosed_thgroup
+ thgrp = ThreadGroup.new
+ assert_equal(false, thgrp.enclosed?)
+
+ t = Thread.new{1}
+ Thread.new{
+ thgrp.add(Thread.current)
+ thgrp.enclose
+ assert_equal(true, thgrp.enclosed?)
+ assert_nothing_raised do
+ Thread.new{1}.join
+ end
+ assert_raise(ThreadError) do
+ thgrp.add t
+ end
+ assert_raise(ThreadError) do
+ ThreadGroup.new.add Thread.current
+ end
+ }.join
+ t.join
+ end
+end
diff --git a/jni/ruby/test/ruby/test_time.rb b/jni/ruby/test/ruby/test_time.rb
new file mode 100644
index 0000000..f4fb5bf
--- /dev/null
+++ b/jni/ruby/test/ruby/test_time.rb
@@ -0,0 +1,1049 @@
+require 'test/unit'
+require 'delegate'
+require 'timeout'
+require 'delegate'
+
+class TestTime < Test::Unit::TestCase
+ def setup
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ def teardown
+ $VERBOSE = @verbose
+ end
+
+ def in_timezone(zone)
+ orig_zone = ENV['TZ']
+
+ ENV['TZ'] = zone
+ yield
+ ensure
+ ENV['TZ'] = orig_zone
+ end
+
+ def no_leap_seconds?
+ # 1972-06-30T23:59:60Z is the first leap second.
+ Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59) == 1
+ end
+
+ def get_t2000
+ if no_leap_seconds?
+ # Sat Jan 01 00:00:00 UTC 2000
+ Time.at(946684800).gmtime
+ else
+ Time.utc(2000, 1, 1)
+ end
+ end
+
+ def test_new
+ assert_equal(Time.utc(2000,2,10), Time.new(2000,2,10, 11,0,0, 3600*11))
+ assert_equal(Time.utc(2000,2,10), Time.new(2000,2,9, 13,0,0, -3600*11))
+ assert_equal(Time.utc(2000,2,10), Time.new(2000,2,10, 11,0,0, "+11:00"))
+ assert_equal(Rational(1,2), Time.new(2000,2,10, 11,0,5.5, "+11:00").subsec)
+ bug4090 = '[ruby-dev:42631]'
+ tm = [2001,2,28,23,59,30]
+ t = Time.new(*tm, "-12:00")
+ assert_equal([2001,2,28,23,59,30,-43200], [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.gmt_offset], bug4090)
+ assert_raise(ArgumentError) { Time.new(2000,1,1, 0,0,0, "+01:60") }
+ end
+
+ def test_time_add()
+ assert_equal(Time.utc(2000, 3, 21, 3, 30) + 3 * 3600,
+ Time.utc(2000, 3, 21, 6, 30))
+ assert_equal(Time.utc(2000, 3, 21, 3, 30) + (-3 * 3600),
+ Time.utc(2000, 3, 21, 0, 30))
+ assert_equal(0, (Time.at(1.1) + 0.9).usec)
+
+ assert_predicate((Time.utc(2000, 4, 1) + 24), :utc?)
+ assert_not_predicate((Time.local(2000, 4, 1) + 24), :utc?)
+
+ t = Time.new(2000, 4, 1, 0, 0, 0, "+01:00") + 24
+ assert_not_predicate(t, :utc?)
+ assert_equal(3600, t.utc_offset)
+ t = Time.new(2000, 4, 1, 0, 0, 0, "+02:00") + 24
+ assert_not_predicate(t, :utc?)
+ assert_equal(7200, t.utc_offset)
+ end
+
+ def test_time_subt()
+ assert_equal(Time.utc(2000, 3, 21, 3, 30) - 3 * 3600,
+ Time.utc(2000, 3, 21, 0, 30))
+ assert_equal(Time.utc(2000, 3, 21, 3, 30) - (-3 * 3600),
+ Time.utc(2000, 3, 21, 6, 30))
+ assert_equal(900000, (Time.at(1.1) - 0.2).usec)
+ end
+
+ def test_time_time()
+ assert_equal(Time.utc(2000, 3, 21, 3, 30) \
+ -Time.utc(2000, 3, 21, 0, 30), 3*3600)
+ assert_equal(Time.utc(2000, 3, 21, 0, 30) \
+ -Time.utc(2000, 3, 21, 3, 30), -3*3600)
+ end
+
+ def negative_time_t?
+ begin
+ Time.at(-1)
+ true
+ rescue ArgumentError
+ false
+ end
+ end
+
+ def test_timegm
+ if negative_time_t?
+ assert_equal(-0x80000000, Time.utc(1901, 12, 13, 20, 45, 52).tv_sec)
+ assert_equal(-2, Time.utc(1969, 12, 31, 23, 59, 58).tv_sec)
+ assert_equal(-1, Time.utc(1969, 12, 31, 23, 59, 59).tv_sec)
+ end
+
+ assert_equal(0, Time.utc(1970, 1, 1, 0, 0, 0).tv_sec) # the Epoch
+ assert_equal(1, Time.utc(1970, 1, 1, 0, 0, 1).tv_sec)
+ assert_equal(31535999, Time.utc(1970, 12, 31, 23, 59, 59).tv_sec)
+ assert_equal(31536000, Time.utc(1971, 1, 1, 0, 0, 0).tv_sec)
+ assert_equal(78796799, Time.utc(1972, 6, 30, 23, 59, 59).tv_sec)
+
+ if no_leap_seconds?
+ assert_equal(78796800, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec)
+ assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec)
+ assert_equal(946684800, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec)
+ assert_equal(0x7fffffff, Time.utc(2038, 1, 19, 3, 14, 7).tv_sec)
+ assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec)
+ else
+ assert_equal(2, Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59))
+ assert_equal(78796800, Time.utc(1972, 6, 30, 23, 59, 60).tv_sec)
+ assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec)
+ assert_equal(78796802, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec)
+ assert_equal(946684822, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec)
+ end
+ end
+
+ def test_strtime
+ t = nil
+ assert_nothing_raised { t = Time.utc("2000", "1", "2" , "3", "4", "5") }
+ assert_equal(Time.utc(2000,1,2,3,4,5), t)
+ end
+
+ def test_huge_difference
+ if negative_time_t?
+ assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) - 0xffffffff, "[ruby-dev:22619]")
+ assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) + (-0xffffffff))
+ assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) + 0xffffffff, "[ruby-dev:22619]")
+ assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) - (-0xffffffff))
+ end
+ end
+
+ def test_big_minus
+ begin
+ bigtime0 = Time.at(2**60)
+ bigtime1 = Time.at(2**60+1)
+ rescue RangeError
+ return
+ end
+ assert_equal(1.0, bigtime1 - bigtime0)
+ end
+
+ def test_at
+ assert_equal(100000, Time.at("0.1".to_r).usec)
+ assert_equal(10000, Time.at("0.01".to_r).usec)
+ assert_equal(1000, Time.at("0.001".to_r).usec)
+ assert_equal(100, Time.at("0.0001".to_r).usec)
+ assert_equal(10, Time.at("0.00001".to_r).usec)
+ assert_equal(1, Time.at("0.000001".to_r).usec)
+ assert_equal(100000000, Time.at("0.1".to_r).nsec)
+ assert_equal(10000000, Time.at("0.01".to_r).nsec)
+ assert_equal(1000000, Time.at("0.001".to_r).nsec)
+ assert_equal(100000, Time.at("0.0001".to_r).nsec)
+ assert_equal(10000, Time.at("0.00001".to_r).nsec)
+ assert_equal(1000, Time.at("0.000001".to_r).nsec)
+ assert_equal(100, Time.at("0.0000001".to_r).nsec)
+ assert_equal(10, Time.at("0.00000001".to_r).nsec)
+ assert_equal(1, Time.at("0.000000001".to_r).nsec)
+ assert_equal(100000, Time.at(0.1).usec)
+ assert_equal(10000, Time.at(0.01).usec)
+ assert_equal(1000, Time.at(0.001).usec)
+ assert_equal(100, Time.at(0.0001).usec)
+ assert_equal(10, Time.at(0.00001).usec)
+ assert_equal(3, Time.at(0.000003).usec)
+ assert_equal(100000000, Time.at(0.1).nsec)
+ assert_equal(10000000, Time.at(0.01).nsec)
+ assert_equal(1000000, Time.at(0.001).nsec)
+ assert_equal(100000, Time.at(0.0001).nsec)
+ assert_equal(10000, Time.at(0.00001).nsec)
+ assert_equal(3000, Time.at(0.000003).nsec)
+ assert_equal(200, Time.at(0.0000002r).nsec)
+ assert_equal(199, Time.at(0.0000002).nsec)
+ assert_equal(10, Time.at(0.00000001).nsec)
+ assert_equal(1, Time.at(0.000000001).nsec)
+
+ assert_equal(0, Time.at(1e-10).nsec)
+ assert_equal(0, Time.at(4e-10).nsec)
+ assert_equal(0, Time.at(6e-10).nsec)
+ assert_equal(1, Time.at(14e-10).nsec)
+ assert_equal(1, Time.at(16e-10).nsec)
+ if negative_time_t?
+ assert_equal(999999999, Time.at(-1e-10).nsec)
+ assert_equal(999999999, Time.at(-4e-10).nsec)
+ assert_equal(999999999, Time.at(-6e-10).nsec)
+ assert_equal(999999998, Time.at(-14e-10).nsec)
+ assert_equal(999999998, Time.at(-16e-10).nsec)
+ end
+
+ t = Time.at(-4611686019).utc
+ assert_equal(1823, t.year)
+
+ t = Time.at(4611686018, 999999).utc
+ assert_equal(2116, t.year)
+ assert_equal("0.999999".to_r, t.subsec)
+
+ t = Time.at(2**40 + "1/3".to_r, 9999999999999).utc
+ assert_equal(36812, t.year)
+
+ t = Time.at(-0x3fff_ffff_ffff_ffff)
+ assert_equal(-146138510344, t.year)
+ t = Time.at(-0x4000_0000_0000_0000)
+ assert_equal(-146138510344, t.year)
+ t = Time.at(-0x4000_0000_0000_0001)
+ assert_equal(-146138510344, t.year)
+ t = Time.at(-0x5000_0000_0000_0001)
+ assert_equal(-182673138422, t.year)
+ t = Time.at(-0x6000_0000_0000_0000)
+ assert_equal(-219207766501, t.year)
+
+ t = Time.at(0).utc
+ assert_equal([1970,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-86400).utc
+ assert_equal([1969,12,31, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-86400 * (400 * 365 + 97)).utc
+ assert_equal([1970-400,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-86400 * (400 * 365 + 97)*1000).utc
+ assert_equal([1970-400*1000,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-86400 * (400 * 365 + 97)*2421).utc
+ assert_equal([1970-400*2421,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-86400 * (400 * 365 + 97)*1000000).utc
+ assert_equal([1970-400*1000000,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+
+ t = Time.at(-30613683110400).utc
+ assert_equal([-968139,1,1, 0,0,0], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ t = Time.at(-30613683110401).utc
+ assert_equal([-968140,12,31, 23,59,59], [t.year, t.mon, t.day, t.hour, t.min, t.sec])
+ end
+
+ def test_at2
+ assert_equal(100, Time.at(0, 0.1).nsec)
+ assert_equal(10, Time.at(0, 0.01).nsec)
+ assert_equal(1, Time.at(0, 0.001).nsec)
+ end
+
+ def test_at_rational
+ assert_equal(1, Time.at(Rational(1,1) / 1000000000).nsec)
+ assert_equal(1, Time.at(1167609600 + Rational(1,1) / 1000000000).nsec)
+ end
+
+ def test_utc_subsecond
+ assert_equal(500000, Time.utc(2007,1,1,0,0,1.5).usec)
+ assert_equal(100000, Time.utc(2007,1,1,0,0,Rational(11,10)).usec)
+ end
+
+ def test_eq_nsec
+ assert_equal(Time.at(0, 0.123), Time.at(0, 0.123))
+ assert_not_equal(Time.at(0, 0.123), Time.at(0, 0.124))
+ end
+
+ def assert_marshal_roundtrip(t)
+ iv_names = t.instance_variables
+ iv_vals1 = iv_names.map {|n| t.instance_variable_get n }
+ m = Marshal.dump(t)
+ t2 = Marshal.load(m)
+ iv_vals2 = iv_names.map {|n| t2.instance_variable_get n }
+ assert_equal(t, t2)
+ assert_equal(iv_vals1, iv_vals2)
+ t2
+ end
+
+ def test_marshal_nsec
+ assert_marshal_roundtrip(Time.at(0, 0.123))
+ assert_marshal_roundtrip(Time.at(0, 0.120))
+ end
+
+ def test_marshal_nsec_191
+ # generated by ruby 1.9.1p376
+ m = "\x04\bIu:\tTime\r \x80\x11\x80@\xE2\x01\x00\x06:\rsubmicro\"\ax\x90"
+ t = Marshal.load(m)
+ assert_equal(Time.at(Rational(123456789, 1000000000)), t, "[ruby-dev:40133]")
+ end
+
+ def test_marshal_rational
+ assert_marshal_roundtrip(Time.at(0, Rational(1,3)))
+ assert_not_match(/Rational/, Marshal.dump(Time.at(0, Rational(1,3))))
+ end
+
+ def test_marshal_ivar
+ t = Time.at(123456789, 987654.321)
+ t.instance_eval { @var = 135 }
+ assert_marshal_roundtrip(t)
+ assert_marshal_roundtrip(Marshal.load(Marshal.dump(t)))
+ end
+
+ def test_marshal_timezone
+ bug = '[ruby-dev:40063]'
+
+ t1 = Time.gm(2000)
+ m = Marshal.dump(t1.getlocal("-02:00"))
+ t2 = Marshal.load(m)
+ assert_equal(t1, t2)
+ assert_equal(-7200, t2.utc_offset, bug)
+ m = Marshal.dump(t1.getlocal("+08:15"))
+ t2 = Marshal.load(m)
+ assert_equal(t1, t2)
+ assert_equal(29700, t2.utc_offset, bug)
+ end
+
+ def test_marshal_zone
+ t = Time.utc(2013, 2, 24)
+ assert_equal('UTC', t.zone)
+ assert_equal('UTC', Marshal.load(Marshal.dump(t)).zone)
+
+ in_timezone('JST-9') do
+ t = Time.local(2013, 2, 24)
+ assert_equal('JST', Time.local(2013, 2, 24).zone)
+ assert_equal('JST', Marshal.load(Marshal.dump(t)).zone)
+ end
+ end
+
+ def test_marshal_zone_gc
+ assert_separately(%w(--disable-gems), <<-'end;', timeout: 30)
+ ENV["TZ"] = "JST-9"
+ s = Marshal.dump(Time.now)
+ t = Marshal.load(s)
+ n = 0
+ done = 100000
+ while t.zone.dup == "JST" && n < done
+ n += 1
+ end
+ assert_equal done, n, "Bug #9652"
+ assert_equal "JST", t.zone, "Bug #9652"
+ end;
+ end
+
+ def test_marshal_to_s
+ t1 = Time.new(2011,11,8, 0,42,25, 9*3600)
+ t2 = Time.at(Marshal.load(Marshal.dump(t1)))
+ assert_equal("2011-11-08 00:42:25 +0900", t2.to_s,
+ "[ruby-dev:44827] [Bug #5586]")
+ end
+
+ Bug8795 = '[ruby-core:56648] [Bug #8795]'
+
+ def test_marshal_broken_offset
+ data = "\x04\bIu:\tTime\r\xEFF\x1C\x80\x00\x00\x00\x00\x06:\voffset"
+ t1 = t2 = nil
+ in_timezone('UTC') do
+ assert_nothing_raised(TypeError, ArgumentError, Bug8795) do
+ t1 = Marshal.load(data + "T")
+ t2 = Marshal.load(data + "\"\x0ebadoffset")
+ end
+ assert_equal(0, t1.utc_offset)
+ assert_equal(0, t2.utc_offset)
+ end
+ end
+
+ def test_marshal_broken_zone
+ data = "\x04\bIu:\tTime\r\xEFF\x1C\x80\x00\x00\x00\x00\x06:\tzone"
+ t1 = t2 = nil
+ in_timezone('UTC') do
+ assert_nothing_raised(TypeError, ArgumentError, Bug8795) do
+ t1 = Marshal.load(data + "T")
+ t2 = Marshal.load(data + "\"\b\0\0\0")
+ end
+ assert_equal('UTC', t1.zone)
+ assert_equal('UTC', t2.zone)
+ end
+ end
+
+ def test_at3
+ t2000 = get_t2000
+ assert_equal(t2000, Time.at(t2000))
+# assert_raise(RangeError) do
+# Time.at(2**31-1, 1_000_000)
+# Time.at(2**63-1, 1_000_000)
+# end
+# assert_raise(RangeError) do
+# Time.at(-2**31, -1_000_000)
+# Time.at(-2**63, -1_000_000)
+# end
+ end
+
+ def test_utc_or_local
+ t2000 = get_t2000
+ assert_equal(t2000, Time.gm(2000))
+ assert_equal(t2000, Time.gm(0, 0, 0, 1, 1, 2000, :foo, :bar, false, :baz))
+ assert_equal(t2000, Time.gm(2000, "jan"))
+ assert_equal(t2000, Time.gm(2000, "1"))
+ assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, 0, 0))
+ assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, 0, "0"))
+ assert_equal(t2000, Time.gm(2000, 1, 1, 0, 0, "0", :foo, :foo))
+ assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -1, :foo, :foo) }
+ assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -1.0, :foo, :foo) }
+ assert_raise(RangeError) do
+ Time.gm(2000, 1, 1, 0, 0, 10_000_000_000_000_000_001.0, :foo, :foo)
+ end
+ assert_raise(ArgumentError) { Time.gm(2000, 1, 1, 0, 0, -(2**31), :foo, :foo) }
+ o = Object.new
+ def o.to_int; 0; end
+ def o.to_r; nil; end
+ assert_raise(TypeError) { Time.gm(2000, 1, 1, 0, 0, o, :foo, :foo) }
+ def o.to_r; ""; end
+ assert_raise(TypeError) { Time.gm(2000, 1, 1, 0, 0, o, :foo, :foo) }
+ def o.to_r; Rational(11); end
+ assert_equal(11, Time.gm(2000, 1, 1, 0, 0, o).sec)
+ o = Object.new
+ def o.to_int; 10; end
+ assert_equal(10, Time.gm(2000, 1, 1, 0, 0, o).sec)
+ assert_raise(ArgumentError) { Time.gm(2000, 13) }
+
+ t = Time.local(2000)
+ assert_equal(t.gmt_offset, t2000 - t)
+
+ assert_equal(-4427700000, Time.utc(-4427700000,12,1).year)
+ assert_equal(-2**30+10, Time.utc(-2**30+10,1,1).year)
+ end
+
+ def test_time_interval
+ m = Mutex.new.lock
+ assert_nothing_raised {
+ Timeout.timeout(10) {
+ m.sleep(0)
+ }
+ }
+ assert_raise(ArgumentError) { m.sleep(-1) }
+ end
+
+ def test_to_f
+ t2000 = Time.at(946684800).gmtime
+ assert_equal(946684800.0, t2000.to_f)
+ end
+
+ def test_to_f_accuracy
+ # https://bugs.ruby-lang.org/issues/10135#note-1
+ f = 1381089302.195
+ assert_equal(f, Time.at(f).to_f, "[ruby-core:64373] [Bug #10135] note-1")
+ end
+
+ def test_cmp
+ t2000 = get_t2000
+ assert_equal(-1, t2000 <=> Time.gm(2001))
+ assert_equal(1, t2000 <=> Time.gm(1999))
+ assert_nil(t2000 <=> 0)
+ end
+
+ def test_eql
+ t2000 = get_t2000
+ assert_operator(t2000, :eql?, t2000)
+ assert_not_operator(t2000, :eql?, Time.gm(2001))
+ end
+
+ def test_utc_p
+ assert_predicate(Time.gm(2000), :gmt?)
+ assert_not_predicate(Time.local(2000), :gmt?)
+ assert_not_predicate(Time.at(0), :gmt?)
+ end
+
+ def test_hash
+ t2000 = get_t2000
+ assert_kind_of(Integer, t2000.hash)
+ end
+
+ def test_reinitialize
+ bug8099 = '[ruby-core:53436] [Bug #8099]'
+ t2000 = get_t2000
+ assert_raise(TypeError, bug8099) {
+ t2000.send(:initialize, 2013, 03, 14)
+ }
+ assert_equal(get_t2000, t2000, bug8099)
+ end
+
+ def test_init_copy
+ t2000 = get_t2000
+ assert_equal(t2000, t2000.dup)
+ assert_raise(TypeError) do
+ t2000.instance_eval { initialize_copy(nil) }
+ end
+ end
+
+ def test_localtime_gmtime
+ assert_nothing_raised do
+ t = Time.gm(2000)
+ assert_predicate(t, :gmt?)
+ t.localtime
+ assert_not_predicate(t, :gmt?)
+ t.localtime
+ assert_not_predicate(t, :gmt?)
+ t.gmtime
+ assert_predicate(t, :gmt?)
+ t.gmtime
+ assert_predicate(t, :gmt?)
+ end
+
+ t1 = Time.gm(2000)
+ t2 = t1.getlocal
+ assert_equal(t1, t2)
+ t3 = t1.getlocal("-02:00")
+ assert_equal(t1, t3)
+ assert_equal(-7200, t3.utc_offset)
+ assert_equal([1999, 12, 31, 22, 0, 0], [t3.year, t3.mon, t3.mday, t3.hour, t3.min, t3.sec])
+ t1.localtime
+ assert_equal(t1, t2)
+ assert_equal(t1.gmt?, t2.gmt?)
+ assert_equal(t1, t3)
+
+ t1 = Time.local(2000)
+ t2 = t1.getgm
+ assert_equal(t1, t2)
+ t3 = t1.getlocal("-02:00")
+ assert_equal(t1, t3)
+ assert_equal(-7200, t3.utc_offset)
+ t1.gmtime
+ assert_equal(t1, t2)
+ assert_equal(t1.gmt?, t2.gmt?)
+ assert_equal(t1, t3)
+ end
+
+ def test_asctime
+ t2000 = get_t2000
+ assert_equal("Sat Jan 1 00:00:00 2000", t2000.asctime)
+ assert_equal(Encoding::US_ASCII, t2000.asctime.encoding)
+ assert_kind_of(String, Time.at(0).asctime)
+ end
+
+ def test_to_s
+ t2000 = get_t2000
+ assert_equal("2000-01-01 00:00:00 UTC", t2000.to_s)
+ assert_equal(Encoding::US_ASCII, t2000.to_s.encoding)
+ assert_kind_of(String, Time.at(946684800).getlocal.to_s)
+ assert_equal(Time.at(946684800).getlocal.to_s, Time.at(946684800).to_s)
+ end
+
+ def assert_zone_encoding(time)
+ zone = time.zone
+ assert_predicate(zone, :valid_encoding?)
+ if zone.ascii_only?
+ assert_equal(Encoding::US_ASCII, zone.encoding)
+ else
+ enc = Encoding.default_internal || Encoding.find('locale')
+ assert_equal(enc, zone.encoding)
+ end
+ end
+
+ def test_zone
+ assert_zone_encoding Time.now
+ end
+
+ def test_plus_minus_succ
+ t2000 = get_t2000
+ # assert_raise(RangeError) { t2000 + 10000000000 }
+ # assert_raise(RangeError) t2000 - 3094168449 }
+ # assert_raise(RangeError) { t2000 + 1200798848 }
+ assert_raise(TypeError) { t2000 + Time.now }
+ assert_equal(t2000 + 1, t2000.succ)
+ end
+
+ def test_plus_type
+ t0 = Time.utc(2000,1,1)
+ n0 = t0.to_i
+ n1 = n0+1
+ t1 = Time.at(n1)
+ assert_equal(t1, t0 + 1)
+ assert_equal(t1, t0 + 1.0)
+ assert_equal(t1, t0 + Rational(1,1))
+ assert_equal(t1, t0 + SimpleDelegator.new(1))
+ assert_equal(t1, t0 + SimpleDelegator.new(1.0))
+ assert_equal(t1, t0 + SimpleDelegator.new(Rational(1,1)))
+ assert_raise(TypeError) { t0 + nil }
+ assert_raise(TypeError) { t0 + "1" }
+ assert_raise(TypeError) { t0 + SimpleDelegator.new("1") }
+ assert_equal(0.5, (t0 + 1.5).subsec)
+ assert_equal(Rational(1,3), (t0 + Rational(4,3)).subsec)
+ assert_equal(0.5, (t0 + SimpleDelegator.new(1.5)).subsec)
+ assert_equal(Rational(1,3), (t0 + SimpleDelegator.new(Rational(4,3))).subsec)
+ end
+
+ def test_minus
+ t = Time.at(-4611686018).utc - 100
+ assert_equal(1823, t.year)
+ end
+
+ def test_readers
+ t2000 = get_t2000
+ assert_equal(0, t2000.sec)
+ assert_equal(0, t2000.min)
+ assert_equal(0, t2000.hour)
+ assert_equal(1, t2000.mday)
+ assert_equal(1, t2000.mon)
+ assert_equal(2000, t2000.year)
+ assert_equal(6, t2000.wday)
+ assert_equal(1, t2000.yday)
+ assert_equal(false, t2000.isdst)
+ assert_equal("UTC", t2000.zone)
+ assert_zone_encoding(t2000)
+ assert_equal(0, t2000.gmt_offset)
+ assert_not_predicate(t2000, :sunday?)
+ assert_not_predicate(t2000, :monday?)
+ assert_not_predicate(t2000, :tuesday?)
+ assert_not_predicate(t2000, :wednesday?)
+ assert_not_predicate(t2000, :thursday?)
+ assert_not_predicate(t2000, :friday?)
+ assert_predicate(t2000, :saturday?)
+ assert_equal([0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], t2000.to_a)
+
+ t = Time.at(946684800).getlocal
+ assert_equal(t.sec, Time.at(946684800).sec)
+ assert_equal(t.min, Time.at(946684800).min)
+ assert_equal(t.hour, Time.at(946684800).hour)
+ assert_equal(t.mday, Time.at(946684800).mday)
+ assert_equal(t.mon, Time.at(946684800).mon)
+ assert_equal(t.year, Time.at(946684800).year)
+ assert_equal(t.wday, Time.at(946684800).wday)
+ assert_equal(t.yday, Time.at(946684800).yday)
+ assert_equal(t.isdst, Time.at(946684800).isdst)
+ assert_equal(t.zone, Time.at(946684800).zone)
+ assert_zone_encoding(Time.at(946684800))
+ assert_equal(t.gmt_offset, Time.at(946684800).gmt_offset)
+ assert_equal(t.sunday?, Time.at(946684800).sunday?)
+ assert_equal(t.monday?, Time.at(946684800).monday?)
+ assert_equal(t.tuesday?, Time.at(946684800).tuesday?)
+ assert_equal(t.wednesday?, Time.at(946684800).wednesday?)
+ assert_equal(t.thursday?, Time.at(946684800).thursday?)
+ assert_equal(t.friday?, Time.at(946684800).friday?)
+ assert_equal(t.saturday?, Time.at(946684800).saturday?)
+ assert_equal(t.to_a, Time.at(946684800).to_a)
+ end
+
+ def test_strftime
+ t2000 = get_t2000
+ t = Time.at(946684800).getlocal
+ assert_equal("Sat", t2000.strftime("%a"))
+ assert_equal("Saturday", t2000.strftime("%A"))
+ assert_equal("Jan", t2000.strftime("%b"))
+ assert_equal("January", t2000.strftime("%B"))
+ assert_kind_of(String, t2000.strftime("%c"))
+ assert_equal("01", t2000.strftime("%d"))
+ assert_equal("00", t2000.strftime("%H"))
+ assert_equal("12", t2000.strftime("%I"))
+ assert_equal("001", t2000.strftime("%j"))
+ assert_equal("01", t2000.strftime("%m"))
+ assert_equal("00", t2000.strftime("%M"))
+ assert_equal("AM", t2000.strftime("%p"))
+ assert_equal("00", t2000.strftime("%S"))
+ assert_equal("00", t2000.strftime("%U"))
+ assert_equal("00", t2000.strftime("%W"))
+ assert_equal("6", t2000.strftime("%w"))
+ assert_equal("01/01/00", t2000.strftime("%x"))
+ assert_equal("00:00:00", t2000.strftime("%X"))
+ assert_equal("00", t2000.strftime("%y"))
+ assert_equal("2000", t2000.strftime("%Y"))
+ assert_equal("UTC", t2000.strftime("%Z"))
+ assert_equal("%", t2000.strftime("%%"))
+ assert_equal("0", t2000.strftime("%-S"))
+
+ assert_equal("", t2000.strftime(""))
+ assert_equal("foo\0bar\x0000\x0000\x0000", t2000.strftime("foo\0bar\0%H\0%M\0%S"))
+ assert_equal("foo" * 1000, t2000.strftime("foo" * 1000))
+
+ t = Time.mktime(2000, 1, 1)
+ assert_equal("Sat", t.strftime("%a"))
+ end
+
+ def test_strftime_subsec
+ t = Time.at(946684800, 123456.789)
+ assert_equal("123", t.strftime("%3N"))
+ assert_equal("123456", t.strftime("%6N"))
+ assert_equal("123456789", t.strftime("%9N"))
+ assert_equal("1234567890", t.strftime("%10N"))
+ assert_equal("123456789", t.strftime("%0N"))
+ end
+
+ def test_strftime_sec
+ t = get_t2000.getlocal
+ assert_equal("000", t.strftime("%3S"))
+ end
+
+ def test_strftime_seconds_from_epoch
+ t = Time.at(946684800, 123456.789)
+ assert_equal("946684800", t.strftime("%s"))
+ assert_equal("946684800", t.utc.strftime("%s"))
+ end
+
+ def test_strftime_zone
+ t = Time.mktime(2001, 10, 1)
+ assert_equal("2001-10-01", t.strftime("%F"))
+ assert_equal(Encoding::UTF_8, t.strftime("\u3042%Z").encoding)
+ assert_equal(true, t.strftime("\u3042%Z").valid_encoding?)
+ end
+
+ def test_strftime_flags
+ t = Time.mktime(2001, 10, 1, 2, 0, 0)
+ assert_equal("01", t.strftime("%d"))
+ assert_equal("01", t.strftime("%0d"))
+ assert_equal(" 1", t.strftime("%_d"))
+ assert_equal(" 1", t.strftime("%e"))
+ assert_equal("01", t.strftime("%0e"))
+ assert_equal(" 1", t.strftime("%_e"))
+ assert_equal("AM", t.strftime("%p"))
+ assert_equal("am", t.strftime("%#p"))
+ assert_equal("am", t.strftime("%P"))
+ assert_equal("AM", t.strftime("%#P"))
+ assert_equal("02", t.strftime("%H"))
+ assert_equal("02", t.strftime("%0H"))
+ assert_equal(" 2", t.strftime("%_H"))
+ assert_equal("02", t.strftime("%I"))
+ assert_equal("02", t.strftime("%0I"))
+ assert_equal(" 2", t.strftime("%_I"))
+ assert_equal(" 2", t.strftime("%k"))
+ assert_equal("02", t.strftime("%0k"))
+ assert_equal(" 2", t.strftime("%_k"))
+ assert_equal(" 2", t.strftime("%l"))
+ assert_equal("02", t.strftime("%0l"))
+ assert_equal(" 2", t.strftime("%_l"))
+ t = Time.mktime(2001, 10, 1, 14, 0, 0)
+ assert_equal("PM", t.strftime("%p"))
+ assert_equal("pm", t.strftime("%#p"))
+ assert_equal("pm", t.strftime("%P"))
+ assert_equal("PM", t.strftime("%#P"))
+ assert_equal("14", t.strftime("%H"))
+ assert_equal("14", t.strftime("%0H"))
+ assert_equal("14", t.strftime("%_H"))
+ assert_equal("02", t.strftime("%I"))
+ assert_equal("02", t.strftime("%0I"))
+ assert_equal(" 2", t.strftime("%_I"))
+ assert_equal("14", t.strftime("%k"))
+ assert_equal("14", t.strftime("%0k"))
+ assert_equal("14", t.strftime("%_k"))
+ assert_equal(" 2", t.strftime("%l"))
+ assert_equal("02", t.strftime("%0l"))
+ assert_equal(" 2", t.strftime("%_l"))
+ end
+
+ def test_strftime_invalid_flags
+ t = Time.mktime(2001, 10, 1, 2, 0, 0)
+ assert_equal("%4^p", t.strftime("%4^p"), 'prec after flag')
+ end
+
+ def test_strftime_year
+ t = Time.utc(1,1,4)
+ assert_equal("0001", t.strftime("%Y"))
+ assert_equal("0001", t.strftime("%G"))
+
+ t = Time.utc(0,1,4)
+ assert_equal("0000", t.strftime("%Y"))
+ assert_equal("0000", t.strftime("%G"))
+
+ t = Time.utc(-1,1,4)
+ assert_equal("-0001", t.strftime("%Y"))
+ assert_equal("-0001", t.strftime("%G"))
+ end
+
+ def test_strftime_weeknum
+ # [ruby-dev:37155]
+ t = Time.mktime(1970, 1, 18)
+ assert_equal("0", t.strftime("%w"))
+ assert_equal("7", t.strftime("%u"))
+ end
+
+ def test_strftime_ctrlchar
+ # [ruby-dev:37160]
+ t2000 = get_t2000
+ assert_equal("\t", t2000.strftime("%t"))
+ assert_equal("\t", t2000.strftime("%0t"))
+ assert_equal("\t", t2000.strftime("%1t"))
+ assert_equal(" \t", t2000.strftime("%3t"))
+ assert_equal("00\t", t2000.strftime("%03t"))
+ assert_equal("\n", t2000.strftime("%n"))
+ assert_equal("\n", t2000.strftime("%0n"))
+ assert_equal("\n", t2000.strftime("%1n"))
+ assert_equal(" \n", t2000.strftime("%3n"))
+ assert_equal("00\n", t2000.strftime("%03n"))
+ end
+
+ def test_strftime_weekflags
+ # [ruby-dev:37162]
+ t2000 = get_t2000
+ assert_equal("SAT", t2000.strftime("%#a"))
+ assert_equal("SATURDAY", t2000.strftime("%#A"))
+ assert_equal("JAN", t2000.strftime("%#b"))
+ assert_equal("JANUARY", t2000.strftime("%#B"))
+ assert_equal("JAN", t2000.strftime("%#h"))
+ assert_equal("FRIDAY", Time.local(2008,1,4).strftime("%#A"))
+ end
+
+ def test_strftime_rational
+ t = Time.utc(2000,3,14, 6,53,"58.979323846".to_r) # Pi Day
+ assert_equal("03/14/2000 6:53:58.97932384600000000000000000000",
+ t.strftime("%m/%d/%Y %l:%M:%S.%29N"))
+ assert_equal("03/14/2000 6:53:58.9793238460",
+ t.strftime("%m/%d/%Y %l:%M:%S.%10N"))
+ assert_equal("03/14/2000 6:53:58.979323846",
+ t.strftime("%m/%d/%Y %l:%M:%S.%9N"))
+ assert_equal("03/14/2000 6:53:58.97932384",
+ t.strftime("%m/%d/%Y %l:%M:%S.%8N"))
+
+ t = Time.utc(1592,3,14, 6,53,"58.97932384626433832795028841971".to_r) # Pi Day
+ assert_equal("03/14/1592 6:53:58.97932384626433832795028841971",
+ t.strftime("%m/%d/%Y %l:%M:%S.%29N"))
+ assert_equal("03/14/1592 6:53:58.9793238462",
+ t.strftime("%m/%d/%Y %l:%M:%S.%10N"))
+ assert_equal("03/14/1592 6:53:58.979323846",
+ t.strftime("%m/%d/%Y %l:%M:%S.%9N"))
+ assert_equal("03/14/1592 6:53:58.97932384",
+ t.strftime("%m/%d/%Y %l:%M:%S.%8N"))
+ end
+
+ def test_strftime_far_future
+ # [ruby-core:33985]
+ assert_equal("3000000000", Time.at(3000000000).strftime('%s'))
+ end
+
+ def test_strftime_too_wide
+ bug4457 = '[ruby-dev:43285]'
+ assert_raise(Errno::ERANGE, bug4457) {Time.now.strftime('%8192z')}
+ end
+
+ def test_strfimte_zoneoffset
+ t2000 = get_t2000
+ t = t2000.getlocal("+09:00:00")
+ assert_equal("+0900", t.strftime("%z"))
+ assert_equal("+09:00", t.strftime("%:z"))
+ assert_equal("+09:00:00", t.strftime("%::z"))
+ assert_equal("+09", t.strftime("%:::z"))
+
+ t = t2000.getlocal("+09:00:01")
+ assert_equal("+0900", t.strftime("%z"))
+ assert_equal("+09:00", t.strftime("%:z"))
+ assert_equal("+09:00:01", t.strftime("%::z"))
+ assert_equal("+09:00:01", t.strftime("%:::z"))
+ end
+
+ def test_strftime_padding
+ bug4458 = '[ruby-dev:43287]'
+ t2000 = get_t2000
+ t = t2000.getlocal("+09:00")
+ assert_equal("+0900", t.strftime("%z"))
+ assert_equal("+09:00", t.strftime("%:z"))
+ assert_equal(" +900", t.strftime("%_10z"), bug4458)
+ assert_equal("+000000900", t.strftime("%10z"), bug4458)
+ assert_equal(" +9:00", t.strftime("%_10:z"), bug4458)
+ assert_equal("+000009:00", t.strftime("%10:z"), bug4458)
+ assert_equal(" +9:00:00", t.strftime("%_10::z"), bug4458)
+ assert_equal("+009:00:00", t.strftime("%10::z"), bug4458)
+ assert_equal("+000000009", t.strftime("%10:::z"))
+ t = t2000.getlocal("-05:00")
+ assert_equal("-0500", t.strftime("%z"))
+ assert_equal("-05:00", t.strftime("%:z"))
+ assert_equal(" -500", t.strftime("%_10z"), bug4458)
+ assert_equal("-000000500", t.strftime("%10z"), bug4458)
+ assert_equal(" -5:00", t.strftime("%_10:z"), bug4458)
+ assert_equal("-000005:00", t.strftime("%10:z"), bug4458)
+ assert_equal(" -5:00:00", t.strftime("%_10::z"), bug4458)
+ assert_equal("-005:00:00", t.strftime("%10::z"), bug4458)
+ assert_equal("-000000005", t.strftime("%10:::z"))
+
+ bug6323 = '[ruby-core:44447]'
+ t = t2000.getlocal("+00:36")
+ assert_equal(" +036", t.strftime("%_10z"), bug6323)
+ assert_equal("+000000036", t.strftime("%10z"), bug6323)
+ assert_equal(" +0:36", t.strftime("%_10:z"), bug6323)
+ assert_equal("+000000:36", t.strftime("%10:z"), bug6323)
+ assert_equal(" +0:36:00", t.strftime("%_10::z"), bug6323)
+ assert_equal("+000:36:00", t.strftime("%10::z"), bug6323)
+ assert_equal("+000000:36", t.strftime("%10:::z"))
+ t = t2000.getlocal("-00:55")
+ assert_equal(" -055", t.strftime("%_10z"), bug6323)
+ assert_equal("-000000055", t.strftime("%10z"), bug6323)
+ assert_equal(" -0:55", t.strftime("%_10:z"), bug6323)
+ assert_equal("-000000:55", t.strftime("%10:z"), bug6323)
+ assert_equal(" -0:55:00", t.strftime("%_10::z"), bug6323)
+ assert_equal("-000:55:00", t.strftime("%10::z"), bug6323)
+ assert_equal("-000000:55", t.strftime("%10:::z"))
+ end
+
+ def test_strftime_invalid_modifier
+ t2000 = get_t2000
+ t = t2000.getlocal("+09:00")
+ assert_equal("%:y", t.strftime("%:y"), 'invalid conversion after : modifier')
+ assert_equal("%:0z", t.strftime("%:0z"), 'flag after : modifier')
+ assert_equal("%:10z", t.strftime("%:10z"), 'prec after : modifier')
+ assert_equal("%Ob", t.strftime("%Ob"), 'invalid conversion after locale modifier')
+ assert_equal("%Eb", t.strftime("%Eb"), 'invalid conversion after locale modifier')
+ assert_equal("%O0y", t.strftime("%O0y"), 'flag after locale modifier')
+ assert_equal("%E0y", t.strftime("%E0y"), 'flag after locale modifier')
+ assert_equal("%O10y", t.strftime("%O10y"), 'prec after locale modifier')
+ assert_equal("%E10y", t.strftime("%E10y"), 'prec after locale modifier')
+ end
+
+ def test_delegate
+ d1 = SimpleDelegator.new(t1 = Time.utc(2000))
+ d2 = SimpleDelegator.new(t2 = Time.utc(2001))
+ assert_equal(-1, t1 <=> t2)
+ assert_equal(1, t2 <=> t1)
+ assert_equal(-1, d1 <=> d2)
+ assert_equal(1, d2 <=> d1)
+ end
+
+ def test_to_r
+ assert_kind_of(Rational, Time.new(2000,1,1,0,0,Rational(4,3)).to_r)
+ assert_kind_of(Rational, Time.utc(1970).to_r)
+ end
+
+ def test_round
+ t = Time.utc(1999,12,31, 23,59,59)
+ t2 = (t+0.4).round
+ assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+ t2 = (t+0.49).round
+ assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+ t2 = (t+0.5).round
+ assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+ t2 = (t+1.4).round
+ assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+ t2 = (t+1.49).round
+ assert_equal([0,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+ t2 = (t+1.5).round
+ assert_equal([1,0,0, 1,1,2000, 6,1,false,"UTC"], t2.to_a)
+ assert_equal(0, t2.subsec)
+
+ t2 = (t+0.123456789).round(4)
+ assert_equal([59,59,23, 31,12,1999, 5,365,false,"UTC"], t2.to_a)
+ assert_equal(Rational(1235,10000), t2.subsec)
+
+ off = 0.0
+ 100.times {|i|
+ t2 = (t+off).round(1)
+ assert_equal(Rational(i % 10, 10), t2.subsec)
+ off += 0.1
+ }
+ end
+
+ def test_getlocal_dont_share_eigenclass
+ bug5012 = "[ruby-dev:44071]"
+
+ t0 = Time.now
+ class << t0; end
+ t1 = t0.getlocal
+
+ def t0.m
+ 0
+ end
+
+ assert_raise(NoMethodError, bug5012) { t1.m }
+ end
+
+ def test_sec_str
+ bug6193 = '[ruby-core:43569]'
+ t = nil
+ assert_nothing_raised(bug6193) {t = Time.new(2012, 1, 2, 3, 4, "5")}
+ assert_equal(Time.new(2012, 1, 2, 3, 4, 5), t, bug6193)
+ end
+
+ def test_past
+ [
+ [-(1 << 100), 1, 1, 0, 0, 0],
+ [-4000, 1, 1, 0, 0, 0],
+ [-3000, 1, 1, 0, 0, 0],
+ ].each {|year, mon, day, hour, min, sec|
+ t = Time.utc(year, mon, day, hour, min, sec)
+ assert_equal(year, t.year)
+ assert_equal(mon, t.mon)
+ assert_equal(day, t.day)
+ assert_equal(hour, t.hour)
+ assert_equal(min, t.min)
+ assert_equal(sec, t.sec)
+ }
+ end
+
+ def test_1901
+ assert_equal(-0x80000001, Time.utc(1901, 12, 13, 20, 45, 51).tv_sec)
+ [
+ [1901, 12, 13, 20, 45, 50],
+ [1901, 12, 13, 20, 45, 51],
+ [1901, 12, 13, 20, 45, 52], # -0x80000000
+ [1901, 12, 13, 20, 45, 53],
+ ].each {|year, mon, day, hour, min, sec|
+ t = Time.utc(year, mon, day, hour, min, sec)
+ assert_equal(year, t.year)
+ assert_equal(mon, t.mon)
+ assert_equal(day, t.day)
+ assert_equal(hour, t.hour)
+ assert_equal(min, t.min)
+ assert_equal(sec, t.sec)
+ }
+ end
+
+ def test_1970
+ assert_equal(0, Time.utc(1970, 1, 1, 0, 0, 0).tv_sec)
+ [
+ [1969, 12, 31, 23, 59, 59],
+ [1970, 1, 1, 0, 0, 0],
+ [1970, 1, 1, 0, 0, 1],
+ ].each {|year, mon, day, hour, min, sec|
+ t = Time.utc(year, mon, day, hour, min, sec)
+ assert_equal(year, t.year)
+ assert_equal(mon, t.mon)
+ assert_equal(day, t.day)
+ assert_equal(hour, t.hour)
+ assert_equal(min, t.min)
+ assert_equal(sec, t.sec)
+ }
+ end
+
+ def test_2038
+ if no_leap_seconds?
+ assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec)
+ end
+ [
+ [2038, 1, 19, 3, 14, 7],
+ [2038, 1, 19, 3, 14, 8],
+ [2038, 1, 19, 3, 14, 9],
+ [2039, 1, 1, 0, 0, 0],
+ ].each {|year, mon, day, hour, min, sec|
+ t = Time.utc(year, mon, day, hour, min, sec)
+ assert_equal(year, t.year)
+ assert_equal(mon, t.mon)
+ assert_equal(day, t.day)
+ assert_equal(hour, t.hour)
+ assert_equal(min, t.min)
+ assert_equal(sec, t.sec)
+ }
+ end
+
+ def test_future
+ [
+ [3000, 1, 1, 0, 0, 0],
+ [4000, 1, 1, 0, 0, 0],
+ [1 << 100, 1, 1, 0, 0, 0],
+ ].each {|year, mon, day, hour, min, sec|
+ t = Time.utc(year, mon, day, hour, min, sec)
+ assert_equal(year, t.year)
+ assert_equal(mon, t.mon)
+ assert_equal(day, t.day)
+ assert_equal(hour, t.hour)
+ assert_equal(min, t.min)
+ assert_equal(sec, t.sec)
+ }
+ end
+
+ def test_getlocal_nil
+ now = Time.now
+ now2 = nil
+ now3 = nil
+ assert_nothing_raised {
+ now2 = now.getlocal
+ now3 = now.getlocal(nil)
+ }
+ assert_equal now2, now3
+ assert_equal now2.zone, now3.zone
+ end
+end
diff --git a/jni/ruby/test/ruby/test_time_tz.rb b/jni/ruby/test/ruby/test_time_tz.rb
new file mode 100644
index 0000000..fb1ab9b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_time_tz.rb
@@ -0,0 +1,415 @@
+require 'test/unit'
+
+class TestTimeTZ < Test::Unit::TestCase
+ has_right_tz = true
+ has_lisbon_tz = true
+ force_tz_test = ENV["RUBY_FORCE_TIME_TZ_TEST"] == "yes"
+ case RUBY_PLATFORM
+ when /linux/
+ force_tz_test = true
+ when /darwin|freebsd/
+ has_lisbon_tz = false
+ force_tz_test = true
+ end
+
+ if force_tz_test
+ module Util
+ def with_tz(tz)
+ old = ENV["TZ"]
+ begin
+ ENV["TZ"] = tz
+ yield
+ ensure
+ ENV["TZ"] = old
+ end
+ end
+ end
+ else
+ module Util
+ def with_tz(tz)
+ if ENV["TZ"] == tz
+ yield
+ end
+ end
+ end
+ end
+
+ module Util
+ def have_tz_offset?(tz)
+ with_tz(tz) {!Time.now.utc_offset.zero?}
+ end
+
+ def format_gmtoff(gmtoff, colon=false)
+ if gmtoff < 0
+ expected = "-"
+ gmtoff = -gmtoff
+ else
+ expected = "+"
+ end
+ gmtoff /= 60
+ expected << "%02d" % [gmtoff / 60]
+ expected << ":" if colon
+ expected << "%02d" % [gmtoff % 60]
+ expected
+ end
+
+ def format_gmtoff2(gmtoff)
+ if gmtoff < 0
+ expected = "-"
+ gmtoff = -gmtoff
+ else
+ expected = "+"
+ end
+ expected << "%02d:%02d:%02d" % [gmtoff / 3600, gmtoff % 3600 / 60, gmtoff % 60]
+ expected
+ end
+
+ def group_by(e, &block)
+ if e.respond_to? :group_by
+ e.group_by(&block)
+ else
+ h = {}
+ e.each {|o|
+ (h[yield(o)] ||= []) << o
+ }
+ h
+ end
+ end
+
+ end
+
+ include Util
+ extend Util
+
+ has_right_tz &&= have_tz_offset?("right/America/Los_Angeles")
+ has_lisbon_tz &&= have_tz_offset?("Europe/Lisbon")
+
+ def time_to_s(t)
+ t.to_s
+ end
+
+
+ def assert_time_constructor(tz, expected, method, args, message=nil)
+ m = message ? "#{message}\n" : ""
+ m << "TZ=#{tz} Time.#{method}(#{args.map {|arg| arg.inspect }.join(', ')})"
+ real = time_to_s(Time.send(method, *args))
+ assert_equal(expected, real, m)
+ end
+
+ def test_america_los_angeles
+ with_tz(tz="America/Los_Angeles") {
+ assert_time_constructor(tz, "2007-03-11 03:00:00 -0700", :local, [2007,3,11,2,0,0])
+ assert_time_constructor(tz, "2007-03-11 03:59:59 -0700", :local, [2007,3,11,2,59,59])
+ assert_equal("PST", Time.new(0x1_0000_0000_0000_0000, 1).zone)
+ assert_equal("PDT", Time.new(0x1_0000_0000_0000_0000, 8).zone)
+ assert_equal(false, Time.new(0x1_0000_0000_0000_0000, 1).isdst)
+ assert_equal(true, Time.new(0x1_0000_0000_0000_0000, 8).isdst)
+ }
+ end
+
+ def test_america_managua
+ with_tz(tz="America/Managua") {
+ assert_time_constructor(tz, "1993-01-01 01:00:00 -0500", :local, [1993,1,1,0,0,0])
+ assert_time_constructor(tz, "1993-01-01 01:59:59 -0500", :local, [1993,1,1,0,59,59])
+ }
+ end
+
+ def test_asia_singapore
+ with_tz(tz="Asia/Singapore") {
+ assert_time_constructor(tz, "1981-12-31 23:59:59 +0730", :local, [1981,12,31,23,59,59])
+ assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,0,0])
+ assert_time_constructor(tz, "1982-01-01 00:59:59 +0800", :local, [1982,1,1,0,29,59])
+ assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,30,0])
+ }
+ end
+
+ def test_asia_tokyo
+ with_tz(tz="Asia/Tokyo") {
+ assert_time_constructor(tz, "1951-05-06 03:00:00 +1000", :local, [1951,5,6,2,0,0])
+ assert_time_constructor(tz, "1951-05-06 03:59:59 +1000", :local, [1951,5,6,2,59,59])
+ assert_time_constructor(tz, "2010-06-10 06:13:28 +0900", :local, [2010,6,10,6,13,28])
+ }
+ end
+
+ def test_canada_newfoundland
+ with_tz(tz="America/St_Johns") {
+ assert_time_constructor(tz, "2007-11-03 23:00:59 -0230", :new, [2007,11,3,23,0,59,:dst])
+ assert_time_constructor(tz, "2007-11-03 23:01:00 -0230", :new, [2007,11,3,23,1,0,:dst])
+ assert_time_constructor(tz, "2007-11-03 23:59:59 -0230", :new, [2007,11,3,23,59,59,:dst])
+ assert_time_constructor(tz, "2007-11-04 00:00:00 -0230", :new, [2007,11,4,0,0,0,:dst])
+ assert_time_constructor(tz, "2007-11-04 00:00:59 -0230", :new, [2007,11,4,0,0,59,:dst])
+ assert_time_constructor(tz, "2007-11-03 23:01:00 -0330", :new, [2007,11,3,23,1,0,:std])
+ assert_time_constructor(tz, "2007-11-03 23:59:59 -0330", :new, [2007,11,3,23,59,59,:std])
+ assert_time_constructor(tz, "2007-11-04 00:00:59 -0330", :new, [2007,11,4,0,0,59,:std])
+ assert_time_constructor(tz, "2007-11-04 00:01:00 -0330", :new, [2007,11,4,0,1,0,:std])
+ }
+ end
+
+ def test_europe_brussels
+ with_tz(tz="Europe/Brussels") {
+ assert_time_constructor(tz, "1916-04-30 23:59:59 +0100", :local, [1916,4,30,23,59,59])
+ assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1], "[ruby-core:30672]")
+ assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,0,59,59])
+ assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1,1,0,0])
+ assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,1,59,59])
+ }
+ end
+
+ def test_europe_berlin
+ with_tz(tz="Europe/Berlin") {
+ assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [2011,10,30,2,0,0], "[ruby-core:67345] [Bug #10698]")
+ assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [0,0,2,30,10,2011,nil,nil,false,nil])
+ assert_time_constructor(tz, "2011-10-30 02:00:00 +0200", :local, [0,0,2,30,10,2011,nil,nil,true,nil])
+ }
+ end
+
+ def test_europe_lisbon
+ with_tz("Europe/Lisbon") {
+ assert_equal("LMT", Time.new(-0x1_0000_0000_0000_0000).zone)
+ }
+ end if has_lisbon_tz
+
+ def test_europe_moscow
+ with_tz(tz="Europe/Moscow") {
+ assert_time_constructor(tz, "1992-03-29 00:00:00 +0400", :local, [1992,3,28,23,0,0])
+ assert_time_constructor(tz, "1992-03-29 00:59:59 +0400", :local, [1992,3,28,23,59,59])
+ }
+ end
+
+ def test_pacific_kiritimati
+ with_tz(tz="Pacific/Kiritimati") {
+ assert_time_constructor(tz, "1994-12-31 23:59:59 -1000", :local, [1994,12,31,23,59,59])
+ assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,1,0,0,0])
+ assert_time_constructor(tz, "1995-01-02 23:59:59 +1400", :local, [1995,1,1,23,59,59])
+ assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,2,0,0,0])
+ }
+ end
+
+ def test_right_utc
+ with_tz(tz="right/UTC") {
+ assert_time_constructor(tz, "2008-12-31 23:59:59 UTC", :utc, [2008,12,31,23,59,59])
+ assert_time_constructor(tz, "2008-12-31 23:59:60 UTC", :utc, [2008,12,31,23,59,60])
+ assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,24,0,0])
+ assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2009,1,1,0,0,0])
+ }
+ end if has_right_tz
+
+ def test_right_america_los_angeles
+ with_tz(tz="right/America/Los_Angeles") {
+ assert_time_constructor(tz, "2008-12-31 15:59:59 -0800", :local, [2008,12,31,15,59,59])
+ assert_time_constructor(tz, "2008-12-31 15:59:60 -0800", :local, [2008,12,31,15,59,60])
+ assert_time_constructor(tz, "2008-12-31 16:00:00 -0800", :local, [2008,12,31,16,0,0])
+ }
+ end if has_right_tz
+
+ MON2NUM = {
+ "Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6,
+ "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12
+ }
+
+ @testnum = 0
+ def self.gen_test_name(hint)
+ @testnum += 1
+ s = "test_gen_#{@testnum}"
+ s.sub(/gen_/) { "gen" + "_#{hint}_".gsub(/[^0-9A-Za-z]+/, '_') }
+ end
+
+ def self.parse_zdump_line(line)
+ return nil if /\A\#/ =~ line || /\A\s*\z/ =~ line
+ if /\A(\S+)\s+
+ \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+UTC?
+ \s+=\s+
+ \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+\S+
+ \s+isdst=\d+\s+gmtoff=(-?\d+)\n
+ \z/x !~ line
+ raise "unexpected zdump line: #{line.inspect}"
+ end
+ tz, u_mon, u_day, u_hour, u_min, u_sec, u_year,
+ l_mon, l_day, l_hour, l_min, l_sec, l_year, gmtoff = $~.captures
+ u_year = u_year.to_i
+ u_mon = MON2NUM[u_mon]
+ u_day = u_day.to_i
+ u_hour = u_hour.to_i
+ u_min = u_min.to_i
+ u_sec = u_sec.to_i
+ l_year = l_year.to_i
+ l_mon = MON2NUM[l_mon]
+ l_day = l_day.to_i
+ l_hour = l_hour.to_i
+ l_min = l_min.to_i
+ l_sec = l_sec.to_i
+ gmtoff = gmtoff.to_i
+ [tz,
+ [u_year, u_mon, u_day, u_hour, u_min, u_sec],
+ [l_year, l_mon, l_day, l_hour, l_min, l_sec],
+ gmtoff]
+ end
+
+ def self.gen_zdump_test(data)
+ sample = []
+ data.each_line {|line|
+ s = parse_zdump_line(line)
+ sample << s if s
+ }
+ sample.each {|tz, u, l, gmtoff|
+ expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u
+ expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
+ mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})"
+ mesg = "#{mesg_utc}.localtime"
+ define_method(gen_test_name(tz)) {
+ with_tz(tz) {
+ t = nil
+ assert_nothing_raised(mesg) { t = Time.utc(*u) }
+ assert_equal(expected_utc, time_to_s(t), mesg_utc)
+ assert_nothing_raised(mesg) { t.localtime }
+ assert_equal(expected, time_to_s(t), mesg)
+ assert_equal(gmtoff, t.gmtoff)
+ assert_equal(format_gmtoff(gmtoff), t.strftime("%z"))
+ assert_equal(format_gmtoff(gmtoff, true), t.strftime("%:z"))
+ assert_equal(format_gmtoff2(gmtoff), t.strftime("%::z"))
+ assert_equal(Encoding::US_ASCII, t.zone.encoding)
+ }
+ }
+ }
+
+ group_by(sample) {|tz, _, _, _| tz }.each {|tz, a|
+ a.each_with_index {|(_, _, l, gmtoff), i|
+ expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
+ monotonic_to_past = i == 0 || (a[i-1][2] <=> l) < 0
+ monotonic_to_future = i == a.length-1 || (l <=> a[i+1][2]) < 0
+ if monotonic_to_past && monotonic_to_future
+ define_method(gen_test_name(tz)) {
+ with_tz(tz) {
+ assert_time_constructor(tz, expected, :local, l)
+ assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil])
+ assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil])
+ assert_time_constructor(tz, expected, :new, l)
+ assert_time_constructor(tz, expected, :new, l+[:std])
+ assert_time_constructor(tz, expected, :new, l+[:dst])
+ }
+ }
+ elsif monotonic_to_past && !monotonic_to_future
+ define_method(gen_test_name(tz)) {
+ with_tz(tz) {
+ assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil])
+ assert_time_constructor(tz, expected, :new, l+[:dst])
+ }
+ }
+ elsif !monotonic_to_past && monotonic_to_future
+ define_method(gen_test_name(tz)) {
+ with_tz(tz) {
+ assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil])
+ assert_time_constructor(tz, expected, :new, l+[:std])
+ }
+ }
+ else
+ define_method(gen_test_name(tz)) {
+ flunk("time in reverse order: TZ=#{tz} #{expected}")
+ }
+ end
+ }
+ }
+ end
+
+ gen_zdump_test <<'End'
+America/Lima Sun Apr 1 03:59:59 1990 UTC = Sat Mar 31 23:59:59 1990 PEST isdst=1 gmtoff=-14400
+America/Lima Sun Apr 1 04:00:00 1990 UTC = Sat Mar 31 23:00:00 1990 PET isdst=0 gmtoff=-18000
+America/Lima Sat Jan 1 04:59:59 1994 UTC = Fri Dec 31 23:59:59 1993 PET isdst=0 gmtoff=-18000
+America/Lima Sat Jan 1 05:00:00 1994 UTC = Sat Jan 1 01:00:00 1994 PEST isdst=1 gmtoff=-14400
+America/Lima Fri Apr 1 03:59:59 1994 UTC = Thu Mar 31 23:59:59 1994 PEST isdst=1 gmtoff=-14400
+America/Lima Fri Apr 1 04:00:00 1994 UTC = Thu Mar 31 23:00:00 1994 PET isdst=0 gmtoff=-18000
+America/Los_Angeles Sun Apr 2 09:59:59 2006 UTC = Sun Apr 2 01:59:59 2006 PST isdst=0 gmtoff=-28800
+America/Los_Angeles Sun Apr 2 10:00:00 2006 UTC = Sun Apr 2 03:00:00 2006 PDT isdst=1 gmtoff=-25200
+America/Los_Angeles Sun Oct 29 08:59:59 2006 UTC = Sun Oct 29 01:59:59 2006 PDT isdst=1 gmtoff=-25200
+America/Los_Angeles Sun Oct 29 09:00:00 2006 UTC = Sun Oct 29 01:00:00 2006 PST isdst=0 gmtoff=-28800
+America/Los_Angeles Sun Mar 11 09:59:59 2007 UTC = Sun Mar 11 01:59:59 2007 PST isdst=0 gmtoff=-28800
+America/Los_Angeles Sun Mar 11 10:00:00 2007 UTC = Sun Mar 11 03:00:00 2007 PDT isdst=1 gmtoff=-25200
+America/Los_Angeles Sun Nov 4 08:59:59 2007 UTC = Sun Nov 4 01:59:59 2007 PDT isdst=1 gmtoff=-25200
+America/Los_Angeles Sun Nov 4 09:00:00 2007 UTC = Sun Nov 4 01:00:00 2007 PST isdst=0 gmtoff=-28800
+America/Managua Thu Sep 24 04:59:59 1992 UTC = Wed Sep 23 23:59:59 1992 EST isdst=0 gmtoff=-18000
+America/Managua Thu Sep 24 05:00:00 1992 UTC = Wed Sep 23 23:00:00 1992 CST isdst=0 gmtoff=-21600
+America/Managua Fri Jan 1 05:59:59 1993 UTC = Thu Dec 31 23:59:59 1992 CST isdst=0 gmtoff=-21600
+America/Managua Fri Jan 1 06:00:00 1993 UTC = Fri Jan 1 01:00:00 1993 EST isdst=0 gmtoff=-18000
+America/Managua Wed Jan 1 04:59:59 1997 UTC = Tue Dec 31 23:59:59 1996 EST isdst=0 gmtoff=-18000
+America/Managua Wed Jan 1 05:00:00 1997 UTC = Tue Dec 31 23:00:00 1996 CST isdst=0 gmtoff=-21600
+Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0 gmtoff=27000
+Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0 gmtoff=27000
+Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0 gmtoff=28800
+Asia/Tokyo Sat May 5 16:59:59 1951 UTC = Sun May 6 01:59:59 1951 JST isdst=0 gmtoff=32400
+Asia/Tokyo Sat May 5 17:00:00 1951 UTC = Sun May 6 03:00:00 1951 JDT isdst=1 gmtoff=36000
+Asia/Tokyo Fri Sep 7 15:59:59 1951 UTC = Sat Sep 8 01:59:59 1951 JDT isdst=1 gmtoff=36000
+Asia/Tokyo Fri Sep 7 16:00:00 1951 UTC = Sat Sep 8 01:00:00 1951 JST isdst=0 gmtoff=32400
+America/St_Johns Sun Mar 11 03:30:59 2007 UTC = Sun Mar 11 00:00:59 2007 NST isdst=0 gmtoff=-12600
+America/St_Johns Sun Mar 11 03:31:00 2007 UTC = Sun Mar 11 01:01:00 2007 NDT isdst=1 gmtoff=-9000
+America/St_Johns Sun Nov 4 02:30:59 2007 UTC = Sun Nov 4 00:00:59 2007 NDT isdst=1 gmtoff=-9000
+America/St_Johns Sun Nov 4 02:31:00 2007 UTC = Sat Nov 3 23:01:00 2007 NST isdst=0 gmtoff=-12600
+Europe/Brussels Sun Apr 30 22:59:59 1916 UTC = Sun Apr 30 23:59:59 1916 CET isdst=0 gmtoff=3600
+Europe/Brussels Sun Apr 30 23:00:00 1916 UTC = Mon May 1 01:00:00 1916 CEST isdst=1 gmtoff=7200
+Europe/Brussels Sat Sep 30 22:59:59 1916 UTC = Sun Oct 1 00:59:59 1916 CEST isdst=1 gmtoff=7200
+Europe/Brussels Sat Sep 30 23:00:00 1916 UTC = Sun Oct 1 00:00:00 1916 CET isdst=0 gmtoff=3600
+Europe/London Sun Mar 16 01:59:59 1947 UTC = Sun Mar 16 01:59:59 1947 GMT isdst=0 gmtoff=0
+Europe/London Sun Mar 16 02:00:00 1947 UTC = Sun Mar 16 03:00:00 1947 BST isdst=1 gmtoff=3600
+Europe/London Sun Apr 13 00:59:59 1947 UTC = Sun Apr 13 01:59:59 1947 BST isdst=1 gmtoff=3600
+Europe/London Sun Apr 13 01:00:00 1947 UTC = Sun Apr 13 03:00:00 1947 BDST isdst=1 gmtoff=7200
+Europe/London Sun Aug 10 00:59:59 1947 UTC = Sun Aug 10 02:59:59 1947 BDST isdst=1 gmtoff=7200
+Europe/London Sun Aug 10 01:00:00 1947 UTC = Sun Aug 10 02:00:00 1947 BST isdst=1 gmtoff=3600
+Europe/London Sun Nov 2 01:59:59 1947 UTC = Sun Nov 2 02:59:59 1947 BST isdst=1 gmtoff=3600
+Europe/London Sun Nov 2 02:00:00 1947 UTC = Sun Nov 2 02:00:00 1947 GMT isdst=0 gmtoff=0
+Europe/Moscow Sat Jan 18 23:59:59 1992 UTC = Sun Jan 19 01:59:59 1992 MSK isdst=0 gmtoff=7200
+Europe/Moscow Sun Jan 19 00:00:00 1992 UTC = Sun Jan 19 03:00:00 1992 MSK isdst=0 gmtoff=10800
+Europe/Moscow Sat Mar 28 19:59:59 1992 UTC = Sat Mar 28 22:59:59 1992 MSK isdst=0 gmtoff=10800
+Europe/Moscow Sat Mar 28 20:00:00 1992 UTC = Sun Mar 29 00:00:00 1992 MSD isdst=1 gmtoff=14400
+Europe/Moscow Sat Sep 26 18:59:59 1992 UTC = Sat Sep 26 22:59:59 1992 MSD isdst=1 gmtoff=14400
+Europe/Moscow Sat Sep 26 19:00:00 1992 UTC = Sat Sep 26 22:00:00 1992 MSK isdst=0 gmtoff=10800
+Pacific/Kiritimati Sun Jan 1 09:59:59 1995 UTC = Sat Dec 31 23:59:59 1994 LINT isdst=0 gmtoff=-36000
+Pacific/Kiritimati Sun Jan 1 10:00:00 1995 UTC = Mon Jan 2 00:00:00 1995 LINT isdst=0 gmtoff=50400
+End
+ gen_zdump_test <<'End' if has_right_tz
+right/America/Los_Angeles Fri Jun 30 23:59:60 1972 UTC = Fri Jun 30 16:59:60 1972 PDT isdst=1 gmtoff=-25200
+right/America/Los_Angeles Wed Dec 31 23:59:60 2008 UTC = Wed Dec 31 15:59:60 2008 PST isdst=0 gmtoff=-28800
+#right/Asia/Tokyo Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 08:59:60 1972 JST isdst=0 gmtoff=32400
+#right/Asia/Tokyo Sat Dec 31 23:59:60 2005 UTC = Sun Jan 1 08:59:60 2006 JST isdst=0 gmtoff=32400
+right/Europe/Paris Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 00:59:60 1972 CET isdst=0 gmtoff=3600
+right/Europe/Paris Wed Dec 31 23:59:60 2008 UTC = Thu Jan 1 00:59:60 2009 CET isdst=0 gmtoff=3600
+End
+
+ def self.gen_variational_zdump_test(hint, data)
+ sample = []
+ data.each_line {|line|
+ s = parse_zdump_line(line)
+ sample << s if s
+ }
+
+ define_method(gen_test_name(hint)) {
+ results = []
+ sample.each {|tz, u, l, gmtoff|
+ expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u
+ expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
+ mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})"
+ mesg = "#{mesg_utc}.localtime"
+ with_tz(tz) {
+ t = nil
+ assert_nothing_raised(mesg) { t = Time.utc(*u) }
+ assert_equal(expected_utc, time_to_s(t), mesg_utc)
+ assert_nothing_raised(mesg) { t.localtime }
+
+ results << [
+ expected == time_to_s(t),
+ gmtoff == t.gmtoff,
+ format_gmtoff(gmtoff) == t.strftime("%z"),
+ format_gmtoff(gmtoff, true) == t.strftime("%:z"),
+ format_gmtoff2(gmtoff) == t.strftime("%::z")
+ ]
+ }
+ }
+ assert_includes(results, [true, true, true, true, true])
+ }
+ end
+
+ # tzdata-2014g fixed the offset for lisbon from -0:36:32 to -0:36:45.
+ # [ruby-core:65058] [Bug #10245]
+ gen_variational_zdump_test "lisbon", <<'End' if has_lisbon_tz
+Europe/Lisbon Mon Jan 1 00:36:31 1912 UTC = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2192
+Europe/Lisbon Mon Jan 1 00:36:44 1912 UT = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2205
+End
+end
diff --git a/jni/ruby/test/ruby/test_trace.rb b/jni/ruby/test/ruby/test_trace.rb
new file mode 100644
index 0000000..775c458
--- /dev/null
+++ b/jni/ruby/test/ruby/test_trace.rb
@@ -0,0 +1,61 @@
+require 'test/unit'
+
+class TestTrace < Test::Unit::TestCase
+ def test_trace
+ $x = 1234
+ $y = 0
+ trace_var :$x, proc{$y = $x}
+ $x = 40414
+ assert_equal($x, $y)
+
+ untrace_var :$x
+ $x = 19660208
+ assert_not_equal($x, $y)
+
+ trace_var :$x, proc{$x *= 2}
+ $x = 5
+ assert_equal(10, $x)
+
+ untrace_var :$x
+ end
+
+ def test_trace_tainted_proc
+ $x = 1234
+ s = proc { $y = :foo }
+ trace_var :$x, s
+ s.taint
+ $x = 42
+ assert_equal(:foo, $y)
+ ensure
+ untrace_var :$x
+ end
+
+ def test_trace_proc_that_raises_exception
+ $x = 1234
+ trace_var :$x, proc { raise }
+ assert_raise(RuntimeError) { $x = 42 }
+ ensure
+ untrace_var :$x
+ end
+
+ def test_trace_string
+ $x = 1234
+ trace_var :$x, "$y = :bar"
+ $x = 42
+ assert_equal(:bar, $y)
+ ensure
+ untrace_var :$x
+ end
+
+ def test_trace_break
+ bug2722 = '[ruby-core:31783]'
+ a = Object.new.extend(Enumerable)
+ def a.each
+ yield
+ end
+ assert(Thread.start {
+ Thread.current.add_trace_func(proc{})
+ a.any? {true}
+ }.value, bug2722)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_transcode.rb b/jni/ruby/test/ruby/test_transcode.rb
new file mode 100644
index 0000000..4bade11
--- /dev/null
+++ b/jni/ruby/test/ruby/test_transcode.rb
@@ -0,0 +1,2121 @@
+# encoding: ASCII-8BIT # make sure this runs in binary mode
+# some of the comments are in UTF-8
+
+require 'test/unit'
+
+class TestTranscode < Test::Unit::TestCase
+ def test_errors
+ assert_raise(Encoding::ConverterNotFoundError) { 'abc'.encode('foo', 'bar') }
+ assert_raise(Encoding::ConverterNotFoundError) { 'abc'.encode!('foo', 'bar') }
+ assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode('foo') }
+ assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode!('foo') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x80".encode('utf-8','ASCII-8BIT') }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode('utf-8','US-ASCII') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode('utf-8','iso-8859-3') }
+ assert_raise(RuntimeError) { 'hello'.freeze.encode!('iso-8859-1') }
+ assert_raise(RuntimeError) { '\u3053\u3093\u306b\u3061\u306f'.freeze.encode!('iso-8859-1') } # こんにちは
+ end
+
+ def test_arguments
+ assert_equal('abc', 'abc'.force_encoding('utf-8').encode('iso-8859-1'))
+ # check that encoding is kept when no conversion is done
+ assert_equal('abc'.force_encoding('Shift_JIS'), 'abc'.force_encoding('Shift_JIS').encode('Shift_JIS'))
+ assert_equal('abc'.force_encoding('Shift_JIS'), 'abc'.force_encoding('Shift_JIS').encode!('Shift_JIS'))
+ # assert that encoding is correctly set
+ assert_equal("D\u00FCrst".encoding, "D\xFCrst".force_encoding('iso-8859-1').encode('utf-8').encoding)
+ # check that Encoding can be used as parameter
+ assert_equal("D\u00FCrst", "D\xFCrst".encode('utf-8', Encoding.find('ISO-8859-1')))
+ assert_equal("D\u00FCrst", "D\xFCrst".encode(Encoding.find('utf-8'), 'ISO-8859-1'))
+ assert_equal("D\u00FCrst", "D\xFCrst".encode(Encoding.find('utf-8'), Encoding.find('ISO-8859-1')))
+ end
+
+ def test_noargument
+ EnvUtil.with_default_internal(nil) do
+ assert_equal("\u3042".encode, "\u3042")
+ assert_equal("\xE3\x81\x82\x81".force_encoding("utf-8").encode,
+ "\xE3\x81\x82\x81".force_encoding("utf-8"))
+ end
+ EnvUtil.with_default_internal('EUC-JP') do
+ assert_equal("\u3042".encode, "\xA4\xA2".force_encoding('EUC-JP'))
+ assert_equal("\xE3\x81\x82\x81".force_encoding("utf-8").encode,
+ "\xA4\xA2?".force_encoding('EUC-JP'))
+ end
+ end
+
+ def test_length
+ assert_equal("\u20AC"*20, ("\xA4"*20).encode('utf-8', 'iso-8859-15'))
+ assert_equal("\u20AC"*20, ("\xA4"*20).encode!('utf-8', 'iso-8859-15'))
+ assert_equal("\u20AC"*2000, ("\xA4"*2000).encode('utf-8', 'iso-8859-15'))
+ assert_equal("\u20AC"*2000, ("\xA4"*2000).encode!('utf-8', 'iso-8859-15'))
+ assert_equal("\u20AC"*200000, ("\xA4"*200000).encode('utf-8', 'iso-8859-15'))
+ assert_equal("\u20AC"*200000, ("\xA4"*200000).encode!('utf-8', 'iso-8859-15'))
+ end
+
+ def check_both_ways(utf8, raw, encoding)
+ assert_equal(utf8.force_encoding('utf-8'), raw.encode('utf-8', encoding),utf8.dump+raw.dump)
+ assert_equal(raw.force_encoding(encoding), utf8.encode(encoding, 'utf-8'))
+ end
+
+ def check_both_ways2(str1, enc1, str2, enc2)
+ assert_equal(str1.force_encoding(enc1), str2.encode(enc1, enc2))
+ assert_equal(str2.force_encoding(enc2), str1.encode(enc2, enc1))
+ end
+
+ def test_encoding_of_ascii_originating_from_binary
+ binary_string = [0x82, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6c, 0x6f,
+ 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67]
+ class << binary_string
+ # create a copy on write substring that contains
+ # just the ascii characters (i.e. this is...), in JRuby
+ # the underlying string have the same buffer backing
+ # it up, but the offset of the string will be 1 instead
+ # of 0.
+ def make_cow_substring
+ pack('C27').slice(1, 26)
+ end
+ end
+
+ ascii_string = binary_string.make_cow_substring
+ assert_equal("this is a very long string", ascii_string)
+ assert_equal(Encoding::ASCII_8BIT, ascii_string.encoding)
+ utf8_string = nil
+ assert_nothing_raised("JRUBY-6764") do
+ utf8_string = ascii_string.encode(Encoding::UTF_8)
+ end
+ assert_equal("this is a very long string", utf8_string)
+ assert_equal(Encoding::UTF_8, utf8_string.encoding)
+ end
+
+ def test_encodings
+ check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D",
+ "\x82\xdc\x82\xc2\x82\xe0\x82\xc6 \x82\xe4\x82\xab\x82\xd0\x82\xeb", 'shift_jis') # まつもと ゆきひろ
+ check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D",
+ "\xa4\xde\xa4\xc4\xa4\xe2\xa4\xc8 \xa4\xe6\xa4\xad\xa4\xd2\xa4\xed", 'euc-jp')
+ check_both_ways("\u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D",
+ "\xa4\xde\xa4\xc4\xa4\xe2\xa4\xc8 \xa4\xe6\xa4\xad\xa4\xd2\xa4\xed", 'euc-jis-2004')
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\xbe\xbe\xcb\xdc\xb9\xd4\xb9\xb0", 'euc-jp')
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\xbe\xbe\xcb\xdc\xb9\xd4\xb9\xb0", 'euc-jis-2004')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-1') # Dürst
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-2')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-3')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-4')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-9')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-10')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-13')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-14')
+ check_both_ways("D\u00FCrst", "D\xFCrst", 'iso-8859-15')
+ check_both_ways("r\u00E9sum\u00E9", "r\xE9sum\xE9", 'iso-8859-1') # résumé
+ check_both_ways("\u0065\u006C\u0151\u00ED\u0072\u00E1\u0073", "el\xF5\xEDr\xE1s", 'iso-8859-2') # előírás
+ check_both_ways("\u043F\u0435\u0440\u0435\u0432\u043E\u0434",
+ "\xDF\xD5\xE0\xD5\xD2\xDE\xD4", 'iso-8859-5') # перевод
+ check_both_ways("\u0643\u062A\u0628", "\xE3\xCA\xC8", 'iso-8859-6') # كتب
+ check_both_ways("\u65E5\u8A18", "\x93\xFA\x8BL", 'shift_jis') # 日記
+ check_both_ways("\u65E5\u8A18", "\xC6\xFC\xB5\xAD", 'euc-jp')
+ check_both_ways("\u65E5\u8A18", "\xC6\xFC\xB5\xAD", 'euc-jis-2004')
+ check_both_ways("\uC560\uC778\uAD6C\uD568\u0020\u6734\uC9C0\uC778",
+ "\xBE\xD6\xC0\xCE\xB1\xB8\xC7\xD4\x20\xDA\xD3\xC1\xF6\xC0\xCE", 'euc-kr') # 애인구함 朴지인
+ check_both_ways("\uC544\uD58F\uD58F\u0020\uB620\uBC29\uD6BD\uB2D8\u0020\uC0AC\uB791\uD716",
+ "\xBE\xC6\xC1\x64\xC1\x64\x20\x8C\x63\xB9\xE6\xC4\x4F\xB4\xD4\x20\xBB\xE7\xB6\xFB\xC5\x42", 'cp949') # 아햏햏 똠방횽님 사랑휖
+ assert_equal(Encoding::ISO_8859_1, "D\xFCrst".force_encoding('iso-8859-2').encode('iso-8859-1', 'iso-8859-1').encoding)
+ end
+
+ def test_twostep
+ assert_equal("D\xFCrst".force_encoding('iso-8859-2'), "D\xFCrst".encode('iso-8859-2', 'iso-8859-1'))
+ end
+
+ def test_ascii_range
+ encodings = [
+ 'US-ASCII', 'ASCII-8BIT',
+ 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3',
+ 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6',
+ 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
+ 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-13',
+ 'ISO-8859-14', 'ISO-8859-15',
+ 'EUC-JP', 'SHIFT_JIS', 'EUC-KR'
+ ]
+ all_ascii = (0..127).to_a.pack 'C*'
+ encodings.each do |enc|
+ test_start = all_ascii
+ assert_equal(test_start, test_start.encode('UTF-8',enc).encode(enc).force_encoding('ASCII-8BIT'))
+ end
+ end
+
+ def test_all_bytes
+ encodings_8859 = [
+ 'ISO-8859-1', 'ISO-8859-2',
+ #'ISO-8859-3', # not all bytes used
+ 'ISO-8859-4', 'ISO-8859-5',
+ #'ISO-8859-6', # not all bytes used
+ #'ISO-8859-7', # not all bytes used
+ #'ISO-8859-8', # not all bytes used
+ 'ISO-8859-9', 'ISO-8859-10',
+ #'ISO-8859-11', # not all bytes used
+ #'ISO-8859-12', # not available
+ 'ISO-8859-13','ISO-8859-14','ISO-8859-15',
+ #'ISO-8859-16', # not available
+ ]
+ all_bytes = (0..255).to_a.pack 'C*'
+ encodings_8859.each do |enc|
+ test_start = all_bytes
+ assert_equal(test_start, test_start.encode('UTF-8',enc).encode(enc).force_encoding('ASCII-8BIT'))
+ end
+ end
+
+ def test_windows_874
+ check_both_ways("\u20AC", "\x80", 'windows-874') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x84".encode("utf-8", 'windows-874') }
+ check_both_ways("\u2026", "\x85", 'windows-874') # …
+ assert_raise(Encoding::UndefinedConversionError) { "\x86".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-874') }
+ check_both_ways("\u2018", "\x91", 'windows-874') # ‘
+ check_both_ways("\u2014", "\x97", 'windows-874') # —
+ assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-874') }
+ check_both_ways("\u00A0", "\xA0", 'windows-874') # non-breaking space
+ check_both_ways("\u0E0F", "\xAF", 'windows-874') # ฏ
+ check_both_ways("\u0E10", "\xB0", 'windows-874') # ฐ
+ check_both_ways("\u0E1F", "\xBF", 'windows-874') # ฟ
+ check_both_ways("\u0E20", "\xC0", 'windows-874') # ภ
+ check_both_ways("\u0E2F", "\xCF", 'windows-874') # ฯ
+ check_both_ways("\u0E30", "\xD0", 'windows-874') # ะ
+ check_both_ways("\u0E3A", "\xDA", 'windows-874') # ฺ
+ assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'windows-874') }
+ check_both_ways("\u0E3F", "\xDF", 'windows-874') # ฿
+ check_both_ways("\u0E40", "\xE0", 'windows-874') # เ
+ check_both_ways("\u0E4F", "\xEF", 'windows-874') # ๏
+ check_both_ways("\u0E50", "\xF0", 'windows-874') # ๐
+ check_both_ways("\u0E5B", "\xFB", 'windows-874') # ๛
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-874') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-874') }
+ end
+
+ def test_windows_1250
+ check_both_ways("\u20AC", "\x80", 'windows-1250') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1250') }
+ check_both_ways("\u201A", "\x82", 'windows-1250') # ‚
+ assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1250') }
+ check_both_ways("\u201E", "\x84", 'windows-1250') # „
+ check_both_ways("\u2021", "\x87", 'windows-1250') # ‡
+ assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1250') }
+ check_both_ways("\u2030", "\x89", 'windows-1250') # ‰
+ check_both_ways("\u0179", "\x8F", 'windows-1250') # Ź
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1250') }
+ check_both_ways("\u2018", "\x91", 'windows-1250') # ‘
+ check_both_ways("\u2014", "\x97", 'windows-1250') # —
+ assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1250') }
+ check_both_ways("\u2122", "\x99", 'windows-1250') # ™
+ check_both_ways("\u00A0", "\xA0", 'windows-1250') # non-breaking space
+ check_both_ways("\u017B", "\xAF", 'windows-1250') # Ż
+ check_both_ways("\u00B0", "\xB0", 'windows-1250') # °
+ check_both_ways("\u017C", "\xBF", 'windows-1250') # ż
+ check_both_ways("\u0154", "\xC0", 'windows-1250') # Ŕ
+ check_both_ways("\u010E", "\xCF", 'windows-1250') # Ď
+ check_both_ways("\u0110", "\xD0", 'windows-1250') # Đ
+ check_both_ways("\u00DF", "\xDF", 'windows-1250') # ß
+ check_both_ways("\u0155", "\xE0", 'windows-1250') # ŕ
+ check_both_ways("\u010F", "\xEF", 'windows-1250') # ď
+ check_both_ways("\u0111", "\xF0", 'windows-1250') # đ
+ check_both_ways("\u02D9", "\xFF", 'windows-1250') # ˙
+ end
+
+ def test_windows_1251
+ check_both_ways("\u0402", "\x80", 'windows-1251') # Ђ
+ check_both_ways("\u20AC", "\x88", 'windows-1251') # €
+ check_both_ways("\u040F", "\x8F", 'windows-1251') # Џ
+ check_both_ways("\u0452", "\x90", 'windows-1251') # ђ
+ assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1251') }
+ check_both_ways("\u045F", "\x9F", 'windows-1251') # џ
+ check_both_ways("\u00A0", "\xA0", 'windows-1251') # non-breaking space
+ check_both_ways("\u0407", "\xAF", 'windows-1251') # Ї
+ check_both_ways("\u00B0", "\xB0", 'windows-1251') # °
+ check_both_ways("\u0457", "\xBF", 'windows-1251') # ї
+ check_both_ways("\u0410", "\xC0", 'windows-1251') # А
+ check_both_ways("\u041F", "\xCF", 'windows-1251') # П
+ check_both_ways("\u0420", "\xD0", 'windows-1251') # Р
+ check_both_ways("\u042F", "\xDF", 'windows-1251') # Я
+ check_both_ways("\u0430", "\xE0", 'windows-1251') # а
+ check_both_ways("\u043F", "\xEF", 'windows-1251') # п
+ check_both_ways("\u0440", "\xF0", 'windows-1251') # р
+ check_both_ways("\u044F", "\xFF", 'windows-1251') # я
+ end
+
+ def test_windows_1252
+ check_both_ways("\u20AC", "\x80", 'windows-1252') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1252') }
+ check_both_ways("\u201A", "\x82", 'windows-1252') # ‚
+ check_both_ways("\u0152", "\x8C", 'windows-1252') # >Œ
+ assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1252') }
+ check_both_ways("\u017D", "\x8E", 'windows-1252') # Ž
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1252') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1252') }
+ check_both_ways("\u2018", "\x91", 'windows-1252') #‘
+ check_both_ways("\u0153", "\x9C", 'windows-1252') # œ
+ assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1252') }
+ check_both_ways("\u017E", "\x9E", 'windows-1252') # ž
+ check_both_ways("\u00A0", "\xA0", 'windows-1252') # non-breaking space
+ check_both_ways("\u00AF", "\xAF", 'windows-1252') # ¯
+ check_both_ways("\u00B0", "\xB0", 'windows-1252') # °
+ check_both_ways("\u00BF", "\xBF", 'windows-1252') # ¿
+ check_both_ways("\u00C0", "\xC0", 'windows-1252') # À
+ check_both_ways("\u00CF", "\xCF", 'windows-1252') # Ï
+ check_both_ways("\u00D0", "\xD0", 'windows-1252') # Ð
+ check_both_ways("\u00DF", "\xDF", 'windows-1252') # ß
+ check_both_ways("\u00E0", "\xE0", 'windows-1252') # à
+ check_both_ways("\u00EF", "\xEF", 'windows-1252') # ï
+ check_both_ways("\u00F0", "\xF0", 'windows-1252') # ð
+ check_both_ways("\u00FF", "\xFF", 'windows-1252') # ÿ
+ end
+
+ def test_windows_1253
+ check_both_ways("\u20AC", "\x80", 'windows-1253') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u201A", "\x82", 'windows-1253') # ‚
+ check_both_ways("\u2021", "\x87", 'windows-1253') # ‡
+ assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u2030", "\x89", 'windows-1253') # ‰
+ assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u2039", "\x8B", 'windows-1253') # ‹
+ assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1253') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1253') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u2018", "\x91", 'windows-1253') # ‘
+ check_both_ways("\u2014", "\x97", 'windows-1253') # —
+ assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u2122", "\x99", 'windows-1253') # ™
+ assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u203A", "\x9B", 'windows-1253') # ›
+ assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1253') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u00A0", "\xA0", 'windows-1253') # non-breaking space
+ check_both_ways("\u2015", "\xAF", 'windows-1253') # ―
+ check_both_ways("\u00B0", "\xB0", 'windows-1253') # °
+ check_both_ways("\u038F", "\xBF", 'windows-1253') # Ώ
+ check_both_ways("\u0390", "\xC0", 'windows-1253') # ΐ
+ check_both_ways("\u039F", "\xCF", 'windows-1253') # Ο
+ check_both_ways("\u03A0", "\xD0", 'windows-1253') # Π
+ check_both_ways("\u03A1", "\xD1", 'windows-1253') # Ρ
+ assert_raise(Encoding::UndefinedConversionError) { "\xD2".encode("utf-8", 'windows-1253') }
+ check_both_ways("\u03A3", "\xD3", 'windows-1253') # Σ
+ check_both_ways("\u03AF", "\xDF", 'windows-1253') # ί
+ check_both_ways("\u03B0", "\xE0", 'windows-1253') # ΰ
+ check_both_ways("\u03BF", "\xEF", 'windows-1253') # ο
+ check_both_ways("\u03C0", "\xF0", 'windows-1253') # π
+ check_both_ways("\u03CE", "\xFE", 'windows-1253') # ώ
+ assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1253') }
+ end
+
+ def test_windows_1254
+ check_both_ways("\u20AC", "\x80", 'windows-1254') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1254') }
+ check_both_ways("\u201A", "\x82", 'windows-1254') # ‚
+ check_both_ways("\u0152", "\x8C", 'windows-1254') # Œ
+ assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1254') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1254') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1254') }
+ check_both_ways("\u2018", "\x91", 'windows-1254') # ‘
+ check_both_ways("\u0153", "\x9C", 'windows-1254') # œ
+ assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1254') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x9E".encode("utf-8", 'windows-1254') }
+ check_both_ways("\u0178", "\x9F", 'windows-1254') # Ÿ
+ check_both_ways("\u00A0", "\xA0", 'windows-1254') # non-breaking space
+ check_both_ways("\u00AF", "\xAF", 'windows-1254') # ¯
+ check_both_ways("\u00B0", "\xB0", 'windows-1254') # °
+ check_both_ways("\u00BF", "\xBF", 'windows-1254') # ¿
+ check_both_ways("\u00C0", "\xC0", 'windows-1254') # À
+ check_both_ways("\u00CF", "\xCF", 'windows-1254') # Ï
+ check_both_ways("\u011E", "\xD0", 'windows-1254') # Ğ
+ check_both_ways("\u00DF", "\xDF", 'windows-1254') # ß
+ check_both_ways("\u00E0", "\xE0", 'windows-1254') # à
+ check_both_ways("\u00EF", "\xEF", 'windows-1254') # ï
+ check_both_ways("\u011F", "\xF0", 'windows-1254') # ğ
+ check_both_ways("\u00FF", "\xFF", 'windows-1254') # ÿ
+ end
+
+ def test_windows_1255
+ check_both_ways("\u20AC", "\x80", 'windows-1255') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u201A", "\x82", 'windows-1255') # ‚
+ check_both_ways("\u2030", "\x89", 'windows-1255') # ‰
+ assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u2039", "\x8B", 'windows-1255') # ‹
+ assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1255') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1255') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u2018", "\x91", 'windows-1255') # ‘
+ check_both_ways("\u2122", "\x99", 'windows-1255') # ™
+ assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u203A", "\x9B", 'windows-1255') # ›
+ assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1255') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u00A0", "\xA0", 'windows-1255') # non-breaking space
+ check_both_ways("\u00A1", "\xA1", 'windows-1255') # ¡
+ check_both_ways("\u00D7", "\xAA", 'windows-1255') # ×
+ check_both_ways("\u00AF", "\xAF", 'windows-1255') # ¯
+ check_both_ways("\u00B0", "\xB0", 'windows-1255') # °
+ check_both_ways("\u00B8", "\xB8", 'windows-1255') # ¸
+ check_both_ways("\u00F7", "\xBA", 'windows-1255') # ÷
+ check_both_ways("\u00BF", "\xBF", 'windows-1255') # ¿
+ check_both_ways("\u05B0", "\xC0", 'windows-1255') # ְ
+ check_both_ways("\u05B9", "\xC9", 'windows-1255') # ֹ
+ assert_raise(Encoding::UndefinedConversionError) { "\xCA".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u05BB", "\xCB", 'windows-1255') # ֻ
+ check_both_ways("\u05BF", "\xCF", 'windows-1255') # ֿ
+ check_both_ways("\u05C0", "\xD0", 'windows-1255') # ׀
+ check_both_ways("\u05F3", "\xD7", 'windows-1255') # ׳
+ check_both_ways("\u05F4", "\xD8", 'windows-1255') # ״
+ assert_raise(Encoding::UndefinedConversionError) { "\xD9".encode("utf-8", 'windows-1255') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xDF".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u05D0", "\xE0", 'windows-1255') # א
+ check_both_ways("\u05DF", "\xEF", 'windows-1255') # ן
+ check_both_ways("\u05E0", "\xF0", 'windows-1255') # נ
+ check_both_ways("\u05EA", "\xFA", 'windows-1255') # ת
+ assert_raise(Encoding::UndefinedConversionError) { "\xFB".encode("utf-8", 'windows-1255') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-1255') }
+ check_both_ways("\u200E", "\xFD", 'windows-1255') # left-to-right mark
+ check_both_ways("\u200F", "\xFE", 'windows-1255') # right-to-left mark
+ assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1255') }
+ end
+
+ def test_windows_1256
+ check_both_ways("\u20AC", "\x80", 'windows-1256') # €
+ check_both_ways("\u0679", "\x8A", 'windows-1256') # ٹ
+ check_both_ways("\u0688", "\x8F", 'windows-1256') # ڈ
+ check_both_ways("\u06AF", "\x90", 'windows-1256') # گ
+ check_both_ways("\u06A9", "\x98", 'windows-1256') # ک
+ check_both_ways("\u0691", "\x9A", 'windows-1256') # ڑ
+ check_both_ways("\u06BA", "\x9F", 'windows-1256') # ں
+ check_both_ways("\u00A0", "\xA0", 'windows-1256') # non-breaking space
+ check_both_ways("\u06BE", "\xAA", 'windows-1256') # ھ
+ check_both_ways("\u00AF", "\xAF", 'windows-1256') # ¯
+ check_both_ways("\u00B0", "\xB0", 'windows-1256') # °
+ check_both_ways("\u061F", "\xBF", 'windows-1256') # ؟
+ check_both_ways("\u06C1", "\xC0", 'windows-1256') # ہ
+ check_both_ways("\u062F", "\xCF", 'windows-1256') # د
+ check_both_ways("\u0630", "\xD0", 'windows-1256') # ذ
+ check_both_ways("\u0643", "\xDF", 'windows-1256') # ك
+ check_both_ways("\u00E0", "\xE0", 'windows-1256') # à
+ check_both_ways("\u00EF", "\xEF", 'windows-1256') # ï
+ check_both_ways("\u064B", "\xF0", 'windows-1256') # ًً
+ check_both_ways("\u06D2", "\xFF", 'windows-1256') # ے
+ end
+
+ def test_windows_1257
+ check_both_ways("\u20AC", "\x80", 'windows-1257') # €
+ assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u201A", "\x82", 'windows-1257') # ‚
+ assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u201E", "\x84", 'windows-1257') # „
+ check_both_ways("\u2021", "\x87", 'windows-1257') # ‡
+ assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u2030", "\x89", 'windows-1257') # ‰
+ assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u2039", "\x8B", 'windows-1257') # ‹
+ assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u00A8", "\x8D", 'windows-1257') # ¨
+ check_both_ways("\u02C7", "\x8E", 'windows-1257') # ˇ
+ check_both_ways("\u00B8", "\x8F", 'windows-1257') # ¸
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u2018", "\x91", 'windows-1257') # ‘
+ check_both_ways("\u2014", "\x97", 'windows-1257') # —
+ assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u2122", "\x99", 'windows-1257') # ™
+ assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u203A", "\x9B", 'windows-1257') # ›
+ assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u00AF", "\x9D", 'windows-1257') # ¯
+ check_both_ways("\u02DB", "\x9E", 'windows-1257') # ˛
+ assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u00A0", "\xA0", 'windows-1257') # non-breaking space
+ assert_raise(Encoding::UndefinedConversionError) { "\xA1".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u00A2", "\xA2", 'windows-1257') # ¢
+ check_both_ways("\u00A4", "\xA4", 'windows-1257') # ¤
+ assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode("utf-8", 'windows-1257') }
+ check_both_ways("\u00A6", "\xA6", 'windows-1257') # ¦
+ check_both_ways("\u00C6", "\xAF", 'windows-1257') # Æ
+ check_both_ways("\u00B0", "\xB0", 'windows-1257') # °
+ check_both_ways("\u00E6", "\xBF", 'windows-1257') # æ
+ check_both_ways("\u0104", "\xC0", 'windows-1257') # Ą
+ check_both_ways("\u013B", "\xCF", 'windows-1257') # Ļ
+ check_both_ways("\u0160", "\xD0", 'windows-1257') # Š
+ check_both_ways("\u00DF", "\xDF", 'windows-1257') # ß
+ check_both_ways("\u0105", "\xE0", 'windows-1257') # ą
+ check_both_ways("\u013C", "\xEF", 'windows-1257') # ļ
+ check_both_ways("\u0161", "\xF0", 'windows-1257') # š
+ check_both_ways("\u02D9", "\xFF", 'windows-1257') # ˙
+ end
+
+ def test_IBM437
+ check_both_ways("\u00C7", "\x80", 'IBM437') # Ç
+ check_both_ways("\u00C5", "\x8F", 'IBM437') # Å
+ check_both_ways("\u00C9", "\x90", 'IBM437') # É
+ check_both_ways("\u0192", "\x9F", 'IBM437') # ƒ
+ check_both_ways("\u00E1", "\xA0", 'IBM437') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM437') # »
+ check_both_ways("\u2591", "\xB0", 'IBM437') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM437') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM437') # └
+ check_both_ways("\u2567", "\xCF", 'IBM437') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM437') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM437') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM437') # α
+ check_both_ways("\u2229", "\xEF", 'IBM437') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM437') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM437') # non-breaking space
+ end
+
+ def test_IBM775
+ check_both_ways("\u0106", "\x80", 'IBM775') # Ć
+ check_both_ways("\u00C5", "\x8F", 'IBM775') # Å
+ check_both_ways("\u00C9", "\x90", 'IBM775') # É
+ check_both_ways("\u00A4", "\x9F", 'IBM775') # ¤
+ check_both_ways("\u0100", "\xA0", 'IBM775') # Ā
+ check_both_ways("\u00BB", "\xAF", 'IBM775') # »
+ check_both_ways("\u2591", "\xB0", 'IBM775') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM775') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM775') # └
+ check_both_ways("\u017D", "\xCF", 'IBM775') # Ž
+ check_both_ways("\u0105", "\xD0", 'IBM775') # ą
+ check_both_ways("\u2580", "\xDF", 'IBM775') # ▀
+ check_both_ways("\u00D3", "\xE0", 'IBM775') # Ó
+ check_both_ways("\u2019", "\xEF", 'IBM775') # ’
+ check_both_ways("\u00AD", "\xF0", 'IBM775') # osft hyphen
+ check_both_ways("\u00A0", "\xFF", 'IBM775') # non-breaking space
+ end
+
+ def test_IBM852
+ check_both_ways("\u00C7", "\x80", 'IBM852') # Ç
+ check_both_ways("\u0106", "\x8F", 'IBM852') # Ć
+ check_both_ways("\u00C9", "\x90", 'IBM852') # É
+ check_both_ways("\u010D", "\x9F", 'IBM852') # č
+ check_both_ways("\u00E1", "\xA0", 'IBM852') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM852') # »
+ check_both_ways("\u2591", "\xB0", 'IBM852') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM852') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM852') # └
+ check_both_ways("\u00A4", "\xCF", 'IBM852') # ¤
+ check_both_ways("\u0111", "\xD0", 'IBM852') # đ
+ check_both_ways("\u2580", "\xDF", 'IBM852') # ▀
+ check_both_ways("\u00D3", "\xE0", 'IBM852') # Ó
+ check_both_ways("\u00B4", "\xEF", 'IBM852') # ´
+ check_both_ways("\u00AD", "\xF0", 'IBM852') # osft hyphen
+ check_both_ways("\u00A0", "\xFF", 'IBM852') # non-breaking space
+ end
+
+ def test_IBM855
+ check_both_ways("\u0452", "\x80", 'IBM855') # ђ
+ check_both_ways("\u0408", "\x8F", 'IBM855') # Ј
+ check_both_ways("\u0459", "\x90", 'IBM855') # љ
+ check_both_ways("\u042A", "\x9F", 'IBM855') # Ъ
+ check_both_ways("\u0430", "\xA0", 'IBM855') # а
+ check_both_ways("\u00BB", "\xAF", 'IBM855') # »
+ check_both_ways("\u2591", "\xB0", 'IBM855') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM855') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM855') # └
+ check_both_ways("\u00A4", "\xCF", 'IBM855') # ¤
+ check_both_ways("\u043B", "\xD0", 'IBM855') # л
+ check_both_ways("\u2580", "\xDF", 'IBM855') # ▀
+ check_both_ways("\u042F", "\xE0", 'IBM855') # Я
+ check_both_ways("\u2116", "\xEF", 'IBM855') # №
+ check_both_ways("\u00AD", "\xF0", 'IBM855') # osft hyphen
+ check_both_ways("\u00A0", "\xFF", 'IBM855') # non-breaking space
+ end
+
+ def test_IBM857
+ check_both_ways("\u00C7", "\x80", 'IBM857') # Ç
+ check_both_ways("\u00C5", "\x8F", 'IBM857') # Å
+ check_both_ways("\u00C9", "\x90", 'IBM857') # É
+ check_both_ways("\u015F", "\x9F", 'IBM857') # ş
+ check_both_ways("\u00E1", "\xA0", 'IBM857') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM857') # »
+ check_both_ways("\u2591", "\xB0", 'IBM857') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM857') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM857') # └
+ check_both_ways("\u00A4", "\xCF", 'IBM857') # ¤
+ check_both_ways("\u00BA", "\xD0", 'IBM857') # º
+ check_both_ways("\u00C8", "\xD4", 'IBM857') # È
+ assert_raise(Encoding::UndefinedConversionError) { "\xD5".encode("utf-8", 'IBM857') }
+ check_both_ways("\u00CD", "\xD6", 'IBM857') # Í
+ check_both_ways("\u2580", "\xDF", 'IBM857') # ▀
+ check_both_ways("\u00D3", "\xE0", 'IBM857') # Ó
+ check_both_ways("\u00B5", "\xE6", 'IBM857') # µ
+ assert_raise(Encoding::UndefinedConversionError) { "\xE7".encode("utf-8", 'IBM857') }
+ check_both_ways("\u00D7", "\xE8", 'IBM857') # ×
+ check_both_ways("\u00B4", "\xEF", 'IBM857') # ´
+ check_both_ways("\u00AD", "\xF0", 'IBM857') # soft hyphen
+ check_both_ways("\u00B1", "\xF1", 'IBM857') # ±
+ assert_raise(Encoding::UndefinedConversionError) { "\xF2".encode("utf-8", 'IBM857') }
+ check_both_ways("\u00BE", "\xF3", 'IBM857') # ¾
+ check_both_ways("\u00A0", "\xFF", 'IBM857') # non-breaking space
+ end
+
+ def test_IBM860
+ check_both_ways("\u00C7", "\x80", 'IBM860') # Ç
+ check_both_ways("\u00C2", "\x8F", 'IBM860') # Â
+ check_both_ways("\u00C9", "\x90", 'IBM860') # É
+ check_both_ways("\u00D3", "\x9F", 'IBM860') # Ó
+ check_both_ways("\u00E1", "\xA0", 'IBM860') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM860') # »
+ check_both_ways("\u2591", "\xB0", 'IBM860') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM860') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM860') # └
+ check_both_ways("\u2567", "\xCF", 'IBM860') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM860') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM860') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM860') # α
+ check_both_ways("\u2229", "\xEF", 'IBM860') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM860') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM860') # non-breaking space
+ end
+
+ def test_IBM861
+ check_both_ways("\u00C7", "\x80", 'IBM861') # Ç
+ check_both_ways("\u00C5", "\x8F", 'IBM861') # Å
+ check_both_ways("\u00C9", "\x90", 'IBM861') # É
+ check_both_ways("\u0192", "\x9F", 'IBM861') # ƒ
+ check_both_ways("\u00E1", "\xA0", 'IBM861') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM861') # »
+ check_both_ways("\u2591", "\xB0", 'IBM861') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM861') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM861') # └
+ check_both_ways("\u2567", "\xCF", 'IBM861') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM861') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM861') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM861') # α
+ check_both_ways("\u2229", "\xEF", 'IBM861') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM861') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM861') # non-breaking space
+ end
+
+ def test_IBM862
+ check_both_ways("\u05D0", "\x80", 'IBM862') # א
+ check_both_ways("\u05DF", "\x8F", 'IBM862') # ן
+ check_both_ways("\u05E0", "\x90", 'IBM862') # נ
+ check_both_ways("\u0192", "\x9F", 'IBM862') # ƒ
+ check_both_ways("\u00E1", "\xA0", 'IBM862') # á
+ check_both_ways("\u00BB", "\xAF", 'IBM862') # »
+ check_both_ways("\u2591", "\xB0", 'IBM862') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM862') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM862') # └
+ check_both_ways("\u2567", "\xCF", 'IBM862') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM862') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM862') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM862') # α
+ check_both_ways("\u2229", "\xEF", 'IBM862') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM862') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM862') # non-breaking space
+ end
+
+ def test_IBM863
+ check_both_ways("\u00C7", "\x80", 'IBM863') # Ç
+ check_both_ways("\u00A7", "\x8F", 'IBM863') # §
+ check_both_ways("\u00C9", "\x90", 'IBM863') # É
+ check_both_ways("\u0192", "\x9F", 'IBM863') # ƒ
+ check_both_ways("\u00A6", "\xA0", 'IBM863') # ¦
+ check_both_ways("\u00BB", "\xAF", 'IBM863') # »
+ check_both_ways("\u2591", "\xB0", 'IBM863') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM863') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM863') # └
+ check_both_ways("\u2567", "\xCF", 'IBM863') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM863') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM863') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM863') # α
+ check_both_ways("\u2229", "\xEF", 'IBM863') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM863') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM863') # non-breaking space
+ end
+
+ def test_IBM865
+ check_both_ways("\u00C7", "\x80", 'IBM865') # Ç
+ check_both_ways("\u00C5", "\x8F", 'IBM865') # Å
+ check_both_ways("\u00C9", "\x90", 'IBM865') # É
+ check_both_ways("\u0192", "\x9F", 'IBM865') # ƒ
+ check_both_ways("\u00E1", "\xA0", 'IBM865') # á
+ check_both_ways("\u00A4", "\xAF", 'IBM865') # ¤
+ check_both_ways("\u2591", "\xB0", 'IBM865') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM865') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM865') # └
+ check_both_ways("\u2567", "\xCF", 'IBM865') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM865') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM865') # ▀
+ check_both_ways("\u03B1", "\xE0", 'IBM865') # α
+ check_both_ways("\u2229", "\xEF", 'IBM865') # ∩
+ check_both_ways("\u2261", "\xF0", 'IBM865') # ≡
+ check_both_ways("\u00A0", "\xFF", 'IBM865') # non-breaking space
+ end
+
+ def test_IBM866
+ check_both_ways("\u0410", "\x80", 'IBM866') # А
+ check_both_ways("\u041F", "\x8F", 'IBM866') # П
+ check_both_ways("\u0420", "\x90", 'IBM866') # Р
+ check_both_ways("\u042F", "\x9F", 'IBM866') # Я
+ check_both_ways("\u0430", "\xA0", 'IBM866') # а
+ check_both_ways("\u043F", "\xAF", 'IBM866') # п
+ check_both_ways("\u2591", "\xB0", 'IBM866') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM866') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM866') # └
+ check_both_ways("\u2567", "\xCF", 'IBM866') # ╧
+ check_both_ways("\u2568", "\xD0", 'IBM866') # ╨
+ check_both_ways("\u2580", "\xDF", 'IBM866') # ▀
+ check_both_ways("\u0440", "\xE0", 'IBM866') # р
+ check_both_ways("\u044F", "\xEF", 'IBM866') # я
+ check_both_ways("\u0401", "\xF0", 'IBM866') # Ё
+ check_both_ways("\u00A0", "\xFF", 'IBM866') # non-breaking space
+ end
+
+ def test_IBM869
+ assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'IBM869') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x85".encode("utf-8", 'IBM869') }
+ check_both_ways("\u0386", "\x86", 'IBM869') # Ά
+ assert_raise(Encoding::UndefinedConversionError) { "\x87".encode("utf-8", 'IBM869') }
+ check_both_ways("\u00B7", "\x88", 'IBM869') # ·
+ check_both_ways("\u0389", "\x8F", 'IBM869') # Ή
+ check_both_ways("\u038A", "\x90", 'IBM869') # Ί
+ check_both_ways("\u038C", "\x92", 'IBM869') # Ό
+ assert_raise(Encoding::UndefinedConversionError) { "\x93".encode("utf-8", 'IBM869') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x94".encode("utf-8", 'IBM869') }
+ check_both_ways("\u038E", "\x95", 'IBM869') # Ύ
+ check_both_ways("\u03AF", "\x9F", 'IBM869') # ί
+ check_both_ways("\u03CA", "\xA0", 'IBM869') # ϊ
+ check_both_ways("\u00BB", "\xAF", 'IBM869') # »
+ check_both_ways("\u2591", "\xB0", 'IBM869') # ░
+ check_both_ways("\u2510", "\xBF", 'IBM869') # ┐
+ check_both_ways("\u2514", "\xC0", 'IBM869') # └
+ check_both_ways("\u03A3", "\xCF", 'IBM869') # Σ
+ check_both_ways("\u03A4", "\xD0", 'IBM869') # Τ
+ check_both_ways("\u2580", "\xDF", 'IBM869') # ▀
+ check_both_ways("\u03B6", "\xE0", 'IBM869') # ζ
+ check_both_ways("\u0384", "\xEF", 'IBM869') # ΄
+ check_both_ways("\u00AD", "\xF0", 'IBM869') # soft hyphen
+ check_both_ways("\u00A0", "\xFF", 'IBM869') # non-breaking space
+ end
+
+ def test_macCroatian
+ check_both_ways("\u00C4", "\x80", 'macCroatian') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macCroatian') # è
+ check_both_ways("\u00EA", "\x90", 'macCroatian') # ê
+ check_both_ways("\u00FC", "\x9F", 'macCroatian') # ü
+ check_both_ways("\u2020", "\xA0", 'macCroatian') # †
+ check_both_ways("\u00D8", "\xAF", 'macCroatian') # Ø
+ check_both_ways("\u221E", "\xB0", 'macCroatian') # ∞
+ check_both_ways("\u00F8", "\xBF", 'macCroatian') # ø
+ check_both_ways("\u00BF", "\xC0", 'macCroatian') # ¿
+ check_both_ways("\u0153", "\xCF", 'macCroatian') # œ
+ check_both_ways("\u0110", "\xD0", 'macCroatian') # Đ
+ check_both_ways("\u00A9", "\xD9", 'macCroatian') # ©
+ check_both_ways("\u2044", "\xDA", 'macCroatian') # ⁄
+ check_both_ways("\u203A", "\xDD", 'macCroatian') # ›
+ check_both_ways("\u00C6", "\xDE", 'macCroatian') # Æ
+ check_both_ways("\u00BB", "\xDF", 'macCroatian') # »
+ check_both_ways("\u2013", "\xE0", 'macCroatian') # –
+ check_both_ways("\u00B7", "\xE1", 'macCroatian') # ·
+ check_both_ways("\u00C2", "\xE5", 'macCroatian') # Â
+ check_both_ways("\u0107", "\xE6", 'macCroatian') # ć
+ check_both_ways("\u00C1", "\xE7", 'macCroatian') # Á
+ check_both_ways("\u010D", "\xE8", 'macCroatian') # č
+ check_both_ways("\u00C8", "\xE9", 'macCroatian') # È
+ check_both_ways("\u00D4", "\xEF", 'macCroatian') # Ô
+ check_both_ways("\u0111", "\xF0", 'macCroatian') # đ
+ check_both_ways("\u00D2", "\xF1", 'macCroatian') # Ò
+ check_both_ways("\u00AF", "\xF8", 'macCroatian') # ¯
+ check_both_ways("\u03C0", "\xF9", 'macCroatian') # π
+ check_both_ways("\u00CB", "\xFA", 'macCroatian') # Ë
+ check_both_ways("\u00CA", "\xFD", 'macCroatian') # Ê
+ check_both_ways("\u00E6", "\xFE", 'macCroatian') # æ
+ check_both_ways("\u02C7", "\xFF", 'macCroatian') # ˇ
+ end
+
+ def test_macCyrillic
+ check_both_ways("\u0410", "\x80", 'macCyrillic') # А
+ check_both_ways("\u041F", "\x8F", 'macCyrillic') # П
+ check_both_ways("\u0420", "\x90", 'macCyrillic') # Р
+ check_both_ways("\u042F", "\x9F", 'macCyrillic') # Я
+ check_both_ways("\u2020", "\xA0", 'macCyrillic') # †
+ check_both_ways("\u0453", "\xAF", 'macCyrillic') # ѓ
+ check_both_ways("\u221E", "\xB0", 'macCyrillic') # ∞
+ check_both_ways("\u045A", "\xBF", 'macCyrillic') # њ
+ check_both_ways("\u0458", "\xC0", 'macCyrillic') # ј
+ check_both_ways("\u0455", "\xCF", 'macCyrillic') # ѕ
+ check_both_ways("\u2013", "\xD0", 'macCyrillic') # –
+ check_both_ways("\u044F", "\xDF", 'macCyrillic') # я
+ check_both_ways("\u0430", "\xE0", 'macCyrillic') # а
+ check_both_ways("\u043F", "\xEF", 'macCyrillic') # п
+ check_both_ways("\u0440", "\xF0", 'macCyrillic') # р
+ check_both_ways("\u00A4", "\xFF", 'macCyrillic') # ¤
+ end
+
+ def test_macGreek
+ check_both_ways("\u00C4", "\x80", 'macGreek') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macGreek') # è
+ check_both_ways("\u00EA", "\x90", 'macGreek') # ê
+ check_both_ways("\u00FC", "\x9F", 'macGreek') # ü
+ check_both_ways("\u2020", "\xA0", 'macGreek') # †
+ check_both_ways("\u0393", "\xA1", 'macGreek') # Γ
+ check_both_ways("\u0387", "\xAF", 'macGreek') # ·
+ check_both_ways("\u0391", "\xB0", 'macGreek') # Α
+ check_both_ways("\u03A9", "\xBF", 'macGreek') # Ω
+ check_both_ways("\u03AC", "\xC0", 'macGreek') # ά
+ check_both_ways("\u0153", "\xCF", 'macGreek') # œ
+ check_both_ways("\u2013", "\xD0", 'macGreek') # –
+ check_both_ways("\u038F", "\xDF", 'macGreek') # Ώ
+ check_both_ways("\u03CD", "\xE0", 'macGreek') # ύ
+ check_both_ways("\u03BF", "\xEF", 'macGreek') # ο
+ check_both_ways("\u03C0", "\xF0", 'macGreek') # π
+ check_both_ways("\u03B0", "\xFE", 'macGreek') # ΰ
+ assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'macGreek') }
+ end
+
+ def test_macIceland
+ check_both_ways("\u00C4", "\x80", 'macIceland') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macIceland') # è
+ check_both_ways("\u00EA", "\x90", 'macIceland') # ê
+ check_both_ways("\u00FC", "\x9F", 'macIceland') # ü
+ check_both_ways("\u00DD", "\xA0", 'macIceland') # Ý
+ check_both_ways("\u00D8", "\xAF", 'macIceland') # Ø
+ check_both_ways("\u221E", "\xB0", 'macIceland') # ∞
+ check_both_ways("\u00F8", "\xBF", 'macIceland') # ø
+ check_both_ways("\u00BF", "\xC0", 'macIceland') # ¿
+ check_both_ways("\u0153", "\xCF", 'macIceland') # œ
+ check_both_ways("\u2013", "\xD0", 'macIceland') # –
+ check_both_ways("\u00FE", "\xDF", 'macIceland') # þ
+ check_both_ways("\u00FD", "\xE0", 'macIceland') # ý
+ check_both_ways("\u00D4", "\xEF", 'macIceland') # Ô
+ #check_both_ways("\uF8FF", "\xF0", 'macIceland') # Apple logo
+ check_both_ways("\u02C7", "\xFF", 'macIceland') # ˇ
+ end
+
+ def test_macRoman
+ check_both_ways("\u00C4", "\x80", 'macRoman') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macRoman') # è
+ check_both_ways("\u00EA", "\x90", 'macRoman') # ê
+ check_both_ways("\u00FC", "\x9F", 'macRoman') # ü
+ check_both_ways("\u2020", "\xA0", 'macRoman') # †
+ #check_both_ways("\u00DB", "\xAF", 'macRoman') # Ø
+ check_both_ways("\u221E", "\xB0", 'macRoman') # ∞
+ check_both_ways("\u00F8", "\xBF", 'macRoman') # ø
+ check_both_ways("\u00BF", "\xC0", 'macRoman') # ¿
+ check_both_ways("\u0153", "\xCF", 'macRoman') # œ
+ check_both_ways("\u2013", "\xD0", 'macRoman') # –
+ check_both_ways("\u00A4", "\xDB", 'macRoman') # ¤
+ check_both_ways("\uFB02", "\xDF", 'macRoman') # fl
+ check_both_ways("\u2021", "\xE0", 'macRoman') # ‡
+ check_both_ways("\u00D4", "\xEF", 'macRoman') # Ô
+ #check_both_ways("\uF8FF", "\xF0", 'macRoman') # Apple logo
+ check_both_ways("\u02C7", "\xFF", 'macRoman') # ˇ
+ end
+
+ def test_macRomania
+ check_both_ways("\u00C4", "\x80", 'macRomania') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macRomania') # è
+ check_both_ways("\u00EA", "\x90", 'macRomania') # ê
+ check_both_ways("\u00FC", "\x9F", 'macRomania') # ü
+ check_both_ways("\u2020", "\xA0", 'macRomania') # †
+ check_both_ways("\u015E", "\xAF", 'macRomania') # Ş
+ check_both_ways("\u221E", "\xB0", 'macRomania') # ∞
+ check_both_ways("\u015F", "\xBF", 'macRomania') # ş
+ check_both_ways("\u00BF", "\xC0", 'macRomania') # ¿
+ check_both_ways("\u0153", "\xCF", 'macRomania') # œ
+ check_both_ways("\u2013", "\xD0", 'macRomania') # –
+ check_both_ways("\u00A4", "\xDB", 'macRomania') # €
+ check_both_ways("\u0163", "\xDF", 'macRomania') # ţ
+ check_both_ways("\u2021", "\xE0", 'macRomania') # ‡
+ check_both_ways("\u00D4", "\xEF", 'macRomania') # Ô
+ #check_both_ways("\uF8FF", "\xF0", 'macRomania') # Apple logo
+ check_both_ways("\u02C7", "\xFF", 'macRomania') # ˇ
+ end
+
+ def test_macTurkish
+ check_both_ways("\u00C4", "\x80", 'macTurkish') # Ä
+ check_both_ways("\u00E8", "\x8F", 'macTurkish') # è
+ check_both_ways("\u00EA", "\x90", 'macTurkish') # ê
+ check_both_ways("\u00FC", "\x9F", 'macTurkish') # ü
+ check_both_ways("\u2020", "\xA0", 'macTurkish') # †
+ check_both_ways("\u00D8", "\xAF", 'macTurkish') # Ø
+ check_both_ways("\u221E", "\xB0", 'macTurkish') # ∞
+ check_both_ways("\u00F8", "\xBF", 'macTurkish') # ø
+ check_both_ways("\u00BF", "\xC0", 'macTurkish') # ¿
+ check_both_ways("\u0153", "\xCF", 'macTurkish') # œ
+ check_both_ways("\u2013", "\xD0", 'macTurkish') # –
+ check_both_ways("\u015F", "\xDF", 'macTurkish') # ş
+ check_both_ways("\u2021", "\xE0", 'macTurkish') # ‡
+ check_both_ways("\u00D4", "\xEF", 'macTurkish') # Ô
+ #check_both_ways("\uF8FF", "\xF0", 'macTurkish') # Apple logo
+ check_both_ways("\u00D9", "\xF4", 'macTurkish') # Ù
+ assert_raise(Encoding::UndefinedConversionError) { "\xF5".encode("utf-8", 'macTurkish') }
+ check_both_ways("\u02C6", "\xF6", 'macTurkish') # ˆ
+ check_both_ways("\u02C7", "\xFF", 'macTurkish') # ˇ
+ end
+
+ def test_macUkraine
+ check_both_ways("\u0410", "\x80", 'macUkraine') # А
+ check_both_ways("\u041F", "\x8F", 'macUkraine') # П
+ check_both_ways("\u0420", "\x90", 'macUkraine') # Р
+ check_both_ways("\u042F", "\x9F", 'macUkraine') # Я
+ check_both_ways("\u2020", "\xA0", 'macUkraine') # †
+ check_both_ways("\u0453", "\xAF", 'macUkraine') # ѓ
+ check_both_ways("\u221E", "\xB0", 'macUkraine') # ∞
+ check_both_ways("\u045A", "\xBF", 'macUkraine') # њ
+ check_both_ways("\u0458", "\xC0", 'macUkraine') # ј
+ check_both_ways("\u0455", "\xCF", 'macUkraine') # ѕ
+ check_both_ways("\u2013", "\xD0", 'macUkraine') # –
+ check_both_ways("\u044F", "\xDF", 'macUkraine') # я
+ check_both_ways("\u0430", "\xE0", 'macUkraine') # а
+ check_both_ways("\u043F", "\xEF", 'macUkraine') # п
+ check_both_ways("\u0440", "\xF0", 'macUkraine') # р
+ check_both_ways("\u00A4", "\xFF", 'macUkraine') # ¤
+ end
+
+ def test_koi8_u
+ check_both_ways("\u2500", "\x80", 'KOI8-U') # ─
+ check_both_ways("\u2590", "\x8F", 'KOI8-U') # ▐
+ check_both_ways("\u2591", "\x90", 'KOI8-U') # ░
+ check_both_ways("\u00F7", "\x9F", 'KOI8-U') # ÷
+ check_both_ways("\u2550", "\xA0", 'KOI8-U') # ═
+ check_both_ways("\u0454", "\xA4", 'KOI8-U') # є
+ check_both_ways("\u0456", "\xA6", 'KOI8-U') # і
+ check_both_ways("\u0457", "\xA7", 'KOI8-U') # ї
+ check_both_ways("\u0491", "\xAD", 'KOI8-U') # ґ
+ check_both_ways("\u255E", "\xAF", 'KOI8-U') # ╞
+ check_both_ways("\u255F", "\xB0", 'KOI8-U') # ╟
+ check_both_ways("\u0404", "\xB4", 'KOI8-U') # Є
+ check_both_ways("\u0406", "\xB6", 'KOI8-U') # І
+ check_both_ways("\u0407", "\xB7", 'KOI8-U') # Ї
+ check_both_ways("\u0490", "\xBD", 'KOI8-U') # Ґ
+ check_both_ways("\u00A9", "\xBF", 'KOI8-U') # ©
+ check_both_ways("\u044E", "\xC0", 'KOI8-U') # ю
+ check_both_ways("\u043E", "\xCF", 'KOI8-U') # о
+ check_both_ways("\u043F", "\xD0", 'KOI8-U') # п
+ check_both_ways("\u044A", "\xDF", 'KOI8-U') # ъ
+ check_both_ways("\u042E", "\xE0", 'KOI8-U') # Ю
+ check_both_ways("\u041E", "\xEF", 'KOI8-U') # О
+ check_both_ways("\u041F", "\xF0", 'KOI8-U') # П
+ check_both_ways("\u042A", "\xFF", 'KOI8-U') # Ъ
+ end
+
+ def test_koi8_r
+ check_both_ways("\u2500", "\x80", 'KOI8-R') # ─
+ check_both_ways("\u2590", "\x8F", 'KOI8-R') # ▐
+ check_both_ways("\u2591", "\x90", 'KOI8-R') # ░
+ check_both_ways("\u00F7", "\x9F", 'KOI8-R') # ÷
+ check_both_ways("\u2550", "\xA0", 'KOI8-R') # ═
+ check_both_ways("\u255E", "\xAF", 'KOI8-R') # ╞
+ check_both_ways("\u255F", "\xB0", 'KOI8-R') # ╟
+ check_both_ways("\u00A9", "\xBF", 'KOI8-R') # ©
+ check_both_ways("\u044E", "\xC0", 'KOI8-R') # ю
+ check_both_ways("\u043E", "\xCF", 'KOI8-R') # о
+ check_both_ways("\u043F", "\xD0", 'KOI8-R') # п
+ check_both_ways("\u044A", "\xDF", 'KOI8-R') # ъ
+ check_both_ways("\u042E", "\xE0", 'KOI8-R') # Ю
+ check_both_ways("\u041E", "\xEF", 'KOI8-R') # О
+ check_both_ways("\u041F", "\xF0", 'KOI8-R') # П
+ check_both_ways("\u042A", "\xFF", 'KOI8-R') # Ъ
+ end
+
+ def test_TIS_620
+ assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA0".encode("utf-8", 'TIS-620') }
+ check_both_ways("\u0E01", "\xA1", 'TIS-620') # ก
+ check_both_ways("\u0E0F", "\xAF", 'TIS-620') # ฏ
+ check_both_ways("\u0E10", "\xB0", 'TIS-620') # ฐ
+ check_both_ways("\u0E1F", "\xBF", 'TIS-620') # ฟ
+ check_both_ways("\u0E20", "\xC0", 'TIS-620') # ภ
+ check_both_ways("\u0E2F", "\xCF", 'TIS-620') # ฯ
+ check_both_ways("\u0E30", "\xD0", 'TIS-620') # ะ
+ check_both_ways("\u0E3A", "\xDA", 'TIS-620') # ฺ
+ assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'TIS-620') }
+ check_both_ways("\u0E3F", "\xDF", 'TIS-620') # ฿
+ check_both_ways("\u0E40", "\xE0", 'TIS-620') # เ
+ check_both_ways("\u0E4F", "\xEF", 'TIS-620') # ๏
+ check_both_ways("\u0E50", "\xF0", 'TIS-620') # ๐
+ check_both_ways("\u0E5B", "\xFB", 'TIS-620') # ๛
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'TIS-620') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'TIS-620') }
+ end
+
+ def test_CP850
+ check_both_ways("\u00C7", "\x80", 'CP850') # Ç
+ check_both_ways("\u00C5", "\x8F", 'CP850') # Å
+ check_both_ways("\u00C9", "\x90", 'CP850') # É
+ check_both_ways("\u0192", "\x9F", 'CP850') # ƒ
+ check_both_ways("\u00E1", "\xA0", 'CP850') # á
+ check_both_ways("\u00BB", "\xAF", 'CP850') # »
+ check_both_ways("\u2591", "\xB0", 'CP850') # ░
+ check_both_ways("\u2510", "\xBF", 'CP850') # ┐
+ check_both_ways("\u2514", "\xC0", 'CP850') # └
+ check_both_ways("\u00A4", "\xCF", 'CP850') # ¤
+ check_both_ways("\u00F0", "\xD0", 'CP850') # ð
+ check_both_ways("\u2580", "\xDF", 'CP850') # ▀
+ check_both_ways("\u00D3", "\xE0", 'CP850') # Ó
+ check_both_ways("\u00B4", "\xEF", 'CP850') # ´
+ check_both_ways("\u00AD", "\xF0", 'CP850') # soft hyphen
+ check_both_ways("\u00A0", "\xFF", 'CP850') # non-breaking space
+ end
+
+ def test_CP852
+ check_both_ways("\u00C7", "\x80", 'CP852') # Ç
+ check_both_ways("\u0106", "\x8F", 'CP852') # Ć
+ check_both_ways("\u00C9", "\x90", 'CP852') # É
+ check_both_ways("\u010D", "\x9F", 'CP852') # č
+ check_both_ways("\u00E1", "\xA0", 'CP852') # á
+ check_both_ways("\u00BB", "\xAF", 'CP852') # »
+ check_both_ways("\u2591", "\xB0", 'CP852') # ░
+ check_both_ways("\u2510", "\xBF", 'CP852') # ┐
+ check_both_ways("\u2514", "\xC0", 'CP852') # └
+ check_both_ways("\u00A4", "\xCF", 'CP852') # ¤
+ check_both_ways("\u0111", "\xD0", 'CP852') # đ
+ check_both_ways("\u2580", "\xDF", 'CP852') # ▀
+ check_both_ways("\u00D3", "\xE0", 'CP852') # Ó
+ check_both_ways("\u00B4", "\xEF", 'CP852') # ´
+ check_both_ways("\u00AD", "\xF0", 'CP852') # soft hyphen
+ check_both_ways("\u00A0", "\xFF", 'CP852') # non-breaking space
+ end
+
+ def test_CP855
+ check_both_ways("\u0452", "\x80", 'CP855') # ђ
+ check_both_ways("\u0408", "\x8F", 'CP855') # Ј
+ check_both_ways("\u0459", "\x90", 'CP855') # љ
+ check_both_ways("\u042A", "\x9F", 'CP855') # Ъ
+ check_both_ways("\u0430", "\xA0", 'CP855') # а
+ check_both_ways("\u00BB", "\xAF", 'CP855') # »
+ check_both_ways("\u2591", "\xB0", 'CP855') # ░
+ check_both_ways("\u2510", "\xBF", 'CP855') # ┐
+ check_both_ways("\u2514", "\xC0", 'CP855') # └
+ check_both_ways("\u00A4", "\xCF", 'CP855') # ¤
+ check_both_ways("\u043B", "\xD0", 'CP855') # л
+ check_both_ways("\u2580", "\xDF", 'CP855') # ▀
+ check_both_ways("\u042F", "\xE0", 'CP855') # Я
+ check_both_ways("\u2116", "\xEF", 'CP855') # №
+ check_both_ways("\u00AD", "\xF0", 'CP855') # soft hyphen
+ check_both_ways("\u00A0", "\xFF", 'CP855') # non-breaking space
+ end
+
+ def check_utf_16_both_ways(utf8, raw)
+ copy = raw.dup
+ 0.step(copy.length-1, 2) { |i| copy[i+1], copy[i] = copy[i], copy[i+1] }
+ check_both_ways(utf8, raw, 'utf-16be')
+ check_both_ways(utf8, copy, 'utf-16le')
+ end
+
+ def test_utf_16
+ check_utf_16_both_ways("abc", "\x00a\x00b\x00c")
+ check_utf_16_both_ways("\u00E9", "\x00\xE9");
+ check_utf_16_both_ways("\u00E9\u0070\u00E9\u0065", "\x00\xE9\x00\x70\x00\xE9\x00\x65") # épée
+ check_utf_16_both_ways("\u677E\u672C\u884C\u5F18", "\x67\x7E\x67\x2C\x88\x4C\x5F\x18") # 松本行弘
+ check_utf_16_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x97\x52\x5C\x71\x5B\x66\x96\x62\x59\x27\x5B\x66") # 青山学院大学
+ check_utf_16_both_ways("Martin D\u00FCrst", "\x00M\x00a\x00r\x00t\x00i\x00n\x00 \x00D\x00\xFC\x00r\x00s\x00t") # Martin Dürst
+ # BMP
+ check_utf_16_both_ways("\u0000", "\x00\x00")
+ check_utf_16_both_ways("\u007F", "\x00\x7F")
+ check_utf_16_both_ways("\u0080", "\x00\x80")
+ check_utf_16_both_ways("\u0555", "\x05\x55")
+ check_utf_16_both_ways("\u04AA", "\x04\xAA")
+ check_utf_16_both_ways("\u0333", "\x03\x33")
+ check_utf_16_both_ways("\u04CC", "\x04\xCC")
+ check_utf_16_both_ways("\u00F0", "\x00\xF0")
+ check_utf_16_both_ways("\u070F", "\x07\x0F")
+ check_utf_16_both_ways("\u07FF", "\x07\xFF")
+ check_utf_16_both_ways("\u0800", "\x08\x00")
+ check_utf_16_both_ways("\uD7FF", "\xD7\xFF")
+ check_utf_16_both_ways("\uE000", "\xE0\x00")
+ check_utf_16_both_ways("\uFFFF", "\xFF\xFF")
+ check_utf_16_both_ways("\u5555", "\x55\x55")
+ check_utf_16_both_ways("\uAAAA", "\xAA\xAA")
+ check_utf_16_both_ways("\u3333", "\x33\x33")
+ check_utf_16_both_ways("\uCCCC", "\xCC\xCC")
+ check_utf_16_both_ways("\uF0F0", "\xF0\xF0")
+ check_utf_16_both_ways("\u0F0F", "\x0F\x0F")
+ check_utf_16_both_ways("\uFF00", "\xFF\x00")
+ check_utf_16_both_ways("\u00FF", "\x00\xFF")
+ # outer planes
+ check_utf_16_both_ways("\u{10000}", "\xD8\x00\xDC\x00")
+ check_utf_16_both_ways("\u{FFFFF}", "\xDB\xBF\xDF\xFF")
+ check_utf_16_both_ways("\u{100000}", "\xDB\xC0\xDC\x00")
+ check_utf_16_both_ways("\u{10FFFF}", "\xDB\xFF\xDF\xFF")
+ check_utf_16_both_ways("\u{105555}", "\xDB\xD5\xDD\x55")
+ check_utf_16_both_ways("\u{55555}", "\xD9\x15\xDD\x55")
+ check_utf_16_both_ways("\u{AAAAA}", "\xDA\x6A\xDE\xAA")
+ check_utf_16_both_ways("\u{33333}", "\xD8\x8C\xDF\x33")
+ check_utf_16_both_ways("\u{CCCCC}", "\xDA\xF3\xDC\xCC")
+ check_utf_16_both_ways("\u{8F0F0}", "\xD9\xFC\xDC\xF0")
+ check_utf_16_both_ways("\u{F0F0F}", "\xDB\x83\xDF\x0F")
+ check_utf_16_both_ways("\u{8FF00}", "\xD9\xFF\xDF\x00")
+ check_utf_16_both_ways("\u{F00FF}", "\xDB\x80\xDC\xFF")
+ end
+
+ def test_utf_16_bom
+ expected = "\u{3042}\u{3044}\u{20bb7}"
+ assert_equal(expected, %w/fffe4230443042d8b7df/.pack("H*").encode("UTF-8","UTF-16"))
+ check_both_ways(expected, %w/feff30423044d842dfb7/.pack("H*"), "UTF-16")
+ assert_raise(Encoding::InvalidByteSequenceError){%w/feffdfb7/.pack("H*").encode("UTF-8","UTF-16")}
+ assert_raise(Encoding::InvalidByteSequenceError){%w/fffeb7df/.pack("H*").encode("UTF-8","UTF-16")}
+ end
+
+ def test_utf_32_bom
+ expected = "\u{3042}\u{3044}\u{20bb7}"
+ assert_equal(expected, %w/fffe00004230000044300000b70b0200/.pack("H*").encode("UTF-8","UTF-32"))
+ check_both_ways(expected, %w/0000feff000030420000304400020bb7/.pack("H*"), "UTF-32")
+ assert_raise(Encoding::InvalidByteSequenceError){%w/0000feff00110000/.pack("H*").encode("UTF-8","UTF-32")}
+ end
+
+ def check_utf_32_both_ways(utf8, raw)
+ copy = raw.dup
+ 0.step(copy.length-1, 4) do |i|
+ copy[i+3], copy[i+2], copy[i+1], copy[i] = copy[i], copy[i+1], copy[i+2], copy[i+3]
+ end
+ check_both_ways(utf8, raw, 'utf-32be')
+ #check_both_ways(utf8, copy, 'utf-32le')
+ end
+
+ def test_utf_32
+ check_utf_32_both_ways("abc", "\x00\x00\x00a\x00\x00\x00b\x00\x00\x00c")
+ check_utf_32_both_ways("\u00E9", "\x00\x00\x00\xE9");
+ check_utf_32_both_ways("\u00E9\u0070\u00E9\u0065",
+ "\x00\x00\x00\xE9\x00\x00\x00\x70\x00\x00\x00\xE9\x00\x00\x00\x65") # épée
+ check_utf_32_both_ways("\u677E\u672C\u884C\u5F18",
+ "\x00\x00\x67\x7E\x00\x00\x67\x2C\x00\x00\x88\x4C\x00\x00\x5F\x18") # 松本行弘
+ check_utf_32_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66",
+ "\x00\x00\x97\x52\x00\x00\x5C\x71\x00\x00\x5B\x66\x00\x00\x96\x62\x00\x00\x59\x27\x00\x00\x5B\x66") # 青山学院大学
+ check_utf_32_both_ways("Martin D\u00FCrst",
+ "\x00\x00\x00M\x00\x00\x00a\x00\x00\x00r\x00\x00\x00t\x00\x00\x00i\x00\x00\x00n\x00\x00\x00 \x00\x00\x00D\x00\x00\x00\xFC\x00\x00\x00r\x00\x00\x00s\x00\x00\x00t") # Martin Dürst
+ # BMP
+ check_utf_32_both_ways("\u0000", "\x00\x00\x00\x00")
+ check_utf_32_both_ways("\u007F", "\x00\x00\x00\x7F")
+ check_utf_32_both_ways("\u0080", "\x00\x00\x00\x80")
+ check_utf_32_both_ways("\u0555", "\x00\x00\x05\x55")
+ check_utf_32_both_ways("\u04AA", "\x00\x00\x04\xAA")
+ check_utf_32_both_ways("\u0333", "\x00\x00\x03\x33")
+ check_utf_32_both_ways("\u04CC", "\x00\x00\x04\xCC")
+ check_utf_32_both_ways("\u00F0", "\x00\x00\x00\xF0")
+ check_utf_32_both_ways("\u070F", "\x00\x00\x07\x0F")
+ check_utf_32_both_ways("\u07FF", "\x00\x00\x07\xFF")
+ check_utf_32_both_ways("\u0800", "\x00\x00\x08\x00")
+ check_utf_32_both_ways("\uD7FF", "\x00\x00\xD7\xFF")
+ check_utf_32_both_ways("\uE000", "\x00\x00\xE0\x00")
+ check_utf_32_both_ways("\uFFFF", "\x00\x00\xFF\xFF")
+ check_utf_32_both_ways("\u5555", "\x00\x00\x55\x55")
+ check_utf_32_both_ways("\uAAAA", "\x00\x00\xAA\xAA")
+ check_utf_32_both_ways("\u3333", "\x00\x00\x33\x33")
+ check_utf_32_both_ways("\uCCCC", "\x00\x00\xCC\xCC")
+ check_utf_32_both_ways("\uF0F0", "\x00\x00\xF0\xF0")
+ check_utf_32_both_ways("\u0F0F", "\x00\x00\x0F\x0F")
+ check_utf_32_both_ways("\uFF00", "\x00\x00\xFF\x00")
+ check_utf_32_both_ways("\u00FF", "\x00\x00\x00\xFF")
+ # outer planes
+ check_utf_32_both_ways("\u{10000}", "\x00\x01\x00\x00")
+ check_utf_32_both_ways("\u{FFFFF}", "\x00\x0F\xFF\xFF")
+ check_utf_32_both_ways("\u{100000}","\x00\x10\x00\x00")
+ check_utf_32_both_ways("\u{10FFFF}","\x00\x10\xFF\xFF")
+ check_utf_32_both_ways("\u{105555}","\x00\x10\x55\x55")
+ check_utf_32_both_ways("\u{55555}", "\x00\x05\x55\x55")
+ check_utf_32_both_ways("\u{AAAAA}", "\x00\x0A\xAA\xAA")
+ check_utf_32_both_ways("\u{33333}", "\x00\x03\x33\x33")
+ check_utf_32_both_ways("\u{CCCCC}", "\x00\x0C\xCC\xCC")
+ check_utf_32_both_ways("\u{8F0F0}", "\x00\x08\xF0\xF0")
+ check_utf_32_both_ways("\u{F0F0F}", "\x00\x0F\x0F\x0F")
+ check_utf_32_both_ways("\u{8FF00}", "\x00\x08\xFF\x00")
+ check_utf_32_both_ways("\u{F00FF}", "\x00\x0F\x00\xFF")
+ end
+
+ def test_invalid_ignore
+ # arguments only
+ assert_nothing_raised { 'abc'.encode('utf-8', invalid: :replace, replace: "") }
+ # check handling of UTF-8 ill-formed subsequences
+ assert_equal("\x00\x41\x00\x3E\x00\x42".force_encoding('UTF-16BE'),
+ "\x41\xC2\x3E\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: ""))
+ assert_equal("\x00\x41\x00\xF1\x00\x42".force_encoding('UTF-16BE'),
+ "\x41\xC2\xC3\xB1\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: ""))
+ assert_equal("\x00\x42".force_encoding('UTF-16BE'),
+ "\xF0\x80\x80\x42".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: ""))
+ assert_equal(''.force_encoding('UTF-16BE'),
+ "\x82\xAB".encode('UTF-16BE', 'UTF-8', invalid: :replace, replace: ""))
+
+ assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"),
+ "\xA1\xA1\xFF".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: ""))
+ assert_equal("\e$B\x24\x22\x24\x24\e(B".force_encoding("ISO-2022-JP"),
+ "\xA4\xA2\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: ""))
+ assert_equal("\e$B\x24\x22\x24\x24\e(B".force_encoding("ISO-2022-JP"),
+ "\xA4\xA2\xFF\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace, replace: ""))
+ end
+
+ def test_invalid_replace
+ # arguments only
+ assert_nothing_raised { 'abc'.encode('UTF-8', invalid: :replace) }
+ assert_equal("\xEF\xBF\xBD".force_encoding("UTF-8"),
+ "\x80".encode("UTF-8", "UTF-16BE", invalid: :replace))
+ assert_equal("\xFF\xFD".force_encoding("UTF-16BE"),
+ "\x80".encode("UTF-16BE", "UTF-8", invalid: :replace))
+ assert_equal("\xFD\xFF".force_encoding("UTF-16LE"),
+ "\x80".encode("UTF-16LE", "UTF-8", invalid: :replace))
+ assert_equal("\x00\x00\xFF\xFD".force_encoding("UTF-32BE"),
+ "\x80".encode("UTF-32BE", "UTF-8", invalid: :replace))
+ assert_equal("\xFD\xFF\x00\x00".force_encoding("UTF-32LE"),
+ "\x80".encode("UTF-32LE", "UTF-8", invalid: :replace))
+
+ assert_equal("\uFFFD!",
+ "\xdc\x00\x00!".encode("utf-8", "utf-16be", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\xd8\x00\x00!".encode("utf-8", "utf-16be", :invalid=>:replace))
+
+ assert_equal("\uFFFD!",
+ "\x00\xdc!\x00".encode("utf-8", "utf-16le", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x00\xd8!\x00".encode("utf-8", "utf-16le", :invalid=>:replace))
+
+ assert_equal("\uFFFD!",
+ "\x01\x00\x00\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace), "[ruby-dev:35726]")
+ assert_equal("\uFFFD!",
+ "\x00\xff\x00\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x00\x00\xd8\x00\x00\x00\x00!".encode("utf-8", "utf-32be", :invalid=>:replace))
+
+ assert_equal("\uFFFD!",
+ "\x00\x00\x00\xff!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x00\x00\xff\x00!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x00\xd8\x00\x00!\x00\x00\x00".encode("utf-8", "utf-32le", :invalid=>:replace))
+
+ assert_equal("\uFFFD!",
+ "\xff!".encode("utf-8", "euc-jp", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\xff!".encode("utf-8", "euc-jis-2004", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\xa1!".encode("utf-8", "euc-jp", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\xa1!".encode("utf-8", "euc-jis-2004", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x8f\xa1!".encode("utf-8", "euc-jp", :invalid=>:replace))
+ assert_equal("\uFFFD!",
+ "\x8f\xa1!".encode("utf-8", "euc-jis-2004", :invalid=>:replace))
+
+ assert_equal("?",
+ "\xdc\x00".encode("EUC-JP", "UTF-16BE", :invalid=>:replace), "[ruby-dev:35776]")
+ assert_equal("ab?cd?ef",
+ "\0a\0b\xdc\x00\0c\0d\xdf\x00\0e\0f".encode("EUC-JP", "UTF-16BE", :invalid=>:replace))
+
+ assert_equal("\e$B!!\e(B?".force_encoding("ISO-2022-JP"),
+ "\xA1\xA1\xFF".encode("ISO-2022-JP", "EUC-JP", invalid: :replace))
+ assert_equal("\e$B\x24\x22\e(B?\e$B\x24\x24\e(B".force_encoding("ISO-2022-JP"),
+ "\xA4\xA2\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace))
+ assert_equal("\e$B\x24\x22\e(B??\e$B\x24\x24\e(B".force_encoding("ISO-2022-JP"),
+ "\xA4\xA2\xFF\xFF\xA4\xA4".encode("ISO-2022-JP", "EUC-JP", invalid: :replace))
+ end
+
+ def test_invalid_replace_string
+ assert_equal("a<x>A", "a\x80A".encode("us-ascii", "euc-jp", :invalid=>:replace, :replace=>"<x>"))
+ assert_equal("a<x>A", "a\x80A".encode("us-ascii", "euc-jis-2004", :invalid=>:replace, :replace=>"<x>"))
+ end
+
+ def test_undef_replace
+ assert_equal("?", "\u20AC".encode("EUC-JP", :undef=>:replace), "[ruby-dev:35709]")
+ end
+
+ def test_undef_replace_string
+ assert_equal("a<x>A", "a\u3042A".encode("us-ascii", :undef=>:replace, :replace=>"<x>"))
+ end
+
+ def test_shift_jis
+ check_both_ways("\u3000", "\x81\x40", 'shift_jis') # full-width space
+ check_both_ways("\u00D7", "\x81\x7E", 'shift_jis') # ×
+ check_both_ways("\u00F7", "\x81\x80", 'shift_jis') # ÷
+ check_both_ways("\u25C7", "\x81\x9E", 'shift_jis') # ◇
+ check_both_ways("\u25C6", "\x81\x9F", 'shift_jis') # ◆
+ check_both_ways("\u25EF", "\x81\xFC", 'shift_jis') # ◯
+ check_both_ways("\u6A97", "\x9F\x40", 'shift_jis') # 檗
+ check_both_ways("\u6BEF", "\x9F\x7E", 'shift_jis') # 毯
+ check_both_ways("\u9EBE", "\x9F\x80", 'shift_jis') # 麾
+ check_both_ways("\u6CBE", "\x9F\x9E", 'shift_jis') # 沾
+ check_both_ways("\u6CBA", "\x9F\x9F", 'shift_jis') # 沺
+ check_both_ways("\u6ECC", "\x9F\xFC", 'shift_jis') # 滌
+ check_both_ways("\u6F3E", "\xE0\x40", 'shift_jis') # 漾
+ check_both_ways("\u70DD", "\xE0\x7E", 'shift_jis') # 烝
+ check_both_ways("\u70D9", "\xE0\x80", 'shift_jis') # 烙
+ check_both_ways("\u71FC", "\xE0\x9E", 'shift_jis') # 燼
+ check_both_ways("\u71F9", "\xE0\x9F", 'shift_jis') # 燹
+ check_both_ways("\u73F1", "\xE0\xFC", 'shift_jis') # 珱
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\x40".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\x7E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\x80".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9F".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xEF\xFC".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\x40".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\x7E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\x80".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9F".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xF0\xFC".encode("utf-8", 'shift_jis') }
+ #check_both_ways("\u9ADC", "\xFC\x40", 'shift_jis') # 髜 (IBM extended)
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC\x7E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC\x80".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9E".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9F".encode("utf-8", 'shift_jis') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xFC\xFC".encode("utf-8", 'shift_jis') }
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x90\xC2\x8E\x52\x8A\x77\x89\x40\x91\xE5\x8A\x77", 'shift_jis') # 青山学院大学
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\x90\x5F\x97\xD1\x8B\x60\x94\x8E", 'shift_jis') # 神林義博
+ end
+
+ def test_windows_31j
+ check_both_ways("\u222A", "\x81\xBE", 'Windows-31J') # Union
+ check_both_ways("\uFFE2", "\x81\xCA", 'Windows-31J') # Fullwidth Not Sign
+ check_both_ways("\u2235", "\x81\xE6", 'Windows-31J') # Because
+ check_both_ways("\u2160", "\x87\x54", 'Windows-31J') # Roman Numeral One
+ check_both_ways("\u2170", "\xFA\x40", 'Windows-31J') # Small Roman Numeral One
+ end
+
+ def test_euc_jp
+ check_both_ways("\u3000", "\xA1\xA1", 'euc-jp') # full-width space
+ check_both_ways("\u00D7", "\xA1\xDF", 'euc-jp') # ×
+ check_both_ways("\u00F7", "\xA1\xE0", 'euc-jp') # ÷
+ check_both_ways("\u25C7", "\xA1\xFE", 'euc-jp') # ◇
+ check_both_ways("\u25C6", "\xA2\xA1", 'euc-jp') # ◆
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xAF".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB9".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC2".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC9".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xD1".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xDB".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xEB".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF1".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFA".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFD".encode("utf-8", 'euc-jp') }
+ check_both_ways("\u25EF", "\xA2\xFE", 'euc-jp') # ◯
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xAF".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xBA".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xDB".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xE0".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xFB".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA4\xF4".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA6\xB9".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA6\xC0".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA6\xD9".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA7\xC2".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA7\xD0".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA7\xF2".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC1".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xCF\xD4".encode("utf-8", 'euc-jp') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xCF\xFE".encode("utf-8", 'euc-jp') }
+ check_both_ways("\u6A97", "\xDD\xA1", 'euc-jp') # 檗
+ check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jp') # 毯
+ check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jp') # 麾
+ check_both_ways("\u6CBE", "\xDD\xFE", 'euc-jp') # 沾
+ check_both_ways("\u6CBA", "\xDE\xA1", 'euc-jp') # 沺
+ check_both_ways("\u6ECC", "\xDE\xFE", 'euc-jp') # 滌
+ check_both_ways("\u6F3E", "\xDF\xA1", 'euc-jp') # 漾
+ check_both_ways("\u70DD", "\xDF\xDF", 'euc-jp') # 烝
+ check_both_ways("\u70D9", "\xDF\xE0", 'euc-jp') # 烙
+ check_both_ways("\u71FC", "\xDF\xFE", 'euc-jp') # 燼
+ check_both_ways("\u71F9", "\xE0\xA1", 'euc-jp') # 燹
+ check_both_ways("\u73F1", "\xE0\xFE", 'euc-jp') # 珱
+ assert_raise(Encoding::UndefinedConversionError) { "\xF4\xA7".encode("utf-8", 'euc-jp') }
+ #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended)
+
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jp') # 松本行弘
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC0\xC4\xBB\xB3\xB3\xD8\xB1\xA1\xC2\xE7\xB3\xD8", 'euc-jp') # 青山学院大学
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xBF\xC0\xCE\xD3\xB5\xC1\xC7\xEE", 'euc-jp') # 神林義博
+ end
+
+ def test_euc_jis_2004
+ check_both_ways("\u3000", "\xA1\xA1", 'euc-jis-2004') # full-width space
+ check_both_ways("\u00D7", "\xA1\xDF", 'euc-jis-2004') # ×
+ check_both_ways("\u00F7", "\xA1\xE0", 'euc-jis-2004') # ÷
+ check_both_ways("\u25C7", "\xA1\xFE", 'euc-jis-2004') # ◇
+ check_both_ways("\u25C6", "\xA2\xA1", 'euc-jis-2004') # ◆
+ check_both_ways("\uFF07", "\xA2\xAF", 'euc-jis-2004') # '
+ check_both_ways("\u309F", "\xA2\xB9", 'euc-jis-2004') # ゟ
+ check_both_ways("\u2284", "\xA2\xC2", 'euc-jis-2004') # ⊄
+ check_both_ways("\u2306", "\xA2\xC9", 'euc-jis-2004') # ⌆
+ check_both_ways("\u2295", "\xA2\xD1", 'euc-jis-2004') # ⊕
+ check_both_ways("\u3017", "\xA2\xDB", 'euc-jis-2004') # 〗
+ check_both_ways("\u2262", "\xA2\xEB", 'euc-jis-2004') # ≢
+ check_both_ways("\u2194", "\xA2\xF1", 'euc-jis-2004') # ↔
+ check_both_ways("\u266E", "\xA2\xFA", 'euc-jis-2004') # ♮
+ check_both_ways("\u2669", "\xA2\xFD", 'euc-jis-2004') # ♩
+ check_both_ways("\u25EF", "\xA2\xFE", 'euc-jis-2004') # ◯
+ check_both_ways("\u2935", "\xA3\xAF", 'euc-jis-2004') # ⤵
+ check_both_ways("\u29BF", "\xA3\xBA", 'euc-jis-2004') # ⦿
+ check_both_ways("\u2022", "\xA3\xC0", 'euc-jis-2004') # •
+ check_both_ways("\u2213", "\xA3\xDB", 'euc-jis-2004') # ∓
+ check_both_ways("\u2127", "\xA3\xE0", 'euc-jis-2004') # ℧
+ check_both_ways("\u30A0", "\xA3\xFB", 'euc-jis-2004') # ゠
+ check_both_ways("\uFF54", "\xA3\xF4", 'euc-jis-2004') # t
+ assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jis-2004') }
+ check_both_ways("\u2664", "\xA6\xB9", 'euc-jis-2004') # ♤
+ check_both_ways("\u2663", "\xA6\xC0", 'euc-jis-2004') # ♣
+ check_both_ways("\u03C2", "\xA6\xD9", 'euc-jis-2004') # ς
+ check_both_ways("\u23BE", "\xA7\xC2", 'euc-jis-2004') # ⎾
+ check_both_ways("\u23CC", "\xA7\xD0", 'euc-jis-2004') # ⏌
+ check_both_ways("\u30F7", "\xA7\xF2", 'euc-jis-2004') # ヷ
+ check_both_ways("\u3251", "\xA8\xC1", 'euc-jis-2004') # ㉑
+ check_both_ways("\u{20B9F}", "\xCF\xD4", 'euc-jis-2004') # 𠮑
+ check_both_ways("\u541E", "\xCF\xFE", 'euc-jis-2004') # 吞
+ check_both_ways("\u6A97", "\xDD\xA1", 'euc-jis-2004') # 檗
+ check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jis-2004') # 毯
+ check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jis-2004') # 麾
+ check_both_ways("\u6CBE", "\xDD\xFE", 'euc-jis-2004') # 沾
+ check_both_ways("\u6CBA", "\xDE\xA1", 'euc-jis-2004') # 沺
+ check_both_ways("\u6ECC", "\xDE\xFE", 'euc-jis-2004') # 滌
+ check_both_ways("\u6F3E", "\xDF\xA1", 'euc-jis-2004') # 漾
+ check_both_ways("\u70DD", "\xDF\xDF", 'euc-jis-2004') # 烝
+ check_both_ways("\u70D9", "\xDF\xE0", 'euc-jis-2004') # 烙
+ check_both_ways("\u71FC", "\xDF\xFE", 'euc-jis-2004') # 燼
+ check_both_ways("\u71F9", "\xE0\xA1", 'euc-jis-2004') # 燹
+ check_both_ways("\u73F1", "\xE0\xFE", 'euc-jis-2004') # 珱
+ check_both_ways("\u5653", "\xF4\xA7", 'euc-jis-2004') # 噓
+ #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended)
+
+ check_both_ways("\u9DD7", "\xFE\xE5", 'euc-jis-2004') # 鷗
+ check_both_ways("\u{2000B}", "\xAE\xA2", 'euc-jis-2004') # 𠀋
+ check_both_ways("\u{2A6B2}", "\x8F\xFE\xF6", 'euc-jis-2004') # 𪚲
+
+ check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jis-2004') # 松本行弘
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC0\xC4\xBB\xB3\xB3\xD8\xB1\xA1\xC2\xE7\xB3\xD8", 'euc-jis-2004') # 青山学院大学
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xBF\xC0\xCE\xD3\xB5\xC1\xC7\xEE", 'euc-jis-2004') # 神林義博
+ end
+
+ def test_eucjp_ms
+ check_both_ways("\u2116", "\xAD\xE2", 'eucJP-ms') # NUMERO SIGN
+ check_both_ways("\u221A", "\xA2\xE5", 'eucJP-ms') # SQUARE ROOT
+ check_both_ways("\u3231", "\xAD\xEA", 'eucJP-ms') # PARENTHESIZED IDEOGRAPH STOCK
+ check_both_ways("\uFF5E", "\xA1\xC1", 'eucJP-ms') # WAVE DASH
+ end
+
+ def test_eucjp_sjis
+ check_both_ways2("\xa1\xa1", "EUC-JP", "\x81\x40", "Shift_JIS")
+ check_both_ways2("\xa1\xdf", "EUC-JP", "\x81\x7e", "Shift_JIS")
+ check_both_ways2("\xa1\xe0", "EUC-JP", "\x81\x80", "Shift_JIS")
+ check_both_ways2("\xa1\xfe", "EUC-JP", "\x81\x9e", "Shift_JIS")
+ check_both_ways2("\xa2\xa1", "EUC-JP", "\x81\x9f", "Shift_JIS")
+ check_both_ways2("\xa2\xfe", "EUC-JP", "\x81\xfc", "Shift_JIS")
+
+ check_both_ways2("\xdd\xa1", "EUC-JP", "\x9f\x40", "Shift_JIS")
+ check_both_ways2("\xdd\xdf", "EUC-JP", "\x9f\x7e", "Shift_JIS")
+ check_both_ways2("\xdd\xe0", "EUC-JP", "\x9f\x80", "Shift_JIS")
+ check_both_ways2("\xdd\xfe", "EUC-JP", "\x9f\x9e", "Shift_JIS")
+ check_both_ways2("\xde\xa1", "EUC-JP", "\x9f\x9f", "Shift_JIS")
+ check_both_ways2("\xde\xfe", "EUC-JP", "\x9f\xfc", "Shift_JIS")
+
+ check_both_ways2("\xdf\xa1", "EUC-JP", "\xe0\x40", "Shift_JIS")
+ check_both_ways2("\xdf\xdf", "EUC-JP", "\xe0\x7e", "Shift_JIS")
+ check_both_ways2("\xdf\xe0", "EUC-JP", "\xe0\x80", "Shift_JIS")
+ check_both_ways2("\xdf\xfe", "EUC-JP", "\xe0\x9e", "Shift_JIS")
+ check_both_ways2("\xe0\xa1", "EUC-JP", "\xe0\x9f", "Shift_JIS")
+ check_both_ways2("\xe0\xfe", "EUC-JP", "\xe0\xfc", "Shift_JIS")
+
+ check_both_ways2("\xf4\xa1", "EUC-JP", "\xea\x9f", "Shift_JIS")
+ check_both_ways2("\xf4\xa2", "EUC-JP", "\xea\xa0", "Shift_JIS")
+ check_both_ways2("\xf4\xa3", "EUC-JP", "\xea\xa1", "Shift_JIS")
+ check_both_ways2("\xf4\xa4", "EUC-JP", "\xea\xa2", "Shift_JIS") # end of JIS X 0208 1983
+ check_both_ways2("\xf4\xa5", "EUC-JP", "\xea\xa3", "Shift_JIS")
+ check_both_ways2("\xf4\xa6", "EUC-JP", "\xea\xa4", "Shift_JIS") # end of JIS X 0208 1990
+
+ check_both_ways2("\x8e\xa1", "EUC-JP", "\xa1", "Shift_JIS")
+ check_both_ways2("\x8e\xdf", "EUC-JP", "\xdf", "Shift_JIS")
+ end
+
+ def test_eucjp_sjis_unassigned
+ check_both_ways2("\xfd\xa1", "EUC-JP", "\xef\x40", "Shift_JIS")
+ check_both_ways2("\xfd\xa1", "EUC-JP", "\xef\x40", "Shift_JIS")
+ check_both_ways2("\xfd\xdf", "EUC-JP", "\xef\x7e", "Shift_JIS")
+ check_both_ways2("\xfd\xe0", "EUC-JP", "\xef\x80", "Shift_JIS")
+ check_both_ways2("\xfd\xfe", "EUC-JP", "\xef\x9e", "Shift_JIS")
+ check_both_ways2("\xfe\xa1", "EUC-JP", "\xef\x9f", "Shift_JIS")
+ check_both_ways2("\xfe\xfe", "EUC-JP", "\xef\xfc", "Shift_JIS")
+ end
+
+ def test_eucjp_sjis_undef
+ assert_raise(Encoding::UndefinedConversionError) { "\x8e\xe0".encode("Shift_JIS", "EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8e\xfe".encode("Shift_JIS", "EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xa1".encode("Shift_JIS", "EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xfe".encode("Shift_JIS", "EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xa1".encode("Shift_JIS", "EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xfe".encode("Shift_JIS", "EUC-JP") }
+
+ assert_raise(Encoding::UndefinedConversionError) { "\xf0\x40".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xf0\x7e".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xf0\x80".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xf0\xfc".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xfc\x40".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xfc\x7e".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xfc\x80".encode("EUC-JP", "Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\xfc\xfc".encode("EUC-JP", "Shift_JIS") }
+ end
+
+ def test_iso_2022_jp
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(A".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(A".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$C".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x0e".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(Dd!\x1b(B".encode("utf-8", "iso-2022-jp") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u9299".encode("iso-2022-jp") }
+ assert_raise(Encoding::UndefinedConversionError) { "\uff71\uff72\uff73\uff74\uff75".encode("iso-2022-jp") }
+ assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(I12345\x1b(B".encode("utf-8", "iso-2022-jp") }
+ assert_equal("\xA1\xA1".force_encoding("euc-jp"),
+ "\e$B!!\e(B".encode("EUC-JP", "ISO-2022-JP"))
+ assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"),
+ "\xA1\xA1".encode("ISO-2022-JP", "EUC-JP"))
+ end
+
+ def test_from_cp50221
+ assert_equal("!", "\e(B\x21".encode("utf-8", "cp50221"))
+ assert_equal("!", "\e(J\x21".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\xB1".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\e(B\xB1".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\e(J\xB1".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\e(I\xB1".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\e(I\x31".encode("utf-8", "cp50221"))
+ assert_equal("\uFF71", "\x0E\xB1".encode("utf-8", "cp50221"))
+ assert_equal("\u3000", "\e$@\x21\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u3000", "\e$B\x21\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u2460", "\e$B\x2D\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u7e8a", "\e$B\x79\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u5fde", "\e$B\x7A\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u72be", "\e$B\x7B\x21".encode("utf-8", "cp50221"))
+ assert_equal("\u91d7", "\e$B\x7C\x21".encode("utf-8", "cp50221"))
+ assert_equal("\xA1\xDF".force_encoding("sjis"),
+ "\e(I!_\e(B".encode("sjis","cp50220"))
+ end
+
+ def test_to_cp50221
+ assert_equal("\e$B!#!,\e(B".force_encoding("cp50220"),
+ "\xA1\xDF".encode("cp50220","sjis"))
+ assert_equal("\e$B%*!+%,%I%J!+%N!+%P%\\%^!+%Q%]%\"\e(B".force_encoding("cp50220"),
+ "\xB5\xDE\xB6\xDE\xC4\xDE\xC5\xDE\xC9\xDE\xCA\xDE\xCE\xDE\xCF\xDE\xCA\xDF\xCE\xDF\xB1".
+ encode("cp50220", "sjis"))
+ end
+
+ def test_iso_2022_jp_1
+ # check_both_ways("\u9299", "\x1b$(Dd!\x1b(B", "iso-2022-jp-1") # JIS X 0212 区68 点01 銙
+ end
+
+ def test_unicode_public_review_issue_121 # see http://www.unicode.org/review/pr-121.html
+ assert_equal("\x00\x61\xFF\xFD\xFF\xFD\xFF\xFD\x00\x62".force_encoding('UTF-16BE'),
+ "\x61\xF1\x80\x80\xE1\x80\xC2\x62".encode('UTF-16BE', 'UTF-8', invalid: :replace)) # option 2
+ assert_equal("\x61\x00\xFD\xFF\xFD\xFF\xFD\xFF\x62\x00".force_encoding('UTF-16LE'),
+ "\x61\xF1\x80\x80\xE1\x80\xC2\x62".encode('UTF-16LE', 'UTF-8', invalid: :replace)) # option 2
+
+ # additional clarification
+ assert_equal("\xFF\xFD\xFF\xFD\xFF\xFD\xFF\xFD".force_encoding('UTF-16BE'),
+ "\xF0\x80\x80\x80".encode('UTF-16BE', 'UTF-8', invalid: :replace))
+ assert_equal("\xFD\xFF\xFD\xFF\xFD\xFF\xFD\xFF".force_encoding('UTF-16LE'),
+ "\xF0\x80\x80\x80".encode('UTF-16LE', 'UTF-8', invalid: :replace))
+ end
+
+ def test_yen_sign
+ check_both_ways("\u005C", "\x5C", "Shift_JIS")
+ check_both_ways("\u005C", "\x5C", "Windows-31J")
+ check_both_ways("\u005C", "\x5C", "EUC-JP")
+ check_both_ways("\u005C", "\x5C", "eucJP-ms")
+ check_both_ways("\u005C", "\x5C", "CP51932")
+ check_both_ways("\u005C", "\x5C", "ISO-2022-JP")
+ assert_equal("\u005C", "\e(B\x5C\e(B".encode("UTF-8", "ISO-2022-JP"))
+ assert_equal("\u005C", "\e(J\x5C\e(B".encode("UTF-8", "ISO-2022-JP"))
+ assert_equal("\u005C", "\x5C".encode("stateless-ISO-2022-JP", "ISO-2022-JP"))
+ assert_equal("\u005C", "\e(J\x5C\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP"))
+ assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Windows-31J") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("eucJP-ms") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("CP51932") }
+
+ # FULLWIDTH REVERSE SOLIDUS
+ check_both_ways("\uFF3C", "\x81\x5F", "Shift_JIS")
+ check_both_ways("\uFF3C", "\x81\x5F", "Windows-31J")
+ check_both_ways("\uFF3C", "\xA1\xC0", "EUC-JP")
+ check_both_ways("\uFF3C", "\xA1\xC0", "eucJP-ms")
+ check_both_ways("\uFF3C", "\xA1\xC0", "CP51932")
+ end
+
+ def test_tilde_overline
+ check_both_ways("\u007E", "\x7E", "Shift_JIS")
+ check_both_ways("\u007E", "\x7E", "Windows-31J")
+ check_both_ways("\u007E", "\x7E", "EUC-JP")
+ check_both_ways("\u007E", "\x7E", "eucJP-ms")
+ check_both_ways("\u007E", "\x7E", "CP51932")
+ check_both_ways("\u007E", "\x7E", "ISO-2022-JP")
+ assert_equal("\u007E", "\e(B\x7E\e(B".encode("UTF-8", "ISO-2022-JP"))
+ assert_equal("\u007E", "\e(J\x7E\e(B".encode("UTF-8", "ISO-2022-JP"))
+ assert_equal("\u007E", "\x7E".encode("stateless-ISO-2022-JP", "ISO-2022-JP"))
+ assert_equal("\u007E", "\e(J\x7E\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP"))
+ assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Shift_JIS") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Windows-31J") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("EUC-JP") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("eucJP-ms") }
+ assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("CP51932") }
+ end
+
+ def test_gb2312
+ check_both_ways("\u3000", "\xA1\xA1", 'GB2312') # full-width space
+ check_both_ways("\u3013", "\xA1\xFE", 'GB2312') # 〓
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB2312') }
+ check_both_ways("\u2488", "\xA2\xB1", 'GB2312') # ⒈
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB2312') }
+ check_both_ways("\u3220", "\xA2\xE5", 'GB2312') # ㈠
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB2312') }
+ check_both_ways("\u2160", "\xA2\xF1", 'GB2312') # Ⅰ
+ check_both_ways("\uFF01", "\xA3\xA1", 'GB2312') # !
+ check_both_ways("\uFFE3", "\xA3\xFE", 'GB2312') #  ̄
+ check_both_ways("\u3041", "\xA4\xA1", 'GB2312') # ぁ
+ check_both_ways("\u30A1", "\xA5\xA1", 'GB2312') # ァ
+ check_both_ways("\u0391", "\xA6\xA1", 'GB2312') # Α
+ check_both_ways("\u03B1", "\xA6\xC1", 'GB2312') # α
+ check_both_ways("\u0410", "\xA7\xA1", 'GB2312') # А
+ check_both_ways("\u0430", "\xA7\xD1", 'GB2312') # а
+ check_both_ways("\u0101", "\xA8\xA1", 'GB2312') # ā
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB2312') }
+ check_both_ways("\u3105", "\xA8\xC5", 'GB2312') # ㄅ
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB2312') }
+ check_both_ways("\u2500", "\xA9\xA4", 'GB2312') # ─
+ check_both_ways("\u554A", "\xB0\xA1", 'GB2312') # 啊
+ check_both_ways("\u5265", "\xB0\xFE", 'GB2312') # 剥
+ check_both_ways("\u4FCA", "\xBF\xA1", 'GB2312') # 俊
+ check_both_ways("\u5080", "\xBF\xFE", 'GB2312') # 傀
+ check_both_ways("\u9988", "\xC0\xA1", 'GB2312') # 馈
+ check_both_ways("\u4FD0", "\xC0\xFE", 'GB2312') # 俐
+ check_both_ways("\u7A00", "\xCF\xA1", 'GB2312') # 稀
+ check_both_ways("\u6653", "\xCF\xFE", 'GB2312') # 晓
+ check_both_ways("\u5C0F", "\xD0\xA1", 'GB2312') # 小
+ check_both_ways("\u7384", "\xD0\xFE", 'GB2312') # 玄
+ check_both_ways("\u4F4F", "\xD7\xA1", 'GB2312') # 住
+ check_both_ways("\u5EA7", "\xD7\xF9", 'GB2312') # 座
+ assert_raise(Encoding::UndefinedConversionError) { "\xD7\xFA".encode("utf-8", 'GB2312') }
+ check_both_ways("\u647A", "\xDF\xA1", 'GB2312') # 摺
+ check_both_ways("\u553C", "\xDF\xFE", 'GB2312') # 唼
+ check_both_ways("\u5537", "\xE0\xA1", 'GB2312') # 唷
+ check_both_ways("\u5E3C", "\xE0\xFE", 'GB2312') # 帼
+ check_both_ways("\u94E9", "\xEF\xA1", 'GB2312') # 铩
+ check_both_ways("\u7A14", "\xEF\xFE", 'GB2312') # 稔
+ check_both_ways("\u7A39", "\xF0\xA1", 'GB2312') # 稹
+ check_both_ways("\u7619", "\xF0\xFE", 'GB2312') # 瘙
+ check_both_ways("\u9CCC", "\xF7\xA1", 'GB2312') # 鳌
+ check_both_ways("\u9F44", "\xF7\xFE", 'GB2312') # 齄
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GB2312') # 青山学院大学
+ end
+
+ def test_gbk
+ check_both_ways("\u4E02", "\x81\x40", 'GBK') # 丂
+ check_both_ways("\u4E8A", "\x81\x7E", 'GBK') # 亊
+ check_both_ways("\u4E90", "\x81\x80", 'GBK') # 亐
+ check_both_ways("\u4FA2", "\x81\xFE", 'GBK') # 侢
+ check_both_ways("\u5EC6", "\x8F\x40", 'GBK') # 廆
+ check_both_ways("\u5F24", "\x8F\x7E", 'GBK') # 弤
+ check_both_ways("\u5F28", "\x8F\x80", 'GBK') # 弨
+ check_both_ways("\u6007", "\x8F\xFE", 'GBK') # 怇
+ check_both_ways("\u6008", "\x90\x40", 'GBK') # 怈
+ check_both_ways("\u6080", "\x90\x7E", 'GBK') # 悀
+ check_both_ways("\u6081", "\x90\x80", 'GBK') # 悁
+ check_both_ways("\u6146", "\x90\xFE", 'GBK') # 慆
+ check_both_ways("\u70DC", "\x9F\x40", 'GBK') # 烜
+ check_both_ways("\u7134", "\x9F\x7E", 'GBK') # 焴
+ check_both_ways("\u7135", "\x9F\x80", 'GBK') # 焵
+ check_both_ways("\u71D3", "\x9F\xFE", 'GBK') # 燓
+ check_both_ways("\u71D6", "\xA0\x40", 'GBK') # 燖
+ check_both_ways("\u721A", "\xA0\x7E", 'GBK') # 爚
+ check_both_ways("\u721B", "\xA0\x80", 'GBK') # 爛
+ check_both_ways("\u72DB", "\xA0\xFE", 'GBK') # 狛
+ check_both_ways("\u3000", "\xA1\xA1", 'GBK') # full-width space
+ check_both_ways("\u3001", "\xA1\xA2", 'GBK') # 、
+ check_both_ways("\u3013", "\xA1\xFE", 'GBK') # 〓
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GBK') }
+ check_both_ways("\u2170", "\xA2\xA1", 'GBK') # ⅰ
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GBK') }
+ check_both_ways("\u2488", "\xA2\xB1", 'GBK') # ⒈
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GBK') }
+ check_both_ways("\u3220", "\xA2\xE5", 'GBK') # ㈠
+ assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GBK') }
+ check_both_ways("\u2160", "\xA2\xF1", 'GBK') # Ⅰ
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GBK') }
+ check_both_ways("\uFF01", "\xA3\xA1", 'GBK') # !
+ check_both_ways("\uFFE3", "\xA3\xFE", 'GBK') #  ̄
+ assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GBK') }
+ check_both_ways("\u3041", "\xA4\xA1", 'GBK') # ぁ
+ assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GBK') }
+ check_both_ways("\u30A1", "\xA5\xA1", 'GBK') # ァ
+ check_both_ways("\u0391", "\xA6\xA1", 'GBK') # Α
+ check_both_ways("\u03B1", "\xA6\xC1", 'GBK') # α
+ assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GBK') }
+ check_both_ways("\uFE3B", "\xA6\xEE", 'GBK') # ︻
+ check_both_ways("\u0410", "\xA7\xA1", 'GBK') # А
+ check_both_ways("\u0430", "\xA7\xD1", 'GBK') # а
+ check_both_ways("\u02CA", "\xA8\x40", 'GBK') # ˊ
+ check_both_ways("\u2587", "\xA8\x7E", 'GBK') # ▇
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GBK') }
+ check_both_ways("\u0101", "\xA8\xA1", 'GBK') # ā
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GBK') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GBK') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GBK') }
+ check_both_ways("\u3105", "\xA8\xC5", 'GBK') # ㄅ
+ check_both_ways("\u3021", "\xA9\x40", 'GBK') # 〡
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GBK') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GBK') }
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GBK') }
+ check_both_ways("\u3007", "\xA9\x96", 'GBK') # 〇
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GBK') }
+ check_both_ways("\u2500", "\xA9\xA4", 'GBK') # ─
+ assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GBK') }
+ check_both_ways("\u7588", "\xAF\x40", 'GBK') # 疈
+ check_both_ways("\u7607", "\xAF\x7E", 'GBK') # 瘇
+ check_both_ways("\u7608", "\xAF\x80", 'GBK') # 瘈
+ check_both_ways("\u7644", "\xAF\xA0", 'GBK') # 癄
+ assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GBK') }
+ check_both_ways("\u7645", "\xB0\x40", 'GBK') # 癅
+ check_both_ways("\u769B", "\xB0\x7E", 'GBK') # 皛
+ check_both_ways("\u769C", "\xB0\x80", 'GBK') # 皜
+ check_both_ways("\u5265", "\xB0\xFE", 'GBK') # 剥
+ check_both_ways("\u7DFB", "\xBF\x40", 'GBK') # 緻
+ check_both_ways("\u7E39", "\xBF\x7E", 'GBK') # 縹
+ check_both_ways("\u7E3A", "\xBF\x80", 'GBK') # 縺
+ check_both_ways("\u5080", "\xBF\xFE", 'GBK') # 傀
+ check_both_ways("\u7E5E", "\xC0\x40", 'GBK') # 繞
+ check_both_ways("\u7E9E", "\xC0\x7E", 'GBK') # 纞
+ check_both_ways("\u7EAE", "\xC0\x80", 'GBK') # 纮
+ check_both_ways("\u4FD0", "\xC0\xFE", 'GBK') # 俐
+ check_both_ways("\u87A5", "\xCF\x40", 'GBK') # 螥
+ check_both_ways("\u87F8", "\xCF\x7E", 'GBK') # 蟸
+ check_both_ways("\u87FA", "\xCF\x80", 'GBK') # 蟺
+ check_both_ways("\u6653", "\xCF\xFE", 'GBK') # 晓
+ check_both_ways("\u8824", "\xD0\x40", 'GBK') # 蠤
+ check_both_ways("\u887A", "\xD0\x7E", 'GBK') # 衺
+ check_both_ways("\u887B", "\xD0\x80", 'GBK') # 衻
+ check_both_ways("\u7384", "\xD0\xFE", 'GBK') # 玄
+ check_both_ways("\u9019", "\xDF\x40", 'GBK') # 這
+ check_both_ways("\u9081", "\xDF\x7E", 'GBK') # 邁
+ check_both_ways("\u9084", "\xDF\x80", 'GBK') # 還
+ check_both_ways("\u553C", "\xDF\xFE", 'GBK') # 唼
+ check_both_ways("\u90C2", "\xE0\x40", 'GBK') # 郂
+ check_both_ways("\u911C", "\xE0\x7E", 'GBK') # 鄜
+ check_both_ways("\u911D", "\xE0\x80", 'GBK') # 鄝
+ check_both_ways("\u5E3C", "\xE0\xFE", 'GBK') # 帼
+ check_both_ways("\u986F", "\xEF\x40", 'GBK') # 顯
+ check_both_ways("\u98E4", "\xEF\x7E", 'GBK') # 飤
+ check_both_ways("\u98E5", "\xEF\x80", 'GBK') # 飥
+ check_both_ways("\u7A14", "\xEF\xFE", 'GBK') # 稔
+ check_both_ways("\u9908", "\xF0\x40", 'GBK') # 餈
+ check_both_ways("\u9949", "\xF0\x7E", 'GBK') # 饉
+ check_both_ways("\u994A", "\xF0\x80", 'GBK') # 饊
+ check_both_ways("\u7619", "\xF0\xFE", 'GBK') # 瘙
+ check_both_ways("\u9F32", "\xFD\x40", 'GBK') # 鼲
+ check_both_ways("\u9F78", "\xFD\x7E", 'GBK') # 齸
+ check_both_ways("\u9F79", "\xFD\x80", 'GBK') # 齹
+ check_both_ways("\uF9F1", "\xFD\xA0", 'GBK') # 隣
+ assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GBK') }
+ check_both_ways("\uFA0C", "\xFE\x40", 'GBK') # 兀
+ check_both_ways("\uFA29", "\xFE\x4F", 'GBK') # 﨩
+ assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GBK') }
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GBK') # 青山学院大学
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GBK') # 神林義博
+ end
+
+ def test_gb18030
+ # overall roundtrip test
+ all_unicode = (0x0..0xD7FF).to_a.pack 'U*' #追加
+ all_unicode << (0xE000..0xFFFF).to_a.pack("U*") #追加
+
+ assert_equal(all_unicode, all_unicode.encode("gb18030").encode("UTF-8")) #追加
+
+ # tests from GBK
+ check_both_ways("\u4E02", "\x81\x40", 'GB18030') #
+ check_both_ways("\u4E8A", "\x81\x7E", 'GB18030') #
+ check_both_ways("\u4E90", "\x81\x80", 'GB18030') #
+ check_both_ways("\u4FA2", "\x81\xFE", 'GB18030') # 侢
+ check_both_ways("\u5EC6", "\x8F\x40", 'GB18030') #
+ check_both_ways("\u5F24", "\x8F\x7E", 'GB18030') # 弤
+ check_both_ways("\u5F28", "\x8F\x80", 'GB18030') # 弨
+ check_both_ways("\u6007", "\x8F\xFE", 'GB18030') #
+ check_both_ways("\u6008", "\x90\x40", 'GB18030') #
+ check_both_ways("\u6080", "\x90\x7E", 'GB18030') # 悀
+ check_both_ways("\u6081", "\x90\x80", 'GB18030') #
+ check_both_ways("\u6146", "\x90\xFE", 'GB18030') #
+ check_both_ways("\u70DC", "\x9F\x40", 'GB18030') #
+ check_both_ways("\u7134", "\x9F\x7E", 'GB18030') # 焴
+ check_both_ways("\u7135", "\x9F\x80", 'GB18030') # 焵
+ check_both_ways("\u71D3", "\x9F\xFE", 'GB18030') #
+ check_both_ways("\u71D6", "\xA0\x40", 'GB18030') #
+ check_both_ways("\u721A", "\xA0\x7E", 'GB18030') #
+ check_both_ways("\u721B", "\xA0\x80", 'GB18030') #
+ check_both_ways("\u72DB", "\xA0\xFE", 'GB18030') #
+ check_both_ways("\u3000", "\xA1\xA1", 'GB18030') # full-width space
+ check_both_ways("\u3001", "\xA1\xA2", 'GB18030') #
+ check_both_ways("\u3013", "\xA1\xFE", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u2170", "\xA2\xA1", 'GB18030') # ⅰ
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u2488", "\xA2\xB1", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB18030') }
+ check_both_ways("\u3220", "\xA2\xE5", 'GB18030') # ㈠
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u2160", "\xA2\xF1", 'GB18030') # Ⅰ
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GB18030') }
+ check_both_ways("\uFF01", "\xA3\xA1", 'GB18030') # E
+ check_both_ways("\uFFE3", "\xA3\xFE", 'GB18030') # E
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u3041", "\xA4\xA1", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u30A1", "\xA5\xA1", 'GB18030') # ァ
+ check_both_ways("\u0391", "\xA6\xA1", 'GB18030') #
+ check_both_ways("\u03B1", "\xA6\xC1", 'GB18030') # α
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GB18030') }
+ check_both_ways("\uFE3B", "\xA6\xEE", 'GB18030') # E
+ check_both_ways("\u0410", "\xA7\xA1", 'GB18030') #
+ check_both_ways("\u0430", "\xA7\xD1", 'GB18030') # а
+ check_both_ways("\u02CA", "\xA8\x40", 'GB18030') #
+ check_both_ways("\u2587", "\xA8\x7E", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GB18030') }
+ check_both_ways("\u0101", "\xA8\xA1", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GB18030') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GB18030') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB18030') }
+ check_both_ways("\u3105", "\xA8\xC5", 'GB18030') #
+ check_both_ways("\u3021", "\xA9\x40", 'GB18030') # 〡
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GB18030') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GB18030') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GB18030') }
+ check_both_ways("\u3007", "\xA9\x96", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB18030') }
+ check_both_ways("\u2500", "\xA9\xA4", 'GB18030') # ─
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GB18030') }
+ check_both_ways("\u7588", "\xAF\x40", 'GB18030') #
+ check_both_ways("\u7607", "\xAF\x7E", 'GB18030') #
+ check_both_ways("\u7608", "\xAF\x80", 'GB18030') #
+ check_both_ways("\u7644", "\xAF\xA0", 'GB18030') #
+ #assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GB18030') }
+ check_both_ways("\u7645", "\xB0\x40", 'GB18030') #
+ check_both_ways("\u769B", "\xB0\x7E", 'GB18030') #
+ check_both_ways("\u769C", "\xB0\x80", 'GB18030') #
+ check_both_ways("\u5265", "\xB0\xFE", 'GB18030') # 剥
+ check_both_ways("\u7DFB", "\xBF\x40", 'GB18030') # 緻
+ check_both_ways("\u7E39", "\xBF\x7E", 'GB18030') # 縹
+ check_both_ways("\u7E3A", "\xBF\x80", 'GB18030') # 縺
+ check_both_ways("\u5080", "\xBF\xFE", 'GB18030') # 傀
+ check_both_ways("\u7E5E", "\xC0\x40", 'GB18030') #
+ check_both_ways("\u7E9E", "\xC0\x7E", 'GB18030') #
+ check_both_ways("\u7EAE", "\xC0\x80", 'GB18030') # 纮
+ check_both_ways("\u4FD0", "\xC0\xFE", 'GB18030') #
+ check_both_ways("\u87A5", "\xCF\x40", 'GB18030') # 螥
+ check_both_ways("\u87F8", "\xCF\x7E", 'GB18030') # 蟸
+ check_both_ways("\u87FA", "\xCF\x80", 'GB18030') # 蟺
+ check_both_ways("\u6653", "\xCF\xFE", 'GB18030') #
+ check_both_ways("\u8824", "\xD0\x40", 'GB18030') # 蠤
+ check_both_ways("\u887A", "\xD0\x7E", 'GB18030') # 衺
+ check_both_ways("\u887B", "\xD0\x80", 'GB18030') # 衻
+ check_both_ways("\u7384", "\xD0\xFE", 'GB18030') #
+ check_both_ways("\u9019", "\xDF\x40", 'GB18030') #
+ check_both_ways("\u9081", "\xDF\x7E", 'GB18030') #
+ check_both_ways("\u9084", "\xDF\x80", 'GB18030') #
+ check_both_ways("\u553C", "\xDF\xFE", 'GB18030') # 唼
+ check_both_ways("\u90C2", "\xE0\x40", 'GB18030') #
+ check_both_ways("\u911C", "\xE0\x7E", 'GB18030') #
+ check_both_ways("\u911D", "\xE0\x80", 'GB18030') #
+ check_both_ways("\u5E3C", "\xE0\xFE", 'GB18030') # 帼
+ check_both_ways("\u986F", "\xEF\x40", 'GB18030') # 顯
+ check_both_ways("\u98E4", "\xEF\x7E", 'GB18030') # 飤
+ check_both_ways("\u98E5", "\xEF\x80", 'GB18030') # 飥
+ check_both_ways("\u7A14", "\xEF\xFE", 'GB18030') #
+ check_both_ways("\u9908", "\xF0\x40", 'GB18030') #
+ check_both_ways("\u9949", "\xF0\x7E", 'GB18030') #
+ check_both_ways("\u994A", "\xF0\x80", 'GB18030') #
+ check_both_ways("\u7619", "\xF0\xFE", 'GB18030') #
+ check_both_ways("\u9F32", "\xFD\x40", 'GB18030') # 鼲
+ check_both_ways("\u9F78", "\xFD\x7E", 'GB18030') # 齸
+ check_both_ways("\u9F79", "\xFD\x80", 'GB18030') # 齹
+ check_both_ways("\uF9F1", "\xFD\xA0", 'GB18030') # E
+ #assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GB18030') }
+ check_both_ways("\uFA0C", "\xFE\x40", 'GB18030') # E
+ check_both_ways("\uFA29", "\xFE\x4F", 'GB18030') # E
+ #assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GB18030') }
+ check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GB18030') # 青山学院大学
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GB18030') # 神林義
+
+ # new tests for GB18030
+ check_both_ways("\u9FA6", "\x82\x35\x8F\x33", 'GB18030') # 龦
+ check_both_ways("\uD7FF", "\x83\x36\xC7\x38", 'GB18030') # No name ()
+
+ check_both_ways("\u0452", "\x81\x30\xD3\x30", 'GB18030') #
+ check_both_ways("\u200F", "\x81\x36\xA5\x31", 'GB18030') # RIGHT-TO-LEFT MARK
+
+ check_both_ways("\uE865", "\x83\x36\xD0\x30", 'GB18030') # No name (Private Use Area)
+ check_both_ways("\uF92B", "\x84\x30\x85\x34", 'GB18030') # E
+
+ check_both_ways("\u2643", "\x81\x37\xA8\x39", 'GB18030') #
+ check_both_ways("\u2E80", "\x81\x38\xFD\x38", 'GB18030') # ⺀
+
+ check_both_ways("\uFA2A", "\x84\x30\x9C\x38", 'GB18030') # E
+ check_both_ways("\uFE2F", "\x84\x31\x85\x37", 'GB18030') # No name (Combining Half Marks)
+
+ check_both_ways("\u3CE1", "\x82\x31\xD4\x38", 'GB18030') # 㳡
+ check_both_ways("\u4055", "\x82\x32\xAF\x32", 'GB18030') #
+
+ check_both_ways("\u361B", "\x82\x30\xA6\x33", 'GB18030') #
+ check_both_ways("\u3917", "\x82\x30\xF2\x37", 'GB18030') #
+
+ check_both_ways("\u49B8", "\x82\x34\xA1\x31", 'GB18030') # 䦸
+ check_both_ways("\u4C76", "\x82\x34\xE7\x33", 'GB18030') # 䱶
+
+ check_both_ways("\u4160", "\x82\x32\xC9\x37", 'GB18030') # 䅠
+ check_both_ways("\u4336", "\x82\x32\xF8\x37", 'GB18030') # 䌶
+
+ check_both_ways("\u478E", "\x82\x33\xE8\x38", 'GB18030') #
+ check_both_ways("\u4946", "\x82\x34\x96\x38", 'GB18030') #
+
+ check_both_ways("\u44D7", "\x82\x33\xA3\x39", 'GB18030') #
+ check_both_ways("\u464B", "\x82\x33\xC9\x31", 'GB18030') #
+
+ check_both_ways("\uFFE6", "\x84\x31\xA2\x34", 'GB18030') # E
+ check_both_ways("\uFFFF", "\x84\x31\xA4\x39", 'GB18030') # not a character
+
+ check_both_ways("\u{10000}", "\x90\x30\x81\x30", 'GB18030') # 𐀀
+ check_both_ways("\u{10FFFE}", "\xE3\x32\x9A\x34", 'GB18030') # No name (Not a character)
+ check_both_ways("\u{10FFFF}", "\xE3\x32\x9A\x35", 'GB18030') # No name (Not a character)
+ end
+
+ def test_Big5
+ check_both_ways("\u3000", "\xA1\x40", 'Big5') # full-width space
+ check_both_ways("\uFE5A", "\xA1\x7E", 'Big5') # ﹚
+ check_both_ways("\uFE5B", "\xA1\xA1", 'Big5') # ﹛
+ #check_both_ways("\uFF0F", "\xA1\xFE", 'Big5') # /
+ check_both_ways("\uFF57", "\xA3\x40", 'Big5') # w
+ check_both_ways("\u310F", "\xA3\x7E", 'Big5') # ㄏ
+ check_both_ways("\u3110", "\xA3\xA1", 'Big5') # ㄐ
+ check_both_ways("\u02CB", "\xA3\xBF", 'Big5') # ˋ
+ assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5') }
+ check_both_ways("\u6D6C", "\xAF\x40", 'Big5') # 浬
+ check_both_ways("\u7837", "\xAF\x7E", 'Big5') # 砷
+ check_both_ways("\u7825", "\xAF\xA1", 'Big5') # 砥
+ check_both_ways("\u8343", "\xAF\xFE", 'Big5') # 荃
+ check_both_ways("\u8654", "\xB0\x40", 'Big5') # 虔
+ check_both_ways("\u9661", "\xB0\x7E", 'Big5') # 陡
+ check_both_ways("\u965B", "\xB0\xA1", 'Big5') # 陛
+ check_both_ways("\u5A40", "\xB0\xFE", 'Big5') # 婀
+ check_both_ways("\u6FC3", "\xBF\x40", 'Big5') # 濃
+ check_both_ways("\u7E0A", "\xBF\x7E", 'Big5') # 縊
+ check_both_ways("\u7E11", "\xBF\xA1", 'Big5') # 縑
+ check_both_ways("\u931A", "\xBF\xFE", 'Big5') # 錚
+ check_both_ways("\u9310", "\xC0\x40", 'Big5') # 錐
+ check_both_ways("\u5687", "\xC0\x7E", 'Big5') # 嚇
+ check_both_ways("\u568F", "\xC0\xA1", 'Big5') # 嚏
+ check_both_ways("\u77AC", "\xC0\xFE", 'Big5') # 瞬
+ check_both_ways("\u8B96", "\xC6\x40", 'Big5') # 讖
+ check_both_ways("\u7C72", "\xC6\x7E", 'Big5') # 籲
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5') }
+ check_both_ways("\u4E42", "\xC9\x40", 'Big5') # 乂
+ check_both_ways("\u6C15", "\xC9\x7E", 'Big5') # 氕
+ check_both_ways("\u6C36", "\xC9\xA1", 'Big5') # 氶
+ check_both_ways("\u6C4B", "\xC9\xFE", 'Big5') # 汋
+ check_both_ways("\u67DC", "\xCF\x40", 'Big5') # 柜
+ check_both_ways("\u6D42", "\xCF\x7E", 'Big5') # 浂
+ check_both_ways("\u6D01", "\xCF\xA1", 'Big5') # 洁
+ check_both_ways("\u7A80", "\xCF\xFE", 'Big5') # 窀
+ check_both_ways("\u7A7E", "\xD0\x40", 'Big5') # 穾
+ check_both_ways("\u82EA", "\xD0\x7E", 'Big5') # 苪
+ check_both_ways("\u82E4", "\xD0\xA1", 'Big5') # 苤
+ check_both_ways("\u54F1", "\xD0\xFE", 'Big5') # 哱
+ check_both_ways("\u7A1B", "\xDF\x40", 'Big5') # 稛
+ check_both_ways("\u816F", "\xDF\x7E", 'Big5') # 腯
+ check_both_ways("\u8144", "\xDF\xA1", 'Big5') # 腄
+ check_both_ways("\u89E4", "\xDF\xFE", 'Big5') # 觤
+ check_both_ways("\u89E1", "\xE0\x40", 'Big5') # 觡
+ check_both_ways("\u903F", "\xE0\x7E", 'Big5') # 逿
+ check_both_ways("\u9044", "\xE0\xA1", 'Big5') # 遄
+ check_both_ways("\u50E0", "\xE0\xFE", 'Big5') # 僠
+ check_both_ways("\u979E", "\xEF\x40", 'Big5') # 鞞
+ check_both_ways("\u9D30", "\xEF\x7E", 'Big5') # 鴰
+ check_both_ways("\u9D45", "\xEF\xA1", 'Big5') # 鵅
+ check_both_ways("\u7376", "\xEF\xFE", 'Big5') # 獶
+ check_both_ways("\u74B8", "\xF0\x40", 'Big5') # 璸
+ check_both_ways("\u81D2", "\xF0\x7E", 'Big5') # 臒
+ check_both_ways("\u81D0", "\xF0\xA1", 'Big5') # 臐
+ check_both_ways("\u8E67", "\xF0\xFE", 'Big5') # 蹧
+ check_both_ways("\u7E98", "\xF9\x40", 'Big5') # 纘
+ check_both_ways("\u9F0A", "\xF9\x7E", 'Big5') # 鼊
+ check_both_ways("\u9FA4", "\xF9\xA1", 'Big5') # 龤
+ check_both_ways("\u9F98", "\xF9\xD5", 'Big5') # 龘
+ #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5') }
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5') # 神林義博
+ end
+
+ def test_Big5_Hkscs
+ check_both_ways("\u3000", "\xA1\x40", 'Big5-HKSCS') # full-width space
+ check_both_ways("\uFE5A", "\xA1\x7E", 'Big5-HKSCS') # ﹚
+ check_both_ways("\uFE5B", "\xA1\xA1", 'Big5-HKSCS') # ﹛
+ #check_both_ways("\uFF0F", "\xA1\xFE", 'Big5-HKSCS') # /
+ check_both_ways("\uFF57", "\xA3\x40", 'Big5-HKSCS') # w
+ check_both_ways("\u310F", "\xA3\x7E", 'Big5-HKSCS') # ㄏ
+ check_both_ways("\u3110", "\xA3\xA1", 'Big5-HKSCS') # ㄐ
+ check_both_ways("\u02CB", "\xA3\xBF", 'Big5-HKSCS') # ˋ
+ #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5-HKSCS') }
+ check_both_ways("\u6D6C", "\xAF\x40", 'Big5-HKSCS') # 浬
+ check_both_ways("\u7837", "\xAF\x7E", 'Big5-HKSCS') # 砷
+ check_both_ways("\u7825", "\xAF\xA1", 'Big5-HKSCS') # 砥
+ check_both_ways("\u8343", "\xAF\xFE", 'Big5-HKSCS') # 荃
+ check_both_ways("\u8654", "\xB0\x40", 'Big5-HKSCS') # 虔
+ check_both_ways("\u9661", "\xB0\x7E", 'Big5-HKSCS') # 陡
+ check_both_ways("\u965B", "\xB0\xA1", 'Big5-HKSCS') # 陛
+ check_both_ways("\u5A40", "\xB0\xFE", 'Big5-HKSCS') # 婀
+ check_both_ways("\u6FC3", "\xBF\x40", 'Big5-HKSCS') # 濃
+ check_both_ways("\u7E0A", "\xBF\x7E", 'Big5-HKSCS') # 縊
+ check_both_ways("\u7E11", "\xBF\xA1", 'Big5-HKSCS') # 縑
+ check_both_ways("\u931A", "\xBF\xFE", 'Big5-HKSCS') # 錚
+ check_both_ways("\u9310", "\xC0\x40", 'Big5-HKSCS') # 錐
+ check_both_ways("\u5687", "\xC0\x7E", 'Big5-HKSCS') # 嚇
+ check_both_ways("\u568F", "\xC0\xA1", 'Big5-HKSCS') # 嚏
+ check_both_ways("\u77AC", "\xC0\xFE", 'Big5-HKSCS') # 瞬
+ check_both_ways("\u8B96", "\xC6\x40", 'Big5-HKSCS') # 讖
+ check_both_ways("\u7C72", "\xC6\x7E", 'Big5-HKSCS') # 籲
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5-HKSCS') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5-HKSCS') }
+ #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5-HKSCS') }
+ check_both_ways("\u4E42", "\xC9\x40", 'Big5-HKSCS') # 乂
+ check_both_ways("\u6C15", "\xC9\x7E", 'Big5-HKSCS') # 氕
+ check_both_ways("\u6C36", "\xC9\xA1", 'Big5-HKSCS') # 氶
+ check_both_ways("\u6C4B", "\xC9\xFE", 'Big5-HKSCS') # 汋
+ check_both_ways("\u67DC", "\xCF\x40", 'Big5-HKSCS') # 柜
+ check_both_ways("\u6D42", "\xCF\x7E", 'Big5-HKSCS') # 浂
+ check_both_ways("\u6D01", "\xCF\xA1", 'Big5-HKSCS') # 洁
+ check_both_ways("\u7A80", "\xCF\xFE", 'Big5-HKSCS') # 窀
+ check_both_ways("\u7A7E", "\xD0\x40", 'Big5-HKSCS') # 穾
+ check_both_ways("\u82EA", "\xD0\x7E", 'Big5-HKSCS') # 苪
+ check_both_ways("\u82E4", "\xD0\xA1", 'Big5-HKSCS') # 苤
+ check_both_ways("\u54F1", "\xD0\xFE", 'Big5-HKSCS') # 哱
+ check_both_ways("\u7A1B", "\xDF\x40", 'Big5-HKSCS') # 稛
+ check_both_ways("\u816F", "\xDF\x7E", 'Big5-HKSCS') # 腯
+ check_both_ways("\u8144", "\xDF\xA1", 'Big5-HKSCS') # 腄
+ check_both_ways("\u89E4", "\xDF\xFE", 'Big5-HKSCS') # 觤
+ check_both_ways("\u89E1", "\xE0\x40", 'Big5-HKSCS') # 觡
+ check_both_ways("\u903F", "\xE0\x7E", 'Big5-HKSCS') # 逿
+ check_both_ways("\u9044", "\xE0\xA1", 'Big5-HKSCS') # 遄
+ check_both_ways("\u50E0", "\xE0\xFE", 'Big5-HKSCS') # 僠
+ check_both_ways("\u979E", "\xEF\x40", 'Big5-HKSCS') # 鞞
+ check_both_ways("\u9D30", "\xEF\x7E", 'Big5-HKSCS') # 鴰
+ check_both_ways("\u9D45", "\xEF\xA1", 'Big5-HKSCS') # 鵅
+ check_both_ways("\u7376", "\xEF\xFE", 'Big5-HKSCS') # 獶
+ check_both_ways("\u74B8", "\xF0\x40", 'Big5-HKSCS') # 璸
+ check_both_ways("\u81D2", "\xF0\x7E", 'Big5-HKSCS') # 臒
+ check_both_ways("\u81D0", "\xF0\xA1", 'Big5-HKSCS') # 臐
+ check_both_ways("\u8E67", "\xF0\xFE", 'Big5-HKSCS') # 蹧
+ check_both_ways("\u7E98", "\xF9\x40", 'Big5-HKSCS') # 纘
+ check_both_ways("\u9F0A", "\xF9\x7E", 'Big5-HKSCS') # 鼊
+ check_both_ways("\u9FA4", "\xF9\xA1", 'Big5-HKSCS') # 龤
+ check_both_ways("\u9F98", "\xF9\xD5", 'Big5-HKSCS') # 龘
+ #check_both_ways("\u{23ED7}", "\x8E\x40", 'Big5-HKSCS') # 𣻗
+ #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5-HKSCS') }
+ check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5-HKSCS') # 神林義博
+ end
+
+ def test_Big5_UAO
+ check_both_ways("\u4e17", "\x81\x40", 'Big5-UAO') # 丗
+ end
+
+ def test_nothing_changed
+ a = "James".force_encoding("US-ASCII")
+ b = a.encode("Shift_JIS")
+ assert_equal(Encoding::US_ASCII, a.encoding)
+ assert_equal(Encoding::Shift_JIS, b.encoding)
+ end
+
+ def test_utf8_mac
+ # composition exclusion
+ assert_equal("\u05DB\u05BF", "\u05DB\u05BF".encode("UTF-8", "UTF8-MAC")) #"\u{fb4d}"
+
+ assert_equal("\u{1ff7}", "\u03C9\u0342\u0345".encode("UTF-8", "UTF8-MAC"))
+
+ assert_equal("\u05DB\u05BF", "\u{fb4d}".encode("UTF8-MAC").force_encoding("UTF-8"))
+ assert_equal("\u03C9\u0342\u0345", "\u{1ff7}".encode("UTF8-MAC").force_encoding("UTF-8"))
+
+ check_both_ways("\u{e9 74 e8}", "e\u0301te\u0300", 'UTF8-MAC')
+ end
+
+ def test_fallback
+ assert_equal("\u3042".encode("EUC-JP"), "\u{20000}".encode("EUC-JP",
+ fallback: {"\u{20000}" => "\u3042".encode("EUC-JP")}))
+ assert_equal("\u3042".encode("EUC-JP"), "\u{20000}".encode("EUC-JP",
+ fallback: {"\u{20000}" => "\u3042"}))
+ assert_equal("[ISU]", "\u{1F4BA}".encode("SJIS-KDDI",
+ fallback: {"\u{1F4BA}" => "[ISU]"}))
+ end
+
+ def test_fallback_hash_default
+ fallback = Hash.new {|h, x| "U+%.4X" % x.unpack("U")}
+ assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback))
+ end
+
+ def test_fallback_proc
+ fallback = proc {|x| "U+%.4X" % x.unpack("U")}
+ assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback))
+ end
+
+ def test_fallback_method
+ def (fallback = "U+%.4X").escape(x)
+ self % x.unpack("U")
+ end
+ assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback.method(:escape)))
+ end
+
+ bug8940 = '[ruby-core:57318] [Bug #8940]'
+ %w[UTF-32 UTF-16].each do |enc|
+ define_method("test_pseudo_encoding_inspect(#{enc})") do
+ assert_normal_exit("'aaa'.encode('#{enc}').inspect", bug8940)
+ assert_equal(4, 'aaa'.encode(enc).length, "should count in #{enc} with BOM")
+ end
+ end
+
+ def test_encode_with_invalid_chars
+ bug8995 = '[ruby-dev:47747]'
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ str = "\xff".force_encoding('utf-8')
+ assert_equal str, str.encode, bug8995
+ assert_equal "\ufffd", str.encode(invalid: :replace), bug8995
+ end
+ end
+
+ def test_valid_dummy_encoding
+ bug9314 = '[ruby-core:59354] [Bug #9314]'
+ assert_separately(%W[- -- #{bug9314}], <<-'end;')
+ bug = ARGV.shift
+ result = assert_nothing_raised(TypeError, bug) {break "test".encode(Encoding::UTF_16)}
+ assert_equal("\xFE\xFF\x00t\x00e\x00s\x00t", result.b, bug)
+ result = assert_nothing_raised(TypeError, bug) {break "test".encode(Encoding::UTF_32)}
+ assert_equal("\x00\x00\xFE\xFF\x00\x00\x00t\x00\x00\x00e\x00\x00\x00s\x00\x00\x00t", result.b, bug)
+ end;
+ end
+
+ def test_loading_race
+ assert_separately([], <<-'end;') #do
+ bug11277 = '[ruby-dev:49106] [Bug #11277]'
+ num = 2
+ th = (0...num).map do |i|
+ Thread.new {"\u3042".encode("EUC-JP")}
+ end
+ result = nil
+ assert_warning("", bug11277) do
+ assert_nothing_raised(Encoding::ConverterNotFoundError, bug11277) do
+ result = th.map(&:value)
+ end
+ end
+ expected = "\xa4\xa2".force_encoding(Encoding::EUC_JP)
+ assert_equal([expected]*num, result, bug11277)
+ end;
+ end
+
+ def test_universal_newline
+ bug11324 = '[ruby-core:69841] [Bug #11324]'
+ usascii = Encoding::US_ASCII
+ s = "A\nB\r\nC".force_encoding(usascii)
+ assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true), bug11324)
+ assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true, undef: :replace), bug11324)
+ assert_equal("A\nB\nC", s.encode(usascii, universal_newline: true, undef: :replace, replace: ''), bug11324)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_undef.rb b/jni/ruby/test/ruby/test_undef.rb
new file mode 100644
index 0000000..e1c9807
--- /dev/null
+++ b/jni/ruby/test/ruby/test_undef.rb
@@ -0,0 +1,37 @@
+require 'test/unit'
+
+class TestUndef < Test::Unit::TestCase
+ class Undef0
+ def foo
+ "foo"
+ end
+ undef foo
+ end
+
+ class Undef1
+ def bar
+ "bar"
+ end
+ end
+
+ class Undef2 < Undef1
+ undef bar
+ end
+
+ def test_undef
+ x = Undef0.new
+ assert_raise(NoMethodError) { x.foo }
+ y = Undef1.new
+ assert_equal "bar", y.bar
+ z = Undef2.new
+ assert_raise(NoMethodError) { z.foo }
+ end
+
+ def test_special_const_undef
+ assert_raise(TypeError) do
+ 1.instance_eval do
+ undef to_s
+ end
+ end
+ end
+end
diff --git a/jni/ruby/test/ruby/test_unicode_escape.rb b/jni/ruby/test/ruby/test_unicode_escape.rb
new file mode 100644
index 0000000..9d0d787
--- /dev/null
+++ b/jni/ruby/test/ruby/test_unicode_escape.rb
@@ -0,0 +1,270 @@
+# -*- coding: utf-8 -*-
+
+require 'test/unit'
+
+class TestUnicodeEscape < Test::Unit::TestCase
+ def test_basic
+ assert_equal('Matz - 松本行弘',
+ "Matz - \u677E\u672C\u884C\u5F18")
+ assert_equal('Matz - まつもと ゆきひろ',
+ "Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D")
+ assert_equal('Matz - まつもと ゆきひろ',
+ "Matz - \u{307E}\u{3064}\u{3082}\u{3068} \u{3086}\u{304D}\u{3072}\u{308D}")
+ assert_equal('Matz - まつもと ゆきひろ',
+ "Matz - \u{307E 3064 3082 3068 20 3086 304D 3072 308D}")
+ assert_equal("Aoyama Gakuin University - \xE9\x9D\x92\xE5\xB1\xB1\xE5\xAD\xA6\xE9\x99\xA2\xE5\xA4\xA7\xE5\xAD\xA6",
+ "Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66")
+ assert_equal('Aoyama Gakuin University - 青山学院大学',
+ "Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66")
+ assert_equal('青山学院大学', "\u9752\u5C71\u5B66\u9662\u5927\u5B66")
+ assert_equal("Martin D\xC3\xBCrst", "Martin D\u00FCrst")
+ assert_equal('Martin Dürst', "Martin D\u00FCrst")
+ assert_equal('ü', "\u00FC")
+ assert_equal("Martin D\xC3\xBCrst", "Martin D\u{FC}rst")
+ assert_equal('Martin Dürst', "Martin D\u{FC}rst")
+ assert_equal('ü', "\u{FC}")
+ assert_equal('ü', %Q|\u{FC}|)
+ assert_equal('ü', %W{\u{FC}}[0])
+
+ # \u escapes in here documents
+ assert_equal('Matz - まつもと ゆきひろ', <<EOS.chop)
+Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D
+EOS
+
+ assert_equal('Matz - まつもと ゆきひろ', <<"EOS".chop)
+Matz - \u{307E 3064 3082 3068} \u{3086 304D 3072 308D}
+EOS
+ assert_not_equal('Matz - まつもと ゆきひろ', <<'EOS'.chop)
+Matz - \u{307E 3064 3082 3068} \u{3086 304D 3072 308D}
+EOS
+
+ # single-quoted things don't expand \u
+ assert_not_equal('ü', '\u{FC}')
+ assert_not_equal('ü', %q|\u{FC}|)
+ assert_not_equal('ü', %w{\u{FC}}[0])
+ assert_equal('\u00fc', "\\" + "u00fc")
+
+ # \u in %x strings
+ assert_match(/^("?)A\1$/, `echo "\u0041"`) #"
+ assert_match(/^("?)A\1$/, %x{echo "\u0041"}) #"
+ assert_match(/^("?)ü\1$/,
+ `#{EnvUtil.rubybin} -e "#coding:utf-8\nputs \\"\\u{FC}\\""`.force_encoding("utf-8")) #"
+
+ # \u in quoted symbols
+ assert_equal(:A, :"\u0041")
+ assert_equal(:a, :"\u0061")
+ assert_equal(:ま, :ま)
+ assert_equal(:ü, :ü)
+ assert_equal(:"\u{41}", :"\u0041")
+ assert_equal(:ü, :"\u{fc}")
+
+ # the NUL character is allowed in symbols
+ bug = '[ruby-dev:41447]'
+ sym = "\0".to_sym
+ assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\u{0}")))}
+ assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\u0000")))}
+ assert_nothing_raised(SyntaxError, bug) {assert_equal("\u{fc}\0A".to_sym, eval(%q(:"\u{fc 0 0041}")))}
+ assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\x00")))}
+ assert_nothing_raised(SyntaxError, bug) {assert_equal(sym, eval(%q(:"\0")))}
+ end
+
+ def test_regexp
+
+ # Compare regexps to regexps
+ assert_not_equal(/Yukihiro Matsumoto - 松本行弘/,
+ /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/)
+ assert_not_equal(/Yukihiro Matsumoto - 松本行弘/,
+ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/)
+ assert_not_equal(/Matz - まつもと ゆきひろ/,
+ /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/)
+ assert_not_equal(/Aoyama Gakuin University - 青山学院大学/,
+ /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/)
+ assert_not_equal(/青山学院大学/, /\u9752\u5C71\u5B66\u9662\u5927\u5B66/)
+ assert_not_equal(/Martin Dürst/, /Martin D\u00FCrst/)
+ assert_not_equal(/ü/, /\u00FC/)
+ assert_not_equal(/Martin Dürst/, /Martin D\u{FC}rst/)
+ assert_not_equal(/ü/, /\u{FC}/)
+ assert_not_equal(/ü/, %r{\u{FC}})
+ assert_not_equal(/ü/i, %r{\u00FC}i)
+
+ assert_equal('Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18',
+ /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/.source)
+ assert_equal('Yukihiro Matsumoto - \u{677E 672C 884C 5F18}',
+ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/.source)
+ assert_equal('Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D',
+ /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/.source)
+ assert_equal('Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66',
+ /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/.source)
+ assert_equal('\u9752\u5C71\u5B66\u9662\u5927\u5B66',
+ /\u9752\u5C71\u5B66\u9662\u5927\u5B66/.source)
+ assert_equal('Martin D\u00FCrst', /Martin D\u00FCrst/.source)
+ assert_equal('\u00FC', /\u00FC/.source)
+ assert_equal('Martin D\u{FC}rst', /Martin D\u{FC}rst/.source)
+ assert_equal('\u{FC}', /\u{FC}/.source)
+ assert_equal('\u{FC}', %r{\u{FC}}.source)
+ assert_equal('\u00FC', %r{\u00FC}i.source)
+
+ # match strings to regexps
+ assert_equal(0, "Yukihiro Matsumoto - 松本行弘" =~ /Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18/)
+ assert_equal(0, "Yukihiro Matsumoto - \u677E\u672C\u884C\u5F18" =~ /Yukihiro Matsumoto - \u677E\u672C\u884C/)
+ assert_equal(0, "Yukihiro Matsumoto - 松本行弘" =~ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/)
+ assert_equal(0, %Q{Yukihiro Matsumoto - \u{677E 672C 884C 5F18}} =~ /Yukihiro Matsumoto - \u{677E 672C 884C 5F18}/)
+ assert_equal(0, "Matz - まつもと ゆきひろ" =~ /Matz - \u307E\u3064\u3082\u3068 \u3086\u304D\u3072\u308D/)
+ assert_equal(0, "Aoyama Gakuin University - 青山学院大学" =~ /Aoyama Gakuin University - \u9752\u5C71\u5B66\u9662\u5927\u5B66/)
+ assert_equal(0, "青山学院大学" =~ /\u9752\u5C71\u5B66\u9662\u5927\u5B66/)
+ assert_equal(0, "Martin Dürst" =~ /Martin D\u00FCrst/)
+ assert_equal(0, "ü" =~ /\u00FC/)
+ assert_equal(0, "Martin Dürst" =~ /Martin D\u{FC}rst/)
+ assert_equal(0, "ü" =~ %r{\u{FC}})
+ assert_equal(0, "ü" =~ %r{\u00FC}i)
+
+ # Flip order of the two operands
+ assert_equal(0, /Martin D\u00FCrst/ =~ "Martin Dürst")
+ assert_equal(4, /\u00FC/ =~ "testü")
+ assert_equal(3, /Martin D\u{FC}rst/ =~ "fooMartin Dürstbar")
+ assert_equal(3, %r{\u{FC}} =~ "fooübar")
+
+ # Put \u in strings, literal character in regexp
+ assert_equal(0, "Martin D\u00FCrst" =~ /Martin Dürst/)
+ assert_equal(4, "test\u00FC" =~ /ü/)
+ assert_equal(3, "fooMartin D\u{FC}rstbar" =~ /Martin Dürst/)
+ assert_equal(3, %Q{foo\u{FC}bar} =~ %r<ü>)
+
+ assert_match(eval('/\u{2a}/'), "*")
+ assert_raise(SyntaxError) { eval('/\u{6666}/n') }
+ assert_raise(SyntaxError) { eval('/\u{6666}/e') }
+ assert_raise(SyntaxError) { eval('/\u{6666}/s') }
+ assert_nothing_raised { eval('/\u{6666}/u') }
+ end
+
+ def test_dynamic_regexp
+ assert_match(Regexp.new("Martin D\\u{FC}rst"), "Martin Dürst")
+ end
+
+ def test_syntax_variants
+ # all hex digits
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89AB\uCDEF")
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89AB\uCDEF")
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89ab\ucdef")
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89ab\ucdef")
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89aB\uCdEf")
+ assert_equal("\xC4\xA3\xE4\x95\xA7\xE8\xA6\xAB\xEC\xB7\xAF", "\u0123\u4567\u89aB\ucDEF")
+ end
+
+ def test_fulton
+ # examples from Hal Fulton's book (second edition), chapter 4
+ # precomposed e'pe'e
+ assert_equal('épée', "\u00E9\u0070\u00E9\u0065")
+ assert_equal('épée', "\u00E9p\u00E9e")
+ assert_equal("\xC3\xA9\x70\xC3\xA9\x65", "\u00E9\u0070\u00E9\u0065")
+ assert_equal("\xC3\xA9\x70\xC3\xA9\x65", "\u00E9p\u00E9e")
+ # decomposed e'pe'e
+ assert_equal('épée', "\u0065\u0301\u0070\u0065\u0301\u0065")
+ assert_equal('épée', "e\u0301pe\u0301e")
+ assert_equal("\x65\xCC\x81\x70\x65\xCC\x81\x65", "\u0065\u0301\u0070\u0065\u0301\u0065")
+ assert_equal("\x65\xCC\x81\x70\x65\xCC\x81\x65", "e\u0301pe\u0301e")
+ # combinations of NFC/D, NFKC/D
+ assert_equal('öffnen', "\u00F6\u0066\u0066\u006E\u0065\u006E")
+ assert_equal("\xC3\xB6ffnen", "\u00F6\u0066\u0066\u006E\u0065\u006E")
+ assert_equal('öffnen', "\u00F6ffnen")
+ assert_equal("\xC3\xB6ffnen", "\u00F6ffnen")
+ assert_equal('öffnen', "\u006F\u0308\u0066\u0066\u006E\u0065\u006E")
+ assert_equal("\x6F\xCC\x88ffnen", "\u006F\u0308\u0066\u0066\u006E\u0065\u006E")
+ assert_equal('öffnen', "o\u0308ffnen")
+ assert_equal("\x6F\xCC\x88ffnen", "o\u0308ffnen")
+ assert_equal('öffnen', "\u00F6\uFB00\u006E\u0065\u006E")
+ assert_equal("\xC3\xB6\xEF\xAC\x80nen", "\u00F6\uFB00\u006E\u0065\u006E")
+ assert_equal('öffnen', "\u00F6\uFB00nen")
+ assert_equal("\xC3\xB6\xEF\xAC\x80nen", "\u00F6\uFB00nen")
+ assert_equal('öffnen', "\u006F\u0308\uFB00\u006E\u0065\u006E")
+ assert_equal("\x6F\xCC\x88\xEF\xAC\x80nen", "\u006F\u0308\uFB00\u006E\u0065\u006E")
+ assert_equal('öffnen', "o\u0308\uFB00nen")
+ assert_equal("\x6F\xCC\x88\xEF\xAC\x80nen", "o\u0308\uFB00nen")
+ # German sharp s (sz)
+ assert_equal('Straße', "\u0053\u0074\u0072\u0061\u00DF\u0065")
+ assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u0053\u0074\u0072\u0061\u00DF\u0065")
+ assert_equal('Straße', "Stra\u00DFe")
+ assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "Stra\u00DFe")
+ assert_equal('Straße', "\u{53}\u{74}\u{72}\u{61}\u{DF}\u{65}")
+ assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u{53}\u{74}\u{72}\u{61}\u{DF}\u{65}")
+ assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "\u{53 74 72 61 DF 65}")
+ assert_equal('Straße', "Stra\u{DF}e")
+ assert_equal("\x53\x74\x72\x61\xC3\x9F\x65", "Stra\u{DF}e")
+ end
+
+ def test_edge_cases
+ # start and end of each outer plane
+ assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}")
+ assert_equal("\xF4\x80\x80\x80", "\u{100000}")
+ assert_equal("\xF3\xBF\xBF\xBF", "\u{FFFFF}")
+ assert_equal("\xF3\xB0\x80\x80", "\u{F0000}")
+ assert_equal("\xF3\xAF\xBF\xBF", "\u{EFFFF}")
+ assert_equal("\xF3\xA0\x80\x80", "\u{E0000}")
+ assert_equal("\xF3\x9F\xBF\xBF", "\u{DFFFF}")
+ assert_equal("\xF3\x90\x80\x80", "\u{D0000}")
+ assert_equal("\xF3\x8F\xBF\xBF", "\u{CFFFF}")
+ assert_equal("\xF3\x80\x80\x80", "\u{C0000}")
+ assert_equal("\xF2\xBF\xBF\xBF", "\u{BFFFF}")
+ assert_equal("\xF2\xB0\x80\x80", "\u{B0000}")
+ assert_equal("\xF2\xAF\xBF\xBF", "\u{AFFFF}")
+ assert_equal("\xF2\xA0\x80\x80", "\u{A0000}")
+ assert_equal("\xF2\x9F\xBF\xBF", "\u{9FFFF}")
+ assert_equal("\xF2\x90\x80\x80", "\u{90000}")
+ assert_equal("\xF2\x8F\xBF\xBF", "\u{8FFFF}")
+ assert_equal("\xF2\x80\x80\x80", "\u{80000}")
+ assert_equal("\xF1\xBF\xBF\xBF", "\u{7FFFF}")
+ assert_equal("\xF1\xB0\x80\x80", "\u{70000}")
+ assert_equal("\xF1\xAF\xBF\xBF", "\u{6FFFF}")
+ assert_equal("\xF1\xA0\x80\x80", "\u{60000}")
+ assert_equal("\xF1\x9F\xBF\xBF", "\u{5FFFF}")
+ assert_equal("\xF1\x90\x80\x80", "\u{50000}")
+ assert_equal("\xF1\x8F\xBF\xBF", "\u{4FFFF}")
+ assert_equal("\xF1\x80\x80\x80", "\u{40000}")
+ assert_equal("\xF0\xBF\xBF\xBF", "\u{3FFFF}")
+ assert_equal("\xF0\xB0\x80\x80", "\u{30000}")
+ assert_equal("\xF0\xAF\xBF\xBF", "\u{2FFFF}")
+ assert_equal("\xF0\xA0\x80\x80", "\u{20000}")
+ assert_equal("\xF0\x9F\xBF\xBF", "\u{1FFFF}")
+ assert_equal("\xF0\x90\x80\x80", "\u{10000}")
+ # BMP
+ assert_equal("\xEF\xBF\xBF", "\uFFFF")
+ assert_equal("\xEE\x80\x80", "\uE000")
+ assert_equal("\xED\x9F\xBF", "\uD7FF")
+ assert_equal("\xE0\xA0\x80", "\u0800")
+ assert_equal("\xDF\xBF", "\u07FF")
+ assert_equal("\xC2\x80", "\u0080")
+ assert_equal("\x7F", "\u007F")
+ assert_equal("\x00", "\u0000")
+ end
+
+ def test_chars
+ assert_equal(?\u0041, ?A)
+ assert_equal(?\u{79}, ?\x79)
+ assert_equal(?\u{0}, ?\000)
+ assert_equal(?\u0000, ?\000)
+ end
+
+ # Tests to make sure that disallowed cases fail
+ def test_fail
+ assert_raise(SyntaxError) { eval %q("\uabc") } # too short
+ assert_raise(SyntaxError) { eval %q("\uab") } # too short
+ assert_raise(SyntaxError) { eval %q("\ua") } # too short
+ assert_raise(SyntaxError) { eval %q("\u") } # too short
+ assert_raise(SyntaxError) { eval %q("\u{110000}") } # too high
+ assert_raise(SyntaxError) { eval %q("\u{abcdeff}") } # too long
+ assert_raise(SyntaxError) { eval %q("\ughij") } # bad hex digits
+ assert_raise(SyntaxError) { eval %q("\u{ghij}") } # bad hex digits
+
+ assert_raise(SyntaxError) { eval %q("\u{123 456 }")} # extra space
+ assert_raise(SyntaxError) { eval %q("\u{ 123 456}")} # extra space
+ assert_raise(SyntaxError) { eval %q("\u{123 456}")} # extra space
+
+# The utf-8 encoding object currently does not object to codepoints
+# in the surrogate blocks, so these do not raise an error.
+# assert_raise(SyntaxError) { "\uD800" } # surrogate block
+# assert_raise(SyntaxError) { "\uDCBA" } # surrogate block
+# assert_raise(SyntaxError) { "\uDFFF" } # surrogate block
+# assert_raise(SyntaxError) { "\uD847\uDD9A" } # surrogate pair
+
+ end
+end
diff --git a/jni/ruby/test/ruby/test_variable.rb b/jni/ruby/test/ruby/test_variable.rb
new file mode 100644
index 0000000..8f5329b
--- /dev/null
+++ b/jni/ruby/test/ruby/test_variable.rb
@@ -0,0 +1,121 @@
+require 'test/unit'
+
+class TestVariable < Test::Unit::TestCase
+ class Gods
+ @@rule = "Uranus"
+ def ruler0
+ @@rule
+ end
+
+ def self.ruler1 # <= per method definition style
+ @@rule
+ end
+ class << self # <= multiple method definition style
+ def ruler2
+ @@rule
+ end
+ end
+ end
+
+ module Olympians
+ @@rule ="Zeus"
+ def ruler3
+ @@rule
+ end
+ end
+
+ class Titans < Gods
+ @@rule = "Cronus" # modifies @@rule in Gods
+ include Olympians
+ def ruler4
+ EnvUtil.suppress_warning {
+ @@rule
+ }
+ end
+ end
+
+ def test_variable
+ assert_instance_of(Fixnum, $$)
+
+ # read-only variable
+ assert_raise(NameError) do
+ $$ = 5
+ end
+ assert_normal_exit("$*=0; $*", "[ruby-dev:36698]")
+
+ foobar = "foobar"
+ $_ = foobar
+ assert_equal(foobar, $_)
+
+ assert_equal("Cronus", Gods.new.ruler0)
+ assert_equal("Cronus", Gods.ruler1)
+ assert_equal("Cronus", Gods.ruler2)
+ assert_equal("Cronus", Titans.ruler1)
+ assert_equal("Cronus", Titans.ruler2)
+ atlas = Titans.new
+ assert_equal("Cronus", atlas.ruler0)
+ assert_equal("Zeus", atlas.ruler3)
+ assert_equal("Cronus", atlas.ruler4)
+ assert_nothing_raised do
+ class << Gods
+ defined?(@@rule) && @@rule
+ end
+ end
+ end
+
+ def test_local_variables
+ lvar = 1
+ assert_instance_of(Symbol, local_variables[0], "[ruby-dev:34008]")
+ lvar
+ end
+
+ def test_local_variables2
+ x = 1
+ proc do |y|
+ assert_equal([:x, :y], local_variables.sort)
+ end.call
+ x
+ end
+
+ def test_local_variables3
+ x = 1
+ proc do |y|
+ 1.times do |z|
+ assert_equal([:x, :y, :z], local_variables.sort)
+ end
+ end.call
+ x
+ end
+
+ def test_shadowing_local_variables
+ bug9486 = '[ruby-core:60501] [Bug #9486]'
+ x = tap {|x| break local_variables}
+ assert_equal([:x, :bug9486], x)
+ end
+
+ def test_shadowing_block_local_variables
+ bug9486 = '[ruby-core:60501] [Bug #9486]'
+ x = tap {|;x| break local_variables}
+ assert_equal([:x, :bug9486], x)
+ end
+
+ def test_global_variable_0
+ assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, [])
+ end
+
+ def test_global_variable_poped
+ assert_nothing_raised {
+ EnvUtil.suppress_warning {
+ eval("$foo; 1")
+ }
+ }
+ end
+
+ def test_constant_poped
+ assert_nothing_raised {
+ EnvUtil.suppress_warning {
+ eval("TestVariable::Gods; 1")
+ }
+ }
+ end
+end
diff --git a/jni/ruby/test/ruby/test_weakmap.rb b/jni/ruby/test/ruby/test_weakmap.rb
new file mode 100644
index 0000000..1279944
--- /dev/null
+++ b/jni/ruby/test/ruby/test_weakmap.rb
@@ -0,0 +1,133 @@
+require 'test/unit'
+
+class TestWeakMap < Test::Unit::TestCase
+ def setup
+ @wm = ObjectSpace::WeakMap.new
+ end
+
+ def test_map
+ x = Object.new
+ k = "foo"
+ @wm[k] = x
+ assert_same(x, @wm[k])
+ assert_not_same(x, @wm["FOO".downcase])
+ end
+
+ def test_aset_const
+ x = Object.new
+ assert_raise(ArgumentError) {@wm[true] = x}
+ assert_raise(ArgumentError) {@wm[false] = x}
+ assert_raise(ArgumentError) {@wm[nil] = x}
+ assert_raise(ArgumentError) {@wm[42] = x}
+ assert_raise(ArgumentError) {@wm[:foo] = x}
+ assert_raise(ArgumentError) {@wm[x] = true}
+ assert_raise(ArgumentError) {@wm[x] = false}
+ assert_raise(ArgumentError) {@wm[x] = nil}
+ assert_raise(ArgumentError) {@wm[x] = 42}
+ assert_raise(ArgumentError) {@wm[x] = :foo}
+ end
+
+ def test_include?
+ m = __callee__[/test_(.*)/, 1]
+ k = "foo"
+ 1.times do
+ x = Object.new
+ @wm[k] = x
+ assert_send([@wm, m, k])
+ assert_not_send([@wm, m, "FOO".downcase])
+ x = nil
+ end
+ GC.start
+ assert_not_send([@wm, m, k])
+ end
+ alias test_member? test_include?
+ alias test_key? test_include?
+
+ def test_inspect
+ x = Object.new
+ k = BasicObject.new
+ @wm[k] = x
+ assert_match(/\A\#<#{@wm.class.name}:[^:]+:\s\#<BasicObject:[^:]*>\s=>\s\#<Object:[^:]*>>\z/,
+ @wm.inspect)
+ end
+
+ def test_each
+ m = __callee__[/test_(.*)/, 1]
+ x1 = Object.new
+ k1 = "foo"
+ @wm[k1] = x1
+ x2 = Object.new
+ k2 = "bar"
+ @wm[k2] = x2
+ n = 0
+ @wm.__send__(m) do |k, v|
+ assert_match(/\A(?:foo|bar)\z/, k)
+ case k
+ when /foo/
+ assert_same(k1, k)
+ assert_same(x1, v)
+ when /bar/
+ assert_same(k2, k)
+ assert_same(x2, v)
+ end
+ n += 1
+ end
+ assert_equal(2, n)
+ end
+
+ def test_each_key
+ x1 = Object.new
+ k1 = "foo"
+ @wm[k1] = x1
+ x2 = Object.new
+ k2 = "bar"
+ @wm[k2] = x2
+ n = 0
+ @wm.each_key do |k|
+ assert_match(/\A(?:foo|bar)\z/, k)
+ case k
+ when /foo/
+ assert_same(k1, k)
+ when /bar/
+ assert_same(k2, k)
+ end
+ n += 1
+ end
+ assert_equal(2, n)
+ end
+
+ def test_each_value
+ x1 = "foo"
+ k1 = Object.new
+ @wm[k1] = x1
+ x2 = "bar"
+ k2 = Object.new
+ @wm[k2] = x2
+ n = 0
+ @wm.each_value do |v|
+ assert_match(/\A(?:foo|bar)\z/, v)
+ case v
+ when /foo/
+ assert_same(x1, v)
+ when /bar/
+ assert_same(x2, v)
+ end
+ n += 1
+ end
+ assert_equal(2, n)
+ end
+
+ def test_size
+ m = __callee__[/test_(.*)/, 1]
+ assert_equal(0, @wm.__send__(m))
+ x1 = "foo"
+ k1 = Object.new
+ @wm[k1] = x1
+ assert_equal(1, @wm.__send__(m))
+ x2 = "bar"
+ k2 = Object.new
+ @wm[k2] = x2
+ assert_equal(2, @wm.__send__(m))
+ end
+ alias test_length test_size
+end
diff --git a/jni/ruby/test/ruby/test_whileuntil.rb b/jni/ruby/test/ruby/test_whileuntil.rb
new file mode 100644
index 0000000..3d8dbee
--- /dev/null
+++ b/jni/ruby/test/ruby/test_whileuntil.rb
@@ -0,0 +1,82 @@
+require 'test/unit'
+require 'tmpdir'
+
+class TestWhileuntil < Test::Unit::TestCase
+ def test_while
+ Dir.mktmpdir("ruby_while_tmp") {|tmpdir|
+ tmpfilename = "#{tmpdir}/ruby_while_tmp.#{$$}"
+
+ tmp = open(tmpfilename, "w")
+ tmp.print "tvi925\n";
+ tmp.print "tvi920\n";
+ tmp.print "vt100\n";
+ tmp.print "Amiga\n";
+ tmp.print "paper\n";
+ tmp.close
+
+ tmp = open(tmpfilename, "r")
+ assert_instance_of(File, tmp)
+
+ while line = tmp.gets()
+ break if /vt100/ =~ line
+ end
+
+ assert_not_predicate(tmp, :eof?)
+ assert_match(/vt100/, line)
+ tmp.close
+
+ tmp = open(tmpfilename, "r")
+ while line = tmp.gets()
+ next if /vt100/ =~ line
+ assert_no_match(/vt100/, line)
+ end
+ assert_predicate(tmp, :eof?)
+ assert_no_match(/vt100/, line)
+ tmp.close
+
+ tmp = open(tmpfilename, "r")
+ while line = tmp.gets()
+ lastline = line
+ line = line.gsub(/vt100/, 'VT100')
+ if lastline != line
+ line.gsub!('VT100', 'Vt100')
+ redo
+ end
+ assert_no_match(/vt100/, line)
+ assert_no_match(/VT100/, line)
+ end
+ assert_predicate(tmp, :eof?)
+ tmp.close
+
+ sum=0
+ for i in 1..10
+ sum += i
+ i -= 1
+ if i > 0
+ redo
+ end
+ end
+ assert_equal(220, sum)
+
+ tmp = open(tmpfilename, "r")
+ while line = tmp.gets()
+ break if 3
+ assert_no_match(/vt100/, line)
+ assert_no_match(/Amiga/, line)
+ assert_no_match(/paper/, line)
+ end
+ tmp.close
+
+ File.unlink tmpfilename or `/bin/rm -f "#{tmpfilename}"`
+ assert_file.not_exist?(tmpfilename)
+ }
+ end
+
+ def test_until
+ i = 0
+ until i>4
+ i+=1
+ end
+ assert_operator(i, :>, 4)
+ end
+end
diff --git a/jni/ruby/test/ruby/test_yield.rb b/jni/ruby/test/ruby/test_yield.rb
new file mode 100644
index 0000000..82378d4
--- /dev/null
+++ b/jni/ruby/test/ruby/test_yield.rb
@@ -0,0 +1,393 @@
+require 'test/unit'
+require 'stringio'
+
+class TestRubyYield < Test::Unit::TestCase
+
+ def test_ary_each
+ ary = [1]
+ ary.each {|a, b, c, d| assert_equal [1,nil,nil,nil], [a,b,c,d] }
+ ary.each {|a, b, c| assert_equal [1,nil,nil], [a,b,c] }
+ ary.each {|a, b| assert_equal [1,nil], [a,b] }
+ ary.each {|a| assert_equal 1, a }
+ end
+
+ def test_hash_each
+ h = {:a => 1}
+ h.each do |k, v|
+ assert_equal :a, k
+ assert_equal 1, v
+ end
+ h.each do |kv|
+ assert_equal [:a, 1], kv
+ end
+ end
+
+ def test_yield_0
+ assert_equal 1, iter0 { 1 }
+ assert_equal 2, iter0 { 2 }
+ end
+
+ def iter0
+ yield
+ end
+
+ def test_yield_1
+ iter1([]) {|a, b| assert_equal [nil,nil], [a, b] }
+ iter1([1]) {|a, b| assert_equal [1,nil], [a, b] }
+ iter1([1, 2]) {|a, b| assert_equal [1,2], [a,b] }
+ iter1([1, 2, 3]) {|a, b| assert_equal [1,2], [a,b] }
+
+ iter1([]) {|a| assert_equal [], a }
+ iter1([1]) {|a| assert_equal [1], a }
+ iter1([1, 2]) {|a| assert_equal [1,2], a }
+ iter1([1, 2, 3]) {|a| assert_equal [1,2,3], a }
+ end
+
+ def iter1(args)
+ yield args
+ end
+
+ def test_yield2
+ def iter2_1() yield 1, *[2, 3] end
+ iter2_1 {|a, b, c| assert_equal [1,2,3], [a,b,c] }
+ def iter2_2() yield 1, *[] end
+ iter2_2 {|a, b, c| assert_equal [1,nil,nil], [a,b,c] }
+ def iter2_3() yield 1, *[2] end
+ iter2_3 {|a, b, c| assert_equal [1,2,nil], [a,b,c] }
+ end
+
+ def test_yield_nested
+ [[1, [2, 3]]].each {|a, (b, c)|
+ assert_equal [1,2,3], [a,b,c]
+ }
+ [[1, [2, 3]]].map {|a, (b, c)|
+ assert_equal [1,2,3], [a,b,c]
+ }
+ end
+
+ def test_with_enum
+ obj = Object.new
+ def obj.each
+ yield(*[])
+ end
+ obj.each{|*v| assert_equal([], [], '[ruby-dev:32392]')}
+ obj.to_enum.each{|*v| assert_equal([], [], '[ruby-dev:32392]')}
+ end
+
+ def block_args_unleashed
+ yield(1,2,3,4,5)
+ end
+
+ def test_block_args_unleashed
+ r = block_args_unleashed {|a,b=1,*c,d,e|
+ [a,b,c,d,e]
+ }
+ assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]")
+ end
+end
+
+require_relative 'sentence'
+class TestRubyYieldGen < Test::Unit::TestCase
+ Syntax = {
+ :exp => [["0"],
+ ["nil"],
+ ["false"],
+ ["[]"],
+ ["[",:exps,"]"]],
+ :exps => [[:exp],
+ [:exp,",",:exps]],
+ :opt_block_param => [[],
+ [:block_param_def]],
+ :block_param_def => [['|', '|'],
+ ['|', :block_param, '|']],
+ :block_param => [[:f_arg, ",", :f_rest_arg, :opt_f_block_arg],
+ [:f_arg, ","],
+ [:f_arg, ',', :f_rest_arg, ",", :f_arg, :opt_f_block_arg],
+ [:f_arg, :opt_f_block_arg],
+ [:f_rest_arg, :opt_f_block_arg],
+ [:f_rest_arg, ',', :f_arg, :opt_f_block_arg],
+ [:f_block_arg]],
+ :f_arg => [[:f_arg_item],
+ [:f_arg, ',', :f_arg_item]],
+ :f_rest_arg => [['*', "var"],
+ ['*']],
+ :opt_f_block_arg => [[',', :f_block_arg],
+ []],
+ :f_block_arg => [['&', 'var']],
+ :f_arg_item => [[:f_norm_arg],
+ ['(', :f_margs, ')']],
+ :f_margs => [[:f_marg_list],
+ [:f_marg_list, ',', '*', :f_norm_arg],
+ [:f_marg_list, ',', '*', :f_norm_arg, ',', :f_marg_list],
+ [:f_marg_list, ',', '*'],
+ [:f_marg_list, ',', '*', ',', :f_marg_list],
+ [ '*', :f_norm_arg],
+ [ '*', :f_norm_arg, ',', :f_marg_list],
+ [ '*'],
+ [ '*', ',', :f_marg_list]],
+ :f_marg_list => [[:f_marg],
+ [:f_marg_list, ',', :f_marg]],
+ :f_marg => [[:f_norm_arg],
+ ['(', :f_margs, ')']],
+ :f_norm_arg => [['var']],
+
+ :command_args => [[:open_args]],
+ :open_args => [[' ',:call_args],
+ ['(', ')'],
+ ['(', :call_args2, ')']],
+ :call_args => [[:command],
+ [ :args, :opt_block_arg],
+ [ :assocs, :opt_block_arg],
+ [ :args, ',', :assocs, :opt_block_arg],
+ [ :block_arg]],
+ :call_args2 => [[:arg, ',', :args, :opt_block_arg],
+ [:arg, ',', :block_arg],
+ [ :assocs, :opt_block_arg],
+ [:arg, ',', :assocs, :opt_block_arg],
+ [:arg, ',', :args, ',', :assocs, :opt_block_arg],
+ [ :block_arg]],
+
+ :command_args_noblock => [[:open_args_noblock]],
+ :open_args_noblock => [[' ',:call_args_noblock],
+ ['(', ')'],
+ ['(', :call_args2_noblock, ')']],
+ :call_args_noblock => [[:command],
+ [ :args],
+ [ :assocs],
+ [ :args, ',', :assocs]],
+ :call_args2_noblock => [[:arg, ',', :args],
+ [ :assocs],
+ [:arg, ',', :assocs],
+ [:arg, ',', :args, ',', :assocs]],
+
+ :command => [],
+ :args => [[:arg],
+ ["*",:arg],
+ [:args,",",:arg],
+ [:args,",","*",:arg]],
+ :arg => [[:exp]],
+ :assocs => [[:assoc],
+ [:assocs, ',', :assoc]],
+ :assoc => [[:arg, '=>', :arg],
+ ['label', ':', :arg]],
+ :opt_block_arg => [[',', :block_arg],
+ []],
+ :block_arg => [['&', :arg]],
+ #:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
+ :test_proc => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']],
+ :test_lambda => [['def m() yield', :command_args_noblock, ' end; r = m(&lambda {', :block_param_def, 'vars', '}); undef m; r']],
+ :test_enum => [['o = Object.new; def o.each() yield', :command_args_noblock, ' end; r1 = r2 = nil; o.each {|*x| r1 = x }; o.to_enum.each {|*x| r2 = x }; [r1, r2]']]
+ }
+
+ def rename_var(obj)
+ vars = []
+ r = obj.subst('var') {
+ var = "v#{vars.length}"
+ vars << var
+ var
+ }
+ return r, vars
+ end
+
+ def split_by_comma(ary)
+ return [] if ary.empty?
+ result = [[]]
+ ary.each {|e|
+ if e == ','
+ result << []
+ else
+ result.last << e
+ end
+ }
+ result
+ end
+
+ def emu_return_args(*vs)
+ vs
+ end
+
+ def emu_eval_args(args)
+ if args.last == []
+ args = args[0...-1]
+ end
+ code = "emu_return_args(#{args.map {|a| a.join('') }.join(",")})"
+ eval code, nil, 'generated_code_in_emu_eval_args'
+ end
+
+ def emu_bind_single(arg, param, result_binding)
+ #p [:emu_bind_single, arg, param]
+ if param.length == 1 && String === param[0] && /\A[a-z0-9]+\z/ =~ param[0]
+ result_binding[param[0]] = arg
+ elsif param.length == 1 && Array === param[0] && param[0][0] == '(' && param[0][-1] == ')'
+ arg = [arg] unless Array === arg
+ emu_bind_params(arg, split_by_comma(param[0][1...-1]), false, result_binding)
+ else
+ raise "unexpected param: #{param.inspect}"
+ end
+ result_binding
+ end
+
+ def emu_bind_params(args, params, islambda, result_binding={})
+ #p [:emu_bind_params, args, params]
+ if params.last == [] # extra comma
+ params.pop
+ end
+
+ star_index = nil
+ params.each_with_index {|par, i|
+ star_index = i if par[0] == '*'
+ }
+
+ if islambda
+ if star_index
+ if args.length < params.length - 1
+ throw :emuerror, ArgumentError
+ end
+ else
+ if args.length != params.length and !(args.length == 1 and Array === args[0] and args[0].length == params.length)
+ throw :emuerror, ArgumentError
+ end
+ end
+ end
+
+ # TRICK #2 : adjust mismatch on number of arguments
+ if star_index
+ pre_params = params[0...star_index]
+ rest_param = params[star_index]
+ post_params = params[(star_index+1)..-1]
+ pre_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
+ if post_params.length <= args.length
+ post_params.reverse_each {|par| emu_bind_single(args.pop, par, result_binding) }
+ else
+ post_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
+ end
+ if rest_param != ['*']
+ emu_bind_single(args, rest_param[1..-1], result_binding)
+ end
+ else
+ params.each_with_index {|par, i|
+ emu_bind_single(args[i], par, result_binding)
+ }
+ end
+
+ #p [args, params, result_binding]
+
+ result_binding
+ end
+
+ def emu_bind(t, islambda)
+ #puts
+ #p t
+ command_args_noblock = t[1]
+ block_param_def = t[3]
+ command_args_noblock = command_args_noblock.expand {|a| !(a[0] == '[' && a[-1] == ']') }
+ block_param_def = block_param_def.expand {|a| !(a[0] == '(' && a[-1] == ')') }
+
+ if command_args_noblock.to_a[0] == ' '
+ args = command_args_noblock.to_a[1..-1]
+ elsif command_args_noblock.to_a[0] == '(' && command_args_noblock.to_a[-1] == ')'
+ args = command_args_noblock.to_a[1...-1]
+ else
+ raise "unexpected command_args_noblock: #{command_args_noblock.inspect}"
+ end
+ args = emu_eval_args(split_by_comma(args))
+
+ params = block_param_def.to_a[1...-1]
+ params = split_by_comma(params)
+
+ #p [:emu0, args, params]
+
+ result_binding = {}
+
+ if params.last && params.last[0] == '&'
+ result_binding[params.last[1]] = nil
+ params.pop
+ end
+
+ if !islambda
+ # TRICK #1 : single array argument is expanded if there are two or more params.
+ # * block parameter is not counted.
+ # * extra comma after single param forces the expansion.
+ if args.length == 1 && Array === args[0] && 1 < params.length
+ args = args[0]
+ end
+ end
+
+ emu_bind_params(args, params, islambda, result_binding)
+ #p result_binding
+ result_binding
+ end
+
+ def emu(t, vars, islambda)
+ catch(:emuerror) {
+ emu_binding = emu_bind(t, islambda)
+ vars.map {|var| emu_binding.fetch(var, "NOVAL") }
+ }
+ end
+
+ def disable_stderr
+ begin
+ save_stderr = $stderr
+ $stderr = StringIO.new
+ yield
+ ensure
+ $stderr = save_stderr
+ end
+ end
+
+ def check_nofork(t, islambda=false)
+ t, vars = rename_var(t)
+ t = t.subst('vars') { " [#{vars.join(",")}]" }
+ emu_values = emu(t, vars, islambda)
+ s = t.to_s
+ #print "#{s}\t\t"
+ #STDOUT.flush
+ eval_values = disable_stderr {
+ begin
+ eval(s, nil, 'generated_code_in_check_nofork')
+ rescue ArgumentError
+ ArgumentError
+ end
+ }
+ #success = emu_values == eval_values ? 'succ' : 'fail'
+ #puts "eval:#{vs_ev.inspect[1...-1].delete(' ')}\temu:#{vs_emu.inspect[1...-1].delete(' ')}\t#{success}"
+ assert_equal(emu_values, eval_values, s)
+ end
+
+ def test_yield
+ syntax = Sentence.expand_syntax(Syntax)
+ Sentence.each(syntax, :test_proc, 4) {|t|
+ check_nofork(t)
+ }
+ end
+
+ def test_yield_lambda
+ syntax = Sentence.expand_syntax(Syntax)
+ Sentence.each(syntax, :test_lambda, 4) {|t|
+ check_nofork(t, true)
+ }
+ end
+
+ def test_yield_enum
+ syntax = Sentence.expand_syntax(Syntax)
+ Sentence.each(syntax, :test_enum, 4) {|t|
+ code = t.to_s
+ r1, r2 = disable_stderr {
+ eval(code, nil, 'generated_code_in_test_yield_enum')
+ }
+ assert_equal(r1, r2, "#{t}")
+ }
+ end
+
+ def test_block_with_mock
+ y = Object.new
+ def y.s(a)
+ yield(a)
+ end
+ m = Object.new
+ def m.method_missing(*a)
+ super
+ end
+ assert_equal [m, nil], y.s(m){|a,b|[a,b]}
+ end
+end
diff --git a/jni/ruby/test/ruby/ut_eof.rb b/jni/ruby/test/ruby/ut_eof.rb
new file mode 100644
index 0000000..83325f2
--- /dev/null
+++ b/jni/ruby/test/ruby/ut_eof.rb
@@ -0,0 +1,128 @@
+require 'test/unit'
+
+module TestEOF
+ def test_eof_0
+ open_file("") {|f|
+ assert_equal("", f.read(0))
+ assert_equal("", f.read(0))
+ assert_equal("", f.read)
+ assert_equal("", f.read(0))
+ assert_equal("", f.read(0))
+ }
+ open_file("") {|f|
+ assert_nil(f.read(1))
+ assert_equal("", f.read)
+ assert_nil(f.read(1))
+ }
+ open_file("") {|f|
+ s = "x"
+ assert_equal("", f.read(nil, s))
+ assert_equal("", s)
+ }
+ open_file("") {|f|
+ s = "x"
+ assert_nil(f.read(10, s))
+ assert_equal("", s)
+ }
+ end
+
+ def test_eof_0_rw
+ return unless respond_to? :open_file_rw
+ open_file_rw("") {|f|
+ assert_equal("", f.read)
+ assert_equal("", f.read)
+ assert_equal(0, f.syswrite(""))
+ assert_equal("", f.read)
+ }
+ end
+
+ def test_eof_1
+ open_file("a") {|f|
+ assert_equal("", f.read(0))
+ assert_equal("a", f.read(1))
+ assert_equal("" , f.read(0))
+ assert_equal("" , f.read(0))
+ assert_equal("", f.read)
+ assert_equal("", f.read(0))
+ assert_equal("", f.read(0))
+ }
+ open_file("a") {|f|
+ assert_equal("a", f.read(1))
+ assert_nil(f.read(1))
+ }
+ open_file("a") {|f|
+ assert_equal("a", f.read(2))
+ assert_nil(f.read(1))
+ assert_equal("", f.read)
+ assert_nil(f.read(1))
+ }
+ open_file("a") {|f|
+ assert_equal("a", f.read)
+ assert_nil(f.read(1))
+ assert_equal("", f.read)
+ assert_nil(f.read(1))
+ }
+ open_file("a") {|f|
+ assert_equal("a", f.read(2))
+ assert_equal("", f.read)
+ assert_equal("", f.read)
+ }
+ open_file("a") {|f|
+ assert_equal("a", f.read)
+ assert_equal("", f.read(0))
+ }
+ open_file("a") {|f|
+ s = "x"
+ assert_equal("a", f.read(nil, s))
+ assert_equal("a", s)
+ }
+ open_file("a") {|f|
+ s = "x"
+ assert_equal("a", f.read(10, s))
+ assert_equal("a", s)
+ }
+ end
+
+ def test_eof_2
+ open_file("") {|f|
+ assert_equal("", f.read)
+ assert_predicate(f, :eof?)
+ }
+ end
+
+ def test_eof_3
+ open_file("") {|f|
+ assert_predicate(f, :eof?)
+ }
+ end
+
+ module Seek
+ def open_file_seek(content, pos)
+ open_file(content) do |f|
+ f.seek(pos)
+ yield f
+ end
+ end
+
+ def test_eof_0_seek
+ open_file_seek("", 10) {|f|
+ assert_equal(10, f.pos)
+ assert_equal("", f.read(0))
+ assert_equal("", f.read)
+ assert_equal("", f.read(0))
+ assert_equal("", f.read)
+ }
+ end
+
+ def test_eof_1_seek
+ open_file_seek("a", 10) {|f|
+ assert_equal("", f.read)
+ assert_equal("", f.read)
+ }
+ open_file_seek("a", 1) {|f|
+ assert_equal("", f.read)
+ assert_equal("", f.read)
+ }
+ end
+ end
+end