Skip to content

Commit 7e5602f

Browse files
test: cover string-formatting and representation helpers
Add a dedicated test module exercising the previously-uncovered string-formatting paths in injector: - UnsatisfiedRequirement.__str__ (with and without an owner) - _describe (named objects, tuple/list, and the str() fallback) - _get_origin normalization of typing.List/typing.Dict aliases Kept separate from injector_test.py to avoid polluting the functional suite with coverage-driven edge cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 56f3156 commit 7e5602f

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""Targeted tests that exercise the remaining uncovered lines in ``injector``.
2+
3+
These cases don't fit naturally into the functional test suite in
4+
``injector_test.py`` – they poke at internal string-formatting helpers and
5+
rarely-hit edge-case/error branches purely to drive coverage to 100%.
6+
"""
7+
8+
from typing import Dict, List
9+
10+
import injector
11+
from injector import UnsatisfiedRequirement
12+
13+
14+
# --- String / representation formatting --------------------------------------
15+
16+
17+
def test_unsatisfied_requirement_str_without_owner():
18+
# The ``self.owner`` falsy branch of ``UnsatisfiedRequirement.__str__``.
19+
error = UnsatisfiedRequirement(None, int)
20+
assert str(error) == 'unsatisfied requirement on int'
21+
22+
23+
def test_unsatisfied_requirement_str_with_owner():
24+
# The ``self.owner`` truthy branch, which prepends a description of the owner.
25+
class Owner:
26+
pass
27+
28+
owner = Owner()
29+
error = UnsatisfiedRequirement(owner, int)
30+
message = str(error)
31+
assert message.endswith('has an unsatisfied requirement on int')
32+
assert message != 'unsatisfied requirement on int'
33+
34+
35+
def test_describe_named_object():
36+
# Objects exposing ``__name__`` are described by that name.
37+
assert injector._describe(int) == 'int'
38+
39+
40+
def test_describe_tuple_uses_first_element():
41+
# Tuples/lists are described via their first element's ``__name__``.
42+
assert injector._describe((int,)) == '[int]'
43+
assert injector._describe([str]) == '[str]'
44+
45+
46+
def test_describe_falls_back_to_str():
47+
# Anything without ``__name__`` that isn't a tuple/list falls back to ``str``.
48+
assert injector._describe(123) == '123'
49+
50+
51+
def test_get_origin_normalizes_typing_aliases():
52+
# Some (older) typings store ``typing.List``/``typing.Dict`` as ``__origin__``;
53+
# ``_get_origin`` normalizes those back to the builtin containers.
54+
class FakeListAlias:
55+
__origin__ = List
56+
57+
class FakeDictAlias:
58+
__origin__ = Dict
59+
60+
assert injector._get_origin(FakeListAlias) is list
61+
assert injector._get_origin(FakeDictAlias) is dict

0 commit comments

Comments
 (0)