85 lines
2.7 KiB
Python
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"
|