aboutsummaryrefslogtreecommitdiff
path: root/tests/errors
diff options
context:
space:
mode:
authornatsuoto <[email protected]>2026-06-26 19:23:09 +0530
committernatsuoto <[email protected]>2026-06-26 19:23:09 +0530
commit39f16caea1a92c9fb3e7d9c55cdcc20a058174ee (patch)
treef51cbe04af8a387d7d6e2e96eb2a746cca318669 /tests/errors
parent21ec7908c94839fff63b5275871cf84e92787a08 (diff)
downloadedify-39f16caea1a92c9fb3e7d9c55cdcc20a058174ee.tar.xz
edify-39f16caea1a92c9fb3e7d9c55cdcc20a058174ee.zip
chore!: package reorg, toolchain migration to uv+ruff+pytest+hatchling, Python 3.11 floor
Drops the `src/` layout. The package lives at `edify/` at repo root, split into single-purpose subpackages: `builder/` (mixins composing RegexBuilder), `elements/` (sealed dataclass AST), `compile/` (per-family render functions plus dispatch), `validate/`, `errors/` (typed exception hierarchy), and `library/` (per-validator files in family folders). Pattern, serialize, and result subpackages ship as skeletons. Replaces tox / virtualenv / flake8+isort+black / setup.py+setup.cfg / pytest.ini / .coveragerc / .bumpversion.cfg / MANIFEST.in / ci/ / tests.local.sh with a unified uv + ruff + pytest + hatchling + hatch-vcs stack driven entirely from pyproject.toml. CI workflow rewritten to `uv sync --frozen` + `uv run pytest` per matrix entry; required-status- check names preserved for `check`, `docs`, `py3X (ubuntu)`, and `pypy311 (ubuntu)`. `py39` / `py310` / `pypy310` dropped (3.11 floor). Pre-commit replaced with ruff hooks (lint + format), all hook repos SHA-pinned to commit SHAs. Tests reorganised under `tests/builder/` and `tests/library/<family>/` with the `*.test.py` naming shape. 173 tests pass, 100% line coverage. Behaviour changes versus 0.3 (each will get a documented upgrade-guide entry once #80 lands): - `to_regex_string()` returns the bare pattern (no `/.../` wrap) - `to_regex()` on `named_back_reference` compiles successfully via `(?P=name)` instead of raising - builder errors raise typed `EdifyError` subclasses instead of bare `Exception` (catch via `except EdifyError`) - internal helpers (`apply_quantifier`, `frame_creating_element`, `evaluate`, `state`, etc.) removed outright per the 0.3 → 1.0 stub-free policy Closes #68 Closes #69 Closes #253 Co-Authored-By: Claude Opus 4.7 <[email protected]>
Diffstat (limited to 'tests/errors')
-rw-r--r--tests/errors/errors.test.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/tests/errors/errors.test.py b/tests/errors/errors.test.py
new file mode 100644
index 0000000..12cfcd5
--- /dev/null
+++ b/tests/errors/errors.test.py
@@ -0,0 +1,153 @@
+from edify.errors.anchors import (
+ CannotDefineStartAfterEndError,
+ EndInputAlreadyDefinedError,
+ StartInputAlreadyDefinedError,
+)
+from edify.errors.captures import InvalidTotalCaptureGroupsIndexError
+from edify.errors.input import (
+ MustBeAStringError,
+ MustBeInstanceError,
+ MustBeIntegerGreaterThanZeroError,
+ MustBeLessThanError,
+ MustBeOneCharacterError,
+ MustBePositiveIntegerError,
+ MustBeSingleCharacterError,
+ MustHaveASmallerValueError,
+)
+from edify.errors.internal import (
+ FailedToCompileRegexError,
+ NonFusableElementError,
+ UnexpectedFrameTypeError,
+ UnknownElementTypeError,
+)
+from edify.errors.naming import (
+ CannotCreateDuplicateNamedGroupError,
+ NamedGroupDoesNotExistError,
+ NameNotValidError,
+)
+from edify.errors.structure import (
+ CannotCallSubexpressionError,
+ CannotEndWhileBuildingRootExpressionError,
+)
+
+
+def test_start_input_already_defined_outside_subexpression():
+ error = StartInputAlreadyDefinedError()
+ assert "already has a start" in str(error)
+ assert "ignore_start_and_end" not in str(error)
+
+
+def test_start_input_already_defined_in_subexpression():
+ error = StartInputAlreadyDefinedError(in_subexpression=True)
+ assert "ignore_start_and_end" in str(error)
+
+
+def test_end_input_already_defined_outside_subexpression():
+ error = EndInputAlreadyDefinedError()
+ assert "already has an end" in str(error)
+ assert "ignore_start_and_end" not in str(error)
+
+
+def test_end_input_already_defined_in_subexpression():
+ error = EndInputAlreadyDefinedError(in_subexpression=True)
+ assert "ignore_start_and_end" in str(error)
+
+
+def test_cannot_define_start_after_end():
+ error = CannotDefineStartAfterEndError()
+ assert "start of input after defining an end" in str(error)
+
+
+def test_invalid_total_capture_groups_index():
+ error = InvalidTotalCaptureGroupsIndexError(5, 3)
+ assert "Invalid index #5" in str(error)
+ assert "only 3 capture groups" in str(error)
+
+
+def test_must_be_a_string():
+ error = MustBeAStringError("Name", "int")
+ assert "Name must be a string" in str(error)
+ assert "int" in str(error)
+
+
+def test_must_be_one_character():
+ error = MustBeOneCharacterError("Value")
+ assert "Value must be one character long" in str(error)
+
+
+def test_must_be_single_character():
+ error = MustBeSingleCharacterError("Value", "str")
+ assert "Value must be a single character" in str(error)
+ assert "str" in str(error)
+
+
+def test_must_be_positive_integer():
+ error = MustBePositiveIntegerError("count")
+ assert "count must be a positive integer" in str(error)
+
+
+def test_must_be_integer_greater_than_zero():
+ error = MustBeIntegerGreaterThanZeroError("x")
+ assert "x must be an integer greater than zero" in str(error)
+
+
+def test_must_be_instance():
+ error = MustBeInstanceError("Expression", "str", "RegexBuilder")
+ assert "Expression must be an instance of RegexBuilder" in str(error)
+ assert "str" in str(error)
+
+
+def test_must_have_a_smaller_value():
+ error = MustHaveASmallerValueError("z", "a")
+ assert "z must have a smaller character value than a" in str(error)
+
+
+def test_must_be_less_than():
+ error = MustBeLessThanError("X", "Y")
+ assert "X must be less than Y" in str(error)
+
+
+def test_name_not_valid():
+ error = NameNotValidError("bad name")
+ assert "Name bad name is not valid" in str(error)
+
+
+def test_cannot_create_duplicate_named_group():
+ error = CannotCreateDuplicateNamedGroupError("dup")
+ assert 'Can not create duplicate named group "dup"' in str(error)
+
+
+def test_named_group_does_not_exist():
+ error = NamedGroupDoesNotExistError("missing")
+ assert 'Named group "missing" does not exist' in str(error)
+
+
+def test_cannot_end_while_building_root_expression():
+ error = CannotEndWhileBuildingRootExpressionError()
+ assert "Can not end while building the root expression" in str(error)
+
+
+def test_cannot_call_subexpression():
+ error = CannotCallSubexpressionError("capture")
+ assert "Can not call subexpression" in str(error)
+ assert "capture" in str(error)
+
+
+def test_unknown_element_type():
+ error = UnknownElementTypeError("WeirdElement")
+ assert "WeirdElement" in str(error)
+
+
+def test_non_fusable_element():
+ error = NonFusableElementError("DigitElement")
+ assert "Cannot fuse element of type DigitElement" in str(error)
+
+
+def test_unexpected_frame_type():
+ error = UnexpectedFrameTypeError("DigitElement")
+ assert "Stack frame anchored at unexpected element type DigitElement" in str(error)
+
+
+def test_failed_to_compile_regex():
+ error = FailedToCompileRegexError("missing )")
+ assert "Cannot compile regex: missing )" in str(error)