diff options
| author | natsuoto <[email protected]> | 2026-07-15 15:15:21 +0530 |
|---|---|---|
| committer | natsuoto <[email protected]> | 2026-07-15 15:15:21 +0530 |
| commit | 91942559f53003d2ef7a524456aef84f93b7f319 (patch) | |
| tree | d4064676c1188ff23541a1c50072af448ae74068 /tests | |
| parent | c343f05467045bd369aa8ecd6273924fe7c89f95 (diff) | |
| download | edify-91942559f53003d2ef7a524456aef84f93b7f319.tar.xz edify-91942559f53003d2ef7a524456aef84f93b7f319.zip | |
feat(errors): structured open-frame stack with per-frame call sites; DanglingQuantifierError names the pending quantifier
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/errors/errors.test.py | 23 | ||||
| -rw-r--r-- | tests/errors/frames.test.py | 69 |
2 files changed, 89 insertions, 3 deletions
diff --git a/tests/errors/errors.test.py b/tests/errors/errors.test.py index 632045d..82eb8fe 100644 --- a/tests/errors/errors.test.py +++ b/tests/errors/errors.test.py @@ -24,6 +24,7 @@ from edify.errors.naming import ( from edify.errors.structure import ( CannotCallSubexpressionError, CannotEndWhileBuildingRootExpressionError, + OpenFrameInfo, ) @@ -176,10 +177,26 @@ def test_cannot_end_while_building_root_expression(): def test_cannot_call_subexpression(): - error = CannotCallSubexpressionError("capture") + frames = (OpenFrameInfo(kind="capture", opened_at=None),) + error = CannotCallSubexpressionError(frames) text = str(error) assert "cannot merge a subexpression that has an unclosed frame" in text - assert "capture" in text + assert "1 open frame" in text + assert ".capture()" in text + + +def test_cannot_call_subexpression_lists_every_open_frame_in_the_stack(): + frames = ( + OpenFrameInfo(kind="capture", opened_at=None), + OpenFrameInfo(kind="assert_ahead", opened_at=None), + OpenFrameInfo(kind="group", opened_at=None), + ) + error = CannotCallSubexpressionError(frames) + text = str(error) + assert "3 open frame" in text + assert "1. .capture()" in text + assert "2. .assert_ahead()" in text + assert "3. .group()" in text def test_every_annotated_error_message_starts_with_error_prefix(): @@ -202,7 +219,7 @@ def test_every_annotated_error_message_starts_with_error_prefix(): CannotCreateDuplicateNamedGroupError("x"), NamedGroupDoesNotExistError("x"), CannotEndWhileBuildingRootExpressionError(), - CannotCallSubexpressionError("capture"), + CannotCallSubexpressionError((OpenFrameInfo(kind="capture", opened_at=None),)), ] for error in errors: text = str(error) diff --git a/tests/errors/frames.test.py b/tests/errors/frames.test.py new file mode 100644 index 0000000..b4077ba --- /dev/null +++ b/tests/errors/frames.test.py @@ -0,0 +1,69 @@ +"""Tests for the structured open-frame stack surfaced by CannotCallSubexpressionError.""" + +import pytest + +from edify import RegexBuilder +from edify.errors.structure import CannotCallSubexpressionError + + +def test_single_open_capture_frame_is_named_in_the_error_message(): + unfinished = RegexBuilder().capture().digit() + with pytest.raises(CannotCallSubexpressionError) as excinfo: + unfinished.to_regex_string() + text = str(excinfo.value) + assert "1 open frame" in text + assert "1. .capture()" in text + + +def test_nested_open_frames_are_listed_innermost_first(): + unfinished = RegexBuilder().capture().group().assert_ahead().digit() + with pytest.raises(CannotCallSubexpressionError) as excinfo: + unfinished.to_regex_string() + text = str(excinfo.value) + assert "3 open frame" in text + innermost_index = text.index("1. .assert_ahead()") + middle_index = text.index("2. .group()") + outermost_index = text.index("3. .capture()") + assert innermost_index < middle_index < outermost_index + + +def test_named_capture_frame_reports_the_declared_group_name(): + unfinished = RegexBuilder().named_capture("username").letter() + with pytest.raises(CannotCallSubexpressionError) as excinfo: + unfinished.to_regex_string() + text = str(excinfo.value) + assert '.named_capture("username")' in text + + +def test_open_frames_carry_a_file_line_column_pointer_when_the_context_is_captured(): + unfinished = RegexBuilder().assert_behind().digit() + with pytest.raises(CannotCallSubexpressionError) as excinfo: + unfinished.to_regex_string() + text = str(excinfo.value) + assert "opened at" in text + assert __file__ in text or "frames.test.py" in text + + +def test_subexpression_lists_open_frames_from_the_argument_not_the_receiver(): + unfinished = RegexBuilder().named_capture("group").digit() + parent = RegexBuilder() + with pytest.raises(CannotCallSubexpressionError) as excinfo: + parent.subexpression(unfinished) + assert 'named_capture("group")' in str(excinfo.value) + + +def test_dangling_quantifier_reports_the_specific_pending_quantifier_name(): + from edify.errors.quantifier import DanglingQuantifierError + + with pytest.raises(DanglingQuantifierError) as excinfo: + RegexBuilder().exactly(3).to_regex_string() + text = str(excinfo.value) + assert ".exactly(3)" in text + + +def test_dangling_quantifier_falls_back_to_generic_summary_when_name_unknown(): + from edify.errors.quantifier import DanglingQuantifierError + + error = DanglingQuantifierError() + text = str(error) + assert "dangling quantifier" in text |
