171 lines
4.5 KiB
Ruby
171 lines
4.5 KiB
Ruby
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
|