Skip to content

Commit 89ccda5

Browse files
committed
test(client): cover default-decoder resolution matrix for both clients
1 parent b0cdded commit 89ccda5

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
"""Default decoder resolution under varying extras-installed states.
2+
3+
Covers the behavior matrix in planning/specs/2026-06-09-multi-decoder-design.md
4+
— `AsyncClient()` / `Client()` resolve `decoders=None` against the
5+
`import_checker` flags at __init__ time.
6+
"""
7+
8+
from unittest.mock import patch
9+
10+
from httpware import AsyncClient, Client
11+
from httpware.decoders.msgspec import MsgspecDecoder
12+
from httpware.decoders.pydantic import PydanticDecoder
13+
14+
15+
def test_async_default_both_extras_installed() -> None:
16+
client = AsyncClient()
17+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
18+
assert types == (PydanticDecoder, MsgspecDecoder)
19+
20+
21+
def test_async_default_pydantic_only() -> None:
22+
with patch("httpware._internal.import_checker.is_msgspec_installed", False):
23+
client = AsyncClient()
24+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
25+
assert types == (PydanticDecoder,)
26+
27+
28+
def test_async_default_msgspec_only() -> None:
29+
with patch("httpware._internal.import_checker.is_pydantic_installed", False):
30+
client = AsyncClient()
31+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
32+
assert types == (MsgspecDecoder,)
33+
34+
35+
def test_async_default_neither_installed() -> None:
36+
with (
37+
patch("httpware._internal.import_checker.is_pydantic_installed", False),
38+
patch("httpware._internal.import_checker.is_msgspec_installed", False),
39+
):
40+
client = AsyncClient()
41+
assert client._decoders == () # noqa: SLF001
42+
43+
44+
def test_async_empty_explicit_decoders() -> None:
45+
client = AsyncClient(decoders=[])
46+
assert client._decoders == () # noqa: SLF001
47+
48+
49+
def test_async_explicit_decoders_skip_default_probe() -> None:
50+
class _Custom:
51+
def can_decode(self, model: type) -> bool: # noqa: ARG002 # pragma: no cover
52+
return True
53+
54+
def decode(self, content: bytes, model: type) -> object: # noqa: ARG002 # pragma: no cover
55+
return None
56+
57+
custom = _Custom()
58+
with (
59+
patch("httpware._internal.import_checker.is_pydantic_installed", False),
60+
patch("httpware._internal.import_checker.is_msgspec_installed", False),
61+
):
62+
client = AsyncClient(decoders=[custom])
63+
assert client._decoders == (custom,) # noqa: SLF001
64+
65+
66+
def test_sync_default_both_extras_installed() -> None:
67+
client = Client()
68+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
69+
assert types == (PydanticDecoder, MsgspecDecoder)
70+
client.close()
71+
72+
73+
def test_sync_default_pydantic_only() -> None:
74+
with patch("httpware._internal.import_checker.is_msgspec_installed", False):
75+
client = Client()
76+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
77+
assert types == (PydanticDecoder,)
78+
client.close()
79+
80+
81+
def test_sync_default_msgspec_only() -> None:
82+
with patch("httpware._internal.import_checker.is_pydantic_installed", False):
83+
client = Client()
84+
types = tuple(type(d) for d in client._decoders) # noqa: SLF001
85+
assert types == (MsgspecDecoder,)
86+
client.close()
87+
88+
89+
def test_sync_default_neither_installed() -> None:
90+
with (
91+
patch("httpware._internal.import_checker.is_pydantic_installed", False),
92+
patch("httpware._internal.import_checker.is_msgspec_installed", False),
93+
):
94+
client = Client()
95+
assert client._decoders == () # noqa: SLF001
96+
client.close()
97+
98+
99+
def test_sync_empty_explicit_decoders() -> None:
100+
client = Client(decoders=[])
101+
assert client._decoders == () # noqa: SLF001
102+
client.close()

0 commit comments

Comments
 (0)