rf-web/vendor/bundle/gems/eventmachine-1.2.7/tests/test_futures.rb
2019-10-21 10:18:17 +02:00

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