1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
require 'em_test_helper'
class TestFutures < Test::Unit::TestCase
def setup
end
def teardown
end
def test_future
assert_equal(100, EM::Deferrable.future(100) )
p1 = proc { 100 + 1 }
assert_equal(101, EM::Deferrable.future(p1) )
end
class MyFuture
include EM::Deferrable
def initialize *args
super
set_deferred_status :succeeded, 40
end
end
class MyErrorFuture
include EM::Deferrable
def initialize *args
super
set_deferred_status :failed, 41
end
end
def test_future_1
# Call future with one additional argument and it will be treated as a callback.
def my_future
MyFuture.new
end
value = nil
EM::Deferrable.future my_future, proc {|v| value=v}
assert_equal( 40, value )
end
def test_future_2
# Call future with two additional arguments and they will be treated as a callback
# and an errback.
value = nil
EM::Deferrable.future MyErrorFuture.new, nil, proc {|v| value=v}
assert_equal( 41, value )
end
def test_future_3
# Call future with no additional arguments but with a block, and the block will be
# treated as a callback.
value = nil
EM::Deferrable.future MyFuture.new do |v|
value=v
end
assert_equal( 40, value )
end
class RecursiveCallback
include EM::Deferrable
end
# A Deferrable callback can call #set_deferred_status to change the values
# passed to subsequent callbacks.
#
def test_recursive_callbacks
n = 0 # counter assures that all the tests actually run.
rc = RecursiveCallback.new
rc.callback {|a|
assert_equal(100, a)
n += 1
rc.set_deferred_status :succeeded, 101, 101
}
rc.callback {|a,b|
assert_equal(101, a)
assert_equal(101, b)
n += 1
rc.set_deferred_status :succeeded, 102, 102, 102
}
rc.callback {|a,b,c|
assert_equal(102, a)
assert_equal(102, b)
assert_equal(102, c)
n += 1
}
rc.set_deferred_status :succeeded, 100
assert_equal(3, n)
end
def test_syntactic_sugar
rc = RecursiveCallback.new
rc.set_deferred_success 100
rc.set_deferred_failure 200
end
# It doesn't raise an error to set deferred status more than once.
# In fact, this is a desired and useful idiom when it happens INSIDE
# a callback or errback.
# However, it's less useful otherwise, and in fact would generally be
# indicative of a programming error. However, we would like to be resistant
# to such errors. So whenever we set deferred status, we also clear BOTH
# stacks of handlers.
#
def test_double_calls
s = 0
e = 0
d = EM::DefaultDeferrable.new
d.callback {s += 1}
d.errback {e += 1}
d.succeed # We expect the callback to be called, and the errback to be DISCARDED.
d.fail # Presumably an error. We expect the errback NOT to be called.
d.succeed # We expect the callback to have been discarded and NOT to be called again.
assert_equal(1, s)
assert_equal(0, e)
end
# Adding a callback to a Deferrable that is already in a success state executes the callback
# immediately. The same applies to a an errback added to an already-failed Deferrable.
# HOWEVER, we expect NOT to be able to add errbacks to succeeded Deferrables, or callbacks
# to failed ones.
#
# We illustrate this with a rather contrived test. The test calls #fail after #succeed,
# which ordinarily would not happen in a real program.
#
# What we're NOT attempting to specify is what happens if a Deferrable is succeeded and then
# failed (or vice-versa). Should we then be able to add callbacks/errbacks of the appropriate
# type for immediate execution? For now at least, the official answer is "don't do that."
#
def test_delayed_callbacks
s1 = 0
s2 = 0
e = 0
d = EM::DefaultDeferrable.new
d.callback {s1 += 1}
d.succeed # Triggers and discards the callback.
d.callback {s2 += 1} # This callback is executed immediately and discarded.
d.errback {e += 1} # This errback should be DISCARDED and never execute.
d.fail # To prove it, fail and assert e is 0
assert_equal( [1,1], [s1,s2] )
assert_equal( 0, e )
end
def test_timeout
n = 0
EM.run {
d = EM::DefaultDeferrable.new
d.callback {n = 1; EM.stop}
d.errback {n = 2; EM.stop}
d.timeout(0.01)
}
assert_equal( 2, n )
end
end
|