Files

85 lines
2.7 KiB
Python

"""
Shared API contract tests for all SpectrumComponent subclasses.
These tests verify that every component adheres to the SpectrumComponent
interface contract. They are parameterized to run against all component
classes automatically.
## Contract requirements
1. `__call__(W) -> np.ndarray` — the component is callable with W array
2. `__init__` accepts `logger: Optional[Logger] = None`
3. `__repr__` returns a non-empty string
4. Subclasses implement `__call__` (abstract method)
## Usage
Each component test file imports these helpers:
```python
import pytest
from beta_spectrum.components.fermi import FermiFunction
from tests.common.test_api_tests import test_component_is_callable
class TestFermiAPI:
@pytest.mark.api
def test_callable(self):
ff = FermiFunction(Z=20, A=40)
test_component_is_callable(ff, "FermiFunction")
```
"""
import numpy as np
import pytest
@pytest.mark.api
def _test_component_is_callable(component, component_name="Component"):
"""Component must be callable with array input."""
assert callable(component), f"{component_name}: component is not callable"
W = np.array([1.5, 2.0, 3.0])
result = component(W)
assert isinstance(result, np.ndarray), (
f"{component_name}: __call__ returned {type(result)}, " f"expected np.ndarray"
)
assert (
result.shape == W.shape
), f"{component_name}: shape mismatch {W.shape} → {result.shape}"
@pytest.mark.api
def _test_component_repr(component, component_name="Component"):
"""Component must have a non-empty repr."""
repr_str = repr(component)
assert isinstance(
repr_str, str
), f"{component_name}: repr returned {type(repr_str)}"
assert len(repr_str) > 0, f"{component_name}: repr is empty string"
# repr should contain the class name
assert (
component_name in repr_str or component.__class__.__name__ in repr_str
), f"{component_name}: repr should contain class name. Got: {repr_str}"
@pytest.mark.api
def _test_component_list_input(component, component_name="Component"):
"""Component must handle Python list input (numpy converts it)."""
result = component([1.5, 2.0, 3.0])
assert isinstance(
result, np.ndarray
), f"{component_name}: list input returned {type(result)}"
@pytest.mark.api
def _test_component_empty_input(component, component_name="Component"):
"""Component must handle empty array input gracefully."""
result = component(np.array([]))
assert isinstance(
result, np.ndarray
), f"{component_name}: empty input returned {type(result)}"
assert result.shape == (
0,
), f"{component_name}: empty input should return empty array"