summaryrefslogtreecommitdiff
path: root/trunk/yarvtest
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/yarvtest')
-rw-r--r--trunk/yarvtest/runner.rb9
-rw-r--r--trunk/yarvtest/test_block.rb429
-rw-r--r--trunk/yarvtest/test_eval.rb221
-rw-r--r--trunk/yarvtest/test_exception.rb408
-rw-r--r--trunk/yarvtest/test_flow.rb591
-rw-r--r--trunk/yarvtest/test_jump.rb296
-rw-r--r--trunk/yarvtest/test_proc.rb293
-rw-r--r--trunk/yarvtest/test_syntax.rb594
-rw-r--r--trunk/yarvtest/test_test.rb8
-rw-r--r--trunk/yarvtest/test_thread.rb209
-rw-r--r--trunk/yarvtest/yarvtest.rb112
11 files changed, 3170 insertions, 0 deletions
diff --git a/trunk/yarvtest/runner.rb b/trunk/yarvtest/runner.rb
new file mode 100644
index 0000000000..003967b804
--- /dev/null
+++ b/trunk/yarvtest/runner.rb
@@ -0,0 +1,9 @@
+require 'test/unit'
+
+if $0 == __FILE__
+ # exit Test::Unit::AutoRunner.run(false, File.dirname($0))
+ Dir.glob(File.dirname($0) + '/test_*'){|file|
+ require file
+ }
+end
+
diff --git a/trunk/yarvtest/test_block.rb b/trunk/yarvtest/test_block.rb
new file mode 100644
index 0000000000..eae8b077fe
--- /dev/null
+++ b/trunk/yarvtest/test_block.rb
@@ -0,0 +1,429 @@
+require 'yarvtest/yarvtest'
+
+class TestBlock < YarvTestBase
+ def test_simple
+ ae %q(
+ def m
+ yield
+ end
+ m{
+ 1
+ }
+ )
+ end
+
+ def test_param
+ ae %q(
+ def m
+ yield 1
+ end
+ m{|ib|
+ ib*2
+ }
+ )
+
+ ae %q(
+ def m
+ yield 12345, 67890
+ end
+ m{|ib,jb|
+ ib*2+jb
+ }
+ )
+ end
+
+ def test_param2
+ ae %q{
+ def iter
+ yield 10
+ end
+
+ a = nil
+ [iter{|a|
+ a
+ }, a]
+ }
+ ae %q{
+ def iter
+ yield 10
+ end
+
+ iter{|a|
+ iter{|a|
+ a + 1
+ } + a
+ }
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = b = c = d = nil
+ iter{|a, b, c, d|
+ [a, b, c, d]
+ } + [a, b, c, d]
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = b = nil
+ iter{|a, b, c, d|
+ [a, b, c, d]
+ } + [a, b]
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = nil
+ iter{|a, $b, @c, d|
+ [a, $b]
+ } + [a, $b, @c]
+ } if false # 1.9 doesn't support expr block parameters
+ end
+
+ def test_param3
+ if false
+ # TODO: Ruby 1.9 doesn't support expr block parameter
+ ae %q{
+ h = {}
+ [1].each{|h[:foo]|}
+ h
+ }
+ ae %q{
+ obj = Object.new
+ def obj.x=(y)
+ $ans = y
+ end
+ [1].each{|obj.x|}
+ $ans
+ }
+ end
+ end
+
+ def test_blocklocal
+ ae %q{
+ 1.times{
+ begin
+ a = 1
+ ensure
+ foo = nil
+ end
+ }
+ }
+ end
+
+ def test_simplenest
+ ae %q(
+ def m
+ yield 123
+ end
+ m{|ib|
+ m{|jb|
+ ib*jb
+ }
+ }
+ )
+ end
+
+ def test_simplenest2
+ ae %q(
+ def m a
+ yield a
+ end
+ m(1){|ib|
+ m(2){|jb|
+ ib*jb
+ }
+ }
+ )
+ end
+
+ def test_nest2
+ ae %q(
+ def m
+ yield
+ end
+ def n
+ yield
+ end
+
+ m{
+ n{
+ 100
+ }
+ }
+ )
+
+ ae %q(
+ def m
+ yield 1
+ end
+
+ m{|ib|
+ m{|jb|
+ i = 20
+ }
+ }
+ )
+
+ ae %q(
+ def m
+ yield 1
+ end
+
+ m{|ib|
+ m{|jb|
+ ib = 20
+ kb = 2
+ }
+ }
+ )
+
+ ae %q(
+ def iter1
+ iter2{
+ yield
+ }
+ end
+
+ def iter2
+ yield
+ end
+
+ iter1{
+ jb = 2
+ iter1{
+ jb = 3
+ }
+ jb
+ }
+ )
+
+ ae %q(
+ def iter1
+ iter2{
+ yield
+ }
+ end
+
+ def iter2
+ yield
+ end
+
+ iter1{
+ jb = 2
+ iter1{
+ jb
+ }
+ jb
+ }
+ )
+ end
+
+ def test_ifunc
+ ae %q{
+ (1..3).to_a
+ }
+
+ ae %q{
+ (1..3).map{|e|
+ e * 4
+ }
+ }
+
+ ae %q{
+ class C
+ include Enumerable
+ def each
+ [1,2,3].each{|e|
+ yield e
+ }
+ end
+ end
+
+ C.new.to_a
+ }
+
+ ae %q{
+ class C
+ include Enumerable
+ def each
+ [1,2,3].each{|e|
+ yield e
+ }
+ end
+ end
+
+ C.new.map{|e|
+ e + 3
+ }
+ }
+ end
+
+ def test_times
+ ae %q{
+ sum = 0
+ 3.times{|ib|
+ 2.times{|jb|
+ sum += ib + jb
+ }}
+ sum
+ }
+ ae %q{
+ 3.times{|bl|
+ break 10
+ }
+ }
+ end
+
+ def test_for
+ ae %q{
+ sum = 0
+ for x in [1, 2, 3]
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ sum = 0
+ for x in (1..5)
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ sum = 0
+ for x in []
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ ans = []
+ 1.times{
+ for n in 1..3
+ a = n
+ ans << a
+ end
+ }
+ }
+ ae %q{
+ ans = []
+ for m in 1..3
+ for n in 1..3
+ a = [m, n]
+ ans << a
+ end
+ end
+ }
+ end
+
+ def test_unmatched_params
+ ae %q{
+ def iter
+ yield 1,2,3
+ end
+
+ iter{|i, j|
+ [i, j]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1
+ end
+
+ iter{|i, j|
+ [i, j]
+ }
+ }
+ end
+
+ def test_rest
+ # TODO: known bug
+ #ae %q{
+ # def iter
+ # yield 1, 2
+ # end
+ #
+ # iter{|a, |
+ # [a]
+ # }
+ #}
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, *b|
+ [a, b]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|*a|
+ [a]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, b, *c|
+ [a, b, c]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, b, c, *d|
+ [a, b, c, d]
+ }
+ }
+ end
+
+ def test_param_and_locals
+ ae %q{
+ $a = []
+
+ def iter
+ yield 1
+ end
+
+ def m
+ x = iter{|x|
+ $a << x
+ y = 0
+ }
+ end
+ m
+ $a
+ }
+ end
+
+ def test_c_break
+ ae %q{
+ [1,2,3].find{|x| x == 2}
+ }
+ ae %q{
+ class E
+ include Enumerable
+ def each(&block)
+ [1, 2, 3].each(&block)
+ end
+ end
+ E.new.find {|x| x == 2 }
+ }
+ end
+end
diff --git a/trunk/yarvtest/test_eval.rb b/trunk/yarvtest/test_eval.rb
new file mode 100644
index 0000000000..0432caa3f1
--- /dev/null
+++ b/trunk/yarvtest/test_eval.rb
@@ -0,0 +1,221 @@
+require 'yarvtest/yarvtest'
+
+class TestEval < YarvTestBase
+ def test_eval
+ ae %q{
+ eval('1')
+ }
+ ae %q{
+ eval('a=1; a')
+ }
+ ae %q{
+ a = 1
+ eval('a')
+ }
+ end
+
+ def test_eval_with_send
+ ae %q{
+ __send__ :eval, %{
+ :ok
+ }
+ }
+ ae %q{
+ 1.__send__ :instance_eval, %{
+ :ok
+ }
+ }
+ end
+
+ def test_module_eval
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.module_eval{
+ Const
+ }
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.module_eval %{
+ Const
+ }
+ } if false # TODO: Ruby 1.9 error
+
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.class_eval %{
+ def m
+ Const
+ end
+ }
+ C.new.m
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.class_eval{
+ def m
+ Const
+ end
+ }
+ C.new.m
+ }
+ end
+
+ def test_instance_eval
+ ae %q{
+ 1.instance_eval{
+ self
+ }
+ }
+ ae %q{
+ 'foo'.instance_eval{
+ self
+ }
+ }
+ ae %q{
+ class Fixnum
+ Const = 1
+ end
+ 1.instance_eval %{
+ Const
+ }
+ }
+ end
+
+ def test_nest_eval
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ $nest = false
+ $ans = []
+ def m
+ $ans << Const
+ C.module_eval %{
+ $ans << Const
+ Boo = false unless defined? Boo
+ unless $nest
+ $nest = true
+ m
+ end
+ }
+ end
+ m
+ $ans
+ }
+ ae %q{
+ $nested = false
+ $ans = []
+ $pr = proc{
+ $ans << self
+ unless $nested
+ $nested = true
+ $pr.call
+ end
+ }
+ class C
+ def initialize &b
+ 10.instance_eval(&b)
+ end
+ end
+ C.new(&$pr)
+ $ans
+ }
+ end
+
+ def test_binding
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('a', $b)
+ }
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('b = :ok2', $b)
+ eval('[a, b]', $b)
+ }
+ ae %q{
+ $ans = []
+ def m
+ $b = binding
+ end
+ m
+ $ans << eval(%q{
+ $ans << eval(%q{
+ a
+ }, $b)
+ a = 1
+ }, $b)
+ $ans
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ def m
+ binding
+ end
+ end
+ eval('Const', C.new.m)
+ }
+ ae %q{
+ Const = :top
+ a = 1
+ class C
+ Const = :C
+ def m
+ eval('Const', TOPLEVEL_BINDING)
+ end
+ end
+ C.new.m
+ }
+ ae %q{
+ class C
+ $b = binding
+ end
+ eval %q{
+ def m
+ :ok
+ end
+ }, $b
+ p C.new.m
+ }
+ ae %q{
+ b = proc{
+ a = :ok
+ binding
+ }.call
+ a = :ng
+ eval("a", b)
+ }
+ ae %q{
+ class C
+ def foo
+ binding
+ end
+ end
+ C.new.foo.eval("self.class.to_s")
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_exception.rb b/trunk/yarvtest/test_exception.rb
new file mode 100644
index 0000000000..9e69d02909
--- /dev/null
+++ b/trunk/yarvtest/test_exception.rb
@@ -0,0 +1,408 @@
+require 'yarvtest/yarvtest'
+
+class TestException < YarvTestBase
+
+ def test_rescue
+ ae %q{
+ begin
+ 1
+ rescue
+ 2
+ end
+ }
+
+ ae %q{
+ begin
+ 1
+ begin
+ 2
+ rescue
+ 3
+ end
+ 4
+ rescue
+ 5
+ end
+ }
+
+ ae %q{
+ begin
+ 1
+ rescue
+ 2
+ else
+ 3
+ end
+ }
+ end
+
+ def test_ensure
+ ae %q{
+ begin
+ 1+1
+ ensure
+ 2+2
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ ensure
+ 3+3
+ end
+ ensure
+ 4+4
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ ensure
+ 3+3
+ end
+ ensure
+ 4+4
+ begin
+ 5+5
+ ensure
+ 6+6
+ end
+ end
+ }
+ end
+
+ def test_rescue_ensure
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ ensure
+ 3+3
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ ensure
+ 3+3
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ else
+ 3+3
+ ensure
+ 4+4
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ rescue
+ 3+3
+ else
+ 4+4
+ end
+ rescue
+ 5+5
+ else
+ 6+6
+ ensure
+ 7+7
+ end
+ }
+
+ end
+
+ def test_raise
+ ae %q{
+ begin
+ raise
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue
+ :ok
+ ensure
+ :ng
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue => e
+ e.class
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue StandardError
+ :ng
+ rescue Exception
+ :ok
+ end
+ }
+ ae %q{
+ begin
+ begin
+ raise "a"
+ rescue
+ raise "b"
+ ensure
+ raise "c"
+ end
+ rescue => e
+ e.message
+ end
+ }
+ end
+
+ def test_error_variable
+ ae %q{
+ a = nil
+ 1.times{|e|
+ begin
+ rescue => err
+ end
+ a = err.class
+ }
+ }
+ ae %q{
+ a = nil
+ 1.times{|e|
+ begin
+ raise
+ rescue => err
+ end
+ a = err.class
+ }
+ a
+ }
+ end
+
+ def test_raise_in_other_scope
+ ae %q{
+ class E1 < Exception
+ end
+
+ def m
+ yield
+ end
+
+ begin
+ begin
+ begin
+ m{
+ raise
+ }
+ rescue E1
+ :ok2
+ ensure
+ end
+ rescue
+ :ok3
+ ensure
+ end
+ rescue E1
+ :ok
+ ensure
+ end
+ } do
+ remove_const :E1
+ end
+
+ ae %q{
+ $i = 0
+ def m
+ iter{
+ begin
+ $i += 1
+ begin
+ $i += 2
+ break
+ ensure
+
+ end
+ ensure
+ $i += 4
+ end
+ $i = 0
+ }
+ end
+
+ def iter
+ yield
+ end
+ m
+ $i
+ }
+
+ ae %q{
+ $i = 0
+ def m
+ begin
+ $i += 1
+ begin
+ $i += 2
+ return
+ ensure
+ $i += 3
+ end
+ ensure
+ $i += 4
+ end
+ p :end
+ end
+ m
+ $i
+ }
+ end
+
+ def test_raise_in_cont_sp
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1, begin
+ raise
+ rescue
+ 2
+ end) +
+ m(10, begin
+ raise
+ rescue
+ 20
+ ensure
+ 30
+ end)
+ }
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(begin
+ raise
+ rescue
+ 1
+ end,
+ begin
+ raise
+ rescue
+ 2
+ end)
+ }
+ end
+
+ def test_geterror
+ ae %q{
+ $!
+ }
+ ae %q{
+ begin
+ raise "FOO"
+ rescue
+ $!
+ end
+ }
+ ae %q{
+ def m
+ $!
+ end
+ begin
+ raise "FOO"
+ rescue
+ m()
+ end
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+ begin
+ raise "FOO"
+ rescue
+ begin
+ raise "BAR"
+ rescue
+ $ans << m()
+ end
+ $ans << m()
+ end
+ $ans
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+
+ begin
+ begin
+ raise "FOO"
+ ensure
+ $ans << m()
+ end
+ rescue
+ $ans << m()
+ end
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+ def m2
+ 1.times{
+ begin
+ return
+ ensure
+ $ans << m
+ end
+ }
+ end
+ m2
+ $ans
+ }
+ end
+
+ def test_stack_consistency
+ ae %q{ #
+ proc{
+ begin
+ raise
+ break
+ rescue
+ :ok
+ end
+ }.call
+ }
+ ae %q{
+ proc do
+ begin
+ raise StandardError
+ redo
+ rescue StandardError
+ end
+ end.call
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_flow.rb b/trunk/yarvtest/test_flow.rb
new file mode 100644
index 0000000000..bc4d84e5fd
--- /dev/null
+++ b/trunk/yarvtest/test_flow.rb
@@ -0,0 +1,591 @@
+#
+# This test program is contributed by George Marrows
+# Re: [Yarv-devel] Some tests for test_jump.rb
+#
+
+require 'yarvtest/yarvtest'
+
+class TestFlow < YarvTestBase
+ def ae_flow(src, for_value=true)
+ # Tracks flow through the code
+ # A test like
+ # begin
+ # ensure
+ # end
+ # gets transformed into
+ # a = []
+ # begin
+ # begin; a << 1
+ # ensure; a << 2
+ # end; a << 3
+ # rescue Exception
+ # a << 99
+ # end
+ # a
+ # before being run. This tracks control flow through the code.
+
+ cnt = 0
+ src = src.gsub(/(\n|$)/) { "; $a << #{cnt+=1}\n" }
+ src = "$a = []; begin; #{src}; rescue Exception; $a << 99; end; $a"
+
+ if false#||true
+ STDERR.puts
+ STDERR.puts '#----'
+ STDERR.puts src
+ STDERR.puts '#----'
+ end
+
+ ae(src)
+ end
+
+ def test_while_with_ensure
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ next
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ break
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ if i>0
+ break
+ end
+ i+=1
+ begin
+ begin
+ redo
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ end
+
+ def test_ensure_normal_flow
+ ae_flow %{
+ begin
+ ensure
+ end }
+ end
+
+ def test_ensure_exception
+ ae_flow %{
+ begin
+ raise StandardError
+ ensure
+ end
+ }
+ end
+
+ def test_break_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_next_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ next
+ ensure
+ end
+ end
+ }
+ end
+ def test_return_from_method_runs_ensure
+ ae_flow %{
+ o = "test"
+ def o.test(a)
+ return a
+ ensure
+ end
+ o.test(123)
+ }
+ end
+
+ def test_break_from_ifunc
+ ae %q{
+ ["a"].inject("ng"){|x,y|
+ break :ok
+ }
+ }
+ ae %q{
+ unless ''.respond_to? :lines
+ class String
+ def lines
+ self
+ end
+ end
+ end
+
+ ('a').lines.map{|e|
+ break :ok
+ }
+ }
+ ae_flow %q{
+ ["a"].inject("ng"){|x,y|
+ break :ok
+ }
+ }
+ ae_flow %q{
+ ('a'..'b').map{|e|
+ break :ok
+ }
+ }
+ end
+
+ def test_break_ensure_interaction1
+ # make sure that any 'break state' set up in the VM is c
+ # the time of the ensure
+ ae_flow %{
+ [1,2].each{
+ break
+ }
+ begin
+ ensure
+ end
+ }
+ end
+
+ def test_break_ensure_interaction2
+ # ditto, different arrangement
+ ae_flow %{
+ begin
+ [1,2].each do
+ break
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_break_through_2_ensures
+ ae_flow %{
+ [1,2].each do
+ begin
+ begin
+ break
+ ensure
+ end
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_ensure_break_ensure
+ # break through an ensure; run 2nd normally
+ ae_flow %{
+ begin
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_exception_overrides_break
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ raise StandardError
+ end
+ end
+ }
+ end
+
+ def test_break_overrides_exception
+ ae_flow %{
+ [1,2].each do
+ begin
+ raise StandardError
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %{
+ [1,2].each do
+ begin
+ raise StandardError
+ rescue
+ break
+ end
+ end
+ }
+ end
+
+ def test_break_in_exception
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ rescue
+ break
+ end
+ end
+ }
+ end
+
+ def test_next_in_exception
+ return
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ ensure
+ next
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ ensure
+ next
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ rescue
+ next
+ end
+ end
+ }
+ end
+
+ def test_complex_break
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ begin
+ raise
+ rescue
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ 1.times{
+ begin
+ raise
+ rescue
+ break
+ end
+ }
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ begin
+ raise
+ ensure
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ 1.times{
+ begin
+ raise
+ ensure
+ break
+ end
+ }
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ begin
+ break
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ begin
+ break
+ ensure
+ raise
+ end
+ end
+ }
+ end
+
+ def test_jump_from_class
+ ae_flow %q{
+ 3.times{
+ class C
+ break
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class A
+ class B
+ break
+ end
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class C
+ next
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class C
+ class D
+ next
+ end
+ end
+ }
+ }
+ ae_flow %q{
+ while true
+ class C
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ class C
+ class D
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ class C
+ next 10
+ end
+ end
+ }
+ ae %q{
+ 1.times{
+ while true
+ class C
+ begin
+ break
+ ensure
+ break
+ end
+ end
+ end
+ }
+ }
+ end
+
+ def test_flow_with_cont_sp
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1,
+ while true
+ break 2
+ end
+ )
+ }
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1,
+ (i=0; while i<2
+ i+=1
+ class C
+ next 2
+ end
+ end; 3)
+ )
+ }
+ ae %q{
+ def m a, b
+ a+b
+ end
+ m(1, 1.times{break 3}) +
+ m(10, (1.times{next 3}; 20))
+ }
+ end
+
+ def test_return_in_deep_stack
+ ae_flow %q{
+ def m1 *args
+
+ end
+ def m2
+ m1(:a, :b, (return 1; :c))
+ end
+ m2
+ }
+ end
+
+ def test_return_in_ensure
+ ae_flow %q{
+ def m()
+ begin
+ 2
+ ensure
+ return 3
+ end
+ end
+ m
+ }
+ ae_flow %q{
+ def m2
+ end
+ def m()
+ m2(begin
+ 2
+ ensure
+ return 3
+ end)
+ 4
+ end
+ m()
+ }
+ ae_flow %q{
+ def m
+ 1
+ 1.times{
+ 2
+ begin
+ 3
+ return
+ 4
+ ensure
+ 5
+ end
+ 6
+ }
+ 7
+ end
+ m()
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_jump.rb b/trunk/yarvtest/test_jump.rb
new file mode 100644
index 0000000000..4c806380a8
--- /dev/null
+++ b/trunk/yarvtest/test_jump.rb
@@ -0,0 +1,296 @@
+require 'yarvtest/yarvtest'
+
+class TestJump < YarvTestBase
+
+ def test_redo
+ ae %q{
+ def m
+ yield + 10
+ end
+ i=0
+ m{
+ if i>10
+ i*i
+ else
+ i+=1
+ redo
+ end
+ }
+ }
+ end
+
+ def test_next
+ ae %q{
+ def m
+ yield
+ :ok
+ end
+ i=0
+ m{
+ if i>10
+ i*i
+ else
+ i+=1
+ next
+ end
+ }
+ }
+ end
+
+ def test_next_with_val
+ ae %q{
+ def m
+ yield
+ end
+
+ m{
+ next :ok
+ }
+ }
+ end
+
+ def test_return
+ ae %q{
+ def m
+ return 3
+ end
+ m
+ }
+
+ ae %q{
+ def m
+ :ng1
+ mm{
+ return :ok
+ }
+ :ng2
+ end
+
+ def mm
+ :ng3
+ yield
+ :ng4
+ end
+ m
+ }
+ end
+
+ def test_return2
+ ae %q{
+ $i = 0
+ def m
+ begin
+ iter{
+ return
+ }
+ ensure
+ $i = 100
+ end
+ end
+
+ def iter
+ yield
+ end
+ m
+ $i
+ }
+ end
+
+ def test_return3
+ ae %q{
+ def m
+ begin
+ raise
+ rescue
+ return :ok
+ end
+ :ng
+ end
+ m
+ }
+ end
+
+ def test_break
+ ae %q{
+ def m
+ :ng1
+ mm{
+ yield
+ }
+ :ng2
+ end
+
+ def mm
+ :ng3
+ yield
+ :ng4
+ end
+
+ m{
+ break :ok
+ }
+ }
+ end
+
+ def test_exception_and_break
+ ae %q{
+ def m
+ yield
+ end
+
+ m{
+ begin
+ ensure
+ break :ok
+ end
+ }
+ }
+ end
+
+ def test_retry
+ # this test can't run on ruby 1.9(yarv can do)
+ %q{
+ def m a
+ mm{
+ yield
+ }
+ end
+
+ def mm
+ yield
+ end
+
+ i=0
+ m(i+=1){
+ retry if i<10
+ :ok
+ }
+ }
+
+ ae %q{
+ def m a
+ yield
+ end
+
+ i=0
+ m(i+=1){
+ retry if i<10
+ :ok
+ }
+ }
+ end
+
+ def test_complex_jump
+ ae %q{
+ module Enumerable
+ def all_?
+ self.each{|e|
+ unless yield(e)
+ return false
+ end
+ }
+ true
+ end
+ end
+
+ xxx = 0
+ [1,2].each{|bi|
+ [3,4].each{|bj|
+ [true, nil, true].all_?{|be| be}
+ break
+ }
+ xxx += 1
+ }
+ xxx
+ }
+ end
+
+ def test_return_from
+ ae %q{
+ def m
+ begin
+ raise
+ rescue
+ return 1
+ end
+ end
+
+ m
+ }
+ ae %q{
+ def m
+ begin
+ #
+ ensure
+ return 1
+ end
+ end
+
+ m
+ }
+ end
+
+ def test_break_from_times
+ ae %q{
+ 3.times{
+ break :ok
+ }
+ }
+ end
+
+ def test_catch_and_throw
+ ae %q{
+ catch(:foo){
+ throw :foo
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, false
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, nil
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, :ok
+ }
+ }
+ ae %q{
+ catch(:foo){
+ 1.times{
+ throw :foo
+ }
+ }
+ }
+ ae %q{
+ catch(:foo){
+ 1.times{
+ throw :foo, :ok
+ }
+ }
+ }
+ ae %q{
+ catch(:foo){
+ catch(:bar){
+ throw :foo, :ok
+ }
+ :ng
+ }
+ }
+ ae %q{
+ catch(:foo){
+ catch(:bar){
+ 1.times{
+ throw :foo, :ok
+ }
+ }
+ :ng
+ }
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_proc.rb b/trunk/yarvtest/test_proc.rb
new file mode 100644
index 0000000000..2106d2e56e
--- /dev/null
+++ b/trunk/yarvtest/test_proc.rb
@@ -0,0 +1,293 @@
+require 'yarvtest/yarvtest'
+
+class TestProc < YarvTestBase
+ def test_simpleproc
+ ae %q{
+ def m(&b)
+ b
+ end
+ m{1}.call
+ }
+
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{
+ a = 1
+ a + 2
+ }.call
+ }
+ end
+
+ def test_procarg
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{|e_proctest| e_proctest}.call(1)
+ }
+
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{|e_proctest1, e_proctest2|
+ a = e_proctest1 * e_proctest2 * 2
+ a * 3
+ }.call(1, 2)
+ }
+
+ ae %q{
+ [
+ Proc.new{|*args| args}.call(),
+ Proc.new{|*args| args}.call(1),
+ Proc.new{|*args| args}.call(1, 2),
+ Proc.new{|*args| args}.call(1, 2, 3),
+ ]
+ }
+ ae %q{
+ [
+ Proc.new{|a, *b| [a, b]}.call(),
+ Proc.new{|a, *b| [a, b]}.call(1),
+ Proc.new{|a, *b| [a, b]}.call(1, 2),
+ Proc.new{|a, *b| [a, b]}.call(1, 2, 3),
+ ]
+ }
+ end
+
+ def test_closure
+ ae %q{
+ def make_proc(&b)
+ b
+ end
+
+ def make_closure
+ a = 0
+ make_proc{
+ a+=1
+ }
+ end
+
+ cl = make_closure
+ cl.call + cl.call * cl.call
+ }
+ end
+
+ def test_nestproc2
+ ae %q{
+ def iter
+ yield
+ end
+
+ def getproc &b
+ b
+ end
+
+ iter{
+ bvar = 3
+ getproc{
+ bvar2 = 4
+ bvar * bvar2
+ }
+ }.call
+ }
+
+ ae %q{
+ def iter
+ yield
+ end
+
+ def getproc &b
+ b
+ end
+
+ loc1 = 0
+ pr1 = iter{
+ bl1 = 1
+ getproc{
+ loc1 += 1
+ bl1 += 1
+ loc1 + bl1
+ }
+ }
+
+ pr2 = iter{
+ bl1 = 1
+ getproc{
+ loc1 += 1
+ bl1 += 1
+ loc1 + bl1
+ }
+ }
+
+ pr1.call; pr2.call
+ pr1.call; pr2.call
+ pr1.call; pr2.call
+ (pr1.call + pr2.call) * loc1
+ }
+ end
+
+ def test_proc_with_cref
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ $pr = proc{
+ (1..2).map{
+ Const
+ }
+ }
+ end
+ $pr.call
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ pr = proc{
+ Const
+ }
+ C.class_eval %q{
+ pr.call
+ }
+ }
+ end
+
+ def test_3nest
+ ae %q{
+ def getproc &b
+ b
+ end
+
+ def m
+ yield
+ end
+
+ m{
+ i = 1
+ m{
+ j = 2
+ m{
+ k = 3
+ getproc{
+ [i, j, k]
+ }
+ }
+ }
+ }.call
+ }
+ end
+
+ def test_nestproc1
+ ae %q{
+ def proc &b
+ b
+ end
+
+ pr = []
+ proc{|i_b|
+ p3 = proc{|j_b|
+ pr << proc{|k_b|
+ [i_b, j_b, k_b]
+ }
+ }
+ p3.call(1)
+ p3.call(2)
+ }.call(0)
+
+ pr[0].call(:last).concat pr[1].call(:last)
+ }
+ end
+
+ def test_proc_with_block
+ ae %q{
+ def proc(&pr)
+ pr
+ end
+
+ def m
+ a = 1
+ m2{
+ a
+ }
+ end
+
+ def m2
+ b = 2
+ proc{
+ [yield, b]
+ }
+ end
+
+ pr = m
+ x = ['a', 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,]
+ pr.call
+ }
+ ae %q{
+ def proc(&pr)
+ pr
+ end
+
+ def m
+ a = 1
+ m2{
+ a
+ }
+ end
+
+ def m2
+ b = 2
+ proc{
+ [yield, b]
+ }
+ 100000.times{|x|
+ "#{x}"
+ }
+ yield
+ end
+ m
+ }
+ end
+
+ def test_method_to_proc
+ ae %q{
+ class C
+ def foo
+ :ok
+ end
+ end
+
+ def block
+ C.method(:new).to_proc
+ end
+ b = block()
+ b.call.foo
+ }
+ end
+
+ def test_safe
+ ae %q{
+ pr = proc{
+ $SAFE
+ }
+ $SAFE = 1
+ pr.call
+ }
+ ae %q{
+ pr = proc{
+ $SAFE += 1
+ }
+ [pr.call, $SAFE]
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_syntax.rb b/trunk/yarvtest/test_syntax.rb
new file mode 100644
index 0000000000..a15159acdf
--- /dev/null
+++ b/trunk/yarvtest/test_syntax.rb
@@ -0,0 +1,594 @@
+require 'yarvtest/yarvtest'
+
+# test of syntax
+class TestSYNTAX < YarvTestBase
+
+ def test_if_unless
+ ae %q(if true then 1 ; end)
+ ae %q(if false then 1 ; end)
+ ae %q(if true then 1 ; else; 2; end)
+ ae %q(if false then 1 ; else; 2; end)
+ ae %q(if true then ; elsif true then ; 1 ; end)
+ ae %q(if false then ; elsif true then ; 1 ; end)
+
+ ae %q(unless true then 1 ; end)
+ ae %q(unless false then 1 ; end)
+ ae %q(unless true then 1 ; else; 2; end)
+ ae %q(unless false then 1 ; else; 2; end)
+
+ ae %q(1 if true)
+ ae %q(1 if false)
+ ae %q(1 if nil)
+
+ ae %q(1 unless true)
+ ae %q(1 unless false)
+ ae %q(1 unless nil)
+ end
+
+ def test_while_until
+ ae %q(
+ i = 0
+ while i < 10
+ i+=1
+ end)
+
+ ae %q(
+ i = 0
+ while i < 10
+ i+=1
+ end; i)
+
+ ae %q(
+ i = 0
+ until i > 10
+ i+=1
+ end)
+
+ ae %q(
+ i = 0
+ until i > 10
+ i+=1
+ end; i)
+ #
+ ae %q{
+ i = 0
+ begin
+ i+=1
+ end while false
+ i
+ }
+ ae %q{
+ i = 0
+ begin
+ i+=1
+ end until true
+ i
+ }
+ end
+
+ def test_and
+ ae %q(1 && 2 && 3 && 4)
+ ae %q(1 && nil && 3 && 4)
+ ae %q(1 && 2 && 3 && nil)
+ ae %q(1 && 2 && 3 && false)
+
+ ae %q(1 and 2 and 3 and 4)
+ ae %q(1 and nil and 3 and 4)
+ ae %q(1 and 2 and 3 and nil)
+ ae %q(1 and 2 and 3 and false)
+ ae %q(nil && true)
+ ae %q(false && true)
+
+ end
+
+ def test_or
+ ae %q(1 || 2 || 3 || 4)
+ ae %q(1 || false || 3 || 4)
+ ae %q(nil || 2 || 3 || 4)
+ ae %q(false || 2 || 3 || 4)
+ ae %q(nil || false || nil || false)
+
+ ae %q(1 or 2 or 3 or 4)
+ ae %q(1 or false or 3 or 4)
+ ae %q(nil or 2 or 3 or 4)
+ ae %q(false or 2 or 3 or 4)
+ ae %q(nil or false or nil or false)
+ end
+
+ def test_case
+ ae %q(
+ case 1
+ when 2
+ :ng
+ end)
+
+ ae %q(
+ case 1
+ when 10,20,30
+ :ng1
+ when 1,2,3
+ :ok
+ when 100,200,300
+ :ng2
+ else
+ :elseng
+ end)
+ ae %q(
+ case 123
+ when 10,20,30
+ :ng1
+ when 1,2,3
+ :ng2
+ when 100,200,300
+ :ng3
+ else
+ :elseok
+ end
+ )
+ ae %q(
+ case 'test'
+ when /testx/
+ :ng1
+ when /test/
+ :ok
+ when /tetxx/
+ :ng2
+ else
+ :ng_else
+ end
+ )
+ ae %q(
+ case Object.new
+ when Object
+ :ok
+ end
+ )
+ ae %q(
+ case Object
+ when Object.new
+ :ng
+ else
+ :ok
+ end
+ )
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when 'te'
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when 'te'
+ :ng
+ when 'test'
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when /te/
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when /test/
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ def test(arg)
+ case 1
+ when 2
+ 3
+ end
+ return arg
+ end
+
+ test(100)
+ }
+ end
+
+ def test_case_splat
+ ae %q{
+ ary = [1, 2]
+ case 1
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 3
+ when *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 1
+ when :x, *ary
+ :ok
+ when :z
+ :ng1
+ else
+ :ng2
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 3
+ when :x, *ary
+ :ng1
+ when :z
+ :ng2
+ else
+ :ok
+ end
+ }
+ end
+
+ def test_when
+ ae %q(
+ case
+ when 1==2, 2==3
+ :ng1
+ when false, 4==5
+ :ok
+ when false
+ :ng2
+ else
+ :elseng
+ end
+ )
+
+ ae %q(
+ case
+ when nil, nil
+ :ng1
+ when 1,2,3
+ :ok
+ when false, false
+ :ng2
+ else
+ :elseng
+ end
+ )
+
+ ae %q(
+ case
+ when nil
+ :ng1
+ when false
+ :ng2
+ else
+ :elseok
+ end)
+
+ ae %q{
+ case
+ when 1
+ end
+ }
+
+ ae %q{
+ r = nil
+ ary = []
+ case
+ when false
+ r = :ng1
+ when false, false
+ r = :ng2
+ when *ary
+ r = :ng3
+ when false, *ary
+ r = :ng4
+ when true, *ary
+ r = :ok
+ end
+ r
+ }
+ end
+
+ def test_when_splat
+ ae %q{
+ ary = []
+ case
+ when false, *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ng
+ when true
+ :ok
+ else
+ :ng2
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [false, true]
+ case
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [false, true]
+ case
+ when false, false
+ when false, *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ end
+
+ def test_flipflop
+ ae %q{
+ sum = 0
+ 30.times{|ib|
+ if ib % 10 == 0 .. true
+ sum += ib
+ end
+ }
+ sum
+ }
+ ae %q{
+ sum = 0
+ 30.times{|ib|
+ if ib % 10 == 0 ... true
+ sum += ib
+ end
+ }
+ sum
+ }
+ ae %q{
+ t = nil
+ unless ''.respond_to? :lines
+ class String
+ def lines
+ self
+ end
+ end
+ end
+
+ "this must not print
+ Type: NUM
+ 123
+ 456
+ Type: ARP
+ aaa
+ bbb
+ \f
+ this must not print
+ hoge
+ Type: ARP
+ aaa
+ bbb
+ ".lines.each{|l|
+ if (t = l[/^Type: (.*)/, 1])..(/^\f/ =~ l)
+ p [t, l]
+ end
+ }
+ }
+ end
+
+ def test_defined_vars
+ ae %q{
+ defined?(nil) + defined?(self) +
+ defined?(true) + defined?(false)
+ }
+ #ae %q{
+ # a = 1
+ # defined?(a) # yarv returns "in block" in eval context
+ #}
+ ae %q{
+ defined?(@a)
+ }
+ ae %q{
+ @a = 1
+ defined?(@a)
+ }
+ ae %q{
+ defined?(@@a)
+ }
+ ae %q{
+ @@a = 1
+ defined?(@@a)
+ }
+ ae %q{
+ defined?($a)
+ }
+ ae %q{
+ $a = 1
+ defined?($a)
+ }
+ ae %q{
+ defined?(C_definedtest)
+ }
+ ae %q{
+ C_definedtest = 1
+ defined?(C_definedtest)
+ } do
+ remove_const :C_definedtest
+ end
+
+ ae %q{
+ defined?(::C_definedtest)
+ }
+ ae %q{
+ C_definedtest = 1
+ defined?(::C_definedtest)
+ } do
+ remove_const :C_definedtest
+ end
+
+ ae %q{
+ defined?(C_definedtestA::C_definedtestB::C_definedtestC)
+ }
+ ae %q{
+ class C_definedtestA
+ class C_definedtestB
+ C_definedtestC = 1
+ end
+ end
+ defined?(C_definedtestA::C_definedtestB::C_definedtestC)
+ } do
+ remove_const :C_definedtestA
+ end
+ end
+
+ def test_defined_method
+ ae %q{
+ defined?(m)
+ }
+ ae %q{
+ def m
+ end
+ defined?(m)
+ }
+
+ ae %q{
+ defined?(a.class)
+ }
+ ae %q{
+ a = 1
+ defined?(a.class)
+ }
+ ae %q{
+ class C
+ def test
+ [defined?(m1()), defined?(self.m1), defined?(C.new.m1),
+ defined?(m2()), defined?(self.m2), defined?(C.new.m2),
+ defined?(m3()), defined?(self.m3), defined?(C.new.m3)]
+ end
+ def m1
+ end
+ private
+ def m2
+ end
+ protected
+ def m3
+ end
+ end
+ C.new.test + [defined?(C.new.m3)]
+ }
+ ae %q{
+ $ans = [defined?($1), defined?($2), defined?($3), defined?($4)]
+ /(a)(b)/ =~ 'ab'
+ $ans + [defined?($1), defined?($2), defined?($3), defined?($4)]
+ }
+ end
+
+ def test_condition
+ ae %q{
+
+ def make_perm ary, num
+ if num == 1
+ ary.map{|e| [e]}
+ else
+ base = make_perm(ary, num-1)
+ res = []
+ base.each{|b|
+ ary.each{|e|
+ res << [e] + b
+ }
+ }
+ res
+ end
+ end
+
+ def each_test
+ conds = make_perm(['fv', 'tv'], 3)
+ bangs = make_perm(['', '!'], 3)
+ exprs = make_perm(['and', 'or'], 3)
+ ['if', 'unless'].each{|syn|
+ conds.each{|cs|
+ bangs.each{|bs|
+ exprs.each{|es|
+ yield(syn, cs, bs, es)
+ }
+ }
+ }
+ }
+ end
+
+ fv = false
+ tv = true
+
+ $ans = []
+ each_test{|syn, conds, bangs, exprs|
+ c1, c2, c3 = conds
+ bang1, bang2, bang3 = bangs
+ e1, e2 = exprs
+ eval %Q{
+ #{syn} #{bang1}#{c1} #{e1} #{bang2}#{c2} #{e2} #{bang3}#{c3}
+ $ans << :then
+ else
+ $ans << :false
+ end
+ }
+ }
+
+ each_test{|syn, conds, bangs, exprs|
+ c1, c2, c3 = conds
+ bang1, bang2, bang3 = bangs
+ e1, e2 = exprs
+ eval %Q{
+ #{syn} #{bang1}#{c1} #{e1} #{bang2}#{c2} #{e2} #{bang3}#{c3}
+ $ans << :then
+ end
+ $ans << :sep
+ }
+ }
+ $ans
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/test_test.rb b/trunk/yarvtest/test_test.rb
new file mode 100644
index 0000000000..a550f43640
--- /dev/null
+++ b/trunk/yarvtest/test_test.rb
@@ -0,0 +1,8 @@
+require 'yarvtest/yarvtest'
+
+# test of syntax
+class TestTest < YarvTestBase
+ def test_1
+ ae '100'
+ end
+end
diff --git a/trunk/yarvtest/test_thread.rb b/trunk/yarvtest/test_thread.rb
new file mode 100644
index 0000000000..072e065497
--- /dev/null
+++ b/trunk/yarvtest/test_thread.rb
@@ -0,0 +1,209 @@
+
+require 'yarvtest/yarvtest'
+
+class TestThread < YarvTestBase
+ def test_create
+ ae %q{
+ Thread.new{
+ }.join
+ :ok
+ }
+ ae %q{
+ Thread.new{
+ :ok
+ }.value
+ }
+ end
+
+ def test_create_many_threads1
+ ae %q{
+ v = 0
+ (1..200).map{|i|
+ Thread.new{
+ i
+ }
+ }.each{|t|
+ v += t.value
+ }
+ v
+ }
+ end
+
+ def test_create_many_threads2
+ ae %q{
+ 5000.times{|e|
+ (1..2).map{
+ Thread.new{
+ }
+ }.each{|e|
+ e.join
+ }
+ }
+ }
+ end
+
+ def test_create_many_threads3
+ ae %q{
+ 5000.times{
+ t = Thread.new{}
+ while t.alive?
+ Thread.pass
+ end
+ }
+ }
+ end
+
+ def test_create_many_threads4
+ ae %q{
+ 100.times{
+ Thread.new{loop{Thread.pass}}
+ }
+ }
+ end
+
+ def test_raise
+ ae %q{
+ t = Thread.new{
+ sleep
+ }
+ sleep 0.1
+ t.raise
+ begin
+ t.join
+ :ng
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ t = Thread.new{
+ loop{}
+ }
+ Thread.pass
+ t.raise
+ begin
+ t.join
+ :ng
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ t = Thread.new{
+ }
+ Thread.pass
+ t.join
+ t.raise # raise to exited thread
+ begin
+ t.join
+ :ok
+ rescue
+ :ng
+ end
+ }
+ end
+
+ def test_status
+ ae %q{
+ t = Thread.new{
+ loop{}
+ }
+ st = t.status
+ t.kill
+ st
+ }
+ ae %q{
+ t = Thread.new{
+ sleep
+ }
+ sleep 0.1
+ st = t.status
+ t.kill
+ st
+ }
+ ae %q{
+ t = Thread.new{
+ }
+ t.kill
+ sleep 0.1
+ t.status
+ }
+ end
+
+ def test_tlv
+ ae %q{
+ Thread.current[:a] = 1
+ Thread.new{
+ Thread.current[:a] = 10
+ Thread.pass
+ Thread.current[:a]
+ }.value + Thread.current[:a]
+ }
+ end
+
+ def test_thread_group
+ ae %q{
+ ptg = Thread.current.group
+ Thread.new{
+ ctg = Thread.current.group
+ [ctg.class, ctg == ptg]
+ }.value
+ }
+ ae %q{
+ thg = ThreadGroup.new
+
+ t = Thread.new{
+ thg.add Thread.current
+ sleep
+ }
+ sleep 0.1
+ [thg.list.size, ThreadGroup::Default.list.size]
+ }
+ end
+
+ def test_thread_local_svar
+ ae %q{
+ /a/ =~ 'a'
+ $a = $~
+ Thread.new{
+ $b = $~
+ /a/ =~ 'a'
+ $c = $~
+ }
+ $d = $~
+ [$a == $d, $b, $c != $d]
+ }
+ end
+
+ def test_join
+ ae %q{
+ Thread.new{
+ :ok
+ }.join.value
+ }
+ ae %q{
+ begin
+ Thread.new{
+ raise "ok"
+ }.join
+ rescue => e
+ e
+ end
+ }
+ ae %q{
+ ans = nil
+ t = Thread.new{
+ begin
+ sleep 0.5
+ ensure
+ ans = :ok
+ end
+ }
+ Thread.pass
+ t.kill
+ t.join
+ ans
+ }
+ end
+end
+
diff --git a/trunk/yarvtest/yarvtest.rb b/trunk/yarvtest/yarvtest.rb
new file mode 100644
index 0000000000..56c173bbe0
--- /dev/null
+++ b/trunk/yarvtest/yarvtest.rb
@@ -0,0 +1,112 @@
+require 'test/unit'
+require 'rbconfig'
+require 'optparse'
+
+if /mswin32/ !~ RUBY_PLATFORM
+ $ruby = './miniruby'
+else
+ $ruby = 'miniruby'
+end
+$matzruby = Config::CONFIG['ruby_install_name']
+
+ARGV.each{|opt|
+ if /\Aruby=(.+)/ =~ opt
+ $ruby = $1
+ elsif /\Amatzruby=(.+)/ =~ opt
+ $matzruby = $1
+ end
+}
+
+a = "matzruby: #{`#{$matzruby} -v`}"
+b = "ruby : #{`#{$ruby} -v`}"
+puts a, b
+raise "Using same command" if a == b
+
+class YarvTestBase < Test::Unit::TestCase
+ def initialize *args
+ super
+
+ end
+
+ def remove_const sym
+ Object.module_eval{
+ remove_const sym
+ }
+ end
+
+ def remove_method sym
+ Object.module_eval{
+ undef sym
+ }
+ end
+
+ require 'tempfile'
+ def exec exec_file, program
+ dir = []
+ dir << ENV['RAMDISK'] if ENV['RAMDISK']
+ tmpf = Tempfile.new("yarvtest_#{Process.pid}_#{Time.now.to_i}", *dir)
+ tmpf.write program
+ tmpf.close
+ result = `#{exec_file} #{tmpf.path}`
+ tmpf.open
+ tmpf.close(true)
+ result
+ end
+
+ def dump_and_exec exec_file, str
+ asmstr = <<-EOASMSTR
+ iseq = YARVCore::InstructionSequence.compile(<<-'EOS__')
+ #{str}
+ EOS__
+ p YARVCore::InstructionSequence.load(iseq.to_a).eval
+ EOASMSTR
+
+ exec(exec_file, asmstr)
+ end
+
+ def exec_ exec_file, program
+ exec_file.tr!('\\', '/')
+ r = ''
+ IO.popen("#{exec_file}", 'r+'){|io|
+ #
+ io.write program
+ io.close_write
+ begin
+ while line = io.gets
+ r << line
+ # p line
+ end
+ rescue => e
+ # p e
+ end
+ }
+ r
+ end
+
+ def ae str
+ evalstr = %{
+ p eval(%q{
+ #{str}
+ })
+ }
+
+ matzruby = exec($matzruby, evalstr)
+ ruby = exec($ruby, evalstr)
+
+ if $DEBUG #|| true
+ puts "matzruby (#$matzruby): #{matzruby}"
+ puts "ruby (#$ruby): #{ruby}"
+ end
+
+ assert_equal(matzruby.gsub(/\r/, ''), ruby.gsub(/\r/, ''), str)
+
+ # store/load test
+ if false # || true
+ yarvasm = dump_and_exec($ruby, str)
+ assert_equal(ruby.gsub(/\r/, ''), yarvasm.gsub(/\r/, ''))
+ end
+ end
+
+ def test_
+ end
+end