diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdc2024..5880715 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: uv venv uv pip install . -r dev-requirements.txt - name: Run tests - run: uv run python -m pytest + run: uv run python -m pytest --cov crossandra --cov-report term-missing - name: Lint code if: always() run: | diff --git a/dev-requirements.txt b/dev-requirements.txt index 4d6e7cd..0b93279 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,4 @@ mypy ~= 1.10.0 pytest ~= 8.2.0 +pytest-cov ~= 5.0.0 ruff ~= 0.4.2 \ No newline at end of file diff --git a/justfile b/justfile index a970ffc..073e0b0 100644 --- a/justfile +++ b/justfile @@ -7,8 +7,7 @@ install: uv pip install . -r dev-requirements.txt check: - python -m pytest - mypy --strict crossandra - mypy --strict tests + python -m pytest --cov crossandra --cov-report term-missing + mypy --strict crossandra tests ruff check ruff format --check diff --git a/pyproject.toml b/pyproject.toml index 90258ec..d41cb62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,13 @@ archs = ["auto", "aarch64"] [tool.cibuildwheel.macos] archs = ["x86_64", "universal2"] +[tool.coverage.report] +exclude_also = [ + "if TYPE_CHECKING:", + "if sys.version_info.*:", + "if __name__ == \"__main__\":", +] + [tool.ruff] target-version = "py38" diff --git a/tests/test_api.py b/tests/test_api.py index 63bdb1f..c8a6611 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -14,6 +14,7 @@ RuleGroup, common, ) +from crossandra.lib import invert_enum from crossandra.rule import IGNORED, NOT_APPLIED if TYPE_CHECKING: @@ -198,3 +199,68 @@ def test_rule_group() -> None: p, r = RuleGroup((a, b)) assert (a, b) == (x, y) == (p, r) + + +def test_rule_properties() -> None: + a = Rule[str]("a") + b = Rule[str]("a") + + assert a == b + assert a != 1 + assert isinstance(a | a | b, RuleGroup) + assert isinstance(a | (a | b), RuleGroup) + + +@pytest.mark.parametrize( + "rule_or_rulegroup", + [ + Rule[str]("a"), + RuleGroup((Rule[str]("a"), Rule[str]("b"))), + ], +) +def test_rule_group_creation_fail(rule_or_rulegroup: Rule[Any] | RuleGroup) -> None: + with pytest.raises(TypeError): + rule_or_rulegroup | 1 + + +def test_invert_enum_with_aliases() -> None: + class Test(Enum): + FOO = "1" + BAR = ("2", "3") + + assert invert_enum(Test) == {"1": Test.FOO, "2": Test.BAR, "3": Test.BAR} + + +def test_tokenize_lines() -> None: + assert Crossandra(rules=[common.WORD], ignore_whitespace=True).tokenize_lines( + "a b\nc\rde" + ) == [["a", "b"], ["c"], ["de"]] + + +def test_break_path() -> None: + class Test(Enum): + X = "ABC" + Y = "A" + Z = "B" + + assert Crossandra(Test).tokenize("ABABAABABC") == [ + Test.Y, + Test.Z, + Test.Y, + Test.Z, + Test.Y, + Test.Y, + Test.Z, + Test.X, + ] + + +def test_tokenize_fast_with_ignored() -> None: + class Test(Enum): + FOO = "x" + BAR = "y" + + assert Crossandra(Test, ignored_characters="z").tokenize("xzy") == [ + Test.FOO, + Test.BAR, + ]