Exemple #1
0
def test_consume_verify_rehearsals_ignore_extra_args() -> None:
    """It should be able to pop a slice off the stack, retaining order."""
    subject = SpyLog()
    call_1 = SpyEvent(spy_id=1,
                      spy_name="spy_1",
                      payload=SpyCall(args=(), kwargs={}))
    call_2 = SpyEvent(spy_id=2,
                      spy_name="spy_2",
                      payload=SpyCall(args=(), kwargs={}))

    subject.push(call_1)
    subject.push(call_2)

    result = subject.consume_verify_rehearsals(count=2, ignore_extra_args=True)
    assert result == [
        VerifyRehearsal(
            spy_id=1,
            spy_name="spy_1",
            payload=SpyCall(args=(), kwargs={}, ignore_extra_args=True),
        ),
        VerifyRehearsal(
            spy_id=2,
            spy_name="spy_2",
            payload=SpyCall(args=(), kwargs={}, ignore_extra_args=True),
        ),
    ]
Exemple #2
0
def test_verify(
    decoy: Decoy,
    spy_log: SpyLog,
    verifier: Verifier,
    subject: DecoyCore,
) -> None:
    """It should be able to verify a call."""
    spy_id = 42
    rehearsal = VerifyRehearsal(spy_id=spy_id,
                                spy_name="my_spy",
                                payload=SpyCall(args=(), kwargs={}))
    call = SpyEvent(spy_id=spy_id,
                    spy_name="my_spy",
                    payload=SpyCall(args=(), kwargs={}))

    decoy.when(
        spy_log.consume_verify_rehearsals(
            count=1, ignore_extra_args=False)).then_return([rehearsal])

    decoy.when(spy_log.get_calls_to_verify([spy_id])).then_return([call])

    subject.verify("__rehearsal__", times=None, ignore_extra_args=False)

    decoy.verify(
        verifier.verify(rehearsals=[rehearsal], calls=[call], times=None))
Exemple #3
0
def test_get_by_call() -> None:
    """It should be able to add a StubBehavior to the store and get it back."""
    subject = StubStore()
    rehearsal = WhenRehearsal(spy_id=42,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    behavior = StubBehavior(return_value="hello world")

    subject.add(rehearsal=rehearsal, behavior=behavior)
    result = subject.get_by_call(call=SpyEvent(
        spy_id=42, spy_name="my_spy", payload=SpyCall(args=(), kwargs={})))

    assert result == behavior
Exemple #4
0
def test_consume_verify_rehearsals_ignores_prop_gets() -> None:
    """It should be able to pop a slice off the stack, retaining order."""
    subject = SpyLog()
    call_1 = SpyEvent(spy_id=101,
                      spy_name="spy_1",
                      payload=SpyCall(args=(1, ), kwargs={}))
    call_2 = SpyEvent(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyPropAccess(prop_name="child",
                              access_type=PropAccessType.GET),
    )
    call_3 = SpyEvent(
        spy_id=102,
        spy_name="spy_1.child",
        payload=SpyCall(args=(2, ), kwargs={}),
    )
    call_4 = SpyEvent(
        spy_id=102,
        spy_name="spy_1.child",
        payload=SpyPropAccess(prop_name="fizz",
                              access_type=PropAccessType.DELETE),
    )
    subject.push(call_1)
    subject.push(call_2)
    subject.push(call_3)
    subject.push(call_4)

    result = subject.consume_verify_rehearsals(count=3,
                                               ignore_extra_args=False)
    assert result == [
        VerifyRehearsal(
            spy_id=101,
            spy_name="spy_1",
            payload=SpyCall(args=(1, ), kwargs={}),
        ),
        VerifyRehearsal(
            spy_id=102,
            spy_name="spy_1.child",
            payload=SpyCall(args=(2, ), kwargs={}),
        ),
        VerifyRehearsal(
            spy_id=102,
            spy_name="spy_1.child",
            payload=SpyPropAccess(prop_name="fizz",
                                  access_type=PropAccessType.DELETE),
        ),
    ]
Exemple #5
0
def test_when_then_return_multiple_values(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: DecoyCore,
) -> None:
    """It should add multiple return values to a stub."""
    rehearsal = WhenRehearsal(spy_id=1,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    decoy.when(spy_log.consume_when_rehearsal(
        ignore_extra_args=False)).then_return(rehearsal)

    result = subject.when(0, ignore_extra_args=False)
    result.then_return(42, 43, 44)

    decoy.verify(
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(return_value=44, once=False),
        ),
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(return_value=43, once=True),
        ),
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(return_value=42, once=True),
        ),
    )
Exemple #6
0
def test_spy_calls(
    decoy: Decoy,
    call_handler: CallHandler,
    spy_creator: SpyCreator,
    spec: Spec,
) -> None:
    """It should send any calls to the call handler."""
    subject = Spy(spec=spec,
                  call_handler=call_handler,
                  spy_creator=spy_creator)

    decoy.when(spec.get_name()).then_return("spy_name")
    decoy.when(spec.bind_args(1, 2, three=3)).then_return(
        BoundArgs(args=(1, 2, 3), kwargs={}))
    decoy.when(
        call_handler.handle(
            SpyEvent(
                spy_id=id(subject),
                spy_name="spy_name",
                payload=SpyCall(args=(1, 2, 3), kwargs={}),
            ))).then_return(CallHandlerResult(42))

    result = subject(1, 2, three=3)

    assert result == 42
Exemple #7
0
def test_get_by_call_empty() -> None:
    """It should return None if store is empty."""
    subject = StubStore()
    result = subject.get_by_call(call=SpyEvent(
        spy_id=42, spy_name="my_spy", payload=SpyCall(args=(), kwargs={})))

    assert result is None
Exemple #8
0
def test_get_calls_to_verify_skips_prop_gets() -> None:
    """It does not return prop getters for verification."""
    subject = SpyLog()

    call_1 = SpyEvent(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyPropAccess(prop_name="child",
                              access_type=PropAccessType.GET),
    )
    call_2 = PropRehearsal(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyPropAccess(prop_name="child",
                              access_type=PropAccessType.GET),
    )
    call_3 = SpyEvent(
        spy_id=102,
        spy_name="spy_1.child",
        payload=SpyCall(args=(2, ), kwargs={}),
    )
    call_4 = SpyEvent(
        spy_id=102,
        spy_name="spy_1.child",
        payload=SpyPropAccess(prop_name="fizz",
                              access_type=PropAccessType.DELETE),
    )

    subject.push(call_1)
    subject.push(call_2)
    subject.push(call_3)
    subject.push(call_4)
    result = subject.get_calls_to_verify([101, 102])
    assert result == [call_3, call_4]
Exemple #9
0
def test_clear() -> None:
    """It should consume any behavior marked with the `once` flag."""
    subject = StubStore()
    call = SpyEvent(spy_id=42,
                    spy_name="my_spy",
                    payload=SpyCall(args=(), kwargs={}))
    rehearsal = WhenRehearsal(spy_id=42,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    behavior = StubBehavior(return_value="fizzbuzz")

    subject.add(rehearsal=rehearsal, behavior=behavior)
    subject.clear()

    result = subject.get_by_call(call=call)

    assert result is None
Exemple #10
0
def test_get_by_call_prefers_latest() -> None:
    """It should be prefer later stubs if multiple exist."""
    subject = StubStore()
    rehearsal_1 = WhenRehearsal(spy_id=42,
                                spy_name="my_spy",
                                payload=SpyCall(args=(), kwargs={}))
    behavior_1 = StubBehavior(return_value="hello")
    rehearsal_2 = WhenRehearsal(spy_id=42,
                                spy_name="my_spy",
                                payload=SpyCall(args=(), kwargs={}))
    behavior_2 = StubBehavior(return_value="goodbye")

    subject.add(rehearsal=rehearsal_1, behavior=behavior_1)
    subject.add(rehearsal=rehearsal_2, behavior=behavior_2)
    result = subject.get_by_call(call=SpyEvent(
        spy_id=42, spy_name="my_spy", payload=SpyCall(args=(), kwargs={})))

    assert result == behavior_2
Exemple #11
0
def test_consume_verify_rehearsals_raises_error() -> None:
    """It should raise an error if the stack has too few members to pop a slice."""
    subject = SpyLog()
    call_1 = SpyEvent(spy_id=1,
                      spy_name="spy_1",
                      payload=SpyCall(args=(), kwargs={}))

    subject.push(call_1)

    with pytest.raises(MissingRehearsalError):
        subject.consume_verify_rehearsals(count=2, ignore_extra_args=False)
Exemple #12
0
def test_clear() -> None:
    """It can clear all calls and rehearsals."""
    subject = SpyLog()
    call_1 = SpyEvent(spy_id=101,
                      spy_name="spy_1",
                      payload=SpyCall(args=(), kwargs={}))
    call_2 = SpyEvent(spy_id=101,
                      spy_name="spy_1",
                      payload=SpyCall(args=(), kwargs={}))
    call_3 = SpyEvent(spy_id=202,
                      spy_name="spy_2",
                      payload=SpyCall(args=(), kwargs={}))

    subject.push(call_1)
    subject.consume_when_rehearsal(ignore_extra_args=False)
    subject.push(call_2)
    subject.push(call_3)
    subject.consume_when_rehearsal(ignore_extra_args=False)
    subject.clear()

    assert subject.get_all() == []
Exemple #13
0
def test_verify_multiple_calls(
    decoy: Decoy,
    spy_log: SpyLog,
    verifier: Verifier,
    subject: DecoyCore,
) -> None:
    """It should be able to verify a call."""
    spy_id_1 = 42
    spy_id_2 = 9001

    rehearsals = [
        VerifyRehearsal(spy_id=spy_id_1,
                        spy_name="spy_1",
                        payload=SpyCall(args=(), kwargs={})),
        VerifyRehearsal(spy_id=spy_id_2,
                        spy_name="spy_2",
                        payload=SpyCall(args=(), kwargs={})),
    ]
    calls = [
        SpyEvent(spy_id=spy_id_1,
                 spy_name="spy_1",
                 payload=SpyCall(args=(), kwargs={}))
    ]

    decoy.when(
        spy_log.consume_verify_rehearsals(
            count=2, ignore_extra_args=False)).then_return(rehearsals)
    decoy.when(spy_log.get_calls_to_verify([spy_id_1,
                                            spy_id_2])).then_return(calls)

    subject.verify(
        "__rehearsal_1__",
        "__rehearsal_2__",
        times=None,
        ignore_extra_args=False,
    )

    decoy.verify(
        verifier.verify(rehearsals=rehearsals, calls=calls, times=None))
Exemple #14
0
def test_get_calls_to_verify() -> None:
    """It can get a list of calls made matching spy IDs of given rehearsals."""
    subject = SpyLog()
    call_1 = SpyEvent(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyCall(args=(1, ), kwargs={}),
    )
    call_2 = SpyEvent(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyCall(args=(2, ), kwargs={}),
    )
    call_3 = SpyEvent(
        spy_id=202,
        spy_name="spy_2",
        payload=SpyCall(args=(1, ), kwargs={}),
    )
    call_4 = SpyEvent(
        spy_id=101,
        spy_name="spy_1",
        payload=SpyCall(args=(1, ), kwargs={}),
    )

    subject.push(call_1)
    subject.push(call_2)
    subject.consume_when_rehearsal(ignore_extra_args=False)
    subject.push(call_3)
    subject.push(call_4)

    result = subject.get_calls_to_verify([101])
    assert result == [call_1, call_4]

    result = subject.get_calls_to_verify([101, 202])
    assert result == [call_1, call_3, call_4]

    result = subject.get_calls_to_verify([303])
    assert result == []
Exemple #15
0
def test_push_and_consume_when_rehearsal() -> None:
    """It should be able to push and pop from the stack."""
    subject = SpyLog()
    call = SpyEvent(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyCall(args=(), kwargs={}),
    )

    subject.push(call)
    result = subject.consume_when_rehearsal(ignore_extra_args=False)

    assert isinstance(result, WhenRehearsal)
    assert call == result
Exemple #16
0
def test_get_by_call_no_match(call: SpyEvent) -> None:
    """It should return a no-op StubBehavior if there are no matching calls."""
    subject = StubStore()
    rehearsal = WhenRehearsal(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyCall(
            args=("hello", "world"),
            kwargs={"goodbye": "so long"},
        ),
    )
    behavior = StubBehavior(return_value="fizzbuzz")

    subject.add(rehearsal=rehearsal, behavior=behavior)

    result = subject.get_by_call(call=call)
    assert result is None
Exemple #17
0
def test_consume_when_rehearsal_raises_empty_error() -> None:
    """It should raise an error if the stack is empty on pop."""
    subject = SpyLog()

    with pytest.raises(MissingRehearsalError):
        subject.consume_when_rehearsal(ignore_extra_args=False)

    call = SpyEvent(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyCall(args=(), kwargs={}),
    )
    subject.push(call)
    subject.consume_when_rehearsal(ignore_extra_args=False)

    with pytest.raises(MissingRehearsalError):
        subject.consume_when_rehearsal(ignore_extra_args=False)
Exemple #18
0
def test_handle_call_with_raise(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: CallHandler,
) -> None:
    """It raise a Stub's configured error."""
    spy_call = SpyEvent(spy_id=42,
                        spy_name="spy_name",
                        payload=SpyCall(args=(), kwargs={}))
    behavior = StubBehavior(error=RuntimeError("oh no"))

    decoy.when(stub_store.get_by_call(spy_call)).then_return(behavior)

    with pytest.raises(RuntimeError, match="oh no"):
        subject.handle(spy_call)

    decoy.verify(spy_log.push(spy_call))
Exemple #19
0
def test_handle_call_with_return(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: CallHandler,
) -> None:
    """It return a Stub's configured return value."""
    spy_call = SpyEvent(spy_id=42,
                        spy_name="spy_name",
                        payload=SpyCall(args=(), kwargs={}))
    behavior = StubBehavior(return_value="hello world")

    decoy.when(stub_store.get_by_call(spy_call)).then_return(behavior)

    result = subject.handle(spy_call)

    assert result == CallHandlerResult("hello world")
    decoy.verify(spy_log.push(spy_call))
Exemple #20
0
def test_handle_call_with_no_stubbing(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: CallHandler,
) -> None:
    """It should noop and add the call to the stack if no stubbing is configured."""
    spy_call = SpyEvent(spy_id=42,
                        spy_name="spy_name",
                        payload=SpyCall(args=(), kwargs={}))
    behavior = None

    decoy.when(stub_store.get_by_call(spy_call)).then_return(behavior)

    result = subject.handle(spy_call)

    assert result is None
    decoy.verify(spy_log.push(spy_call))
Exemple #21
0
def test_handle_call_with_context_enter(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: CallHandler,
) -> None:
    """It return a Stub's configured context value."""
    spy_call = SpyEvent(spy_id=42,
                        spy_name="spy_name",
                        payload=SpyCall(args=(), kwargs={}))
    behavior = StubBehavior(context_value="hello world")

    decoy.when(stub_store.get_by_call(spy_call)).then_return(behavior)

    with subject.handle(spy_call).value as result:  # type: ignore[union-attr]
        assert result == "hello world"

    decoy.verify(spy_log.push(spy_call))
Exemple #22
0
def test_reset(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    warning_checker: WarningChecker,
    subject: DecoyCore,
) -> None:
    """It should reset the stores."""
    call = SpyEvent(spy_id=1,
                    spy_name="my_spy",
                    payload=SpyCall(args=(), kwargs={}))

    decoy.when(spy_log.get_all()).then_return([call])

    subject.reset()

    decoy.verify(
        warning_checker.check([call]),
        spy_log.clear(),
        stub_store.clear(),
    )
Exemple #23
0
def test_handle_call_with_action(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: CallHandler,
) -> None:
    """It should trigger a stub's configured action."""
    action = decoy.mock()
    spy_call = SpyEvent(
        spy_id=42,
        spy_name="spy_name",
        payload=SpyCall(args=(1, ), kwargs={"foo": "bar"}),
    )
    behavior = StubBehavior(action=action)

    decoy.when(stub_store.get_by_call(spy_call)).then_return(behavior)
    decoy.when(action(1, foo="bar")).then_return("hello world")

    result = subject.handle(spy_call)

    assert result == CallHandlerResult("hello world")
Exemple #24
0
def test_when_ignore_extra_args(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: DecoyCore,
) -> None:
    """It should be able to register a new stubbing."""
    rehearsal = WhenRehearsal(spy_id=1,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    decoy.when(spy_log.consume_when_rehearsal(
        ignore_extra_args=True)).then_return(rehearsal)

    result = subject.when("__rehearsal__", ignore_extra_args=True)
    result.then_return("hello")

    decoy.verify(
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(return_value="hello", once=False),
        ))
Exemple #25
0
def test_when_then_raise(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: DecoyCore,
) -> None:
    """It should add a raise behavior to a stub."""
    rehearsal = WhenRehearsal(spy_id=1,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    decoy.when(spy_log.consume_when_rehearsal(
        ignore_extra_args=False)).then_return(rehearsal)

    error = RuntimeError("oh no")
    result = subject.when("__rehearsal__", ignore_extra_args=False)
    result.then_raise(error)

    decoy.verify(
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(error=error),
        ))
Exemple #26
0
def test_when_then_do(
    decoy: Decoy,
    spy_log: SpyLog,
    stub_store: StubStore,
    subject: DecoyCore,
) -> None:
    """It should add an action behavior to a stub."""
    rehearsal = WhenRehearsal(spy_id=1,
                              spy_name="my_spy",
                              payload=SpyCall(args=(), kwargs={}))
    decoy.when(spy_log.consume_when_rehearsal(
        ignore_extra_args=False)).then_return(rehearsal)

    action = lambda: "hello world"  # noqa: E731
    result = subject.when("__rehearsal__", ignore_extra_args=False)
    result.then_do(action)

    decoy.verify(
        stub_store.add(
            rehearsal=rehearsal,
            behavior=StubBehavior(action=action),
        ))
Exemple #27
0
def test_consume_prop_rehearsal_raises_empty_error() -> None:
    """It should raise an error a valid rehearsal event isn't found."""
    subject = SpyLog()

    with pytest.raises(MissingRehearsalError):
        subject.consume_prop_rehearsal()

    event = SpyEvent(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyPropAccess(prop_name="my_prop",
                              access_type=PropAccessType.GET),
    )
    subject.push(event)
    subject.consume_prop_rehearsal()

    with pytest.raises(MissingRehearsalError):
        subject.consume_prop_rehearsal()

    call = SpyEvent(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyCall(args=(), kwargs={}),
    )
    subject.push(call)

    with pytest.raises(MissingRehearsalError):
        subject.consume_prop_rehearsal()

    event = SpyEvent(
        spy_id=42,
        spy_name="my_spy",
        payload=SpyPropAccess(prop_name="my_prop",
                              access_type=PropAccessType.DELETE),
    )
    subject.push(event)

    with pytest.raises(MissingRehearsalError):
        subject.consume_prop_rehearsal()
Exemple #28
0
class VerifyErrorSpec(NamedTuple):
    """Spec data for VerifyError tests."""

    rehearsals: List[VerifyRehearsal]
    calls: List[SpyEvent]
    times: Optional[int]
    expected_message: str


verify_error_specs = [
    VerifyErrorSpec(
        rehearsals=[
            VerifyRehearsal(spy_id=42,
                            spy_name="my_spy",
                            payload=SpyCall(args=(), kwargs={})),
        ],
        calls=[],
        times=None,
        expected_message=os.linesep.join([
            "Expected at least 1 call:",
            "1.\tmy_spy()",
            "Found 0 calls.",
        ]),
    ),
    VerifyErrorSpec(
        rehearsals=[
            VerifyRehearsal(spy_id=42,
                            spy_name="my_spy",
                            payload=SpyCall(args=(), kwargs={})),
        ],
Exemple #29
0
    all_calls: Sequence[AnySpyEvent]
    expected_warnings: Sequence[DecoyWarning]


warning_checker_specs = [
    # it should not warn if there are no calls
    WarningCheckerSpec(
        all_calls=[],
        expected_warnings=[],
    ),
    # it should not warn if rehearsals and calls match
    WarningCheckerSpec(
        all_calls=[
            WhenRehearsal(
                spy_id=1, spy_name="spy", payload=SpyCall(args=(1,), kwargs={})
            ),
            SpyEvent(spy_id=1, spy_name="spy", payload=SpyCall(args=(1,), kwargs={})),
        ],
        expected_warnings=[],
    ),
    # it should not warn if a call is made and there are no rehearsals
    WarningCheckerSpec(
        all_calls=[
            SpyEvent(spy_id=1, spy_name="spy", payload=SpyCall(args=(1,), kwargs={})),
        ],
        expected_warnings=[],
    ),
    # it should warn if a spy has a rehearsal and a call that doesn't match
    WarningCheckerSpec(
        all_calls=[
Exemple #30
0

class MatchEventSpec(NamedTuple):
    """Spec data for testing `match_event`."""

    event: SpyEvent
    rehearsal: SpyRehearsal
    expected_result: bool


match_event_specs: List[MatchEventSpec] = [
    MatchEventSpec(
        event=SpyEvent(
            spy_id=42,
            spy_name="my_spy",
            payload=SpyCall(args=(), kwargs={}),
        ),
        rehearsal=WhenRehearsal(
            spy_id=42,
            spy_name="my_spy",
            payload=SpyCall(args=(), kwargs={}),
        ),
        expected_result=True,
    ),
    MatchEventSpec(
        event=SpyEvent(
            spy_id=42,
            spy_name="my_spy",
            payload=SpyCall(args=(1, 2), kwargs={
                "foo": "bar",
                "baz": "qux"