diff options
| author | natsuoto <[email protected]> | 2026-06-26 19:23:09 +0530 |
|---|---|---|
| committer | natsuoto <[email protected]> | 2026-06-26 19:23:09 +0530 |
| commit | 39f16caea1a92c9fb3e7d9c55cdcc20a058174ee (patch) | |
| tree | f51cbe04af8a387d7d6e2e96eb2a746cca318669 /tests/errors/errors.test.py | |
| parent | 21ec7908c94839fff63b5275871cf84e92787a08 (diff) | |
| download | edify-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/errors.test.py')
| -rw-r--r-- | tests/errors/errors.test.py | 153 |
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) |
