def test_works_for_common_use_case_with_success(self): s1 = AdHocSignal() s2 = AdHocSignal() fut = first_signal(s1, s2) self.assertFalse(fut.done()) s1() self.assertTrue(fut.done()) self.assertIsNone(fut.result())
def test_works_for_common_use_case_with_exception(self): exc = Exception() s1 = AdHocSignal() s2 = AdHocSignal() fut = first_signal(s1, s2) self.assertFalse(fut.done()) s2(exc) self.assertTrue(fut.done()) self.assertIs(fut.exception(), exc)
def test_future(self): signal = AdHocSignal() with contextlib.ExitStack() as stack: Future = stack.enter_context( unittest.mock.patch("asyncio.Future") ) connect = stack.enter_context( unittest.mock.patch.object( signal, "connect" ) ) fut = signal.future() self.assertSequenceEqual( Future.mock_calls, [ unittest.mock.call.Future() ] ) self.assertSequenceEqual( connect.mock_calls, [ unittest.mock.call( Future(), signal.AUTO_FUTURE, ), ] ) self.assertEqual(fut, Future())
def test_connect_does_not_use_weakref(self): signal = AdHocSignal() with unittest.mock.patch("weakref.ref") as ref: fun = unittest.mock.MagicMock() signal.connect(fun) self.assertFalse(ref.mock_calls)
def test_connect_weak_uses_weakref(self): signal = AdHocSignal() with unittest.mock.patch("weakref.ref") as ref: fun = unittest.mock.MagicMock() signal.connect(fun, AdHocSignal.WEAK) ref.assert_called_once_with(fun)
def test_remove_by_token(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None token = signal.connect(fun) signal() self.assertSequenceEqual([ unittest.mock.call(), ], fun.mock_calls) signal() self.assertSequenceEqual([ unittest.mock.call(), unittest.mock.call(), ], fun.mock_calls) signal.disconnect(token) signal() self.assertSequenceEqual([ unittest.mock.call(), unittest.mock.call(), ], fun.mock_calls)
def test_remove_callback_on_true_result(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = True signal.connect(fun) signal() self.assertSequenceEqual( [ unittest.mock.call(), ], fun.mock_calls ) signal() self.assertSequenceEqual( [ unittest.mock.call(), ], fun.mock_calls )
def test_connect_spawn_emits_always(self): signal = AdHocSignal() mock = CoroutineMock() async def coro(*args, **kwargs): await mock(*args, **kwargs) signal.connect(coro, AdHocSignal.SPAWN_WITH_LOOP(None)) signal.fire("a", 1, b="c") signal.fire("x") self.assertSequenceEqual(mock.mock_calls, []) run_coroutine(asyncio.sleep(0)) run_coroutine(asyncio.sleep(0)) self.assertSequenceEqual( mock.mock_calls, [ unittest.mock.call("a", 1, b="c"), unittest.mock.call("x"), ] )
def test_SPAWN_rejects_non_coroutine(self): def fun(): pass signal = AdHocSignal() with self.assertRaisesRegex(TypeError, "must be coroutine"): signal.SPAWN_WITH_LOOP(None)(fun)
def test_fire_with_arguments(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() signal.connect(fun) signal("a", 1, foo=None) fun.assert_called_once_with("a", 1, foo=None)
def test_disconnect_is_idempotent(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None token = signal.connect(fun) signal.disconnect(token) signal.disconnect(token)
def test_logger_on_connect(self): logger = unittest.mock.Mock() signal = AdHocSignal() signal.logger = logger a = unittest.mock.Mock() signal.connect(a) logger.debug.assert_called_with("connecting %r with mode %r", a, signal.STRONG)
def test_connect_and_call(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None signal.connect(fun) signal() fun.assert_called_once_with()
def test_fire_removes_stale_references(self, ref): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None ref().return_value = None signal.connect(fun, AdHocSignal.WEAK) signal.fire() self.assertFalse(signal._connections)
def test_connect_weak_uses_WeakMethod_for_methods(self): signal = AdHocSignal() class Foo: def meth(self): return None f = Foo() with unittest.mock.patch("weakref.WeakMethod") as ref: signal.connect(f.meth, AdHocSignal.WEAK) ref.assert_called_once_with(f.meth)
def test_connect_async(self): signal = AdHocSignal() mock = unittest.mock.MagicMock() fun = functools.partial(mock) signal.connect(fun, AdHocSignal.ASYNC_WITH_LOOP(None)) signal.fire() mock.assert_not_called() run_coroutine(asyncio.sleep(0)) mock.assert_called_once_with()
def test_logger_on_emit_with_exception(self): logger = unittest.mock.Mock() signal = AdHocSignal() signal.logger = logger a = unittest.mock.Mock() signal.connect(a) a.side_effect = Exception() signal() logger.exception.assert_called_with( "listener attached to signal raised")
def test_connect_auto_future_uses_set_result_with_None(self): signal = AdHocSignal() fut = unittest.mock.Mock() fut.done.return_value = False signal.connect(fut, AdHocSignal.AUTO_FUTURE) signal() signal() self.assertSequenceEqual( [unittest.mock.call.done(), unittest.mock.call.set_result(None)], fut.mock_calls)
def test_connect_and_fire(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None signal.connect(fun) signal.fire() signal.fire() self.assertSequenceEqual([ unittest.mock.call(), unittest.mock.call(), ], fun.mock_calls)
def test_connect_skips_if_future_is_done(self): signal = AdHocSignal() obj = ValueError() fut = unittest.mock.Mock() fut.done.return_value = True signal.connect(fut, AdHocSignal.AUTO_FUTURE) signal("foo") signal(obj) self.assertSequenceEqual([ unittest.mock.call.done(), ], fut.mock_calls)
def test_connect_auto_future_converts_exceptions(self): signal = AdHocSignal() obj = ValueError() fut = unittest.mock.Mock() fut.done.return_value = False signal.connect(fut, AdHocSignal.AUTO_FUTURE) signal(obj) signal(obj) self.assertSequenceEqual( [unittest.mock.call.done(), unittest.mock.call.set_exception(obj)], fut.mock_calls)
def test_full_isolation(self): signal = AdHocSignal() base = unittest.mock.Mock() base.a.return_value = None base.a.side_effect = OSError() base.b.return_value = None base.b.side_effect = Exception() base.c.return_value = None base.d.return_value = None base.d.side_effect = ValueError() signal.connect(base.a) signal.connect(base.b) signal.connect(base.c) signal.connect(base.d) signal() self.assertSequenceEqual( base.mock_calls, [ unittest.mock.call.a(), unittest.mock.call.b(), unittest.mock.call.c(), unittest.mock.call.d(), ] ) signal() self.assertSequenceEqual( base.mock_calls, [ unittest.mock.call.a(), unittest.mock.call.b(), unittest.mock.call.c(), unittest.mock.call.d(), unittest.mock.call.c(), ] )
def test_context_connect_forwards_exceptions_and_disconnects(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None exc = ValueError() with self.assertRaises(ValueError) as ctx: with signal.context_connect(fun): signal("foo") raise exc signal("bar") self.assertIs(exc, ctx.exception) self.assertSequenceEqual([ unittest.mock.call("foo"), ], fun.mock_calls)
def test_context_connect(self): signal = AdHocSignal() fun = unittest.mock.MagicMock() fun.return_value = None with signal.context_connect(fun): signal("foo") signal("bar") with signal.context_connect(fun) as token: signal("baz") signal.disconnect(token) signal("fnord") self.assertSequenceEqual([ unittest.mock.call("foo"), unittest.mock.call("baz"), ], fun.mock_calls)
def test_connect_spawn(self): signal = AdHocSignal() mock = CoroutineMock() @asyncio.coroutine def coro(*args, **kwargs): yield from mock(*args, **kwargs) signal.connect(coro, AdHocSignal.SPAWN_WITH_LOOP(None)) signal.fire("a", 1, b="c") self.assertSequenceEqual(mock.mock_calls, []) run_coroutine(asyncio.sleep(0)) self.assertSequenceEqual(mock.mock_calls, [unittest.mock.call("a", 1, b="c")])
def test_WEAK_rejects_non_callable(self): signal = AdHocSignal() with self.assertRaisesRegex(TypeError, "must be callable"): signal.WEAK(object())
def test_ASYNC_WITH_LOOP_rejects_non_callable(self): signal = AdHocSignal() with self.assertRaisesRegex(TypeError, "must be callable"): signal.ASYNC_WITH_LOOP(asyncio.get_event_loop())(object())