From 6a5208953d0627256b58f560288b617f8118e7fe Mon Sep 17 00:00:00 2001 From: Philip Garrett Date: Sun, 26 Jan 2025 19:27:39 -0300 Subject: [PATCH 1/3] Implementing hard limit for test case name length, default 80 chars --- .../kotlin/org/evomaster/core/EMConfig.kt | 3 + .../naming/ActionTestCaseNamingStrategy.kt | 45 ++++++++--- .../core/output/naming/AmbiguitySolver.kt | 3 +- .../GraphQLActionTestCaseNamingStrategy.kt | 21 +++--- .../naming/NumberedTestCaseNamingStrategy.kt | 7 +- .../naming/RPCActionTestCaseNamingStrategy.kt | 26 ++++--- .../naming/TestCaseNamingStrategyFactory.kt | 9 ++- .../output/naming/rest/PathAmbiguitySolver.kt | 14 +++- .../naming/rest/QueryParamsAmbiguitySolver.kt | 72 +++++++++++++----- .../rest/RestActionTestCaseNamingStrategy.kt | 26 ++++--- .../naming/GraphQLActionNamingStrategyTest.kt | 25 +++---- .../naming/RPCActionNamingStrategyTest.kt | 18 +++-- .../naming/RestActionNamingStrategyTest.kt | 74 +++++++++---------- .../naming/TestCaseDisambiguationTest.kt | 70 +++++++++--------- docs/options.md | 1 + 15 files changed, 245 insertions(+), 169 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/EMConfig.kt b/core/src/main/kotlin/org/evomaster/core/EMConfig.kt index c64cbb2e37..39771d005e 100644 --- a/core/src/main/kotlin/org/evomaster/core/EMConfig.kt +++ b/core/src/main/kotlin/org/evomaster/core/EMConfig.kt @@ -2430,6 +2430,9 @@ class EMConfig { @Cfg("Specify the naming strategy for test cases.") var namingStrategy = defaultTestCaseNamingStrategy + @Cfg("Specify the hard limit for test case name length") + var maxTestCaseNameLength = 80 + @Experimental @Cfg("Specify if true boolean query parameters are included in the test case name." + " Used for test case naming disambiguation. Only valid for Action based naming strategy.") diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt index 7102306d9f..b3817ecf40 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt @@ -14,6 +14,8 @@ import org.evomaster.core.sql.SqlAction abstract class ActionTestCaseNamingStrategy( solution: Solution<*>, private val languageConventionFormatter: LanguageConventionFormatter, + protected val maxTestCaseNameLength: Int, + private val testCasesSize: Int = solution.individuals.size, ) : NumberedTestCaseNamingStrategy(solution) { protected val on = "on" @@ -45,17 +47,42 @@ abstract class ActionTestCaseNamingStrategy( return faults.first().testCaseLabel } - protected fun addResult(individual: EvaluatedIndividual<*>, nameTokens: MutableList) { + protected fun addResult(individual: EvaluatedIndividual<*>, nameTokens: MutableList, remainingNameChars: Int) { val detectedFaults = DetectedFaultUtils.getDetectedFaultCategories(individual) - if (detectedFaults.isNotEmpty()) { - nameTokens.add(fault(detectedFaults)) + val newRemainingNameChars = if (detectedFaults.isNotEmpty()) { + addNameTokenIfAllowed(nameTokens, fault(detectedFaults), remainingNameChars) } else { - addActionResult(individual.evaluatedMainActions().last(), nameTokens) + addActionResult(individual.evaluatedMainActions().last(), nameTokens, remainingNameChars) } - addEnvironmentActions(individual, nameTokens) + addEnvironmentActions(individual, nameTokens, newRemainingNameChars) } - private fun addEnvironmentActions(individual: EvaluatedIndividual<*>, nameTokens: MutableList) { + protected fun namePrefixChars(): Int { + return "test_".length + testCasesSize + 1 + } + + protected fun addNameTokensIfAllowed(nameTokens: MutableList, targetStrings: List, remainingNameChars: Int): Int { + val charsToBeUsed = targetStrings.sumOf { it.length } + if ((remainingNameChars - charsToBeUsed) >= 0) { + nameTokens.addAll(targetStrings) + return remainingNameChars - charsToBeUsed + } + return remainingNameChars + } + + protected fun addNameTokenIfAllowed(nameTokens: MutableList, targetString: String, remainingNameChars: Int): Int { + if (canAddNameTokens(targetString, remainingNameChars)) { + nameTokens.add(targetString) + return remainingNameChars - targetString.length + } + return remainingNameChars + } + + private fun canAddNameTokens(targetString: String, remainingNameChars: Int): Boolean { + return (remainingNameChars - targetString.length) >= 0 + } + + private fun addEnvironmentActions(individual: EvaluatedIndividual<*>, nameTokens: MutableList, remainingNameChars: Int) { val initializingActions = individual.individual.seeInitializingActions() val allActions = individual.individual.seeAllActions() @@ -65,8 +92,8 @@ abstract class ActionTestCaseNamingStrategy( if (usesWireMock(allActions)) initActionNames.add(wiremock) if (initActionNames.isNotEmpty()) { - nameTokens.add(using) - nameTokens.addAll(initActionNames) + initActionNames.add(0, using) + addNameTokensIfAllowed(nameTokens, initActionNames, remainingNameChars) } } @@ -82,6 +109,6 @@ abstract class ActionTestCaseNamingStrategy( return actions.any { it is HttpExternalServiceAction } } - protected abstract fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList) + protected abstract fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList, remainingNameChars: Int): Int } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/AmbiguitySolver.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/AmbiguitySolver.kt index 0f3e151406..8074a4bea8 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/AmbiguitySolver.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/AmbiguitySolver.kt @@ -6,9 +6,10 @@ interface AmbiguitySolver { /** * @param action providing information to disambiguate the test case name + * @param remainingNameChars to decide if a token is added to the name or not * * @return list of strings to be added to the test case name */ - fun apply(action: Action): List + fun apply(action: Action, remainingNameChars: Int): List } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/GraphQLActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/GraphQLActionTestCaseNamingStrategy.kt index e24750c4e4..eb26482183 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/GraphQLActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/GraphQLActionTestCaseNamingStrategy.kt @@ -1,6 +1,6 @@ package org.evomaster.core.output.naming -import org.evomaster.core.output.TestWriterUtils +import org.evomaster.core.output.TestWriterUtils.safeVariableName import org.evomaster.core.problem.graphql.GraphQLAction import org.evomaster.core.problem.graphql.GraphQlCallResult import org.evomaster.core.search.EvaluatedIndividual @@ -9,18 +9,18 @@ import org.evomaster.core.search.action.EvaluatedAction open class GraphQLActionTestCaseNamingStrategy( solution: Solution<*>, - languageConventionFormatter: LanguageConventionFormatter -) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter) { + languageConventionFormatter: LanguageConventionFormatter, + maxTestCaseNameLength: Int, +) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter, maxTestCaseNameLength) { override fun expandName(individual: EvaluatedIndividual<*>, nameTokens: MutableList, ambiguitySolvers: List): String { val evaluatedAction = individual.evaluatedMainActions().last() val action = evaluatedAction.action as GraphQLAction + var remainingNameChars = maxTestCaseNameLength - namePrefixChars() - nameTokens.add(action.methodType.toString().lowercase()) - nameTokens.add(on) - nameTokens.add(TestWriterUtils.safeVariableName(action.methodName)) - addResult(individual, nameTokens) + remainingNameChars = addNameTokensIfAllowed(nameTokens, listOf(action.methodType.toString().lowercase(), on, safeVariableName(action.methodName)), remainingNameChars) + addResult(individual, nameTokens, remainingNameChars) return formatName(nameTokens) } @@ -30,16 +30,17 @@ open class GraphQLActionTestCaseNamingStrategy( return emptyMap() } - override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList) { + override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList, remainingNameChars: Int): Int { val result = evaluatedAction.result as GraphQlCallResult - nameTokens.add(returns) - nameTokens.add( + val candidateTokens = mutableListOf(returns) + candidateTokens.add( when { result.hasErrors() -> error result.hasNonEmptyData() -> data else -> empty } ) + return addNameTokensIfAllowed(nameTokens, candidateTokens, remainingNameChars) } } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt index a325e6b9a4..22f47fdd25 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt @@ -6,7 +6,7 @@ import org.evomaster.core.search.Solution import java.util.Collections.singletonList open class NumberedTestCaseNamingStrategy( - solution: Solution<*> + solution: Solution<*>, ) : TestCaseNamingStrategy(solution) { override fun getTestCases(): List { @@ -37,11 +37,6 @@ open class NumberedTestCaseNamingStrategy( return emptyMap() } - // kicking off with an empty mutableListOf for each test case to accumulate their own name tokens - private fun getName(counter: Int, individual: EvaluatedIndividual<*>): String { - return "test_${counter}${expandName(individual, mutableListOf())}" - } - private fun concatName(counter: Int, expandedName: String): String { return "test_${counter}${expandedName}" } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/RPCActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/RPCActionTestCaseNamingStrategy.kt index 9d4c5989ee..64b2b04f65 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/RPCActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/RPCActionTestCaseNamingStrategy.kt @@ -1,6 +1,6 @@ package org.evomaster.core.output.naming -import org.evomaster.core.output.TestWriterUtils +import org.evomaster.core.output.TestWriterUtils.safeVariableName import org.evomaster.core.problem.rpc.RPCCallAction import org.evomaster.core.problem.rpc.RPCCallResult import org.evomaster.core.search.EvaluatedIndividual @@ -10,17 +10,17 @@ import org.evomaster.core.utils.StringUtils open class RPCActionTestCaseNamingStrategy( solution: Solution<*>, - languageConventionFormatter: LanguageConventionFormatter -) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter) { + languageConventionFormatter: LanguageConventionFormatter, + maxTestCaseNameLength: Int, +) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter, maxTestCaseNameLength) { override fun expandName(individual: EvaluatedIndividual<*>, nameTokens: MutableList, ambiguitySolvers: List): String { val evaluatedAction = individual.evaluatedMainActions().last() val action = evaluatedAction.action as RPCCallAction + var remainingNameChars = maxTestCaseNameLength - namePrefixChars() - nameTokens.add(TestWriterUtils.safeVariableName(action.getSimpleClassName())) - nameTokens.add(on) - nameTokens.add(TestWriterUtils.safeVariableName(action.getExecutedFunctionName())) - addResult(individual, nameTokens) + remainingNameChars = addNameTokensIfAllowed(nameTokens, listOf(safeVariableName(action.getSimpleClassName()), on, safeVariableName(action.getExecutedFunctionName())), remainingNameChars) + addResult(individual, nameTokens, remainingNameChars) return formatName(nameTokens) } @@ -30,18 +30,20 @@ open class RPCActionTestCaseNamingStrategy( return emptyMap() } - override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList) { + override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList, remainingNameChars: Int): Int { val result = evaluatedAction.result as RPCCallResult if (result.hasPotentialFault()) { - nameTokens.add(throws) + val candidateTokens = mutableListOf(throws) val thrownException = StringUtils.extractSimpleClass(result.getExceptionTypeName()?: "") - nameTokens.add(TestWriterUtils.safeVariableName(thrownException)) + candidateTokens.add(safeVariableName(thrownException)) + return addNameTokensIfAllowed(nameTokens, candidateTokens, remainingNameChars) } else { - nameTokens.add(returns) - nameTokens.add(when { + val candidateTokens = mutableListOf(returns) + candidateTokens.add(when { result.failedCall() -> error else -> success }) + return addNameTokensIfAllowed(nameTokens, candidateTokens, remainingNameChars) } } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/TestCaseNamingStrategyFactory.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/TestCaseNamingStrategyFactory.kt index 03b7b92505..e048cdddd1 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/TestCaseNamingStrategyFactory.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/TestCaseNamingStrategyFactory.kt @@ -14,9 +14,10 @@ class TestCaseNamingStrategyFactory( private val namingStrategy: NamingStrategy, private val languageConventionFormatter: LanguageConventionFormatter, private val nameWithQueryParameters: Boolean, + private val maxTestCaseNameLength: Int ) { - constructor(config: EMConfig): this(config.namingStrategy, LanguageConventionFormatter(config.outputFormat), config.nameWithQueryParameters) + constructor(config: EMConfig): this(config.namingStrategy, LanguageConventionFormatter(config.outputFormat), config.nameWithQueryParameters, config.maxTestCaseNameLength) companion object { private val log: Logger = LoggerFactory.getLogger(TestCaseNamingStrategyFactory::class.java) @@ -33,9 +34,9 @@ class TestCaseNamingStrategyFactory( private fun actionBasedNamingStrategy(solution: Solution<*>): NumberedTestCaseNamingStrategy { val individuals = solution.individuals return when { - individuals.any { it.individual is RestIndividual } -> return RestActionTestCaseNamingStrategy(solution, languageConventionFormatter, nameWithQueryParameters) - individuals.any { it.individual is GraphQLIndividual } -> return GraphQLActionTestCaseNamingStrategy(solution, languageConventionFormatter) - individuals.any { it.individual is RPCIndividual } -> return RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter) + individuals.any { it.individual is RestIndividual } -> return RestActionTestCaseNamingStrategy(solution, languageConventionFormatter, nameWithQueryParameters, maxTestCaseNameLength) + individuals.any { it.individual is GraphQLIndividual } -> return GraphQLActionTestCaseNamingStrategy(solution, languageConventionFormatter, maxTestCaseNameLength) + individuals.any { it.individual is RPCIndividual } -> return RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter, maxTestCaseNameLength) individuals.any { it.individual is WebIndividual } -> { log.warn("Web individuals do not have action based test case naming yet. Defaulting to Numbered strategy.") return NamingHelperNumberedTestCaseNamingStrategy(solution) diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/PathAmbiguitySolver.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/PathAmbiguitySolver.kt index 5db6efec03..baeab50dc2 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/PathAmbiguitySolver.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/PathAmbiguitySolver.kt @@ -14,14 +14,18 @@ class PathAmbiguitySolver : AmbiguitySolver { * Example: /products/{productName}/configurations/{configurationName}/features/{featureName} * must now include the name qualifier for configurations */ - override fun apply(action: Action): List { + override fun apply(action: Action, remainingNameChars: Int): List { val restAction = action as RestCallAction val lastPath = restAction.path - var parentPath = restAction.path.parentPath() + val lastPathQualifier = getPath(lastPath.nameQualifier) + + var parentPath = lastPath.parentPath() if (lastPath.isLastElementAParameter()) { parentPath = parentPath.parentPath() } - return listOf(getParentPathQualifier(parentPath), getPath(restAction.path.nameQualifier)) + val candidateTokens = listOf(getParentPathQualifier(parentPath), lastPathQualifier) + + return if (canAddNameTokens(candidateTokens, remainingNameChars)) candidateTokens else listOf(lastPathQualifier) } /* @@ -33,4 +37,8 @@ class PathAmbiguitySolver : AmbiguitySolver { return if (parentPathQualifier == "/") "" else getPath(parentPathQualifier) } + private fun canAddNameTokens(targetString: List, remainingNameChars: Int): Boolean { + return (remainingNameChars - targetString.sumOf { it.length }) >= 0 + } + } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/QueryParamsAmbiguitySolver.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/QueryParamsAmbiguitySolver.kt index c1145e337c..37ad07b286 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/QueryParamsAmbiguitySolver.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/QueryParamsAmbiguitySolver.kt @@ -20,45 +20,70 @@ class QueryParamsAmbiguitySolver(private val nameWithQueryParameters: Boolean) : /* * If there are more than one query parameters, then use plural. */ - override fun apply(action: Action): List { + override fun apply(action: Action, remainingNameChars: Int): List { val restAction = action as RestCallAction val result = mutableListOf() val queryParams = restAction.path.getOnlyUsableQueries(restAction.parameters) .filter { it.getGeneForQuery().staticCheckIfImpactPhenotype() } - result.add(with) - result.add(if (queryParams.size > 1) "${queryParam}s" else queryParam) - if (nameWithQueryParameters) { - addQueryParameterNames(queryParams, result) + val withTokens = listOf(with, if (queryParams.size > 1) "${queryParam}s" else queryParam) + + if (canAddNameTokens(withTokens, remainingNameChars)) { + result.addAll(withTokens) + if (nameWithQueryParameters) { + val localCharsBudget = remainingNameChars - withTokens.sumOf { it.length } + addQueryParameterNames(queryParams, result, localCharsBudget) + } } return result } - private fun addQueryParameterNames(queryParams: List, result: MutableList) { + private fun addQueryParameterNames(queryParams: List, result: MutableList, remainingNameChars: Int) { + var localCharsBudget = addBooleanQueryParams(queryParams, result, remainingNameChars) + localCharsBudget = addNegativeNumbersQueryParams(queryParams, result, localCharsBudget) + addEmptyStringQueryParams(queryParams, result, localCharsBudget) + } + + private fun addBooleanQueryParams(queryParams: List, result: MutableList, remainingNameChars: Int): Int { val booleanQueryParams = getBooleanQueryParams(queryParams) + var localCharsBudget = remainingNameChars booleanQueryParams.forEachIndexed { index, queryParam -> - result.add(queryParam.name) - if (index != booleanQueryParams.lastIndex) { - result.add(and) + val localTokens = mutableListOf() + if (index != 0) { + localTokens.add(and) } + localTokens.add(queryParam.name) + localCharsBudget = addNameTokensIfAllowed(result, localTokens, localCharsBudget) } + return localCharsBudget + } + private fun addNegativeNumbersQueryParams(queryParams: List, result: MutableList, remainingNameChars: Int): Int { val numberQueryParams = getNegativeNumberQueryParams(queryParams) + var localCharsBudget = remainingNameChars numberQueryParams.forEachIndexed { index, queryParam -> - result.add(negative) - result.add(queryParam.name) - if (index != numberQueryParams.lastIndex) { - result.add(and) + val localTokens = mutableListOf() + if (index != 0) { + localTokens.add(and) } + localTokens.add(negative) + localTokens.add(queryParam.name) + localCharsBudget = addNameTokensIfAllowed(result, localTokens, localCharsBudget) } + return localCharsBudget + } + private fun addEmptyStringQueryParams(queryParams: List, result: MutableList, remainingNameChars: Int) { val emptyStringQueryParams = getEmptyStringQueryParams(queryParams) + var localCharsBudget = remainingNameChars emptyStringQueryParams.forEachIndexed { index, queryParam -> - result.add(empty) - result.add(queryParam.name) - if (index != emptyStringQueryParams.lastIndex) { - result.add(and) + val localTokens = mutableListOf() + if (index != 0) { + localTokens.add(and) } + localTokens.add(empty) + localTokens.add(queryParam.name) + localCharsBudget = addNameTokensIfAllowed(result, localTokens, localCharsBudget) } } @@ -82,4 +107,17 @@ class QueryParamsAmbiguitySolver(private val nameWithQueryParameters: Boolean) : stringGene != null && stringGene.staticCheckIfImpactPhenotype() && stringGene.getValueAsRawString().trim().isEmpty() } } + + private fun addNameTokensIfAllowed(nameTokens: MutableList, targetStrings: List, remainingNameChars: Int): Int { + val charsToBeUsed = targetStrings.sumOf { it.length } + if ((remainingNameChars - charsToBeUsed) >= 0) { + nameTokens.addAll(targetStrings) + return remainingNameChars - charsToBeUsed + } + return remainingNameChars + } + + private fun canAddNameTokens(targetString: List, remainingNameChars: Int): Boolean { + return (remainingNameChars - targetString.sumOf { it.length }) >= 0 + } } diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/RestActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/RestActionTestCaseNamingStrategy.kt index 02739110aa..b2b341e9bc 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/rest/RestActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/rest/RestActionTestCaseNamingStrategy.kt @@ -16,34 +16,36 @@ open class RestActionTestCaseNamingStrategy( solution: Solution<*>, languageConventionFormatter: LanguageConventionFormatter, private val nameWithQueryParameters: Boolean, -) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter) { + maxTestCaseNameLength: Int, +) : ActionTestCaseNamingStrategy(solution, languageConventionFormatter, maxTestCaseNameLength) { override fun expandName(individual: EvaluatedIndividual<*>, nameTokens: MutableList, ambiguitySolvers: List): String { val evaluatedAction = individual.evaluatedMainActions().last() val action = evaluatedAction.action as RestCallAction + var remainingNameChars = maxTestCaseNameLength - namePrefixChars() - nameTokens.add(action.verb.toString().lowercase()) - nameTokens.add(on) + remainingNameChars = addNameTokensIfAllowed(nameTokens, listOf(action.verb.toString().lowercase(), on), remainingNameChars) if (ambiguitySolvers.isEmpty()) { - nameTokens.add(getPath(action.path.nameQualifier)) + remainingNameChars = addNameTokenIfAllowed(nameTokens, getPath(action.path.nameQualifier), remainingNameChars) } else { - // TODO: max chars check. Idea: if len(name) + len(resultTokens) + len(foreach:solverResult) <= MAX_CHARS ---> OK - // else keep only name + acceptedSolverResults + resultTokens - ambiguitySolvers.forEach { solver -> nameTokens.addAll(solver.apply(action)) } + ambiguitySolvers.forEach { solver -> + remainingNameChars = addNameTokensIfAllowed(nameTokens, solver.apply(action, remainingNameChars), remainingNameChars) + } } - addResult(individual, nameTokens) + addResult(individual, nameTokens, remainingNameChars) return formatName(nameTokens) } - override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList) { + override fun addActionResult(evaluatedAction: EvaluatedAction, nameTokens: MutableList, remainingNameChars: Int): Int { val result = evaluatedAction.result as RestCallResult - nameTokens.add(returns) + val candidateTokens = mutableListOf(returns) if (isGetCall(evaluatedAction) && result.getStatusCode() == 200) { - nameTokens.addAll(addBodyShape(result)) + candidateTokens.addAll(addBodyShape(result)) } else { - nameTokens.add(result.getStatusCode().toString()) + candidateTokens.add(result.getStatusCode().toString()) } + return addNameTokensIfAllowed(nameTokens, candidateTokens, remainingNameChars) } /** diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt index ba7f8077a3..9e717430a2 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt @@ -24,16 +24,19 @@ import java.util.Collections.singletonList class GraphQLActionNamingStrategyTest { + companion object { + val pythonFormatter = LanguageConventionFormatter(OutputFormat.PYTHON_UNITTEST) + const val MAX_NAME_LENGTH = 80 + } + @Test fun testMutationOnAddReturnsEmpty() { val eIndividual = getEvaluatedIndividualWith(GQMethodType.MUTATION) - val languageConventionFormatter = LanguageConventionFormatter(OutputFormat.PYTHON_UNITTEST) - val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, languageConventionFormatter) - + val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, pythonFormatter, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_mutation_on_add_returns_empty", testCases[0].name) } @@ -41,13 +44,11 @@ class GraphQLActionNamingStrategyTest { @Test fun testQueryOnAddReturnsData() { val eIndividual = getEvaluatedIndividualWith(GQMethodType.QUERY) - val languageConventionFormatter = LanguageConventionFormatter(OutputFormat.PYTHON_UNITTEST) - val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, languageConventionFormatter) - + val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, pythonFormatter, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_query_on_add_returns_empty", testCases[0].name) } @@ -55,13 +56,11 @@ class GraphQLActionNamingStrategyTest { @Test fun testQueryOnAddCausesInternalServerError() { val eIndividual = getEvaluatedIndividualWithFaults(GQMethodType.QUERY, singletonList(DetectedFault(FaultCategory.HTTP_STATUS_500, "items"))) - val languageConventionFormatter = LanguageConventionFormatter(OutputFormat.PYTHON_UNITTEST) - val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, languageConventionFormatter) - + val namingStrategy = GraphQLActionTestCaseNamingStrategy(solution, pythonFormatter, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_query_on_add_causes500_internalServerError", testCases[0].name) } @@ -85,6 +84,6 @@ class GraphQLActionNamingStrategyTest { val result = GraphQlCallResult(action.getLocalId()) faults.forEach { fault -> result.addFault(fault) } val results = listOf(result) - return EvaluatedIndividual(fitnessVal, individual, results) + return EvaluatedIndividual(fitnessVal, individual, results) } } diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt index dc1faa933a..637559fe80 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt @@ -14,28 +14,30 @@ import org.junit.jupiter.api.Test class RPCActionNamingStrategyTest { - @Test - fun testFakeRpcCallAsInterfaceIdAndId() { + companion object { val outputFormat = OutputFormat.KOTLIN_JUNIT_5 val languageConventionFormatter = LanguageConventionFormatter(outputFormat) - val solution = getSolution(outputFormat) + const val MAX_NAME_LENGTH = 80 + } - val namingStrategy = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter) + @Test + fun testFakeRpcCallAsInterfaceIdAndId() { + val solution = getSolution(outputFormat) + val namingStrategy = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_fakeRPCCallOnFunction_4ReturnsSuccess", testCases[0].name) } @Test fun testFakeRpcCallWithException() { - val outputFormat = OutputFormat.KOTLIN_JUNIT_5 - val languageConventionFormatter = LanguageConventionFormatter(outputFormat) val solution = getSolution(outputFormat, true) - val namingStrategy = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter) - + val namingStrategy = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_fakeRPCCallOnFunction_4ThrowsRuntimeException", testCases[0].name) } diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionNamingStrategyTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionNamingStrategyTest.kt index 30ba582ec0..aaabc9bfc1 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionNamingStrategyTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionNamingStrategyTest.kt @@ -22,18 +22,18 @@ open class RestActionNamingStrategyTest { val pythonFormatter = LanguageConventionFormatter(OutputFormat.PYTHON_UNITTEST) val javaFormatter = LanguageConventionFormatter(OutputFormat.JAVA_JUNIT_4) const val NO_QUERY_PARAMS_IN_NAME = false + const val MAX_NAME_LENGTH = 80 } @Test fun testGetOnRootPathIsIncludedInName() { val restAction = getRestCallAction("/") val eIndividual = getEvaluatedIndividualWith(restAction) - val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_root_returns_empty", testCases[0].name) } @@ -44,9 +44,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_empty", testCases[0].name) } @@ -60,9 +60,9 @@ open class RestActionNamingStrategyTest { val itemsIndividual = getEvaluatedIndividualWith(itemsAction) val solution = Solution(mutableListOf(rootIndividual, itemsIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_get_on_root_returns_empty", testCases[0].name) assertEquals("test_1_get_on_items_returns_empty", testCases[1].name) @@ -74,9 +74,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_item_returns_empty", testCases[0].name) } @@ -87,9 +87,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "", MediaType.TEXT_XML_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_content", testCases[0].name) } @@ -100,9 +100,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "[]", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_empty_list", testCases[0].name) } @@ -113,9 +113,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "[1]", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_1_element", testCases[0].name) } @@ -126,9 +126,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "[1,2,3]", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_3_elements", testCases[0].name) } @@ -139,9 +139,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "{}", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_empty_object", testCases[0].name) } @@ -152,9 +152,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "{\"key\": \"value\"}", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_returns_object", testCases[0].name) } @@ -165,9 +165,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 200, "\"myItem\"", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_item_returns_string", testCases[0].name) } @@ -178,9 +178,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 401, "[]", MediaType.APPLICATION_JSON_TYPE) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_item_returns_401", testCases[0].name) } @@ -191,9 +191,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWithFaults(restAction, singletonList(DetectedFault(FaultCategory.HTTP_STATUS_500, "items")), 500) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_causes500_internalServerError", testCases[0].name) } @@ -205,9 +205,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWithFaults(restAction, faults, 500) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, pythonFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_get_on_items_showsFaults_100_102_301", testCases[0].name) } @@ -218,9 +218,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, true) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_getOnItemsReturnsEmptyUsingSql", testCases[0].name) } @@ -231,9 +231,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, withMongo = true) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_getOnItemsReturnsEmptyUsingMongo", testCases[0].name) } @@ -244,9 +244,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, 201, withWireMock = true) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_putOnItemsReturns201UsingWireMock", testCases[0].name) } @@ -257,9 +257,9 @@ open class RestActionNamingStrategyTest { val eIndividual = getEvaluatedIndividualWith(restAction, withSql = true, withWireMock = true) val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(1, testCases.size) assertEquals("test_0_postOnItemsReturns200UsingSqlWireMock", testCases[0].name) } diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt index 8715246c33..7d199b2f6f 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt @@ -29,18 +29,18 @@ class TestCaseDisambiguationTest { val javaFormatter = LanguageConventionFormatter(OutputFormat.JAVA_JUNIT_4) const val NO_QUERY_PARAMS_IN_NAME = false const val QUERY_PARAMS_IN_NAME = true + const val MAX_NAME_LENGTH = 80 } @Test fun parentPathDisambiguation() { val funnyPathIndividual = getEvaluatedIndividualWith(getRestCallAction("/my/funny/path")) val funniestPathIndividual = getEvaluatedIndividualWith(getRestCallAction("/my/funniest/path")) - val solution = Solution(mutableListOf(funnyPathIndividual, funniestPathIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnFunnyPathReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnFunniestPathReturnsEmpty", testCases[1].name) @@ -51,13 +51,11 @@ class TestCaseDisambiguationTest { val languagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) val statisticsLanguagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/statistics/languages")) val syntaxLanguagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages")) - - val solution = Solution(mutableListOf(languagesIndividual, statisticsLanguagesIndividual, syntaxLanguagesIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(3, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnStatisticsLanguagesReturnsEmpty", testCases[1].name) @@ -69,13 +67,11 @@ class TestCaseDisambiguationTest { val languagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) val syntaxLanguagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages")) val syntaxLanguagesIndividual2 = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages")) - - val solution = Solution(mutableListOf(languagesIndividual, syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(3, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesReturnsEmpty", testCases[1].name) @@ -94,9 +90,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(configurationFeatureIndividual, productFeatureIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnConfigurFeaturReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnProductFeaturReturnsEmpty", testCases[1].name) @@ -110,9 +106,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividualWithQP), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnSyntaxLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamReturnsEmpty", testCases[1].name) @@ -127,9 +123,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividualWithQP), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnSyntaxLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamsReturnsEmpty", testCases[1].name) @@ -144,9 +140,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(languagesIndividual, syntaxLanguagesIndividual, syntaxLanguagesIndividualWithQP), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, NO_QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(3, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesReturnsEmpty", testCases[1].name) @@ -160,9 +156,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesReturnsEmpty", testCases[1].name) @@ -176,9 +172,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnSyntaxLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamMyQueryParamReturnsEmpty", testCases[1].name) @@ -192,9 +188,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnSyntaxLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamReturnsEmpty", testCases[1].name) @@ -210,9 +206,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnSyntaxLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamsFirstParamAndFourthParamReturnsEmpty", testCases[1].name) @@ -226,9 +222,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(simpleIndividual, negativeQPIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesWithQueryParamNegativeLimitReturnsEmpty", testCases[1].name) @@ -242,9 +238,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(simpleIndividual, emptyStringIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesWithQueryParamEmptyNameReturnsEmpty", testCases[1].name) @@ -259,9 +255,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(simpleIndividual, queryParamsIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesWithQueryParamsNegativeLimitEmptyNameReturnsEmpty", testCases[1].name) @@ -275,9 +271,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(simpleIndividual, negativeQPIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesWithQueryParamNegativeLimitReturnsEmpty", testCases[1].name) @@ -291,9 +287,9 @@ class TestCaseDisambiguationTest { val solution = Solution(mutableListOf(simpleIndividual, emptyQPIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) - val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME) - + val namingStrategy = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, MAX_NAME_LENGTH) val testCases = namingStrategy.getTestCases() + assertEquals(2, testCases.size) assertEquals("test_0_getOnLanguagesReturnsEmpty", testCases[0].name) assertEquals("test_1_getOnLanguagesWithQueryParamEmptyNameReturnsEmpty", testCases[1].name) diff --git a/docs/options.md b/docs/options.md index 28a299703c..650fe56046 100644 --- a/docs/options.md +++ b/docs/options.md @@ -148,6 +148,7 @@ There are 3 types of options: |`maxResponseByteSize`| __Int__. Maximum size (in bytes) that EM handles response payloads in the HTTP responses. If larger than that, a response will not be stored internally in EM during the test generation. This is needed to avoid running out of memory. *Default value*: `1000000`.| |`maxSearchSuiteSize`| __Int__. Define the maximum number of tests in a suite in the search algorithms that evolve whole suites, e.g. WTS. *Constraints*: `min=1.0`. *Default value*: `50`.| |`maxSqlInitActionsPerMissingData`| __Int__. When generating SQL data, how many new rows (max) to generate for each specific SQL Select. *Constraints*: `min=1.0`. *Default value*: `1`.| +|`maxTestCaseNameLength`| __Int__. Specify the hard limit for test case name length. *Default value*: `80`.| |`maxTestSize`| __Int__. Max number of 'actions' (e.g., RESTful calls or SQL commands) that can be done in a single test. *Constraints*: `min=1.0`. *Default value*: `10`.| |`maxTimeInSeconds`| __Int__. Maximum number of seconds allowed for the search. The more time is allowed, the better results one can expect. But then of course the test generation will take longer. Only applicable depending on the stopping criterion. If this value is 0, the setting 'maxTime' will be used instead. *Constraints*: `min=0.0`. *Default value*: `0`.| |`maxlengthOfHistoryForAGM`| __Int__. Specify a maximum length of history when applying archive-based gene mutation. *Default value*: `10`.| From 5b1227dff23d54dd7c9e45bb2e1f97df8d419e80 Mon Sep 17 00:00:00 2001 From: Philip Garrett Date: Mon, 27 Jan 2025 20:34:45 -0300 Subject: [PATCH 2/3] Added test case naming length tests --- .../naming/ActionTestCaseNamingStrategy.kt | 2 +- .../kotlin/org/evomaster/core/EMConfigTest.kt | 21 ++++ .../naming/GraphQLActionNamingStrategyTest.kt | 15 +++ .../naming/RPCActionNamingStrategyTest.kt | 13 ++ .../output/naming/RestActionTestCaseUtils.kt | 43 +++++++ .../naming/RestTestCaseNameLengthTest.kt | 117 ++++++++++++++++++ .../naming/TestCaseDisambiguationTest.kt | 52 +------- 7 files changed, 215 insertions(+), 48 deletions(-) create mode 100644 core/src/test/kotlin/org/evomaster/core/output/naming/RestTestCaseNameLengthTest.kt diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt index b3817ecf40..515c7d479e 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt @@ -31,7 +31,7 @@ abstract class ActionTestCaseNamingStrategy( protected val wiremock = "wireMock" protected fun formatName(nameTokens: List): String { - return "_${languageConventionFormatter.formatName(nameTokens)}" + return if (nameTokens.isNotEmpty()) "_${languageConventionFormatter.formatName(nameTokens)}" else "" } private fun fault(faults: Set): String { diff --git a/core/src/test/kotlin/org/evomaster/core/EMConfigTest.kt b/core/src/test/kotlin/org/evomaster/core/EMConfigTest.kt index 2018c4926c..64df5a1685 100644 --- a/core/src/test/kotlin/org/evomaster/core/EMConfigTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/EMConfigTest.kt @@ -641,4 +641,25 @@ internal class EMConfigTest{ assertFalse(config.nameWithQueryParameters) } + @Test + fun testMaxCharsLengthIs80ByDefault() { + val parser = EMConfig.getOptionParser() + val config = EMConfig() + + config.updateProperties(parser.parse()) + + assertEquals(config.maxTestCaseNameLength, 80) + } + + @Test + fun testMaxCharsLengthCanBeChangedByParam() { + val parser = EMConfig.getOptionParser() + val config = EMConfig() + + val options = parser.parse("--maxTestCaseNameLength", "30") + config.updateProperties(options) + + assertEquals(config.maxTestCaseNameLength, 30) + } + } diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt index 9e717430a2..f97c738f78 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/GraphQLActionNamingStrategyTest.kt @@ -65,6 +65,21 @@ class GraphQLActionNamingStrategyTest { assertEquals("test_0_query_on_add_causes500_internalServerError", testCases[0].name) } + @Test + fun testActionAndMethodNameAreAddedTogether() { + val eIndividual = getEvaluatedIndividualWithFaults(GQMethodType.QUERY, singletonList(DetectedFault(FaultCategory.HTTP_STATUS_500, "items"))) + val solution = Solution(singletonList(eIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val withActionAndMethodName = GraphQLActionTestCaseNamingStrategy(solution, pythonFormatter, 20).getTestCases() + val noActionAndMethodName = GraphQLActionTestCaseNamingStrategy(solution, pythonFormatter, 15).getTestCases() + + assertEquals(1, withActionAndMethodName.size) + assertEquals(1, noActionAndMethodName.size) + assertEquals(withActionAndMethodName[0].test, noActionAndMethodName[0].test) + assertEquals("test_0_query_on_add", withActionAndMethodName[0].name) + assertEquals("test_0", noActionAndMethodName[0].name) + } + private fun getEvaluatedIndividualWith(query: GQMethodType): EvaluatedIndividual { return getEvaluatedIndividualWithFaults(query, emptyList()) } diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt index 637559fe80..e6e5114853 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/RPCActionNamingStrategyTest.kt @@ -42,6 +42,19 @@ class RPCActionNamingStrategyTest { assertEquals("test_0_fakeRPCCallOnFunction_4ThrowsRuntimeException", testCases[0].name) } + @Test + fun testClassAndFunctionNamesAreAddedIfAllowedByLength() { + val solution = getSolution(outputFormat, true) + + val withClassAndFunctionName = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter, 30).getTestCases() + val noClassAndFunctionName = RPCActionTestCaseNamingStrategy(solution, languageConventionFormatter, 15).getTestCases() + + assertEquals(1, withClassAndFunctionName.size) + assertEquals(1, noClassAndFunctionName.size) + assertEquals("test_0_fakeRPCCallOnFunction_4", withClassAndFunctionName[0].name) + assertEquals("test_0", noClassAndFunctionName[0].name) + } + private fun getSolution(outputFormat: OutputFormat, throwsException: Boolean = false): Solution<*> { return Solution( mutableListOf(getEvaluatedIndividual(outputFormat, throwsException)), diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionTestCaseUtils.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionTestCaseUtils.kt index 2003c32fee..2170160c16 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionTestCaseUtils.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/RestActionTestCaseUtils.kt @@ -12,12 +12,20 @@ import org.evomaster.core.problem.externalservice.httpws.HttpExternalServiceInfo import org.evomaster.core.problem.externalservice.httpws.HttpExternalServiceRequest import org.evomaster.core.problem.externalservice.httpws.HttpWsExternalService import org.evomaster.core.problem.rest.* +import org.evomaster.core.problem.rest.param.PathParam +import org.evomaster.core.problem.rest.param.QueryParam import org.evomaster.core.problem.rest.resource.RestResourceCalls import org.evomaster.core.search.EvaluatedIndividual import org.evomaster.core.search.FitnessValue import org.evomaster.core.search.GroupsOfChildren import org.evomaster.core.search.action.ActionComponent import org.evomaster.core.search.action.ActionResult +import org.evomaster.core.search.gene.BooleanGene +import org.evomaster.core.search.gene.Gene +import org.evomaster.core.search.gene.numeric.IntegerGene +import org.evomaster.core.search.gene.optional.CustomMutationRateGene +import org.evomaster.core.search.gene.optional.OptionalGene +import org.evomaster.core.search.gene.string.StringGene import org.evomaster.core.search.service.Randomness import org.evomaster.core.search.tracer.Traceable import org.evomaster.core.sql.SqlAction @@ -103,6 +111,41 @@ object RestActionTestCaseUtils { return RestCallAction("1", verb, RestPath(path), parameters) } + fun getPathParam(paramName: String): Param { + return PathParam(paramName, CustomMutationRateGene(paramName, StringGene(paramName), 1.0)) + } + + fun getStringQueryParam(paramName: String, wrapped: Boolean = true): Param { + return getQueryParam(paramName, StringGene(paramName), wrapped) + } + + fun getBooleanQueryParam(paramName: String): Param { + return getQueryParam(paramName, BooleanGene(paramName)) + } + + fun getIntegerQueryParam(paramName: String, wrapped: Boolean = true): Param { + return getQueryParam(paramName, IntegerGene(paramName), wrapped) + } + + /* + Since the randomization used to construct the evaluated individuals might set a random boolean value, + we do this to ensure the one we want for unit testing + */ + fun ensureGeneValue(evaluatedIndividual: EvaluatedIndividual, paramName: String, paramValue: String) { + val restCallAction = evaluatedIndividual.evaluatedMainActions().last().action as RestCallAction + (restCallAction.parameters.filter { it.name == paramName }).forEach { + (it as QueryParam).getGeneForQuery().setFromStringValue(paramValue) + } + } + + private fun getQueryParam(paramName: String, gene: Gene, wrapped: Boolean = true): Param { + return QueryParam(paramName, if (wrapped) getWrappedGene(paramName, gene) else gene) + } + + private fun getWrappedGene(paramName: String, gene: Gene): OptionalGene { + return OptionalGene(paramName, gene) + } + private fun getRestCallResult(sourceLocalId: String, statusCode: Int, resultBodyString: String, bodyType: MediaType): RestCallResult { val restResult = RestCallResult(sourceLocalId) restResult.setStatusCode(statusCode) diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/RestTestCaseNameLengthTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/RestTestCaseNameLengthTest.kt new file mode 100644 index 0000000000..457c45723e --- /dev/null +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/RestTestCaseNameLengthTest.kt @@ -0,0 +1,117 @@ +package org.evomaster.core.output.naming + +import org.evomaster.core.output.OutputFormat +import org.evomaster.core.output.Termination +import org.evomaster.core.output.naming.RestActionTestCaseUtils.ensureGeneValue +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getBooleanQueryParam +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getEvaluatedIndividualWith +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getIntegerQueryParam +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getRestCallAction +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getStringQueryParam +import org.evomaster.core.output.naming.rest.RestActionTestCaseNamingStrategy +import org.evomaster.core.search.Solution +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import java.util.Collections.singletonList + +class RestTestCaseNameLengthTest { + + companion object { + val javaFormatter = LanguageConventionFormatter(OutputFormat.JAVA_JUNIT_4) + const val QUERY_PARAMS_IN_NAME = true + } + + @Test + fun simpleTestWithShortNameOnlyIncludesTestNumber() { + val simpleIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) + + val solution = Solution(mutableListOf(simpleIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val testCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 10).getTestCases() + + assertEquals(1, testCases.size) + assertEquals("test_0", testCases[0].name) + } + + @Test + fun pathIsFavouredInsteadOfResult() { + val simpleIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) + + val solution = Solution(mutableListOf(simpleIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val longTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 35).getTestCases() + val shortTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 30).getTestCases() + + assertEquals(1, longTestCases.size) + assertEquals(1, shortTestCases.size) + assertEquals(shortTestCases[0].test, longTestCases[0].test) + assertEquals("test_0_getOnLanguagesReturnsEmpty", longTestCases[0].name) + assertEquals("test_0_getOnLanguages", shortTestCases[0].name) + } + + @Test + fun pathAmbiguitySolverIsFavouredInsteadOfQueryParams() { + val syntaxLanguagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) + val syntaxLanguagesIndividualWithQP = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages", parameters = singletonList(getStringQueryParam("myQueryParam")))) + ensureGeneValue(syntaxLanguagesIndividualWithQP, "myQueryParam", "aStringValue") + + val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividualWithQP), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val longTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 80).getTestCases() + val shortTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 30).getTestCases() + + assertEquals(2, longTestCases.size) + assertEquals(2, shortTestCases.size) + assertEquals(shortTestCases[1].test, longTestCases[1].test) + assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamReturnsEmpty", longTestCases[1].name) + assertEquals("test_1_getOnSyntaxLanguages", shortTestCases[1].name) + } + + @Test + fun queryParamsDisambiguationRespectsBooleanNumberStringOrder() { + val syntaxLanguagesIndividual = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages")) + val syntaxLanguagesIndividual2 = getEvaluatedIndividualWith(getRestCallAction("/syntax/languages", parameters = mutableListOf(getBooleanQueryParam("firstParam"), getStringQueryParam("secondParam"), getIntegerQueryParam("thirdParam")))) + ensureGeneValue(syntaxLanguagesIndividual2, "firstParam", "true") + ensureGeneValue(syntaxLanguagesIndividual2, "secondParam", "") + ensureGeneValue(syntaxLanguagesIndividual2, "thirdParam", "-1") + + val solution = Solution(mutableListOf(syntaxLanguagesIndividual, syntaxLanguagesIndividual2), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val fullNames = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 100).getTestCases() + val noParamsNames = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 50).getTestCases() + val onlyBooleanNames = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 65).getTestCases() + val booleanAndIntegerNames = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 85).getTestCases() + + assertEquals(2, fullNames.size) + assertEquals(2, noParamsNames.size) + assertEquals(2, onlyBooleanNames.size) + assertEquals(2, booleanAndIntegerNames.size) + assertEquals(fullNames[1].test, noParamsNames[1].test) + assertEquals(fullNames[1].test, onlyBooleanNames[1].test) + assertEquals(fullNames[1].test, booleanAndIntegerNames[1].test) + assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamsFirstParamNegativeThirdParamEmptySecondParamReturnsEmpty", fullNames[1].name) + assertEquals("test_1_getOnSyntaxLanguagesWithQueryParams", noParamsNames[1].name) + assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamsFirstParamReturnsEmpty", onlyBooleanNames[1].name) + assertEquals("test_1_getOnSyntaxLanguagesWithQueryParamsFirstParamNegativeThirdParamReturnsEmpty", booleanAndIntegerNames[1].name) + } + + @Test + fun sameTestRespectsMaxCharsLength() { + val simpleIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages")) + val negativeQPIndividual = getEvaluatedIndividualWith(getRestCallAction("/languages", parameters = mutableListOf(getIntegerQueryParam("limit", false)))) + ensureGeneValue(negativeQPIndividual, "limit", "-1") + + val solution = Solution(mutableListOf(simpleIndividual, negativeQPIndividual), "suitePrefix", "suiteSuffix", Termination.NONE, emptyList(), emptyList()) + + val longTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 80).getTestCases() + val shortTestCases = RestActionTestCaseNamingStrategy(solution, javaFormatter, QUERY_PARAMS_IN_NAME, 40).getTestCases() + + assertEquals(2, longTestCases.size) + assertEquals(2, shortTestCases.size) + assertEquals(shortTestCases[1].test, longTestCases[1].test) + assertEquals("test_1_getOnLanguagesWithQueryParamNegativeLimitReturnsEmpty", longTestCases[1].name) + assertEquals("test_1_getOnLanguagesWithQueryParam", shortTestCases[1].name) + } + + +} diff --git a/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt b/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt index 7d199b2f6f..b48ff090ea 100644 --- a/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/output/naming/TestCaseDisambiguationTest.kt @@ -2,23 +2,16 @@ package org.evomaster.core.output.naming import org.evomaster.core.output.OutputFormat import org.evomaster.core.output.Termination +import org.evomaster.core.output.naming.RestActionTestCaseUtils.ensureGeneValue +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getBooleanQueryParam import org.evomaster.core.output.naming.RestActionTestCaseUtils.getEvaluatedIndividualWith +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getIntegerQueryParam +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getPathParam import org.evomaster.core.output.naming.RestActionTestCaseUtils.getRestCallAction +import org.evomaster.core.output.naming.RestActionTestCaseUtils.getStringQueryParam import org.evomaster.core.output.naming.rest.RestActionTestCaseNamingStrategy -import org.evomaster.core.problem.api.param.Param import org.evomaster.core.problem.rest.HttpVerb -import org.evomaster.core.problem.rest.RestCallAction -import org.evomaster.core.problem.rest.RestIndividual -import org.evomaster.core.problem.rest.param.PathParam -import org.evomaster.core.problem.rest.param.QueryParam -import org.evomaster.core.search.EvaluatedIndividual import org.evomaster.core.search.Solution -import org.evomaster.core.search.gene.BooleanGene -import org.evomaster.core.search.gene.Gene -import org.evomaster.core.search.gene.numeric.IntegerGene -import org.evomaster.core.search.gene.optional.CustomMutationRateGene -import org.evomaster.core.search.gene.optional.OptionalGene -import org.evomaster.core.search.gene.string.StringGene import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.util.Collections.singletonList @@ -295,39 +288,4 @@ class TestCaseDisambiguationTest { assertEquals("test_1_getOnLanguagesWithQueryParamEmptyNameReturnsEmpty", testCases[1].name) } - private fun getPathParam(paramName: String): Param { - return PathParam(paramName, CustomMutationRateGene(paramName, StringGene(paramName), 1.0)) - } - - private fun getStringQueryParam(paramName: String, wrapped: Boolean = true): Param { - return getQueryParam(paramName, StringGene(paramName), wrapped) - } - - private fun getBooleanQueryParam(paramName: String): Param { - return getQueryParam(paramName, BooleanGene(paramName)) - } - - private fun getIntegerQueryParam(paramName: String, wrapped: Boolean = true): Param { - return getQueryParam(paramName, IntegerGene(paramName), wrapped) - } - - private fun getQueryParam(paramName: String, gene: Gene, wrapped: Boolean = true): Param { - return QueryParam(paramName, if (wrapped) getWrappedGene(paramName, gene) else gene) - } - - private fun getWrappedGene(paramName: String, gene: Gene): OptionalGene { - return OptionalGene(paramName, gene) - } - - /* - Since the randomization used to construct the evaluated individuals might set a random boolean value, - we do this to ensure the one we want for unit testing - */ - private fun ensureGeneValue(evaluatedIndividual: EvaluatedIndividual, paramName: String, paramValue: String) { - val restCallAction = evaluatedIndividual.evaluatedMainActions().last().action as RestCallAction - (restCallAction.parameters.filter { it.name == paramName }).forEach { - (it as QueryParam).getGeneForQuery().setFromStringValue(paramValue) - } - } - } From c1723498b372bccbafa923bb138b78b2c7b48243 Mon Sep 17 00:00:00 2001 From: Pgarrett Date: Sun, 2 Feb 2025 10:32:26 -0300 Subject: [PATCH 3/3] Remove testCasesSize from constructor parameter --- .../core/output/naming/ActionTestCaseNamingStrategy.kt | 5 +++-- .../core/output/naming/NumberedTestCaseNamingStrategy.kt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt index 515c7d479e..c77a04630b 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/ActionTestCaseNamingStrategy.kt @@ -14,10 +14,11 @@ import org.evomaster.core.sql.SqlAction abstract class ActionTestCaseNamingStrategy( solution: Solution<*>, private val languageConventionFormatter: LanguageConventionFormatter, - protected val maxTestCaseNameLength: Int, - private val testCasesSize: Int = solution.individuals.size, + protected val maxTestCaseNameLength: Int ) : NumberedTestCaseNamingStrategy(solution) { + private val testCasesSize = solution.individuals.size + protected val on = "on" protected val throws = "throws" protected val returns = "returns" diff --git a/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt b/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt index 22f47fdd25..da35a4e105 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/naming/NumberedTestCaseNamingStrategy.kt @@ -6,7 +6,7 @@ import org.evomaster.core.search.Solution import java.util.Collections.singletonList open class NumberedTestCaseNamingStrategy( - solution: Solution<*>, + solution: Solution<*> ) : TestCaseNamingStrategy(solution) { override fun getTestCases(): List {