diff --git a/tests/conftest.py b/tests/conftest.py index 37d9cab..40011d9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,8 +6,12 @@ from tests.dataSamples.Make import allSubclasses from typing import Any import ast # pyright: ignore[reportUnusedImport] +import datetime import pytest +negativeTestsPerClass: int = 3 +stepSize: int = (32 - datetime.date.today().weekday()) * (datetime.date.today().day + 1) + def generateBeTestData() -> Iterator[tuple[str, str, dict[str, Any]]]: """Yield test data for positive Be tests. (AI generated docstring). @@ -29,12 +33,25 @@ def generateBeTestData() -> Iterator[tuple[str, str, dict[str, Any]]]: def getTestData(vsClass: str, testName: str) -> dict[str, Any]: return allSubclasses[vsClass][testName] -def generateBeNegativeTestData(): # noqa: ANN201 +def generateBeNegativeTestData() -> Iterator[tuple[str, str, str, dict[str, Any]]]: for class2test, *list_vsClass in [(C, *list(set(allSubclasses)-{C}-{c.__name__ for c in eval('ast.'+C).__subclasses__()})) for C in allSubclasses]: # noqa: S307 testName = "class Make, maximally empty parameters" - for vsClass in list_vsClass: - testData = getTestData(vsClass, testName) - yield (class2test, vsClass, testName, testData) + + list_vsClass.sort() + indexNormalizer: int = len(list_vsClass) + setIndices: set[int] = set() + step: int = stepSize + while len(setIndices) < negativeTestsPerClass: + setIndices.add(step % indexNormalizer) + step = step + stepSize + 1 + + listIndices: list[int] = sorted(setIndices) + + listTuplesTests: list[tuple[str, str, str, dict[str, Any]]] = [ + (class2test, list_vsClass[index], testName, getTestData(list_vsClass[index], testName)) + for index in listIndices + ] + yield from listTuplesTests @pytest.fixture(params=list(generateBeTestData()), ids=lambda param: f"{param[0]}_{param[1]}") def beTestData(request: pytest.FixtureRequest) -> tuple[str, str, dict[str, Any]]: @@ -72,87 +89,87 @@ def beNegativeTestData(request: pytest.FixtureRequest) -> tuple[str, str, str, d # IfThis test data and fixtures -def generateIdentifierTestData() -> Iterator[tuple[str, str, Callable, bool]]: - """Generate test data for IfThis identifier-based methods.""" - - # Basic identifier patterns - test_cases = [ -# NOTE (method_name, test_identifier, node_factory, expected_result) - ("isNameIdentifier", "test_var", lambda identifier: Make.Name(identifier), True), - ("isNameIdentifier", "different_var", lambda identifier: Make.Name("test_var"), False), - ("isFunctionDefIdentifier", "test_func", lambda identifier: Make.FunctionDef(name=identifier), True), - ("isFunctionDefIdentifier", "other_func", lambda identifier: Make.FunctionDef(name="test_func"), False), - ("isClassDefIdentifier", "TestClass", lambda identifier: Make.ClassDef(name=identifier), True), - ("isClassDefIdentifier", "OtherClass", lambda identifier: Make.ClassDef(name="TestClass"), False), - ("isCallIdentifier", "print", lambda identifier: Make.Call(callee=Make.Name(identifier)), True), - ("isCallIdentifier", "input", lambda identifier: Make.Call(callee=Make.Name("print")), False), - ("is_argIdentifier", "param", lambda identifier: Make.arg(identifier), True), - ("is_argIdentifier", "other_param", lambda identifier: Make.arg("param"), False), - ("is_keywordIdentifier", "key", lambda identifier: Make.keyword(identifier, Make.Constant("value")), True), - ("is_keywordIdentifier", "other_key", lambda identifier: Make.keyword("key", Make.Constant("value")), False), +def generateIfThisIdentifierTestCases() -> Iterator[tuple[str, str, Callable[[str], ast.AST], bool]]: + """Generate test data for IfThis identifier-based methods using non-contiguous test values.""" + + # Using non-contiguous, semantic test values as per instructions + listTestCases: list[tuple[str, str, Callable[[str], ast.AST], bool]] = [ + # methodNameIfThis, identifierToTest, factoryNodeAST, expectedPredicateResult + ("isNameIdentifier", "variableNorthward", lambda identifierParameter: Make.Name(identifierParameter), True), + ("isNameIdentifier", "variableSouthward", lambda _identifierIgnored: Make.Name("variableNorthward"), False), + ("isFunctionDefIdentifier", "functionEastward", lambda identifierParameter: Make.FunctionDef(name=identifierParameter), True), + ("isFunctionDefIdentifier", "functionWestward", lambda _identifierIgnored: Make.FunctionDef(name="functionEastward"), False), + ("isClassDefIdentifier", "ClassNorthEast", lambda identifierParameter: Make.ClassDef(name=identifierParameter), True), + ("isClassDefIdentifier", "ClassSouthWest", lambda _identifierIgnored: Make.ClassDef(name="ClassNorthEast"), False), + ("isCallIdentifier", "callablePrimary", lambda identifierParameter: Make.Call(Make.Name(identifierParameter)), True), + ("isCallIdentifier", "callableSecondary", lambda _identifierIgnored: Make.Call(Make.Name("callablePrimary")), False), + ("is_argIdentifier", "parameterFibonacci", lambda identifierParameter: Make.arg(identifierParameter), True), + ("is_argIdentifier", "parameterPrime", lambda _identifierIgnored: Make.arg("parameterFibonacci"), False), + ("is_keywordIdentifier", "keywordAlpha", lambda identifierParameter: Make.keyword(identifierParameter, Make.Constant("valueBeta")), True), + ("is_keywordIdentifier", "keywordGamma", lambda _identifierIgnored: Make.keyword("keywordAlpha", Make.Constant("valueBeta")), False), ] - yield from test_cases + yield from listTestCases -def generateSimplePredicateTestData() -> Iterator[tuple[str, tuple, Callable, bool]]: - """Generate test data for simple predicate methods.""" +def generateIfThisSimplePredicateTestCases() -> Iterator[tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]]: + """Generate test data for simple predicate methods using unique test values.""" - test_cases = [ - # method_name, test_args, node_factory, expected_result - ("isConstant_value", (42,), lambda: Make.Constant(42), True), - ("isConstant_value", (24,), lambda: Make.Constant(42), False), + listTestCases: list[tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]] = [ + # methodNameIfThis, tupleArgumentsTest, factoryNodeAST, expectedPredicateResult + ("isConstant_value", (233,), lambda: Make.Constant(233), True), # Fibonacci number + ("isConstant_value", (89,), lambda: Make.Constant(233), False), # Different Fibonacci number ] - yield from test_cases + yield from listTestCases -def generateDirectPredicateTestData() -> Iterator[tuple[str, Callable, bool]]: +def generateIfThisDirectPredicateTestCases() -> Iterator[tuple[str, Callable[[], ast.AST], bool]]: """Generate test data for direct predicate methods that take node directly.""" - test_cases = [ - # method_name, node_factory, expected_result - ("isAttributeName", lambda: Make.Attribute(Make.Name("obj"), "attr"), True), - ("isAttributeName", lambda: Make.Name("obj"), False), - ("isCallToName", lambda: Make.Call(callee=Make.Name("func")), True), - ("isCallToName", lambda: Make.Call(callee=Make.Attribute(Make.Name("obj"), "method")), False), + listTestCases: list[tuple[str, Callable[[], ast.AST], bool]] = [ + # methodNameIfThis, factoryNodeAST, expectedPredicateResult + ("isAttributeName", lambda: Make.Attribute(Make.Name("objectPrime"), "attributeSecondary"), True), + ("isAttributeName", lambda: Make.Name("objectPrime"), False), + ("isCallToName", lambda: Make.Call(Make.Name("functionTertiary")), True), + ("isCallToName", lambda: Make.Call(Make.Attribute(Make.Name("objectPrime"), "methodQuinary")), False), ] - yield from test_cases - -def generateComplexPredicateTestData() -> Iterator[tuple[str, tuple, Callable, bool]]: - """Generate test data for complex predicate methods.""" - - test_cases = [ - # method_name, test_args, node_factory, expected_result - ("isAttributeNamespaceIdentifier", ("obj", "method"), lambda: Make.Attribute(Make.Name("obj"), "method"), True), - ("isAttributeNamespaceIdentifier", ("other_obj", "method"), lambda: Make.Attribute(Make.Name("obj"), "method"), False), - ("isCallAttributeNamespaceIdentifier", ("obj", "method"), lambda: Make.Call(callee=Make.Attribute(Make.Name("obj"), "method")), True), - ("isCallAttributeNamespaceIdentifier", ("other_obj", "method"), lambda: Make.Call(callee=Make.Attribute(Make.Name("obj"), "method")), False), - ("isStarredIdentifier", ("args",), lambda: Make.Starred(value=Make.Name("args")), True), - ("isStarredIdentifier", ("kwargs",), lambda: Make.Starred(value=Make.Name("args")), False), - ("isSubscriptIdentifier", ("arr",), lambda: Make.Subscript(value=Make.Name("arr"), slice=Make.Constant(0)), True), - ("isSubscriptIdentifier", ("list",), lambda: Make.Subscript(value=Make.Name("arr"), slice=Make.Constant(0)), False), - ("isUnaryNotAttributeNamespaceIdentifier", ("obj", "flag"), lambda: Make.UnaryOp(op=Make.Not(), operand=Make.Attribute(Make.Name("obj"), "flag")), True), - ("isUnaryNotAttributeNamespaceIdentifier", ("other_obj", "flag"), lambda: Make.UnaryOp(op=Make.Not(), operand=Make.Attribute(Make.Name("obj"), "flag")), False), + yield from listTestCases + +def generateIfThisComplexPredicateTestCases() -> Iterator[tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]]: + """Generate test data for complex predicate methods using cardinal directions and primes.""" + + listTestCases: list[tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]] = [ + # methodNameIfThis, tupleArgumentsTest, factoryNodeAST, expectedPredicateResult + ("isAttributeNamespaceIdentifier", ("namespacePrimary", "methodNorthward"), lambda: Make.Attribute(Make.Name("namespacePrimary"), "methodNorthward"), True), + ("isAttributeNamespaceIdentifier", ("namespaceSecondary", "methodNorthward"), lambda: Make.Attribute(Make.Name("namespacePrimary"), "methodNorthward"), False), + ("isCallAttributeNamespaceIdentifier", ("namespaceAlpha", "methodEastward"), lambda: Make.Call(Make.Attribute(Make.Name("namespaceAlpha"), "methodEastward")), True), + ("isCallAttributeNamespaceIdentifier", ("namespaceBeta", "methodEastward"), lambda: Make.Call(Make.Attribute(Make.Name("namespaceAlpha"), "methodEastward")), False), + ("isStarredIdentifier", ("argumentsCollection",), lambda: Make.Starred(Make.Name("argumentsCollection")), True), + ("isStarredIdentifier", ("keywordsMapping",), lambda: Make.Starred(Make.Name("argumentsCollection")), False), + ("isSubscriptIdentifier", ("arrayFibonacci",), lambda: Make.Subscript(Make.Name("arrayFibonacci"), Make.Constant(13)), True), + ("isSubscriptIdentifier", ("listPrime",), lambda: Make.Subscript(Make.Name("arrayFibonacci"), Make.Constant(13)), False), + ("isUnaryNotAttributeNamespaceIdentifier", ("objectTarget", "flagEnabled"), lambda: Make.UnaryOp(Make.Not(), Make.Attribute(Make.Name("objectTarget"), "flagEnabled")), True), + ("isUnaryNotAttributeNamespaceIdentifier", ("objectAlternate", "flagEnabled"), lambda: Make.UnaryOp(Make.Not(), Make.Attribute(Make.Name("objectTarget"), "flagEnabled")), False), ] - yield from test_cases + yield from listTestCases -@pytest.fixture(params=list(generateIdentifierTestData()), ids=lambda param: f"{param[0]}_{param[1]}_{param[3]}") -def identifierTestData(request: pytest.FixtureRequest) -> tuple[str, str, Callable, bool]: +@pytest.fixture(params=list(generateIfThisIdentifierTestCases()), ids=lambda parametersTest: f"{parametersTest[0]}_{parametersTest[1]}_{parametersTest[3]}") +def ifThisIdentifierTestData(request: pytest.FixtureRequest) -> tuple[str, str, Callable[[str], ast.AST], bool]: """Fixture providing test data for identifier-based IfThis methods.""" return request.param -@pytest.fixture(params=list(generateSimplePredicateTestData()), ids=lambda param: f"{param[0]}_{param[3]}") -def simplePredicateTestData(request: pytest.FixtureRequest) -> tuple[str, tuple, Callable, bool]: +@pytest.fixture(params=list(generateIfThisSimplePredicateTestCases()), ids=lambda parametersTest: f"{parametersTest[0]}_{parametersTest[3]}") +def ifThisSimplePredicateTestData(request: pytest.FixtureRequest) -> tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]: """Fixture providing test data for simple IfThis predicate methods.""" return request.param -@pytest.fixture(params=list(generateDirectPredicateTestData()), ids=lambda param: f"{param[0]}_{param[2]}") -def directPredicateTestData(request: pytest.FixtureRequest) -> tuple[str, Callable, bool]: +@pytest.fixture(params=list(generateIfThisDirectPredicateTestCases()), ids=lambda parametersTest: f"{parametersTest[0]}_{parametersTest[2]}") +def ifThisDirectPredicateTestData(request: pytest.FixtureRequest) -> tuple[str, Callable[[], ast.AST], bool]: """Fixture providing test data for direct IfThis predicate methods.""" return request.param -@pytest.fixture(params=list(generateComplexPredicateTestData()), ids=lambda param: f"{param[0]}_{param[3]}") -def complexPredicateTestData(request: pytest.FixtureRequest) -> tuple[str, tuple, Callable, bool]: +@pytest.fixture(params=list(generateIfThisComplexPredicateTestCases()), ids=lambda parametersTest: f"{parametersTest[0]}_{parametersTest[3]}") +def ifThisComplexPredicateTestData(request: pytest.FixtureRequest) -> tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]: """Fixture providing test data for complex IfThis predicate methods.""" return request.param diff --git a/tests/test_IfThis.py b/tests/test_IfThis.py index 33a741a..06ef0b5 100644 --- a/tests/test_IfThis.py +++ b/tests/test_IfThis.py @@ -1,320 +1,310 @@ """Tests for the IfThis class predicates using parametrized tests and DRY principles.""" # pyright: standard from astToolkit import Be, IfThis, Make -from typing import Any, TYPE_CHECKING +from collections.abc import Callable +from typing import Any +import ast import pytest -if TYPE_CHECKING: - from collections.abc import Callable - import ast - -class TestIfThisBasic: - """Test suite for basic IfThis methods.""" - - @pytest.mark.parametrize("valueInput,expectedResult", [ - ("test_name", True), - ("different_name", False), - (None, False), - ]) - def testIsIdentifierWithString(self, valueInput: str | None, expectedResult: bool) -> None: - """Test isIdentifier with string identifier.""" - predicate: Callable[[str | None], bool] = IfThis.isIdentifier("test_name") - assert predicate(valueInput) is expectedResult - - @pytest.mark.parametrize("valueInput,expectedResult", [ - (None, True), - ("some_name", False), - ]) - def testIsIdentifierWithNone(self, valueInput: str | None, expectedResult: bool) -> None: - """Test isIdentifier with None identifier.""" - predicate: Callable[[str | None], bool] = IfThis.isIdentifier(None) - assert predicate(valueInput) is expectedResult - - @pytest.mark.parametrize("valueTest,valueNode,expectedResult", [ - (42, 42, True), - (42, 24, False), - ("hello", "hello", True), - ("hello", "world", False), - (None, None, True), - (None, 42, False), - ]) - def testIsConstantValue(self, valueTest: Any, valueNode: Any, expectedResult: bool) -> None: - """Test isConstant_value with various values.""" - nodeConstant: ast.Constant = Make.Constant(valueNode) - predicate: Callable[[ast.AST], bool] = IfThis.isConstant_value(valueTest) - assert predicate(nodeConstant) is expectedResult - - def testIsConstantValueWrongNodeType(self) -> None: - """Test isConstant_value with wrong node type.""" - nodeName: ast.Name = Make.Name("test") - predicate: Callable[[ast.AST], bool] = IfThis.isConstant_value(42) - assert predicate(nodeName) is False - - -class TestIfThisIdentifierMethods: - """Test suite for identifier-based IfThis methods using fixtures.""" - - def testIdentifierMethods(self, identifierTestData: tuple[str, str, "Callable[..., Any]", bool]) -> None: - """Test identifier methods using parametrized data.""" - nameMethod, identifierTest, factoryNode, expectedResult = identifierTestData - - # Get the method from IfThis - method = getattr(IfThis, nameMethod) - - # Create the predicate - predicate = method(identifierTest) - - # Create the test node - node = factoryNode(identifierTest) - - # Test the predicate - assert predicate(node) is expectedResult, f"{nameMethod}({identifierTest}) should return {expectedResult}" - - @pytest.mark.parametrize("nameMethod,identifierTest", [ - ("isNameIdentifier", "test_var"), - ("isFunctionDefIdentifier", "test_func"), - ("isClassDefIdentifier", "TestClass"), - ("isCallIdentifier", "print"), - ("is_argIdentifier", "param"), - ("is_keywordIdentifier", "key"), - ]) - def testIdentifierMethodsWrongNodeType(self, nameMethod: str, identifierTest: str) -> None: - """Test identifier methods with wrong node types.""" - method = getattr(IfThis, nameMethod) - predicate = method(identifierTest) - nodeWrong = Make.Constant(42) # Wrong node type for all these methods - assert predicate(nodeWrong) is False - - -class TestIfThisSimpleMethods: - """Test suite for simple predicate IfThis methods using fixtures.""" - - def testSimpleMethods(self, simplePredicateTestData: tuple[str, tuple[Any, ...], "Callable[[], Any]", bool]) -> None: - """Test simple predicate methods using parametrized data.""" - nameMethod, argumentsList, factoryNode, expectedResult = simplePredicateTestData - - # Get the method from IfThis - method = getattr(IfThis, nameMethod) - - # Create the predicate - predicate = method(*argumentsList) - - # Create the test node - node = factoryNode() - - # Test the predicate - assert predicate(node) is expectedResult, f"{nameMethod}({argumentsList}) should return {expectedResult}" - - def testDirectMethods(self, directPredicateTestData: tuple[str, "Callable[[], Any]", bool]) -> None: - """Test direct predicate methods that take node directly.""" - nameMethod, factoryNode, expectedResult = directPredicateTestData - - # Get the method from IfThis - method = getattr(IfThis, nameMethod) - - # Create the test node - node = factoryNode() - - # Test the method directly - result = method(node) - assert result is expectedResult, f"{nameMethod}(node) should return {expectedResult}" - - -class TestIfThisComplexMethods: - """Test suite for complex predicate IfThis methods using fixtures.""" - - def testComplexMethods(self, complexPredicateTestData: tuple[str, tuple[Any, ...], "Callable[[], Any]", bool]) -> None: - """Test complex predicate methods using parametrized data.""" - nameMethod, argumentsList, factoryNode, expectedResult = complexPredicateTestData - - # Get the method from IfThis - method = getattr(IfThis, nameMethod) - - # Create the predicate - predicate = method(*argumentsList) - - # Create the test node - node = factoryNode() - - # Test the predicate - assert predicate(node) is expectedResult, f"{nameMethod}({argumentsList}) should return {expectedResult}" - - @pytest.mark.parametrize("namespaceObject,identifierAttribute", [ - ("obj", "method"), - ("self", "value"), - ("cls", "name"), - ]) - def testIsAttributeNamespaceIdentifierPositive(self, namespaceObject: str, identifierAttribute: str) -> None: - """Test isAttributeNamespaceIdentifier with matching cases.""" - nodeAttribute = Make.Attribute(Make.Name(namespaceObject), identifierAttribute) - predicate = IfThis.isAttributeNamespaceIdentifier(namespaceObject, identifierAttribute) - assert predicate(nodeAttribute) is True - - def testIsIfUnaryNotAttributeNamespaceIdentifierPositive(self) -> None: - """Test isIfUnaryNotAttributeNamespaceIdentifier with matching case.""" - nodeIf = Make.If( - test=Make.UnaryOp( - op=Make.Not(), - operand=Make.Attribute(Make.Name("obj"), "flag") - ), - body=[Make.Pass()] - ) - predicate = IfThis.isIfUnaryNotAttributeNamespaceIdentifier("obj", "flag") - assert predicate(nodeIf) is True - - def testIsIfUnaryNotAttributeNamespaceIdentifierNegative(self) -> None: - """Test isIfUnaryNotAttributeNamespaceIdentifier with non-matching case.""" - nodeIf = Make.If(test=Make.Name("condition"), body=[Make.Pass()]) - predicate = IfThis.isIfUnaryNotAttributeNamespaceIdentifier("obj", "flag") - assert predicate(nodeIf) is False - - -class TestIfThisLogicalMethods: - """Test suite for logical combination IfThis methods.""" - - @pytest.mark.parametrize("listPredicates,nodeTest,expectedResult", [ - # All predicates match - ([Be.Name, lambda node: hasattr(node, 'id') and node.id == "test"], Make.Name("test"), True), - # Some predicates don't match - ([Be.Name, lambda node: hasattr(node, 'id') and node.id == "other"], Make.Name("test"), False), - # No predicates (edge case) - ([], Make.Name("test"), True), # all() returns True for empty sequence - ]) - def testIsAllOf(self, listPredicates: list["Callable[..., Any]"], nodeTest: "ast.AST", expectedResult: bool) -> None: - """Test isAllOf with various predicate combinations.""" - combined = IfThis.isAllOf(*listPredicates) - assert combined(nodeTest) is expectedResult - - @pytest.mark.parametrize("listPredicates,nodeTest,expectedResult", [ - # At least one predicate matches - ([Be.Constant, Be.Name], Make.Name("test"), True), - # No predicates match - ([Be.Constant, Be.FunctionDef], Make.Name("test"), False), - # No predicates (edge case) - ([], Make.Name("test"), False), # any() returns False for empty sequence - ]) - def testIsAnyOf(self, listPredicates: list["Callable[..., Any]"], nodeTest: "ast.AST", expectedResult: bool) -> None: - """Test isAnyOf with various predicate combinations.""" - combined = IfThis.isAnyOf(*listPredicates) - assert combined(nodeTest) is expectedResult - - -class TestIfThisTreeMethods: - """Test suite for tree analysis IfThis methods.""" - - def testMatchesNoDescendantPositive(self) -> None: - """Test matchesNoDescendant when no descendant matches predicate.""" - nodeAssign = Make.Assign( - targets=[Make.Name("x", context=Make.Store())], - value=Make.Constant(42) - ) - def predicateNameMatching(node: "ast.AST") -> bool: - return Be.Name(node) and getattr(node, 'id', None) == "y" - predicate = IfThis.matchesNoDescendant(predicateNameMatching) - assert predicate(nodeAssign) is True - - def testMatchesNoDescendantNegative(self) -> None: - """Test matchesNoDescendant when a descendant matches predicate.""" - nodeAssign = Make.Assign( - targets=[Make.Name("x", context=Make.Store())], - value=Make.Constant(42) - ) - def predicateNameMatching(node: "ast.AST") -> bool: - return Be.Name(node) and getattr(node, 'id', None) == "x" - predicate = IfThis.matchesNoDescendant(predicateNameMatching) - assert predicate(nodeAssign) is False - - def testMatchesMeButNotAnyDescendantPositive(self) -> None: - """Test matchesMeButNotAnyDescendant when node matches but descendants don't.""" - nodeAssign = Make.Assign( - targets=[Make.Name("x", context=Make.Store())], - value=Make.Constant(42) - ) - predicateAssign = Be.Assign - predicate = IfThis.matchesMeButNotAnyDescendant(predicateAssign) - assert predicate(nodeAssign) is True - - def testMatchesMeButNotAnyDescendantNegative(self) -> None: - """Test matchesMeButNotAnyDescendant when node doesn't match.""" - nodeName = Make.Name("x") - predicateAssign = Be.Assign - predicate = IfThis.matchesMeButNotAnyDescendant(predicateAssign) - assert predicate(nodeName) is False - - @pytest.mark.parametrize("nodeFirst,nodeSecond,expectedResult", [ - (Make.Name("x"), Make.Name("x"), True), - (Make.Name("x"), Make.Name("y"), False), - (Make.Constant(42), Make.Constant(42), True), - (Make.Constant(42), Make.Constant(24), False), - ]) - def testUnparseIs(self, nodeFirst: "ast.AST", nodeSecond: "ast.AST", expectedResult: bool) -> None: - """Test unparseIs with various node combinations.""" - predicate = IfThis.unparseIs(nodeFirst) - assert predicate(nodeSecond) is expectedResult - - -class TestIfThisAdvancedCases: - """Test suite for advanced IfThis usage scenarios.""" - - def testNestedIdentifierPatterns(self) -> None: - """Test isNestedNameIdentifier with various node types.""" - identifierTest = "test_var" - predicate = IfThis.isNestedNameIdentifier(identifierTest) - - # Should match Name - nodeName = Make.Name(identifierTest) - assert predicate(nodeName) is True - - # Should match Attribute with matching value - nodeAttribute = Make.Attribute(Make.Name(identifierTest), "method") - assert predicate(nodeAttribute) is True - - # Should not match Attribute with non-matching value - nodeAttributeNoMatch = Make.Attribute(Make.Name("other_var"), "method") - assert predicate(nodeAttributeNoMatch) is False - - def testIsAssignAndTargets0IsPatterns(self) -> None: - """Test isAssignAndTargets0Is with various target predicates.""" - nodeAssign = Make.Assign( - targets=[Make.Name("x", context=Make.Store())], - value=Make.Constant(42) - ) - - # Matching target predicate - def predicateTargetMatching(node: "ast.AST") -> bool: - return Be.Name(node) and getattr(node, 'id', None) == "x" - predicate = IfThis.isAssignAndTargets0Is(predicateTargetMatching) - assert predicate(nodeAssign) is True - - # Non-matching target predicate - def predicateTargetWrong(node: "ast.AST") -> bool: - return Be.Name(node) and getattr(node, 'id', None) == "y" - predicateWrong = IfThis.isAssignAndTargets0Is(predicateTargetWrong) - assert predicateWrong(nodeAssign) is False - - # Wrong node type - nodeName = Make.Name("x") - assert predicate(nodeName) is False - - def testComplexPredicateComposition(self) -> None: - """Test complex predicate compositions with real-world scenarios.""" - # Create a function with assignment in body - nodeFunction = Make.FunctionDef( - name="test_func", - body=[Make.Assign( - targets=[Make.Name("x", context=Make.Store())], - value=Make.Constant(42) - )] - ) - - # Complex predicate combining multiple conditions - predicateComplex = IfThis.isAllOf( - Be.FunctionDef, - lambda node: getattr(node, 'name', None) == "test_func", - lambda node: len(getattr(node, 'body', [])) > 0 - ) - assert predicateComplex(nodeFunction) is True - - # Should fail if any condition doesn't match - functionDifferent = Make.FunctionDef(name="other_func", body=[Make.Pass()]) - assert predicateComplex(functionDifferent) is False +class TestIfThisBasicPredicates: + """Test suite for basic IfThis methods.""" + + @pytest.mark.parametrize("valueInputTest,expectedPredicateResult", [ + ("identifierNorthward", True), + ("identifierSouthward", False), + (None, False), + ]) + def testIsIdentifierWithStringPattern(self, valueInputTest: str | None, expectedPredicateResult: bool) -> None: + """Test isIdentifier with string identifier using cardinal directions.""" + predicateIdentifier: Callable[[str | None], bool] = IfThis.isIdentifier("identifierNorthward") + assert predicateIdentifier(valueInputTest) is expectedPredicateResult + + @pytest.mark.parametrize("valueInputTest,expectedPredicateResult", [ + (None, True), + ("identifierNorthward", False), + ]) + def testIsIdentifierWithNonePattern(self, valueInputTest: str | None, expectedPredicateResult: bool) -> None: + """Test isIdentifier with None identifier.""" + predicateIdentifier: Callable[[str | None], bool] = IfThis.isIdentifier(None) + assert predicateIdentifier(valueInputTest) is expectedPredicateResult + + @pytest.mark.parametrize("valueToTest,valueInNode,expectedPredicateResult", [ + (233, 233, True), # Fibonacci number + (233, 89, False), # Different Fibonacci numbers + ("stringAlpha", "stringAlpha", True), + ("stringAlpha", "stringBeta", False), + (None, None, True), + (None, 233, False), + ]) + def testIsConstantValueWithVariousTypes(self, valueToTest: Any, valueInNode: Any, expectedPredicateResult: bool) -> None: + """Test isConstant_value with various values using Fibonacci numbers.""" + nodeConstant: ast.Constant = Make.Constant(valueInNode) + predicateConstantValue: Callable[[ast.AST], bool] = IfThis.isConstant_value(valueToTest) + assert predicateConstantValue(nodeConstant) is expectedPredicateResult + + def testIsConstantValueWithWrongNodeType(self) -> None: + """Test isConstant_value with wrong node type.""" + nodeNameIncorrect: ast.Name = Make.Name("identifierTest") + predicateConstantValue: Callable[[ast.AST], bool] = IfThis.isConstant_value(233) + assert predicateConstantValue(nodeNameIncorrect) is False + +class TestIfThisIdentifierBasedMethods: + """Test suite for identifier-based IfThis methods using fixtures.""" + + def testIdentifierBasedMethods(self, ifThisIdentifierTestData: tuple[str, str, Callable[[str], ast.AST], bool]) -> None: + """Test identifier methods using parametrized data.""" + methodNameIfThis, identifierToTest, factoryNodeAST, expectedPredicateResult = ifThisIdentifierTestData + + # Get the method from IfThis + methodIfThis = getattr(IfThis, methodNameIfThis) + + # Create the predicate + predicateGenerated = methodIfThis(identifierToTest) + + # Create the test node + nodeAST = factoryNodeAST(identifierToTest) + + # Test the predicate + assert predicateGenerated(nodeAST) is expectedPredicateResult, f"{methodNameIfThis}({identifierToTest}) should return {expectedPredicateResult}" + + @pytest.mark.parametrize("methodNameIfThis,identifierToTest", [ + ("isNameIdentifier", "variableNorthward"), + ("isFunctionDefIdentifier", "functionEastward"), + ("isClassDefIdentifier", "ClassNorthEast"), + ("isCallIdentifier", "callablePrimary"), + ("is_argIdentifier", "parameterFibonacci"), + ("is_keywordIdentifier", "keywordAlpha"), + ]) + def testIdentifierMethodsWithWrongNodeType(self, methodNameIfThis: str, identifierToTest: str) -> None: + """Test identifier methods with wrong node types using cardinal directions.""" + methodIfThis = getattr(IfThis, methodNameIfThis) + predicateGenerated = methodIfThis(identifierToTest) + nodeWrongType = Make.Constant(233) # Wrong node type for all these methods (Fibonacci number) + assert predicateGenerated(nodeWrongType) is False + +class TestIfThisSimplePredicateMethods: + """Test suite for simple predicate IfThis methods using fixtures.""" + + def testSimplePredicateMethods(self, ifThisSimplePredicateTestData: tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]) -> None: + """Test simple predicate methods using parametrized data.""" + methodNameIfThis, tupleArgumentsTest, factoryNodeAST, expectedPredicateResult = ifThisSimplePredicateTestData + + # Get the method from IfThis + methodIfThis = getattr(IfThis, methodNameIfThis) + + # Create the predicate + predicateGenerated = methodIfThis(*tupleArgumentsTest) + + # Create the test node + nodeAST = factoryNodeAST() + + # Test the predicate + assert predicateGenerated(nodeAST) is expectedPredicateResult, f"{methodNameIfThis}({tupleArgumentsTest}) should return {expectedPredicateResult}" + + def testDirectPredicateMethods(self, ifThisDirectPredicateTestData: tuple[str, Callable[[], ast.AST], bool]) -> None: + """Test direct predicate methods that take node directly.""" + methodNameIfThis, factoryNodeAST, expectedPredicateResult = ifThisDirectPredicateTestData + + # Get the method from IfThis + methodIfThis = getattr(IfThis, methodNameIfThis) + + # Create the test node + nodeAST = factoryNodeAST() + + # Test the method directly + resultPredicate = methodIfThis(nodeAST) + assert resultPredicate is expectedPredicateResult, f"{methodNameIfThis}(node) should return {expectedPredicateResult}" + +class TestIfThisComplexPredicateMethods: + """Test suite for complex predicate IfThis methods using fixtures.""" + + def testComplexPredicateMethods(self, ifThisComplexPredicateTestData: tuple[str, tuple[Any, ...], Callable[[], ast.AST], bool]) -> None: + """Test complex predicate methods using parametrized data.""" + methodNameIfThis, tupleArgumentsTest, factoryNodeAST, expectedPredicateResult = ifThisComplexPredicateTestData + + # Get the method from IfThis + methodIfThis = getattr(IfThis, methodNameIfThis) + + # Create the predicate + predicateGenerated = methodIfThis(*tupleArgumentsTest) + + # Create the test node + nodeAST = factoryNodeAST() + + # Test the predicate + assert predicateGenerated(nodeAST) is expectedPredicateResult, f"{methodNameIfThis}({tupleArgumentsTest}) should return {expectedPredicateResult}" + + @pytest.mark.parametrize("namespaceObjectTest,identifierAttributeTest", [ + ("objectPrimary", "methodEastward"), + ("objectSecondary", "valueNorthward"), + ("classTertiary", "nameWestward"), + ]) + def testIsAttributeNamespaceIdentifierPositiveCases(self, namespaceObjectTest: str, identifierAttributeTest: str) -> None: + """Test isAttributeNamespaceIdentifier with matching cases using semantic identifiers.""" + nodeAttribute = Make.Attribute(Make.Name(namespaceObjectTest), identifierAttributeTest) + predicateGenerated = IfThis.isAttributeNamespaceIdentifier(namespaceObjectTest, identifierAttributeTest) + assert predicateGenerated(nodeAttribute) is True + + def testIsIfUnaryNotAttributeNamespaceIdentifierPositiveCase(self) -> None: + """Test isIfUnaryNotAttributeNamespaceIdentifier with matching case.""" + nodeIf = Make.If( + test=Make.UnaryOp( + op=Make.Not(), + operand=Make.Attribute(Make.Name("objectTarget"), "flagEnabled") + ), + body=[Make.Pass()] + ) + predicateGenerated = IfThis.isIfUnaryNotAttributeNamespaceIdentifier("objectTarget", "flagEnabled") + assert predicateGenerated(nodeIf) is True + + def testIsIfUnaryNotAttributeNamespaceIdentifierNegativeCase(self) -> None: + """Test isIfUnaryNotAttributeNamespaceIdentifier with non-matching case.""" + nodeIf = Make.If(test=Make.Name("conditionAlternate"), body=[Make.Pass()]) + predicateGenerated = IfThis.isIfUnaryNotAttributeNamespaceIdentifier("objectTarget", "flagEnabled") + assert predicateGenerated(nodeIf) is False + +class TestIfThisLogicalCombinationMethods: + """Test suite for logical combination IfThis methods.""" + + @pytest.mark.parametrize("listPredicatesTest,nodeASTTest,expectedPredicateResult", [ + # All predicates match + ([Be.Name, lambda nodeTarget: hasattr(nodeTarget, 'id') and nodeTarget.id == "identifierNorthward"], Make.Name("identifierNorthward"), True), + # Some predicates don't match + ([Be.Name, lambda nodeTarget: hasattr(nodeTarget, 'id') and nodeTarget.id == "identifierSouthward"], Make.Name("identifierNorthward"), False), + ([], Make.Name("identifierNorthward"), True), # Empty predicates list - all() returns True for empty sequence + ]) + def testIsAllOfWithVariousPredicateCombinations(self, listPredicatesTest: list[Callable[..., Any]], nodeASTTest: ast.AST, expectedPredicateResult: bool) -> None: + """Test isAllOf with various predicate combinations using semantic identifiers.""" + predicateCombined = IfThis.isAllOf(*listPredicatesTest) + assert predicateCombined(nodeASTTest) is expectedPredicateResult + + @pytest.mark.parametrize("listPredicatesTest,nodeASTTest,expectedPredicateResult", [ + # At least one predicate matches + ([Be.Constant, Be.Name], Make.Name("identifierNorthward"), True), + # No predicates match + ([Be.Constant, Be.FunctionDef], Make.Name("identifierNorthward"), False), + ([], Make.Name("identifierNorthward"), False), # Empty predicates list - any() returns False for empty sequence + ]) + def testIsAnyOfWithVariousPredicateCombinations(self, listPredicatesTest: list[Callable[..., Any]], nodeASTTest: ast.AST, expectedPredicateResult: bool) -> None: + """Test isAnyOf with various predicate combinations using semantic identifiers.""" + predicateCombined = IfThis.isAnyOf(*listPredicatesTest) + assert predicateCombined(nodeASTTest) is expectedPredicateResult + +class TestIfThisTreeAnalysisMethods: + """Test suite for tree analysis IfThis methods.""" + + def testMatchesNoDescendantPositiveCase(self) -> None: + """Test matchesNoDescendant when no descendant matches predicate.""" + nodeAssignTarget = Make.Assign( + targets=[Make.Name("variableAlpha", context=Make.Store())], + value=Make.Constant(233) # Fibonacci number + ) + def predicateNameMatching(nodeTarget: ast.AST) -> bool: + return Be.Name(nodeTarget) and getattr(nodeTarget, 'id', None) == "variableBeta" + predicateGenerated = IfThis.matchesNoDescendant(predicateNameMatching) + assert predicateGenerated(nodeAssignTarget) is True + + def testMatchesNoDescendantNegativeCase(self) -> None: + """Test matchesNoDescendant when a descendant matches predicate.""" + nodeAssignTarget = Make.Assign( + targets=[Make.Name("variableAlpha", context=Make.Store())], + value=Make.Constant(233) # Fibonacci number + ) + def predicateNameMatching(nodeTarget: ast.AST) -> bool: + return Be.Name(nodeTarget) and getattr(nodeTarget, 'id', None) == "variableAlpha" + predicateGenerated = IfThis.matchesNoDescendant(predicateNameMatching) + assert predicateGenerated(nodeAssignTarget) is False + + def testMatchesMeButNotAnyDescendantPositiveCase(self) -> None: + """Test matchesMeButNotAnyDescendant when node matches but descendants don't.""" + nodeAssignTarget = Make.Assign( + targets=[Make.Name("variableAlpha", context=Make.Store())], + value=Make.Constant(233) # Fibonacci number + ) + predicateAssignmentMatching = Be.Assign + predicateGenerated = IfThis.matchesMeButNotAnyDescendant(predicateAssignmentMatching) + assert predicateGenerated(nodeAssignTarget) is True + + def testMatchesMeButNotAnyDescendantNegativeCase(self) -> None: + """Test matchesMeButNotAnyDescendant when node doesn't match.""" + nodeNameTarget = Make.Name("variableAlpha") + predicateAssignmentMatching = Be.Assign + predicateGenerated = IfThis.matchesMeButNotAnyDescendant(predicateAssignmentMatching) + assert predicateGenerated(nodeNameTarget) is False + + @pytest.mark.parametrize("nodeFirst,nodeSecond,expectedPredicateResult", [ + (Make.Name("variableAlpha"), Make.Name("variableAlpha"), True), + (Make.Name("variableAlpha"), Make.Name("variableBeta"), False), + (Make.Constant(233), Make.Constant(233), True), # Fibonacci numbers + (Make.Constant(233), Make.Constant(89), False), # Different Fibonacci numbers + ]) + def testUnparseIsWithVariousNodeCombinations(self, nodeFirst: ast.AST, nodeSecond: ast.AST, expectedPredicateResult: bool) -> None: + """Test unparseIs with various node combinations using semantic identifiers and Fibonacci numbers.""" + predicateGenerated = IfThis.unparseIs(nodeFirst) + assert predicateGenerated(nodeSecond) is expectedPredicateResult + +class TestIfThisAdvancedUsageScenarios: + """Test suite for advanced IfThis usage scenarios.""" + + def testNestedIdentifierPatternsWithVariousNodeTypes(self) -> None: + """Test isNestedNameIdentifier with various node types.""" + identifierToTest = "variableTargetAlpha" + predicateGenerated = IfThis.isNestedNameIdentifier(identifierToTest) + + # Should match Name + nodeName = Make.Name(identifierToTest) + assert predicateGenerated(nodeName) is True + + # Should match Attribute with matching value + nodeAttributeMatching = Make.Attribute(Make.Name(identifierToTest), "methodSecondary") + assert predicateGenerated(nodeAttributeMatching) is True + + # Should not match Attribute with non-matching value + nodeAttributeNonMatching = Make.Attribute(Make.Name("variableTargetBeta"), "methodSecondary") + assert predicateGenerated(nodeAttributeNonMatching) is False + + def testIsAssignAndTargets0IsWithVariousTargetPredicates(self) -> None: + """Test isAssignAndTargets0Is with various target predicates.""" + nodeAssignTarget = Make.Assign( + targets=[Make.Name("variableGamma", context=Make.Store())], + value=Make.Constant(233) # Fibonacci number + ) + + # Matching target predicate + def predicateTargetMatching(nodeTarget: ast.AST) -> bool: + return Be.Name(nodeTarget) and getattr(nodeTarget, 'id', None) == "variableGamma" + predicateGenerated = IfThis.isAssignAndTargets0Is(predicateTargetMatching) + assert predicateGenerated(nodeAssignTarget) is True + + # Non-matching target predicate + def predicateTargetWrong(nodeTarget: ast.AST) -> bool: + return Be.Name(nodeTarget) and getattr(nodeTarget, 'id', None) == "variableDelta" + predicateWrong = IfThis.isAssignAndTargets0Is(predicateTargetWrong) + assert predicateWrong(nodeAssignTarget) is False + + # Wrong node type + nodeNameWrongType = Make.Name("variableGamma") + assert predicateGenerated(nodeNameWrongType) is False + + def testComplexPredicateCompositionWithRealWorldScenarios(self) -> None: + """Test complex predicate compositions with real-world scenarios.""" + # Create a function with assignment in body + nodeFunctionWithAssignment = Make.FunctionDef( + name="functionProcessor", + body=[Make.Assign( + targets=[Make.Name("variableResult", context=Make.Store())], + value=Make.Constant(233) # Fibonacci number + )] + ) + + # Complex predicate combining multiple conditions + predicateComplexCombination = IfThis.isAllOf( + Be.FunctionDef, + lambda nodeTarget: getattr(nodeTarget, 'name', None) == "functionProcessor", + lambda nodeTarget: len(getattr(nodeTarget, 'body', [])) > 0 + ) + assert predicateComplexCombination(nodeFunctionWithAssignment) is True + + # Should fail if any condition doesn't match + functionDifferentName = Make.FunctionDef(name="functionAlternate", body=[Make.Pass()]) + assert predicateComplexCombination(functionDifferentName) is False