Skip to content

Testing

didactic.api.testing

Test helpers for didactic-using projects.

Not imported by didactic automatically. Reach for it as from didactic.api import testing or import didactic.testing as dxt inside your test suite.

Public surface

verify_iso Property-test that an Iso satisfies its round-trip laws over a Hypothesis strategy. check_lens_laws Property-test that a Lens satisfies the GetPut and PutGet laws.

Both helpers are thin wrappers around hypothesis.given; they exist so test files don't have to import Hypothesis directly when all they want is a one-liner law check.

See Also

didactic.lenses._lens : the Lens / Iso / Mapping classes.

verify_iso

verify_iso(
    iso: Iso[A, A],
    strategy: SearchStrategy[A],
    *,
    max_examples: int = 100,
) -> None

Property-test that iso is a true bijection on its source class.

Runs max_examples Hypothesis-generated values through iso.backward(iso.forward(x)) == x, asserting equality on every sample. The complementary direction iso.forward(iso.backward(y)) cannot be exercised against a generated input without a generator over the target's value space; verifying both directions requires two strategies and is left to check_lens_laws or hand-written tests.

Parameters:

Name Type Description Default
iso Iso[A, A]

An Iso instance to verify.

required
strategy SearchStrategy[A]

A Hypothesis strategy producing values of the source class.

required
max_examples int

Number of samples to generate. Default 100.

100

Raises:

Type Description
AssertionError

If any sample fails the round-trip law.

Examples:

>>> import didactic.api as dx
>>> from didactic.testing import verify_iso
>>> from hypothesis import strategies as st
>>>
>>> class User(dx.Model):
...     id: str
...     bio: str = ""
>>>
>>> class Identity(dx.Iso[User, User]):
...     def forward(self, u: User) -> User:
...         return u
...
...     def backward(self, u: User) -> User:
...         return u
>>>
>>> users = st.builds(User, id=st.text(), bio=st.text())
>>> verify_iso(Identity(), users)

check_lens_laws

check_lens_laws(
    lens: Lens[A, B],
    strategy: SearchStrategy[A],
    *,
    max_examples: int = 100,
) -> None

Property-test that lens satisfies the GetPut law.

The GetPut law (backward(*forward(a)) == a) is the most useful invariant; PutGet requires generating valid B values plus matching complements, which requires a second strategy and a knowledge of the lens's complement type.

Parameters:

Name Type Description Default
lens Lens[A, B]

A Lens instance to verify.

required
strategy SearchStrategy[A]

A Hypothesis strategy producing values of the source class.

required
max_examples int

Number of samples to generate. Default 100.

100

Raises:

Type Description
AssertionError

If any sample violates GetPut.

verify_mapping

verify_mapping(
    mapping: Mapping[A, B],
    strategy: SearchStrategy[A],
    *,
    max_examples: int = 100,
) -> None

Property-test that a Mapping is a function.

The check runs the mapping on every generated input and asserts that calling it twice on the same input produces equal outputs; the absence of side effects is the property mappings promise.

Parameters:

Name Type Description Default
mapping Mapping[A, B]

A Mapping instance.

required
strategy SearchStrategy[A]

Hypothesis strategy over the source class.

required
max_examples int

Sample count. Default 100.

100

Raises:

Type Description
AssertionError

If a sample produces different outputs on two calls.

verify_iso_inverse

verify_iso_inverse(iso: Iso[A, B]) -> None

Verify that iso.inverse().inverse() == iso (symmetry of inverse).

Parameters:

Name Type Description Default
iso Iso[A, B]

An Iso instance.

required

Raises:

Type Description
AssertionError

If the iso's double-inverse is not the same iso (by identity or by structural fingerprint of forward/backward outputs on a sample).

verify_lens_composition

verify_lens_composition(
    lens_ab: Mapping[A, B],
    lens_bc: Mapping[B, C],
    strategy: SearchStrategy[A],
    *,
    max_examples: int = 100,
) -> None

Verify that (lens_ab >> lens_bc)(x) == lens_bc(lens_ab(x)).

Parameters:

Name Type Description Default
lens_ab Mapping[A, B]

A lens / mapping from A to B.

required
lens_bc Mapping[B, C]

A lens / mapping from B to C.

required
strategy SearchStrategy[A]

Hypothesis strategy over the source class A.

required
max_examples int

Sample count. Default 100.

100

Raises:

Type Description
AssertionError

If the composed lens disagrees with manual chaining on any sample.

verify_migration_round_trip

verify_migration_round_trip(
    iso: Iso[A, A],
    source_strategy: SearchStrategy[A],
    *,
    max_examples: int = 100,
) -> None

Verify that an Iso preserves information across a migration round trip.

Parameters:

Name Type Description Default
iso Iso[A, A]

An Iso meant to be used as a migration; this helper enforces that backward(forward(x)) == x.

required
source_strategy SearchStrategy[A]

Hypothesis strategy over the source Model class.

required
max_examples int

Sample count. Default 100.

100

Raises:

Type Description
AssertionError

If any sample loses information.