Skip to content

Commit

Permalink
Tests for filters, OR edition - refs #21
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Jun 20, 2023
1 parent 0662329 commit 00bab48
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 3 deletions.
16 changes: 13 additions & 3 deletions symbex/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,20 @@ def filter(node: ast.AST) -> bool:
# node can match any of the specified types
if async_ and isinstance(node, ast.AsyncFunctionDef):
return True
if function and isinstance(node, ast.FunctionDef):
if function and isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
return True
if class_ and isinstance(node, ast.ClassDef):
return True
summary = annotation_summary(node)
# TODO: Refactor this, also handle return types
if typed and summary and (summary.num_arguments and summary.num_typed):
if (
typed
and summary
and (
(summary.num_arguments and summary.num_typed)
or summary.return_is_typed
)
):
return True
if (
untyped
Expand All @@ -193,7 +200,10 @@ def filter(node: ast.AST) -> bool:
partially_typed
and summary
and summary.num_typed
and summary.num_typed < summary.num_arguments
and (
(summary.num_typed < summary.num_arguments)
or not summary.return_is_typed
)
):
return True
if fully_typed and summary and summary.num_typed == summary.num_arguments:
Expand Down
38 changes: 38 additions & 0 deletions tests/example_symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,41 @@ def complex_annotations(
code: str, symbols: Iterable[str]
) -> List[Tuple[AST, Optional[str]]]:
pass


# For testing --typed/--untyped/etc


def func_fully_typed(a: int, b: str) -> bool:
pass


async def async_func_fully_typed(a: int, b: str) -> bool:
pass


def func_partially_typed(a: int, b) -> bool:
pass


def func_partially_typed_no_typed_return(a: int, b: int):
pass


def func_partially_typed_only_typed_return(a, b) -> int:
pass


def func_typed_no_params() -> None:
pass


class ClassForTypedTests:
def method_fully_typed(self, a: int, b: str) -> bool:
pass

def method_partially_typed(self, a: int, b) -> bool:
pass

def method_untyped(self, a, b):
pass
105 changes: 105 additions & 0 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Tests for "symbex --async / --class / --typed etc"
import pathlib
import pytest
from click.testing import CliRunner

from symbex.cli import cli


@pytest.mark.parametrize(
"args,expected",
(
(
["--function"],
[
"def func_no_args",
"def func_positional_args",
"async def async_func",
"def func_default_args",
"def func_arbitrary_positional_args",
"def func_arbitrary_keyword_args",
"def func_arbitrary_args",
"def func_positional_only_args",
"def func_keyword_only_args",
"def func_type_annotations",
"def function_with_non_pep_0484_annotation",
"def complex_annotations",
"def func_fully_typed",
"async def async_func_fully_typed",
"def func_partially_typed",
"def func_partially_typed_no_typed_return",
"def func_partially_typed_only_typed_return",
"def func_typed_no_params",
],
),
(
["--class"],
[
"class ClassNoBase",
"class ClassSingleBase",
"class ClassMultipleBase",
"class ClassWithMeta",
"class ClassWithMethods",
"class ClassForTypedTests",
],
),
(
["--async"],
[
"async def async_func",
"async def async_func_fully_typed",
],
),
# Using multiple at the same time returns symbols matching any of them
(
["--async", "--class"],
[
"async def async_func",
"class ClassNoBase",
"class ClassSingleBase",
"class ClassMultipleBase",
"class ClassWithMeta",
"class ClassWithMethods",
"async def async_func_fully_typed",
"class ClassForTypedTests",
],
),
# Various typing options
(
["--typed"],
[
"def func_type_annotations",
"def function_with_non_pep_0484_annotation",
"def complex_annotations",
"def func_fully_typed",
"async def async_func_fully_typed",
"def func_partially_typed",
"def func_partially_typed_no_typed_return",
"def func_partially_typed_only_typed_return",
"def func_typed_no_params",
],
),
),
)
def test_filters(args, expected):
runner = CliRunner()
result = runner.invoke(
cli,
args
+ [
"-s",
"-f",
str(pathlib.Path(__file__).parent / "example_symbols.py"),
],
catch_exceptions=False,
)
assert result.exit_code == 0
# Remove # File: lines and blank lines
lines = [
line.strip()
for line in result.stdout.splitlines()
if line.strip() and not line.startswith("# File:")
]
# We only match up to the opening "("
defs = [line.split("(")[0] for line in lines]
assert defs == expected

0 comments on commit 00bab48

Please sign in to comment.