Skip to content

Commit

Permalink
feature/3338/improve-parser-suggestion-1 (#3384)
Browse files Browse the repository at this point in the history
* No longer ask to merge when only executing one parser, refactor CCSH-Unit-Tests for less duplication and better readability
  • Loading branch information
moritz-suckow committed Oct 30, 2023
1 parent f546e01 commit 03ee67f
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 82 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

## [unreleased] (Added 🚀 | Changed | Removed 🗑 | Fixed 🐞 | Chore 👨‍💻 👩‍💻)

### Added 🚀

- Only ask to merge results after parser suggestion execution when more than one parser was executed [#3384](https://github.com/MaibornWolff/codecharta/pull/3384)

### Fixed 🐞

- Fix command not found issue for --version and --help in the analysis [#3377](https://github.com/MaibornWolff/codecharta/pull/3377)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,25 @@ class Ccsh : Callable<Void?> {
val currentExitCode = executeConfiguredParser(commandLine, configuredParser)
if (currentExitCode != 0) {
exitCode.set(currentExitCode)
logger.info("Code: $currentExitCode")
logger.info { "Code: $currentExitCode" }
}
}
}
threadPool.shutdown()
threadPool.awaitTermination(1, TimeUnit.DAYS)

val finalExitCode = exitCode.get()
logger.info("Code: $finalExitCode")
logger.info { "Code: $finalExitCode" }
if (finalExitCode != 0) {
return finalExitCode
}
if (configuredParsers.size == 1) {
logger.info { "Parser was successfully executed and created a cc.json file." }
return 0
}

// Improvement: Try to extract merge commands before so user does not have to configure merge args?
logger.info("Each parser was successfully executed and created a cc.json file.")
logger.info { "Each parser was successfully executed and created a cc.json file." }
return askAndMergeResults(commandLine)
}

Expand Down Expand Up @@ -178,7 +183,7 @@ class Ccsh : Callable<Void?> {
val exitCode = ParserService.executePreconfiguredParser(commandLine, Pair(configuredParser.key, configuredParser.value))

if (exitCode != 0) {
logger.info("Error executing ${configuredParser.key}, code $exitCode")
logger.info { "Error executing ${configuredParser.key}, code $exitCode" }
}

return exitCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import io.mockk.unmockkAll
import io.mockk.verify
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import picocli.CommandLine
Expand All @@ -24,26 +25,79 @@ import java.io.PrintStream
class CcshTest {
private val outContent = ByteArrayOutputStream()
private val originalOut = System.out
val errContent = ByteArrayOutputStream()
val originalErr = System.err
private val errContent = ByteArrayOutputStream()
private val originalErr = System.err

private val cmdLine = CommandLine(Ccsh())

@BeforeAll
fun setUpStreams() {
@BeforeEach
fun setupStreams() {
System.setOut(PrintStream(outContent))
System.setErr(PrintStream(errContent))
}

@AfterAll
@AfterEach
fun restoreStreams() {
System.setOut(originalOut)
System.setErr(originalErr)
}

@AfterAll
fun afterTest() {
unmockkAll()
}

private fun mockSuccessfulParserService() {
mockkObject(ParserService)
every {
ParserService.selectParser(any(), any())
} returns "someparser"

every {
ParserService.executeSelectedParser(any(), any())
} returns 0

every {
ParserService.executePreconfiguredParser(any(), any())
} returns 0
}

private fun mockUnsuccessfulParserService() {
mockkObject(ParserService)

every {
ParserService.executeSelectedParser(any(), any())
} returns -1

every {
ParserService.executePreconfiguredParser(any(), any())
} returns -1
}

private fun mockInteractiveParserSuggestionDialog(selectedParsers: List<String>,
parserArgs: List<List<String>>) {
if (selectedParsers.size != parserArgs.size) {
throw IllegalArgumentException("There must be the same amount of args as parsers!")
}

val parsersAndArgs = mutableMapOf<String, List<String>>()
selectedParsers.zip(parserArgs) { currentParserName, currentParserArgs ->
parsersAndArgs.put(currentParserName, currentParserArgs)
}

mockkObject(InteractiveParserSuggestionDialog)
every {
InteractiveParserSuggestionDialog.offerAndGetInteractiveParserSuggestionsAndConfigurations(any())
} returns parsersAndArgs
}

private fun mockKInquirerConfirm(shouldConfirm: Boolean) {
mockkStatic("com.github.kinquirer.components.ConfirmKt")
every {
KInquirer.promptConfirm(any(), any())
} returns shouldConfirm
}

@Test
fun `should convert arguments to kebab-case`() {
val outStream = ByteArrayOutputStream()
Expand Down Expand Up @@ -77,20 +131,9 @@ class CcshTest {
val selectedParsers = listOf("parser1", "parser2")
val args = listOf(listOf("dummyArg1"), listOf("dummyArg2"))

mockkObject(InteractiveParserSuggestionDialog)
every {
InteractiveParserSuggestionDialog.offerAndGetInteractiveParserSuggestionsAndConfigurations(any())
} returns mapOf(selectedParsers[0] to args[0], selectedParsers[1] to args[1])

mockkObject(ParserService)
every {
ParserService.executePreconfiguredParser(any(), any())
} returns 0

mockkStatic("com.github.kinquirer.components.ConfirmKt")
every {
KInquirer.promptConfirm(any(), any())
} returns true
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockKInquirerConfirm(true)

mockkStatic("com.github.kinquirer.components.InputKt")
every {
Expand All @@ -106,18 +149,8 @@ class CcshTest {

@Test
fun `should only execute parsers when configuration was successful`() {
mockkObject(InteractiveParserSuggestionDialog)
every {
InteractiveParserSuggestionDialog.offerAndGetInteractiveParserSuggestionsAndConfigurations(any())
} returns emptyMap()

mockkObject(ParserService)
every {
ParserService.executeSelectedParser(any(), any())
} returns 0
every {
ParserService.executePreconfiguredParser(any(), any())
} returns 0
mockInteractiveParserSuggestionDialog(emptyList(), emptyList())
mockSuccessfulParserService()

val exitCode = Ccsh.executeCommandLine(emptyArray())

Expand All @@ -131,23 +164,9 @@ class CcshTest {
val selectedParsers = listOf("parser1", "parser2")
val args = listOf(listOf("dummyArg1"), listOf("dummyArg2"))

mockkObject(InteractiveParserSuggestionDialog)
every {
InteractiveParserSuggestionDialog.offerAndGetInteractiveParserSuggestionsAndConfigurations(any())
} returns mapOf(selectedParsers[0] to args[0], selectedParsers[1] to args[1])

mockkObject(ParserService)
every {
ParserService.executeSelectedParser(any(), any())
} returns 0
every {
ParserService.executePreconfiguredParser(any(), any())
} returns 0

mockkStatic("com.github.kinquirer.components.ConfirmKt")
every {
KInquirer.promptConfirm(any(), any())
} returns false
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockKInquirerConfirm(false)

val exitCode = Ccsh.executeCommandLine(emptyArray())

Expand All @@ -158,16 +177,11 @@ class CcshTest {

@Test
fun `should continue executing parsers even if there is an error while executing one`() {
mockkObject(ParserService)
every {
ParserService.executeSelectedParser(any(), any())
} returns -1
every {
ParserService.executePreconfiguredParser(any(), any())
} returns -1

val dummyConfiguredParsers = mapOf("dummyParser1" to listOf("dummyArg1", "dummyArg2"), "dummyParser2" to listOf("dummyArg1", "dummyArg2"))
mockUnsuccessfulParserService()

val dummyConfiguredParsers =
mapOf("dummyParser1" to listOf("dummyArg1", "dummyArg2"),
"dummyParser2" to listOf("dummyArg1", "dummyArg2"))
Ccsh.executeConfiguredParsers(cmdLine, dummyConfiguredParsers)

verify(exactly = 2) { ParserService.executePreconfiguredParser(any(), any()) }
Expand All @@ -176,13 +190,7 @@ class CcshTest {

@Test
fun `should execute interactive parser when passed parser is unknown`() {
mockkObject(ParserService)
every {
ParserService.selectParser(any(), any())
} returns "someparser"
every {
ParserService.executeSelectedParser(any(), any())
} returns 0
mockSuccessfulParserService()

val exitCode = Ccsh.executeCommandLine(arrayOf("unknownparser"))
Assertions.assertThat(exitCode).isZero
Expand All @@ -192,13 +200,7 @@ class CcshTest {

@Test
fun `should execute interactive parser when -i option is passed`() {
mockkObject(ParserService)
every {
ParserService.selectParser(any(), any())
} returns "someparser"
every {
ParserService.executeSelectedParser(any(), any())
} returns 0
mockSuccessfulParserService()

val exitCode = Ccsh.executeCommandLine(arrayOf("-i"))
Assertions.assertThat(exitCode).isZero
Expand All @@ -208,17 +210,28 @@ class CcshTest {

@Test
fun `should execute the selected interactive parser when only called with name and no args`() {
mockkObject(ParserService)
every {
ParserService.executeSelectedParser(any(), any())
} returns 0
mockSuccessfulParserService()

System.setErr(PrintStream(errContent))
val exitCode = Ccsh.executeCommandLine(arrayOf("sonarimport"))
System.setErr(originalErr)

Assertions.assertThat(exitCode).isEqualTo(0)
Assertions.assertThat(errContent.toString())
.contains("Executing sonarimport")
}

@Test
fun `should not ask for merging results after using parser suggestions if only one parser was executed`() {
val selectedParsers = listOf("parser1")
val args = listOf(listOf("dummyArg1"))

mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockKInquirerConfirm(true)

val exitCode = Ccsh.executeCommandLine(emptyArray())

Assertions.assertThat(exitCode).isZero()
Assertions.assertThat(errContent.toString())
.contains("Parser was successfully executed and created a cc.json file.")
}
}

0 comments on commit 03ee67f

Please sign in to comment.