diff --git a/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonFrontendTest.kt b/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonFrontendTest.kt index 5bcba20b44..e95489f9b4 100644 --- a/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonFrontendTest.kt +++ b/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonFrontendTest.kt @@ -1377,93 +1377,6 @@ class PythonFrontendTest : BaseTest() { assertEquals(2L, fStmtRhsThird.value) } - @Test - fun testFormattedValues() { - val topLevel = Path.of("src", "test", "resources", "python") - val tu = - analyzeAndGetFirstTU( - listOf(topLevel.resolve("datatypes.py").toFile()), - topLevel, - true - ) { - it.registerLanguage() - } - assertNotNull(tu) - val namespace = tu.namespaces.singleOrNull() - assertNotNull(namespace) - - // Test for g = f'Number: {42:.2f}' - val gStmt = namespace.statements[6] - assertIs(gStmt) - val gStmtRhs = gStmt.rhs.singleOrNull() - assertIs(gStmtRhs) - val gFormatCall = gStmtRhs.rhs - assertIs(gFormatCall) - assertEquals("format", gFormatCall.name.localName) - val gArguments = gFormatCall.arguments - assertEquals(2, gArguments.size) - assertIs>(gArguments[0]) - assertEquals(42.toLong(), gArguments[0].value.value) - assertIs>(gArguments[1]) - assertEquals(".2f", gArguments[1].value.value) - - // Test for h = f'Hexadecimal: {255:#x}' - val hStmt = namespace.statements[7] - assertIs(hStmt) - val hStmtRhs = hStmt.rhs.singleOrNull() - assertIs(hStmtRhs) - val hFormatCall = hStmtRhs.rhs - assertIs(hFormatCall) - assertEquals("format", hFormatCall.name.localName) - val hArguments = hFormatCall.arguments - assertEquals(2, hArguments.size) - assertIs>(hArguments[0]) - assertEquals(255L.toLong(), hArguments[0].value.value) - assertIs>(hArguments[1]) - assertEquals("#x", hArguments[1].value.value) - - // Test for i = f'String with conversion: {c!r}' - val iStmt = namespace.statements[8] - assertIs(iStmt) - val iStmtRhs = iStmt.rhs.singleOrNull() - assertIs(iStmtRhs) - val iConversionCall = iStmtRhs.rhs - assertIs(iConversionCall) - assertEquals("repr", iConversionCall.name.localName) - val iArg = iConversionCall.arguments.singleOrNull() - assertNotNull(iArg) - assertEquals("c", iArg.name.localName) - - // Test for j = f'ASCII representation: {d!a}' - val jStmt = namespace.statements[9] - assertIs(jStmt) - val jStmtRhs = jStmt.rhs.singleOrNull() - assertIs(jStmtRhs) - val jConversionCall = jStmtRhs.rhs - assertIs(jConversionCall) - assertEquals("ascii", jConversionCall.name.localName) - val jArg = jConversionCall.arguments.singleOrNull() - assertNotNull(jArg) - assertEquals("d", jArg.name.localName) - - // Test for k = f'Combined: {b!s:10}' - val kStmt = namespace.statements[10] - assertIs(kStmt) - val kStmtRhs = kStmt.rhs.singleOrNull() - assertIs(kStmtRhs) - val kFormatCall = kStmtRhs.rhs - assertIs(kFormatCall) - assertEquals("format", kFormatCall.name.localName) - val kArguments = kFormatCall.arguments - assertEquals(2, kArguments.size) - val kConversionCall = kArguments[0] - assertIs(kConversionCall) - assertEquals("str", kConversionCall.name.localName) - assertEquals("b", kConversionCall.arguments.singleOrNull()?.name?.localName) - assertIs>(kArguments[1]) - assertEquals("10", kArguments[1].value.value) - } - @Test fun testSimpleImport() { val topLevel = Path.of("src", "test", "resources", "python") diff --git a/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/expressionHandler/FormattedValueHandlerTest.kt b/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/expressionHandler/FormattedValueHandlerTest.kt index 694b13dd3e..8efa19a88e 100644 --- a/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/expressionHandler/FormattedValueHandlerTest.kt +++ b/cpg-language-python/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/python/expressionHandler/FormattedValueHandlerTest.kt @@ -25,4 +25,124 @@ */ package de.fraunhofer.aisec.cpg.frontends.python.expressionHandler -class FormattedValueHandlerTest {} +import de.fraunhofer.aisec.cpg.frontends.python.PythonLanguage +import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.statements.expressions.AssignExpression +import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression +import de.fraunhofer.aisec.cpg.graph.statements.expressions.Literal +import de.fraunhofer.aisec.cpg.graph.variables +import de.fraunhofer.aisec.cpg.test.analyzeAndGetFirstTU +import de.fraunhofer.aisec.cpg.test.assertLiteralValue +import de.fraunhofer.aisec.cpg.test.assertLocalName +import java.nio.file.Path +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNotNull +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class FormattedValueHandlerTest { + + private lateinit var topLevel: Path + private lateinit var result: TranslationUnitDeclaration + + @BeforeAll + fun setup() { + topLevel = Path.of("src", "test", "resources", "python") + analyzeFile() + } + + fun analyzeFile() { + result = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("formatted_values.py").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + assertNotNull(result) + } + + @Test + fun testFormattedValues() { + // Test for a = f'Number: {42:.2f}' + val aAssExpression = + result.variables.find { variable -> variable.name.localName == "a" }?.astParent + assertIs(aAssExpression) + val aExprRhs = aAssExpression.rhs.singleOrNull() + assertIs(aExprRhs) + val aFormatCall = aExprRhs.rhs + assertIs(aFormatCall) + assertLocalName("format", aFormatCall) + val aArguments = aFormatCall.arguments + assertEquals(2, aArguments.size) + assertIs>(aArguments[0]) + assertLiteralValue(42.toLong(), aArguments[0]) + assertIs>(aArguments[1]) + assertLiteralValue(".2f", aArguments[1]) + + // Test for b = f'Hexadecimal: {255:#x}' + val bAssExpression = + result.variables.find { variable -> variable.name.localName == "b" }?.astParent + assertIs(bAssExpression) + val bExprRhs = bAssExpression.rhs.singleOrNull() + assertIs(bExprRhs) + val bFormatCall = bExprRhs.rhs + assertIs(bFormatCall) + assertLocalName("format", bFormatCall) + val bArguments = bFormatCall.arguments + assertEquals(2, bArguments.size) + assertIs>(bArguments[0]) + assertLiteralValue(255L.toLong(), bArguments[0]) + assertIs>(bArguments[1]) + assertLiteralValue("#x", bArguments[1]) + + // Test for c = f'String with conversion: {"Hello, world!"!r}' + val cAssExpression = + result.variables.find { variable -> variable.name.localName == "c" }?.astParent + assertIs(cAssExpression) + val cExprRhs = cAssExpression.rhs.singleOrNull() + assertIs(cExprRhs) + val cConversionCall = cExprRhs.rhs + assertIs(cConversionCall) + assertLocalName("repr", cConversionCall) + val cArguments = cConversionCall.arguments.singleOrNull() + assertNotNull(cArguments) + assertLocalName("c", cArguments) + + // Test for d = f'ASCII representation: {"50$"!a}' + val dAssExpression = + result.variables.find { variable -> variable.name.localName == "d" }?.astParent + assertIs(dAssExpression) + val dExprRhs = dAssExpression.rhs.singleOrNull() + assertIs(dExprRhs) + val dConversionCall = dExprRhs.rhs + assertIs(dConversionCall) + assertLocalName("ascii", dConversionCall) + val dArguments = dConversionCall.arguments.singleOrNull() + assertNotNull(dArguments) + assertLocalName("d", dArguments) + + // Test for e = f'Combined: {42!s:10}' + val eAssExpression = + result.variables.find { variable -> variable.name.localName == "e" }?.astParent + assertIs(eAssExpression) + val eExprRhs = eAssExpression.rhs.singleOrNull() + assertIs(eExprRhs) + val eFormatCall = eExprRhs.rhs + assertIs(eFormatCall) + assertLocalName("format", eFormatCall) + val eArguments = eFormatCall.arguments + assertEquals(2, eArguments.size) + val kConversionCall = eArguments[0] + assertIs(kConversionCall) + assertLocalName("str", kConversionCall) + assertLocalName("b", kConversionCall.arguments.singleOrNull()) + assertIs>(eArguments[1]) + assertLiteralValue("10", eArguments[1]) + } +} diff --git a/cpg-language-python/src/test/resources/python/datatypes.py b/cpg-language-python/src/test/resources/python/datatypes.py index c84c162db7..9ad09dcef6 100644 --- a/cpg-language-python/src/test/resources/python/datatypes.py +++ b/cpg-language-python/src/test/resources/python/datatypes.py @@ -9,8 +9,3 @@ e = f'Values of a: {a} and b: {b!s}' f = a[1:3:2] -g = f'Number: {42:.2f}' -h = f'Hexadecimal: {255:#x}' -i = f'String with conversion: {c!r}' -j = f'ASCII representation: {d!a}' -k = f'Combined: {b!s:10}' \ No newline at end of file diff --git a/cpg-language-python/src/test/resources/python/formatted_values.py b/cpg-language-python/src/test/resources/python/formatted_values.py index e69de29bb2..1efd3bc4dc 100644 --- a/cpg-language-python/src/test/resources/python/formatted_values.py +++ b/cpg-language-python/src/test/resources/python/formatted_values.py @@ -0,0 +1,5 @@ +a = f'Number: {42:.2f}' +b = f'Hexadecimal: {255:#x}' +c = f'String with conversion: {"Hello, world!"!r}' +d = f'ASCII representation: {"50$"!a}' +e = f'Combined: {42!s:10}' \ No newline at end of file