Skip to content

Commit 2912cca

Browse files
authored
Merge pull request #1610 from WebFuzzing/phg/llm-naming-json
Set LLM naming strategy prompts to return a json answer
2 parents 3f8a29f + 5f15493 commit 2912cca

3 files changed

Lines changed: 30 additions & 4 deletions

File tree

core/src/main/kotlin/org/evomaster/core/llm/Prompts.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ object Prompts {
5656
const val NEW_TEST_CASE_NAME = """
5757
You are an expert software engineer specializing in test naming.
5858
59-
Given the following test case written in [targetLanguage], produce a descriptive suffix to append to its existing name.
59+
Given the following test case written in [targetLanguage], produce a descriptive suffix to append to its existing name. Return a JSON string.
6060
6161
## Rules
6262
@@ -87,7 +87,7 @@ object Prompts {
8787
[testLines]
8888
"""
8989

90-
const val RE_ITERATE_TEST_CASE_NAME = "Your previous response contained more than just the suffix. Output only the suffix, nothing else. No explanation, no punctuation, no extra text, do not exceed max chars."
90+
const val RE_ITERATE_TEST_CASE_NAME = "Your previous response contained more than just the suffix. Output only the suffix, nothing else. No explanation, no punctuation, no extra text, do not exceed max chars. Return a JSON string."
9191

9292
fun getPromptForNameDescription(name: String, description: String?): Pair<String,String> {
9393
var user = "Your input is\n [name]:$name"

core/src/main/kotlin/org/evomaster/core/output/naming/LlmServiceTestCaseNamingStrategy.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class LlmServiceTestCaseNamingStrategy(
2323
) : NumberedTestCaseNamingStrategy(solution) {
2424

2525
private val log: Logger = LoggerFactory.getLogger(TestSuiteWriter::class.java)
26+
private val fallbackLlmTestCaseName = "llmInteractionFailed_reviewName"
2627
private val generatedNames = mutableSetOf<String>()
2728

2829
private val remainingNameChars = maxTestCaseNameLength - namePrefixChars()
@@ -38,8 +39,14 @@ class LlmServiceTestCaseNamingStrategy(
3839

3940
private fun generateLlmName(test: TestCase): String {
4041
var newName = sanitizeName(getNewName(test))
41-
while (!isValidSuffix(newName)) {
42+
if (!isValidSuffix(newName)) {
4243
newName = sanitizeName(promptReIterateName())
44+
if (!isValidSuffix(newName)) {
45+
// If prompting the LLM to re-iterate the naming returned an invalid name again,
46+
// then we fall back to a default name. Since this is a special case that should not happen,
47+
// this name is not added to the list of names the LLM is provided to avoid repetition
48+
return fallbackLlmTestCaseName
49+
}
4350
}
4451
generatedNames.add(newName)
4552
return newName

core/src/test/kotlin/org/evomaster/core/output/naming/LlmServiceTestCaseNamingStrategyTest.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ import kotlin.jvm.java
3232
class LlmServiceTestCaseNamingStrategyTest {
3333

3434
companion object {
35-
const val MAX_NAME_LENGTH = 80
35+
// Setting a shorter name length just to force a condition in which the LLM response does not comply
36+
// with the ask since the mock will return a longer name, we force the re-prompt and later the fallback name
37+
const val MAX_NAME_LENGTH = 40
3638
}
3739

3840
@Test
@@ -69,6 +71,23 @@ class LlmServiceTestCaseNamingStrategyTest {
6971
assertEquals("test_0_thisTestNameWasLlmGenerated", testCases[0].name)
7072
}
7173

74+
@Test
75+
fun testFallbackNameIsAssignedAfterTwoFailedPrompts() {
76+
val outputFormat = OutputFormat.JAVA_JUNIT_4
77+
val baseModule = BaseModule(arrayOf("--llm", "true", "--llmProvider", "MOCK", "--outputFormat", outputFormat.name))
78+
val llmService = getLlmService(baseModule)
79+
val graphTestCaseWriter = getTestCaseWriter(baseModule.getEMConfig())
80+
81+
MockChatModel.reset()
82+
MockChatModel.mockResponse("[\"aNameThatExceeds The Amount of Characters and has ! f\"]") { it.contains("[targetLanguage]:Java") }
83+
MockChatModel.mockResponse("\"This name+ will !!! also have over 40chars and shouldBe_rejected") { it.contains("Your previous response") }
84+
85+
val testCases = generateTestCases(outputFormat, llmService, graphTestCaseWriter)
86+
87+
assertEquals(1, testCases.size)
88+
assertEquals("test_0_llmInteractionFailed_reviewName", testCases[0].name)
89+
}
90+
7291
private fun getLlmService(baseModule: BaseModule): LlmService {
7392
val injector: Injector = LifecycleInjector.builder()
7493
.withModules(listOf<com.google.inject.Module>(baseModule))

0 commit comments

Comments
 (0)