diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e9f2fb9..79ab392 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.12, 3.13] + python-version: ["3.10", "3.12", "3.13"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} @@ -23,4 +23,4 @@ jobs: python -m pip install --upgrade pip pip install .[test] - name: Run tests with coverage - run: pytest \ No newline at end of file + run: python -m pytest \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 3a7cca2..5c3502b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Explain, test, and generate examples for regular expressions" authors = [{name = "Dev B. Makwana"}] license = {text = "MIT"} readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.10" dependencies = [ "pyrailroad>=0.4.0" ] @@ -18,8 +18,6 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -46,4 +44,5 @@ path = "src/rexplain/__init__.py" [tool.pytest.ini_options] addopts = "--cov=src/rexplain --cov-report=term-missing --cov-fail-under=70" -testpaths = ["tests"] \ No newline at end of file +testpaths = ["tests"] +norecursedirs = ["src", ".git", "dist", "build"] \ No newline at end of file diff --git a/src/rexplain/core/tester.py b/src/rexplain/core/tester.py index 3f7dec1..d3edd2d 100644 --- a/src/rexplain/core/tester.py +++ b/src/rexplain/core/tester.py @@ -24,6 +24,15 @@ def __str__(self): f"failed_at={self.failed_at}, partial_matches={self.partial_matches})" ) + def to_dict(self): + """Convert the result to a dictionary format""" + return { + 'matches': self.matches, + 'reason': self.reason, + 'failed_at': self.failed_at, + 'partial_matches': self.partial_matches + } + class RegexTester: """ Tests if a string matches a regex pattern and provides detailed feedback. diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..79a1ced --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,105 @@ +""" +Tests for the public API wrapper functions in __init__.py +""" +import sys +import os +import re +import tempfile +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) + +import rexplain +from rexplain import explain, examples, diagram + +def test_explain_api(): + """Test the explain() API function""" + result = explain(r'\d+') + assert isinstance(result, str) + assert 'digit' in result.lower() or r'\d' in result + +def test_explain_api_with_flags(): + """Test explain() with regex flags""" + result = explain(r'abc', flags=re.IGNORECASE) + assert isinstance(result, str) + assert 'a' in result.lower() + +def test_examples_api(): + """Test the examples() API function""" + result = examples(r'[a-z]{3}', count=5) + assert isinstance(result, list) + assert len(result) == 5 + # Verify all examples match the pattern + pattern = re.compile(r'[a-z]{3}') + for ex in result: + assert pattern.fullmatch(ex) + +def test_examples_api_default_count(): + """Test examples() with default count""" + result = examples(r'\d+') + assert isinstance(result, list) + assert len(result) == 3 # Default count + +def test_examples_api_with_flags(): + """Test examples() with regex flags""" + result = examples(r'[a-z]+', count=2, flags=re.IGNORECASE) + assert isinstance(result, list) + assert len(result) == 2 + +def test_test_api_match(): + """Test the test() API function with matching string""" + result = rexplain.test(r'foo.*', 'foobar') + assert hasattr(result, 'matches') + assert result.matches is True + assert result.reason + +def test_test_api_no_match(): + """Test the test() API function with non-matching string""" + result = rexplain.test(r'abc', 'xyz') + assert hasattr(result, 'matches') + assert result.matches is False + assert result.reason + +def test_test_api_with_flags(): + """Test test() with regex flags""" + result = rexplain.test(r'abc', 'ABC', flags=re.IGNORECASE) + assert result.matches is True + +def test_diagram_api_basic(): + """Test the diagram() API function without output file""" + result = diagram(r'\w+') + assert isinstance(result, str) + assert '= 2 # Should have at least 2 examples + +def test_cli_test_match(): + """Test test command with matching string""" + result = subprocess.run([sys.executable, '-m', 'rexplain.cli.main', 'test', 'abc', 'abc'], + capture_output=True, text=True, cwd='/home/user/rexplain/src') + assert result.returncode == 0 + +def test_cli_test_no_match(): + """Test test command with non-matching string""" + result = subprocess.run([sys.executable, '-m', 'rexplain.cli.main', 'test', 'abc', 'xyz'], + capture_output=True, text=True, cwd='/home/user/rexplain/src') + assert result.returncode == 1 # Should exit with error code + +def test_cli_diagram_stdout(): + """Test diagram command without output file""" + result = subprocess.run([sys.executable, '-m', 'rexplain.cli.main', 'diagram', r'\w+'], + capture_output=True, text=True, cwd='/home/user/rexplain/src') + assert result.returncode == 0 + assert '