11require "test_helper"
22
33class TCOMethodTest < TCOMethod ::TestCase
4- include TCOMethod ::TestHelpers ::FactorialStackBusterHelper
4+ include TCOMethod ::TestHelpers ::Assertions
55
66 Subject = TCOMethod
77
@@ -14,26 +14,34 @@ class << self
1414
1515 # Equivalent to the below, but provides a target for verifying that
1616 # tco_module_method works on Classes and tco_class_method works on Modules.
17- def self . module_factorial ( n , acc = 1 )
18- n <= 1 ? acc : module_factorial ( n - 1 , n * acc )
17+ def self . module_fib_yielder ( index , back_one = 1 , back_two = 0 , &block )
18+ yield back_two if index > 0
19+ index < 1 ? back_two : module_fib_yielder ( index - 1 , back_one + back_two , back_one , &block )
1920 end
2021
2122 # Equivalent to the above, but provides a target for verifying that
2223 # tco_module_method works on Classes and tco_class_method works on Modules.
23- def self . class_factorial ( n , acc = 1 )
24- n <= 1 ? acc : class_factorial ( n - 1 , n * acc )
24+ def self . class_fib_yielder ( index , back_one = 1 , back_two = 0 , &block )
25+ yield back_two if index > 0
26+ index < 1 ? back_two : class_fib_yielder ( index - 1 , back_one + back_two , back_one , &block )
2527 end
2628
2729 define_method ( :instance_block_method ) { }
2830
29- def instance_factorial ( n , acc = 1 )
30- n <= 1 ? acc : instance_factorial ( n - 1 , n * acc )
31+ # Equivalent to the above, but provides a target for verifying that
32+ # instance methods work for both Classes and Modules
33+ def instance_fib_yielder ( index , back_one = 1 , back_two = 0 , &block )
34+ yield back_two if index > 0
35+ index < 1 ? back_two : instance_fib_yielder ( index - 1 , back_one + back_two , back_one , &block )
3136 end
3237 end
3338
3439 TestModule = Module . new ( &test_subject_builder )
3540 TestClass = Class . new ( &test_subject_builder )
3641
42+ # Grab source before it's recompiled for use later
43+ InstanceFibYielderSource = TestClass . instance_method ( :instance_fib_yielder ) . source
44+
3745 subject { Subject }
3846
3947 context Subject . name do
@@ -57,21 +65,15 @@ def instance_factorial(n, acc = 1)
5765 end
5866
5967 should "compile the given code with tail call optimization" do
60- FactorialEvalDummy = dummy_class = Class . new
68+ EvalDummy = dummy_class = Class . new
6169 subject . tco_eval ( <<-CODE )
6270 class #{ dummy_class . name }
63- def factorial(n, acc = 1)
64- n <= 1 ? acc : factorial(n - 1, n * acc)
65- end
71+ #{ InstanceFibYielderSource }
6672 end
6773 CODE
6874
69- # Exceed maximum available stack depth by 100 for good measure
70- factorial_seed = factorial_stack_buster_stack_depth_remaining + 100
71- assert_unoptimized_factorial_stack_overflow ( factorial_seed )
72-
73- expected_result = iterative_factorial ( factorial_seed )
74- assert_equal expected_result , dummy_class . new . factorial ( factorial_seed )
75+ fib_yielder = dummy_class . new . method ( :instance_fib_yielder )
76+ assert tail_call_optimized? ( fib_yielder , 5 )
7577 end
7678 end
7779
@@ -119,15 +121,12 @@ def factorial(n, acc = 1)
119121 end
120122
121123 should "re-compile the given method with tail call optimization" do
122- # Exceed maximum available stack depth by 100 for good measure
123- factorial_seed = factorial_stack_buster_stack_depth_remaining + 100
124- assert_raises ( SystemStackError ) do
125- method_owner . module_factorial ( factorial_seed )
126- end
124+ fib_yielder = method_owner . method ( :module_fib_yielder )
125+ refute tail_call_optimized? ( fib_yielder , 5 )
127126
128- subject . call ( method_owner , :module_factorial , :module )
129- expected_result = iterative_factorial ( factorial_seed )
130- assert_equal expected_result , method_owner . module_factorial ( factorial_seed )
127+ subject . call ( method_owner , :module_fib_yielder , :module )
128+ fib_yielder = method_owner . method ( :module_fib_yielder )
129+ assert tail_call_optimized? ( fib_yielder , 5 )
131130 end
132131 end
133132
@@ -139,15 +138,12 @@ def factorial(n, acc = 1)
139138 end
140139
141140 should "re-compile the given method with tail call optimization" do
142- # Exceed maximum available stack depth by 100 for good measure
143- factorial_seed = factorial_stack_buster_stack_depth_remaining + 100
144- assert_raises ( SystemStackError ) do
145- method_owner . class_factorial ( factorial_seed )
146- end
141+ fib_yielder = method_owner . method ( :class_fib_yielder )
142+ refute tail_call_optimized? ( fib_yielder , 5 )
147143
148- subject . call ( method_owner , :class_factorial , method_owner_class )
149- expected_result = iterative_factorial ( factorial_seed )
150- assert_equal expected_result , method_owner . class_factorial ( factorial_seed )
144+ subject . call ( method_owner , :class_fib_yielder , :module )
145+ fib_yielder = method_owner . method ( :class_fib_yielder )
146+ assert tail_call_optimized? ( fib_yielder , 5 )
151147 end
152148 end
153149
@@ -159,16 +155,14 @@ def factorial(n, acc = 1)
159155 end
160156
161157 should "re-compile the given method with tail call optimization" do
162- # Exceed maximum available stack depth by 100 for good measure
163- factorial_seed = factorial_stack_buster_stack_depth_remaining + 100
164158 instance_class = instance_class_for_receiver ( method_owner )
165- assert_raises ( SystemStackError ) do
166- instance_class . new . instance_factorial ( factorial_seed )
167- end
168159
169- subject . call ( method_owner , :instance_factorial , :instance )
170- expected_result = iterative_factorial ( factorial_seed )
171- assert_equal expected_result , instance_class . new . instance_factorial ( factorial_seed )
160+ fib_yielder = instance_class . new . method ( :instance_fib_yielder )
161+ refute tail_call_optimized? ( fib_yielder , 5 )
162+
163+ subject . call ( method_owner , :instance_fib_yielder , :instance )
164+ fib_yielder = instance_class . new . method ( :instance_fib_yielder )
165+ assert tail_call_optimized? ( fib_yielder , 5 )
172166 end
173167 end
174168 end
0 commit comments