Skip to content

Commit

Permalink
fix(when): ensure then_enter_with accepts None (#137)
Browse files Browse the repository at this point in the history
Fixes #135
  • Loading branch information
mcous authored Jun 5, 2022
1 parent c23d145 commit 864aad7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 6 deletions.
4 changes: 2 additions & 2 deletions decoy/call_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .spy_log import SpyLog
from .context_managers import ContextWrapper
from .spy_events import SpyCall, SpyEvent
from .stub_store import StubStore
from .stub_store import MISSING, StubStore


class CallHandlerResult(NamedTuple):
Expand Down Expand Up @@ -43,7 +43,7 @@ def handle(self, call: SpyEvent) -> Optional[CallHandlerResult]:
else:
return_value = behavior.action()

elif behavior.context_value:
elif behavior.context_value is not MISSING:
return_value = ContextWrapper(behavior.context_value)

else:
Expand Down
16 changes: 14 additions & 2 deletions decoy/stub_store.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
"""Stub creation and storage."""
from typing import Any, Callable, List, NamedTuple, Optional
from typing import Any, Callable, List, NamedTuple, Optional, Union

from .spy_events import SpyEvent, WhenRehearsal, match_event


class _MISSING:
pass


MISSING = _MISSING()
"""Value not specified sentinel.
Used when `None` could be a valid value,
so `Optional` would be inappropriate.
"""


class StubBehavior(NamedTuple):
"""A recorded stub behavior."""

return_value: Optional[Any] = None
context_value: Optional[Any] = None
context_value: Union[_MISSING, Any] = MISSING
error: Optional[Exception] = None
action: Optional[Callable[..., Any]] = None
once: bool = False
Expand Down
28 changes: 26 additions & 2 deletions tests/test_call_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,11 @@ def test_handle_call_with_context_enter(
stub_store: StubStore,
subject: CallHandler,
) -> None:
"""It return a Stub's configured context value."""
"""It should return a Stub's configured context value."""
spy_call = SpyEvent(
spy_id=42, spy_name="spy_name", payload=SpyCall(args=(), kwargs={})
spy_id=42,
spy_name="spy_name",
payload=SpyCall(args=(), kwargs={}),
)
behavior = StubBehavior(context_value="hello world")

Expand All @@ -157,3 +159,25 @@ def test_handle_call_with_context_enter(
assert result == "hello world"

decoy.verify(spy_log.push(spy_call))


def test_handle_call_with_context_enter_none(
decoy: Decoy,
spy_log: SpyLog,
stub_store: StubStore,
subject: CallHandler,
) -> None:
"""It should allow a configured context value to be None."""
spy_call = SpyEvent(
spy_id=42,
spy_name="spy_name",
payload=SpyCall(args=(), kwargs={}),
)
behavior = StubBehavior(context_value=None)

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 is None

decoy.verify(spy_log.push(spy_call))

0 comments on commit 864aad7

Please sign in to comment.