1# frozen_string_literal: false
2require 'test/unit'
3EnvUtil.suppress_warning {require 'continuation'}
4require 'fiber'
5
6class TestContinuation < Test::Unit::TestCase
7  def test_create
8    assert_equal(:ok, callcc{:ok})
9    assert_equal(:ok, callcc{|c| c.call :ok})
10  end
11
12  def test_call
13    assert_equal(:ok, callcc{|c| c.call :ok})
14
15    ary = []
16    ary << callcc{|c|
17      @cont = c
18      :a
19    }
20    @cont.call :b if ary.length < 3
21    assert_equal([:a, :b, :b], ary)
22  end
23
24  def test_check_localvars
25    vv = 0
26    @v = 0
27    @ary = []
28    [1, 2, 3].each{|i|
29      callcc {|k| @k = k}
30      @v += 1
31      vv += 1
32    }
33    @ary << [vv, @v]
34    @k.call if @v < 10
35    assert_equal((3..10).map{|e| [e, e]}, @ary)
36  end
37
38  def test_error
39    cont = callcc{|c| c}
40    Thread.new{
41      assert_raise(RuntimeError){
42        cont.call
43      }
44    }.join
45    assert_raise(LocalJumpError){
46      callcc
47    }
48    assert_raise(RuntimeError){
49      c = nil
50      Fiber.new do
51        callcc {|c2| c = c2 }
52      end.resume
53      c.call
54    }
55  end
56
57  def test_ary_flatten
58    assert_normal_exit %q{
59      require 'continuation'
60      n = 0
61      o = Object.new
62      def o.to_ary() callcc {|k| $k = k; [1,2,3]} end
63      [10,20,o,30,o,40].flatten.inspect
64      n += 1
65      $k.call if n < 100
66    }, '[ruby-dev:34798]'
67  end
68
69  def test_marshal_dump
70    assert_normal_exit %q{
71      require 'continuation'
72      n = 0
73      o = Object.new
74      def o.marshal_dump() callcc {|k| $k = k };  "fofof" end
75      a = [1,2,3,o,4,5,6]
76      Marshal.dump(a).inspect
77      n += 1
78      $k.call if n < 100
79    }, '[ruby-dev:34802]'
80  end
81
82  def tracing_with_set_trace_func
83    orig_thread = Thread.current
84    cont = nil
85    func = lambda do |*args|
86      if orig_thread == Thread.current
87        if cont
88          @memo += 1
89          c = cont
90          cont = nil
91          begin
92            c.call(nil)
93          rescue RuntimeError
94            set_trace_func(nil)
95          end
96        end
97      end
98    end
99    cont = callcc { |cc| cc }
100
101    if cont
102      set_trace_func(func)
103    else
104      set_trace_func(nil)
105    end
106  end
107
108  def _test_tracing_with_set_trace_func
109    @memo = 0
110    tracing_with_set_trace_func
111    tracing_with_set_trace_func
112    tracing_with_set_trace_func
113    assert_equal 0, @memo
114  end
115
116  def tracing_with_thread_set_trace_func
117    cont = nil
118    func = lambda do |*args|
119      if cont
120        @memo += 1
121        c = cont
122        cont = nil
123        begin
124          c.call(nil)
125        rescue RuntimeError
126          Thread.current.set_trace_func(nil)
127        end
128      end
129    end
130    cont = callcc { |cc| cc }
131    if cont
132      Thread.current.set_trace_func(func)
133    else
134      Thread.current.set_trace_func(nil)
135    end
136  end
137
138  def test_tracing_with_thread_set_trace_func
139    @memo = 0
140    tracing_with_thread_set_trace_func
141    tracing_with_thread_set_trace_func
142    tracing_with_thread_set_trace_func
143    assert_equal 3, @memo
144  end
145end
146