Skip to content

Commit

Permalink
test(analysis): mock startSession #3483
Browse files Browse the repository at this point in the history
  • Loading branch information
BenediktMehl committed Feb 18, 2025
1 parent f82a7b7 commit 6ab8ec5
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import de.maibornwolff.codecharta.tools.ccsh.parser.InteractiveParserSuggestion
import de.maibornwolff.codecharta.tools.ccsh.parser.ParserService
import de.maibornwolff.codecharta.tools.ccsh.parser.repository.PicocliParserRepository
import de.maibornwolff.codecharta.tools.inspection.InspectionTool
import de.maibornwolff.codecharta.tools.interactiveparser.startSession
import de.maibornwolff.codecharta.tools.interactiveparser.util.CodeChartaConstants
import de.maibornwolff.codecharta.tools.validation.ValidationTool
import de.maibornwolff.codecharta.util.AttributeGeneratorRegistry
Expand Down Expand Up @@ -110,7 +111,7 @@ class Ccsh : Callable<Unit?> {
return 0
}

val shouldRunConfiguredParsers = InteractiveDialog.askRunParsers()
val shouldRunConfiguredParsers = startSession { InteractiveDialog.askRunParsers(this) }

return if (shouldRunConfiguredParsers) {
executeConfiguredParsers(commandLine, configuredParsers)
Expand Down Expand Up @@ -150,11 +151,11 @@ class Ccsh : Callable<Unit?> {
}

private fun askAndMergeResults(commandLine: CommandLine): Int {
val shouldMerge = InteractiveDialog.askForMerge()
val shouldMerge = startSession { InteractiveDialog.askForMerge(this) }
var ccJsonFilePath = ""

if (shouldMerge) {
ccJsonFilePath = InteractiveDialog.askJsonPath()
ccJsonFilePath = startSession { InteractiveDialog.askJsonPath(this) }
}

return if (shouldMerge) {
Expand Down Expand Up @@ -205,7 +206,7 @@ class Ccsh : Callable<Unit?> {

private fun isParserKnown(args: Array<String>, commandLine: CommandLine): Boolean {
val firstArg = args.first()
val parserList = commandLine.subcommands.keys
val parserList: Set<String> = commandLine.subcommands.keys
return parserList.contains(firstArg)
}

Expand Down Expand Up @@ -252,6 +253,7 @@ class Ccsh : Callable<Unit?> {
}
}

@SuppressWarnings("kotlin:S6516") // Not possible to use a lambda here, because picocli expects a class type
object ManifestVersionProvider : CommandLine.IVersionProvider {
override fun getVersion(): Array<String> {
return arrayOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,81 +1,69 @@
package de.maibornwolff.codecharta.tools.ccsh.parser

import com.varabyte.kotter.runtime.RunScope
import com.varabyte.kotter.runtime.Session
import de.maibornwolff.codecharta.tools.inquirer.InputType
import de.maibornwolff.codecharta.tools.inquirer.myPromptCheckbox
import de.maibornwolff.codecharta.tools.inquirer.myPromptConfirm
import de.maibornwolff.codecharta.tools.inquirer.myPromptInput
import de.maibornwolff.codecharta.tools.inquirer.myPromptList
import de.maibornwolff.codecharta.tools.inquirer.util.InputValidator
import de.maibornwolff.codecharta.tools.interactiveparser.startSession
import java.nio.file.Paths

class InteractiveDialog {
companion object {
internal fun askParserToExecute(parserOptions: List<String>): String {
return startSession {
myPromptList(
message = "Which parser do you want to execute?",
choices = parserOptions,
onInputReady = parserCallback()
)
}
internal fun askParserToExecute(session: Session, parserOptions: List<String>): String {
return session.myPromptList(
message = "Which parser do you want to execute?",
choices = parserOptions,
onInputReady = parserCallback()
)
}

internal fun askForPath(): String {
internal fun askForPath(session: Session): String {
println("You can provide a directory path / file path / sonar url.")
return startSession {
myPromptInput(
message = "Which path should be scanned?",
hint = Paths.get("").toAbsolutePath().toString(),
allowEmptyInput = false,
onInputReady = pathCallback()
)
}
return session.myPromptInput(
message = "Which path should be scanned?",
hint = Paths.get("").toAbsolutePath().toString(),
allowEmptyInput = false,
onInputReady = pathCallback()
)
}

internal fun askApplicableParser(applicableParsers: List<String>): List<String> {
return startSession {
myPromptCheckbox(
message = "Choose from this list of applicable parsers. You can select individual parsers by pressing spacebar.",
choices = applicableParsers,
allowEmptyInput = true,
onInputReady = applicableCallback()
)
}
internal fun askApplicableParser(session: Session, applicableParsers: List<String>): List<String> {
return session.myPromptCheckbox(
message = "Choose from this list of applicable parsers. You can select individual parsers by pressing spacebar.",
choices = applicableParsers,
allowEmptyInput = true,
onInputReady = applicableCallback()
)
}

internal fun askRunParsers(): Boolean {
return startSession {
myPromptConfirm(
message = "Do you want to run all configured parsers now?",
onInputReady = runCallback()
)
}
internal fun askRunParsers(session: Session): Boolean {
return session.myPromptConfirm(
message = "Do you want to run all configured parsers now?",
onInputReady = runCallback()
)
}

internal fun askForMerge(): Boolean {
return startSession {
myPromptConfirm(
message = "Do you want to merge all generated files into one result now?",
onInputReady = mergeCallback()
)
}
internal fun askForMerge(session: Session): Boolean {
return session.myPromptConfirm(
message = "Do you want to merge all generated files into one result now?",
onInputReady = mergeCallback()
)
}

internal fun askJsonPath(): String {
internal fun askJsonPath(session: Session): String {
println(
"If you did not output all cc.json files into the same folder, " +
"you need to manually move them there before trying to merge."
)
return startSession {
myPromptInput(
message = "What is the folder path containing all cc.json files?",
hint = Paths.get("").toAbsolutePath().toString(),
inputValidator = InputValidator.isFileOrFolderValid(InputType.FOLDER, listOf()),
onInputReady = jsonCallback()
)
}
return session.myPromptInput(
message = "What is the folder path containing all cc.json files?",
hint = Paths.get("").toAbsolutePath().toString(),
inputValidator = InputValidator.isFileOrFolderValid(InputType.FOLDER, listOf()),
onInputReady = jsonCallback()
)
}

internal fun parserCallback(): suspend RunScope.() -> Unit = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package de.maibornwolff.codecharta.tools.ccsh.parser

import de.maibornwolff.codecharta.tools.ccsh.Ccsh
import de.maibornwolff.codecharta.tools.ccsh.parser.repository.PicocliParserRepository
import de.maibornwolff.codecharta.tools.interactiveparser.startSession
import de.maibornwolff.codecharta.util.Logger
import picocli.CommandLine
import java.io.File
Expand All @@ -27,7 +28,7 @@ class InteractiveParserSuggestion {
}

private fun getApplicableInteractiveParsers(commandLine: CommandLine): List<String> {
val inputFilePath: String = InteractiveDialog.askForPath()
val inputFilePath: String = startSession { InteractiveDialog.askForPath(this) }

val inputFile = File(inputFilePath)
if (inputFilePath == "" || !isInputFileOrDirectory(inputFile)) {
Expand All @@ -47,7 +48,7 @@ class InteractiveParserSuggestion {
}

private fun selectToBeExecutedInteractiveParsers(applicableParsers: List<String>): List<String> {
val selectedParsers: List<String> = InteractiveDialog.askApplicableParser(applicableParsers)
val selectedParsers: List<String> = startSession { InteractiveDialog.askApplicableParser(this, applicableParsers) }

if (selectedParsers.isEmpty()) {
Logger.info { "Did not select any parser to be configured!" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ class ParserService {
}

fun selectParser(commandLine: CommandLine, parserRepository: PicocliParserRepository): String {
val selectedParser = InteractiveDialog.askParserToExecute(
parserRepository.getInteractiveParserNamesWithDescription(commandLine)
)
val interactiveParserNames = parserRepository.getInteractiveParserNamesWithDescription(commandLine)
val selectedParser = startSession { InteractiveDialog.askParserToExecute(this, interactiveParserNames) }
return parserRepository.extractParserName(selectedParser)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package de.maibornwolff.codecharta.ccsh

import com.varabyte.kotter.runtime.Session
import com.varabyte.kotterx.test.foundation.testSession
import de.maibornwolff.codecharta.tools.ccsh.Ccsh
import de.maibornwolff.codecharta.tools.ccsh.parser.InteractiveDialog
import de.maibornwolff.codecharta.tools.ccsh.parser.InteractiveParserSuggestion
import de.maibornwolff.codecharta.tools.ccsh.parser.ParserService
import de.maibornwolff.codecharta.tools.interactiveparser.startSession
import de.maibornwolff.codecharta.util.Logger
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import io.mockk.verify
import org.assertj.core.api.Assertions.assertThat
Expand Down Expand Up @@ -95,15 +99,15 @@ class CcshTest {
}

private fun mockDialogMergeResults(shouldMerge: Boolean) {
every { InteractiveDialog.askForMerge() } returns shouldMerge
every { InteractiveDialog.askForMerge(any()) } returns shouldMerge
}

private fun mockDialogRunParsers(shouldRun: Boolean) {
every { InteractiveDialog.askRunParsers() } returns shouldRun
every { InteractiveDialog.askRunParsers(any()) } returns shouldRun
}

private fun mockDialogResultLocation(pathToReturn: String) {
every { InteractiveDialog.askJsonPath() } returns pathToReturn
every { InteractiveDialog.askJsonPath(any()) } returns pathToReturn
}

@Test
Expand Down Expand Up @@ -172,6 +176,7 @@ class CcshTest {
val selectedParsers = listOf("parser1", "parser2")
val args = listOf(listOf("dummyArg1"), listOf("dummyArg2"))

mockStartSession()
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockPrepareInteractiveDialog()
Expand Down Expand Up @@ -208,6 +213,7 @@ class CcshTest {
val selectedParsers = listOf("parser1", "parser2")
val args = listOf(listOf("dummyArg1"), listOf("dummyArg2"))

mockStartSession()
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockPrepareInteractiveDialog()
Expand Down Expand Up @@ -285,6 +291,7 @@ class CcshTest {
val selectedParsers = listOf("parser1")
val args = listOf(listOf("dummyArg1"))

mockStartSession()
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockSuccessfulParserService()
mockPrepareInteractiveDialog()
Expand Down Expand Up @@ -316,6 +323,7 @@ class CcshTest {
mockkObject(Logger)
every { Logger.info(capture(lambdaSlot)) } returns Unit

mockStartSession()
mockPrepareInteractiveDialog()
mockDialogRunParsers(true)
mockDialogMergeResults(true)
Expand All @@ -336,6 +344,7 @@ class CcshTest {
"dummyParser2" to listOf("dummyArg1", "dummyArg2")
)

mockStartSession()
mockPrepareInteractiveDialog()
mockDialogRunParsers(true)
mockDialogMergeResults(false)
Expand Down Expand Up @@ -371,6 +380,7 @@ class CcshTest {
)
)

mockStartSession()
mockInteractiveParserSuggestionDialog(selectedParsers, args)
mockPrepareInteractiveDialog()
mockDialogRunParsers(true)
Expand All @@ -384,4 +394,19 @@ class CcshTest {
assertThat(exitCode).isZero()
assertThat(mergedOutputFile).exists()
}

private fun mockStartSession() {
mockkStatic("de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterfaceKt")
every { startSession(any<Session.() -> Any>()) } answers {
startTestSession { firstArg<Session.() -> Any>()(this) }
}
}

private fun <T> startTestSession(block: Session.() -> T): T {
var returnValue: T? = null
testSession {
returnValue = block()
}
return returnValue ?: throw IllegalStateException("Session did not return a value.")
}
}
Loading

0 comments on commit 6ab8ec5

Please sign in to comment.