"""Entropyk — Unit Tests for Exception Hierarchy.

Tests that all exception types exist, inherit correctly, and carry messages.
"""

import pytest
import entropyk


class TestExceptionHierarchy:
    """Tests for Python exception class hierarchy."""

    def test_entropyk_error_exists(self):
        assert hasattr(entropyk, "EntropykError")
        assert issubclass(entropyk.EntropykError, Exception)

    def test_solver_error_inherits(self):
        assert issubclass(entropyk.SolverError, entropyk.EntropykError)

    def test_timeout_error_inherits(self):
        assert issubclass(entropyk.TimeoutError, entropyk.SolverError)

    def test_control_saturation_error_inherits(self):
        assert issubclass(entropyk.ControlSaturationError, entropyk.SolverError)

    def test_fluid_error_inherits(self):
        assert issubclass(entropyk.FluidError, entropyk.EntropykError)

    def test_component_error_inherits(self):
        assert issubclass(entropyk.ComponentError, entropyk.EntropykError)

    def test_topology_error_inherits(self):
        assert issubclass(entropyk.TopologyError, entropyk.EntropykError)

    def test_validation_error_inherits(self):
        assert issubclass(entropyk.ValidationError, entropyk.EntropykError)


class TestExceptionMessages:
    """Tests that exceptions carry descriptive messages."""

    def test_entropyk_error_message(self):
        err = entropyk.EntropykError("test message")
        assert str(err) == "test message"

    def test_solver_error_message(self):
        err = entropyk.SolverError("convergence failed")
        assert "convergence failed" in str(err)

    def test_timeout_error_message(self):
        err = entropyk.TimeoutError("timed out after 5s")
        assert "timed out" in str(err)

    def test_fluid_error_message(self):
        err = entropyk.FluidError("R134a not found")
        assert "R134a" in str(err)

    def test_topology_error_message(self):
        err = entropyk.TopologyError("graph cycle detected")
        assert "cycle" in str(err)


class TestExceptionCatching:
    """Tests that exceptions can be caught at different hierarchy levels."""

    def test_catch_solver_as_entropyk(self):
        with pytest.raises(entropyk.EntropykError):
            raise entropyk.SolverError("test")

    def test_catch_timeout_as_solver(self):
        with pytest.raises(entropyk.SolverError):
            raise entropyk.TimeoutError("test")

    def test_catch_timeout_as_entropyk(self):
        with pytest.raises(entropyk.EntropykError):
            raise entropyk.TimeoutError("test")

    def test_catch_fluid_as_entropyk(self):
        with pytest.raises(entropyk.EntropykError):
            raise entropyk.FluidError("test")

    def test_catch_component_as_entropyk(self):
        with pytest.raises(entropyk.EntropykError):
            raise entropyk.ComponentError("test")

    def test_timeout_not_caught_as_fluid(self):
        """TimeoutError should NOT be caught by FluidError."""
        with pytest.raises(entropyk.TimeoutError):
            raise entropyk.TimeoutError("test")
        # Verify it doesn't match FluidError
        try:
            raise entropyk.TimeoutError("test")
        except entropyk.FluidError:
            pytest.fail("TimeoutError should not be caught by FluidError")
        except entropyk.TimeoutError:
            pass  # Expected
