Coverage for tests / unit / exceptions / test_exceptions.py: 100%
32 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Unit tests for custom exception hierarchy and messages."""
3from __future__ import annotations
5import pytest
6from assertpy import assert_that
8from lintro.exceptions.errors import (
9 ConfigurationError,
10 FileAccessError,
11 InvalidToolConfigError,
12 InvalidToolOptionError,
13 LintroError,
14 ParserError,
15 ToolExecutionError,
16 ToolTimeoutError,
17)
20@pytest.mark.parametrize(
21 "exception_class,message",
22 [
23 (LintroError, "base error"),
24 (InvalidToolConfigError, "invalid config"),
25 (InvalidToolOptionError, "invalid option"),
26 (ToolExecutionError, "execution failed"),
27 (ToolTimeoutError, "timeout occurred"),
28 (ParserError, "parsing failed"),
29 (ConfigurationError, "config error"),
30 (FileAccessError, "file not found"),
31 ],
32 ids=[
33 "LintroError",
34 "InvalidToolConfigError",
35 "InvalidToolOptionError",
36 "ToolExecutionError",
37 "ToolTimeoutError",
38 "ParserError",
39 "ConfigurationError",
40 "FileAccessError",
41 ],
42)
43def test_exception_inheritance_and_message(exception_class: type, message: str) -> None:
44 """Test all exceptions inherit from LintroError and preserve messages.
46 Args:
47 exception_class: Exception class to test.
48 message: Error message to use.
49 """
50 exc = exception_class(message)
51 assert_that(exc).is_instance_of(LintroError)
52 assert_that(exc).is_instance_of(Exception)
53 assert_that(str(exc)).is_equal_to(message)
56@pytest.mark.parametrize(
57 "exception_class",
58 [
59 LintroError,
60 InvalidToolConfigError,
61 InvalidToolOptionError,
62 ToolExecutionError,
63 ToolTimeoutError,
64 ParserError,
65 ConfigurationError,
66 FileAccessError,
67 ],
68)
69def test_exception_can_be_raised_and_caught(exception_class: type) -> None:
70 """Test exceptions can be raised and caught properly.
72 Args:
73 exception_class: Exception class to test.
75 Raises:
76 exception_class: The exception being tested.
77 """
78 with pytest.raises(exception_class) as exc_info:
79 raise exception_class("test message")
80 assert_that(str(exc_info.value)).is_equal_to("test message")
83@pytest.mark.parametrize(
84 "exception_class",
85 [
86 InvalidToolConfigError,
87 InvalidToolOptionError,
88 ToolExecutionError,
89 ToolTimeoutError,
90 ParserError,
91 ConfigurationError,
92 FileAccessError,
93 ],
94)
95def test_subclass_caught_by_base_exception(exception_class: type) -> None:
96 """Test subclass exceptions can be caught by LintroError.
98 Args:
99 exception_class: Exception class to test.
101 Raises:
102 exception_class: The exception being tested.
103 """
104 with pytest.raises(LintroError):
105 raise exception_class("caught by base")
108def test_exception_args_preserved() -> None:
109 """Test exception args are preserved for introspection."""
110 exc = ToolExecutionError("tool failed", "extra", "info")
111 assert_that(exc.args).is_equal_to(("tool failed", "extra", "info"))
114def test_exception_chaining() -> None:
115 """Test exceptions can be chained with __cause__."""
116 original = ValueError("original error")
117 try:
118 try:
119 raise original
120 except ValueError as e:
121 raise ParserError("parsing failed") from e
122 except ParserError as pe:
123 assert_that(pe.__cause__).is_equal_to(original)
124 assert_that(str(pe.__cause__)).is_equal_to("original error")