def test_reset_state(): """ Test .reset_state() """ m = mock.Mock() p = Publisher() p.subscribe(Sink(m, 1)) m.assert_not_called() # test .reset_state() before and after subscribing p.reset_state() assert p.get() == NONE p.subscribe(Sink(m, 2)) m.assert_not_called() m.reset_mock() # test .reset_state() after notify p.notify('check') assert p.get() == 'check' m.assert_has_calls([mock.call(1, 'check'), mock.call(2, 'check')]) m.reset_mock() # test no subscribers get notified p.reset_state() m.assert_not_called() assert p.get() == NONE
def check_dependencies(operator, *_): publishers = operator.dependencies for p in publishers: assert p.subscriptions == () # operator should not be subscribed yet assert operator.subscriptions == () # subscribe to operator disposable1 = operator.subscribe(Sink()) assert p.subscriptions == (operator, ) # operator should now be subscriped assert operator.subscriptions == (disposable1.subscriber, ) # second subscribe to operator disposable2 = operator.subscribe(Sink(), prepend=True) assert p.subscriptions == (operator, ) assert operator.subscriptions == (disposable2.subscriber, disposable1.subscriber) # remove first subscriber disposable1.dispose() assert p.subscriptions == (operator, ) assert operator.subscriptions == (disposable2.subscriber, ) # remove second subscriber disposable2.dispose() assert p.subscriptions == () # operator should now be subscriped assert operator.subscriptions == ()
def check_subscription(operator, input_vector, output_vector): m = mock.Mock() publishers = operator.dependencies # subscribe operator to publisher disposable = operator.subscribe(Sink(m)) for p in publishers: assert p.subscriptions == (operator, ) # now it should be subscribed assert operator.dependencies == publishers # test emit on subscription if output_vector[0] is not NONE: m.assert_called_once_with(output_vector[0]) m.reset_mock() # test input_vector for input_value, output_value in zip(input_vector[1:], output_vector[1:]): for p, v in zip(publishers, input_value): if v is not NONE: p.notify(v) if output_value is NONE: m.assert_not_called() else: m.assert_called_with(output_value) m.reset_mock() # test input_vector with unsubscriptions between disposable.dispose() assert operator.dependencies == publishers for p, v in zip(publishers, input_vector[0]): p.notify(v) disposable = operator.subscribe(Sink(m)) for input_value, output_value in zip(input_vector, output_vector): m.reset_mock() for p, v in zip(publishers, input_value): if v is not NONE: p.notify(v) if output_value is NONE: m.assert_not_called() else: m.assert_called_with(output_value)
def test_operator_concat(): DUT = Concat(Map(lambda v: v / 2), Map(lambda v: v + 1)) mock_cb = mock.Mock() p = Publisher() o = p | DUT assert o.get() == NONE p.notify(0) assert o.get() == 1.0 o.subscribe(Sink(mock_cb)) for v in range(5): p.notify(v) mock_cb.assert_has_calls([ mock.call(1.0), mock.call(1.5), mock.call(2.0), mock.call(2.5), mock.call(3.0) ]) assert o.get() == 3.0
def test_emit_on(factory, flags): m = mock.Mock() publishers = [Publisher(None) for i in range(3)] emit_on = [p for p, f in zip(publishers, flags) if f] if len(emit_on) == 0: emit_on = None elif len(emit_on) == 1: emit_on = emit_on[0] operator = factory(*publishers, emit_on=emit_on) operator.subscribe(Sink(m)) result = [None] * 3 if flags.count(True) == 0: flags = [True] * 3 for i, f in enumerate(flags): m.reset_mock() result[i] = i publishers[i].notify(i) if f: m.assert_called_once_with(tuple(result)) else: m.assert_not_called()
def test_with_publisher(operator, l_value, r_value, result): vl = Value(l_value) vr = Value(r_value) cl = l_value cr = r_value o1 = operator(vl, vr) o2 = operator(vl, cr) o3 = operator(cl, vr) try: o4 = operator(cl, cr) except Exception as e: assert isinstance(e, result) o4 = result # to pass the following test mock_sink_o3 = mock.Mock() try: o3.subscribe(Sink(mock_sink_o3)) except Exception as e: assert isinstance(e, result) for output in (o1, o2, o3): assert isinstance(output, Publisher) assert o4 == result for output in (o1, o2, o3): try: assert output.get() == result except Exception as e: assert isinstance(e, result)
def test_notify(init, number_of_subscribers): """ Testing .notify(v) method """ p = Publisher(init) m = mock.Mock() # subscribing Sinks to the publisher and test .notify on subscribe subscribers = [Sink(m, i) for i in range(number_of_subscribers)] m.assert_not_called() for s in subscribers: p.subscribe(s) if init is not NONE: m.assert_has_calls([mock.call(i, init) for i in range(number_of_subscribers)]) else: m.assert_not_called() m.reset_mock() # test .notify() for listening subscribers p.notify(1) m.assert_has_calls([mock.call(i, 1) for i in range(number_of_subscribers)]) m.reset_mock() # re- .notify() with the same value p.notify(1) m.assert_has_calls([mock.call(i, 1) for i in range(number_of_subscribers)])
async def test_throttle_reset(event_loop): p = Publisher() mock_sink = mock.Mock() throttle = p | op.Throttle(0.1) disposable = throttle.subscribe(Sink(mock_sink)) p.notify(1) await asyncio.sleep(0.05, loop=event_loop) throttle.reset() p.notify(3) await asyncio.sleep(0.05, loop=event_loop) # reset is called after "1" was emitted mock_sink.assert_has_calls((mock.call(1), mock.call(3))) ## wait until initial state is set and reset mock await asyncio.sleep(0.1, loop=event_loop) mock_sink.reset_mock() p.notify(1) await asyncio.sleep(0.05, loop=event_loop) p.notify(2) throttle.reset() p.notify(3) await asyncio.sleep(0.05, loop=event_loop) # reset is called after "1" was emitted, and while "2" was hold back, # therefore "1" and "3" are emitted, but "2" is ignored mock_sink.assert_has_calls((mock.call(1), mock.call(3))) disposable.dispose()
async def test_throttle_errorhandler(event_loop): from broqer import default_error_handler p = Publisher() mock_sink = mock.Mock() mock_error_handler = mock.Mock() default_error_handler.set(mock_error_handler) throttle = p | op.Throttle(0.1) disposable = throttle.subscribe(Sink(mock_sink)) mock_sink.side_effect = (None, ZeroDivisionError('FAIL')) # test error_handler p.notify(1) await asyncio.sleep(0.05, loop=event_loop) mock_sink.assert_called_once_with(1) p.notify(2) await asyncio.sleep(0.1, loop=event_loop) mock_error_handler.assert_called_once_with(ZeroDivisionError, mock.ANY, mock.ANY) mock_sink.assert_has_calls((mock.call(1), mock.call(2))) mock_sink.reset_mock()
async def test_throttle_unsubscribe(event_loop): p = Publisher() mock_sink = mock.Mock() throttle = p | op.Throttle(0.1) disposable = throttle.subscribe(Sink(mock_sink)) # test subscription and unsubscribe p.notify(2) mock_sink.assert_called_once_with(2) await asyncio.sleep(0.05, loop=event_loop) mock_sink.reset_mock() disposable.dispose() await asyncio.sleep(0.1, loop=event_loop) # dispose must not emit anything mock_sink.assert_not_called() p.notify(3) await asyncio.sleep(0.1, loop=event_loop) # after dispose was called, p.notify must not emit to mock_sink mock_sink.assert_not_called()
def test_operator_with_publishers(): v1 = Value(0) v2 = Value(0) o = v1 + v2 assert isinstance(o, Publisher) assert isinstance(o, Subscriber) assert o.get() == 0 v1.emit(1) assert o.get() == 1 assert len(o.subscriptions) == 0 mock_sink = mock.Mock() o.subscribe(Sink(mock_sink)) assert len(o.subscriptions) == 1 mock_sink.assert_called_once_with(1) mock_sink.reset_mock() v2.emit(3) mock_sink.assert_called_once_with(4) with pytest.raises(ValueError): o.emit(0, who=Publisher()) with pytest.raises(ValueError): Value(1).subscribe(o)
def test_build(build_kwargs, init_args, init_kwargs, ref_args, ref_kwargs, exception): mock_cb = mock.Mock() ref_mock_cb = mock.Mock() reference = Sink(ref_mock_cb, *ref_args, **ref_kwargs) try: if build_kwargs is None: dut = build_sink_factory(mock_cb)(*init_args, **init_kwargs) else: dut = build_sink_factory(**build_kwargs)(mock_cb)(*init_args, **init_kwargs) except Exception as e: assert isinstance(e, exception) return else: assert exception is None assert dut._unpack == reference._unpack v = Publisher((1, 2)) v.subscribe(dut) v.subscribe(reference) assert mock_cb.mock_calls == ref_mock_cb.mock_calls assert len(mock_cb.mock_calls) == 1
def test_operator_with_constant_r(): v1 = 1 v2 = Value(0) o = v1 - v2 assert isinstance(o, Publisher) assert o.get() == 1 v2.emit(1) assert o.get() == 0 assert len(o.subscriptions) == 0 mock_sink = mock.Mock() o.subscribe(Sink(mock_sink)) assert len(o.subscriptions) == 1 mock_sink.assert_called_once_with(0) mock_sink.reset_mock() v2.emit(3) mock_sink.assert_called_once_with(-2) with pytest.raises(TypeError): Value(1) | o with pytest.raises(ValueError): o.emit(0, who=Publisher())
def test_getattr_attribute(): class Foo: a = None def __init__(self, a=5): self.a = a p = Publisher(Foo(3)) p.inherit_type(Foo) dut = p.a m = mock.Mock() dut.subscribe(Sink(m)) m.assert_called_once_with(3) assert dut.get() == 3 m.reset_mock() p.notify(Foo(4)) assert dut.get() == 4 m.assert_called_once_with(4) with pytest.raises(ValueError): dut.emit(0, who=Publisher()) with pytest.raises(AttributeError): dut.assnign(5)
def check_get_method(operator, input_vector, output_vector): input_value, output_value = input_vector[0], output_vector[0] p = Publisher() p.get = mock.MagicMock(return_value=input_value) o = p | operator with pytest.raises(ValueError): o.emit(input_value, who=None) assert o.get() == output_value disposable = o.subscribe(Sink()) if input_value is not NONE: o.emit(input_value, who=p) # simulate emit on subscribe p.get = None # .get should not be called when operator has a subscription assert o.get() == output_value # this should retrieve the internal state # after unsubscription it should remove the internal state and retrieve it # directly from orignator publisher via get disposable.dispose() p.get = mock.MagicMock(return_value=input_value) assert o.get() == output_value p.get.assert_called_once_with()
def check_subscription(operator, input_vector, output_vector): assert len(input_vector) == len(output_vector) m = mock.Mock() p = Publisher(input_vector[0]) o = p | operator o2 = Publisher() | operator # subscribe operator to publisher disposable = o.subscribe(Sink(m)) assert p.subscriptions == (o,) # now it should be subscribed assert o.dependencies == (p,) # test emit on subscription if output_vector[0] is not NONE: m.assert_called_once_with(output_vector[0]) m.reset_mock() # test input_vector for input_value, output_value in zip(input_vector[1:], output_vector[1:]): if input_value is not NONE: p.notify(input_value) if output_value is NONE: m.assert_not_called() else: m.assert_called_with(output_value) m.reset_mock() # test input_vector with unsubscriptions between disposable.dispose() assert o.dependencies == (p,) disposable = o.subscribe(Sink(m)) for input_value, output_value in zip(input_vector, output_vector): if input_value is not NONE: m.reset_mock() p.notify(input_value) if output_value is NONE: m.assert_not_called() else: m.assert_called_once_with(output_value)
def test_prepend(): """ Testing the prepend argument in .subscribe() """ m = mock.Mock() p = Publisher() s1 = Sink(m, 1) s2 = Sink(m, 2) s3 = Sink(m, 3) s4 = Sink(m, 4) p.subscribe(s1) p.subscribe(s2, prepend=True) # will be inserted before s1 p.subscribe(s3) # will be appended after s1 p.subscribe(s4, prepend=True) # will be inserted even before s2 p.notify('test') # notification order should now be: s4, s2, s1, s3 m.assert_has_calls([mock.call(4, 'test'), mock.call(2, 'test'), mock.call(1, 'test'), mock.call(3, 'test')])
def test_inherit_with_operators(): p = Publisher('') p.inherit_type(str) dut = op.Len(('abc' + p + 'ghi').upper()) m = mock.Mock() dut.subscribe(Sink(m)) m.assert_called_once_with(6) m.reset_mock() p.notify('def') m.assert_called_once_with(9)
def test_inherit_getattr(): p = Publisher('') p.inherit_type(str) dut = p.lower().split(' ') m = mock.Mock() dut.subscribe(Sink(m)) m.assert_called_once_with(['']) m.reset_mock() p.notify('This is a TEST') m.assert_called_once_with(['this', 'is', 'a', 'test'])
def check_dependencies(operator, *_): p = Publisher(NONE) assert len(p.subscriptions) == 0 o = p | operator assert p.subscriptions == () # operator should not be subscribed yet assert o.dependencies == (p,) assert o.subscriptions == () # subscribe to operator disposable1 = o.subscribe(Sink()) assert p.subscriptions == (o,) # operator should now be subscriped assert o.dependencies == (p,) assert o.subscriptions == (disposable1.subscriber,) # second subscribe to operator disposable2 = o.subscribe(Sink(), prepend=True) assert p.subscriptions == (o,) assert o.dependencies == (p,) assert o.subscriptions == (disposable2.subscriber, disposable1.subscriber) # remove first subscriber disposable1.dispose() assert p.subscriptions == (o,) assert o.dependencies == (p,) assert o.subscriptions == (disposable2.subscriber,) # remove second subscriber disposable2.dispose() assert p.subscriptions == () # operator should now be subscriped assert o.dependencies == (p,) assert o.subscriptions == ()
def test_getattr_method(): p = Publisher('') p.inherit_type(str) dut1 = p.split() dut2 = p.split(',') dut3 = p.split(sep='!') mock1 = mock.Mock() mock2 = mock.Mock() mock3 = mock.Mock() dut1.subscribe(Sink(mock1)) dut2.subscribe(Sink(mock2)) dut3.subscribe(Sink(mock3)) assert dut1.get() == [] assert dut2.get() == [''] assert dut3.get() == [''] mock1.assert_called_once_with([]) mock2.assert_called_once_with(['']) mock3.assert_called_once_with(['']) mock1.reset_mock() mock2.reset_mock() mock3.reset_mock() p.notify('This is just a test, honestly!') assert dut1.get() == ['This', 'is', 'just', 'a', 'test,', 'honestly!'] assert dut2.get() == ['This is just a test', ' honestly!'] assert dut3.get() == ['This is just a test, honestly', ''] mock1.assert_called_once_with( ['This', 'is', 'just', 'a', 'test,', 'honestly!']) mock2.assert_called_once_with(['This is just a test', ' honestly!']) mock3.assert_called_once_with(['This is just a test, honestly', ''])
def test_subscription_callback(): """ testing .register_on_subscription_callback() """ m = mock.Mock() p = Publisher() p.register_on_subscription_callback(m) # callback should be called on first subscription (with True as argument) d1 = p.subscribe(Sink()) m.assert_called_once_with(True) m.reset_mock() # it should not be called until the last subscriber is unsubscribing d2 = p.subscribe(Sink()) d1.dispose() m.assert_not_called() # callback should be called with False as argument on last unsubscription d2.dispose() m.assert_called_once_with(False) m.reset_mock() # callback should again be called with True as argument on first subscription d3 = p.subscribe(Sink()) m.assert_called_once_with(True) m.reset_mock() # after reseting callback it should no be called again p.register_on_subscription_callback(None) d3.dispose() p.subscribe(Sink()) m.assert_not_called() # check if callback is called when subscriber is already available p.register_on_subscription_callback(m) m.assert_called_once_with(True)
async def test_throttle(event_loop, emit_sequence, expected_emits): p = Publisher() mock_sink = mock.Mock() throttle = p | op.Throttle(0.5) disposable = throttle.subscribe(Sink(mock_sink)) mock_sink.assert_not_called() for item in emit_sequence: await asyncio.sleep(item[0], loop=event_loop) p.notify(item[1]) await asyncio.sleep(0.5, loop=event_loop) mock_sink.assert_has_calls(expected_emits)
async def test_subscribe(event_loop): poll_mock = mock.Mock(return_value=3) sink_mock = mock.Mock() p = PollPublisher(poll_mock, 1) await asyncio.sleep(1, loop=event_loop) assert p.get() is NONE p.subscribe(Sink(sink_mock)) sink_mock.assert_called_once_with(3) poll_mock.assert_called_once() await asyncio.sleep(2.5, loop=event_loop) sink_mock.assert_called_with(3) assert sink_mock.call_count == 3
def test_unsubscibe(subscribe): m = mock.Mock() p1, p2 = Publisher(NONE), Publisher(NONE) operator = op.CombineLatest(p1, p2) if subscribe: operator.subscribe(Sink()) assert operator.get() == NONE p1.notify(1) assert operator.get() == NONE p2.notify(2) assert operator.get() == (1, 2)
def test_unary_operators(operator, value, result): v = Publisher(value) try: value_applied = operator(v).get() except Exception as e: assert isinstance(e, result) else: assert value_applied == result cb = mock.Mock() try: operator(v).subscribe(Sink(cb)) except Exception as e: assert isinstance(e, result) else: assert cb.mock_called_once_with(result) with pytest.raises(TypeError): Value(1) | operator(v) with pytest.raises(ValueError): operator(v).emit(0, who=Publisher())
def check_get_method(operator, input_vector, output_vector): input_value, output_value = input_vector[0], output_vector[0] publishers = operator.dependencies for p, v in zip(publishers, input_value): p.get = mock.MagicMock(return_value=v) with pytest.raises(ValueError): operator.emit(input_value[0], who=None) assert operator.get() == output_value disposable = operator.subscribe(Sink()) for p, v in zip(publishers, input_value): if v is not NONE: operator.emit(v, who=p) # simulate emit on subscribe for p, v in zip(publishers, input_value): p.get = None # .get should not be called when operator has a subscription assert operator.get( ) == output_value # this should retrieve the internal state # after unsubscription it should remove the internal state and retrieve it # directly from orignator publisher via get disposable.dispose() for p, v in zip(publishers, input_value): p.get = mock.MagicMock(return_value=v) assert operator.get() == output_value for p in publishers: p.get.assert_called_once_with()
def test_bitwise_uninitialized_publishers(): m = Mock() p = Publisher() b = BitwiseCombineLatest({p: 0}) b.subscribe(Sink(m)) m.assert_called_once_with(0)