diff --git a/CHANGELOG.md b/CHANGELOG.md index d35401b691..1434636cfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/) - Changed the short-form of the `--no-issues` flag in the SourceCodeParser from `-i` to `-ni` [#3434](https://github.com/MaibornWolff/codecharta/pull/3434) - Clarify sonar user token question [#3445](https://github.com/MaibornWolff/codecharta/pull/3445) - Changed the `--user` flag to `--user-token` in SonarImporter [#3445](https://github.com/MaibornWolff/codecharta/pull/3445) +- Changed the interactive dialog of `modify` to prompt user for single action to perform [#3448](https://github.com/MaibornWolff/codecharta/pull/3448) ### Fixed 🐞 diff --git a/analysis/filter/StructureModifier/README.md b/analysis/filter/StructureModifier/README.md index f29e571f7c..a8e3fa151c 100644 --- a/analysis/filter/StructureModifier/README.md +++ b/analysis/filter/StructureModifier/README.md @@ -1,26 +1,28 @@ # StructureModifier -The StructureModifier is used to modify the structure of .cc.json files. It enables to ... +The StructureModifier modifies .cc.json files.\ +Perform one of the following actions at a time: -- remove nodes from a project. The resulting project will not include these nodes and their children. -- declare a node as root. This means that the chosen node will become the root node of the resulting sub-project. -- move nodes within the project. All children of the source node will be transferred to the destination node. -- print the hierarchy of the project. +- Remove nodes from a project, excluding them and their children. +- Set a node as the root, making it the root of the resulting sub-project. +- Move nodes within the project, transferring all children of the source node to the destination node. +- Print the project hierarchy. -The edges and blacklist entries associated with moved/removed nodes will be altered as well, while all attribute types will be copied. +Specifying multiple actions in a single command results in only one being performed.\ +Edges and blacklist entries associated with moved or removed nodes will be adjusted, and all attribute types will be copied. ## Usage and Parameters -| Parameter | description | +| Parameter | Description | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `[FILE]` | input project file | -| `-f, --move-from=` | move nodes in project folder... | +| `-f, --move-from=` | path of nodes to move in project folder | | `-h, --help` | displays this help and exits | | `-o, --output-file=` | output File (or empty for stdout) | | `-p, --print-levels=` | show first x layers of project hierarchy | | `-r, --remove=` | comma-separated list of nodes to be removed (when using powershell, the list either can't contain spaces or has to be in quotes) | -| `-s, --set-root=` | path within project to be extracted | -| `-t, --move-to=` | ... move nodes to destination folder | +| `-s, --set-root=` | path within project to be extracted as new root | +| `-t, --move-to=` | destination path of nodes to move in project folder
creates / overwrites nodes at destination path | ``` Usage: ccsh modify [-h] [-f=] [-o=] [-p=] diff --git a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/FolderMover.kt b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/FolderMover.kt index 84f2621323..3dfb491b2a 100644 --- a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/FolderMover.kt +++ b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/FolderMover.kt @@ -16,7 +16,7 @@ class FolderMover(private val project: Project) { private var toMove: List? = null fun move(moveFrom: String?, moveTo: String?): Project? { - if ((moveFrom == null) || (moveTo == null)) { + if ((moveFrom.isNullOrEmpty()) || (moveTo.isNullOrEmpty())) { logger.error("In order to move nodes, both source and destination need to be set.") return null } diff --git a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialog.kt b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialog.kt index 4ebbaed86e..10c56b4b08 100644 --- a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialog.kt +++ b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialog.kt @@ -3,6 +3,7 @@ package de.maibornwolff.codecharta.filter.structuremodifier import com.github.kinquirer.KInquirer import com.github.kinquirer.components.promptInput import com.github.kinquirer.components.promptInputNumber +import com.github.kinquirer.components.promptList import de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterface import java.io.File import java.math.BigDecimal @@ -15,40 +16,58 @@ class ParserDialog { val inputFolderName = KInquirer.promptInput( message = "What is the cc.json file that has to be modified?", - hint = Paths.get("").toAbsolutePath().toString() + File.separator + "yourInput.cc.json" - ) + hint = Paths.get("").toAbsolutePath().toString() + File.separator + "yourInput.cc.json") - val outputFileName: String = KInquirer.promptInput( - message = "What is the name of the output file?" + val selectedAction: String = KInquirer.promptList( + message = "Which action do you want to perform?", + choices = listOf( + StructureModifierAction.PRINT_STRUCTURE.descripton, + StructureModifierAction.SET_ROOT.descripton, + StructureModifierAction.MOVE_NODES.descripton, + StructureModifierAction.REMOVE_NODES.descripton + ) ) - val setRoot: String = - KInquirer.promptInput(message = "What path within project to be extracted? (Optional)", default = "") + return when (selectedAction) { + StructureModifierAction.PRINT_STRUCTURE.descripton -> listOf(inputFolderName, *collectPrintArguments()) + StructureModifierAction.SET_ROOT.descripton -> listOf(inputFolderName, *collectSetRootArguments()) + StructureModifierAction.MOVE_NODES.descripton -> listOf(inputFolderName, *collectMoveNodesArguments()) + StructureModifierAction.REMOVE_NODES.descripton -> listOf(inputFolderName, *collectRemoveNodesArguments()) + else -> listOf() + } + } + private fun collectPrintArguments(): Array { val printLevels: BigDecimal = - KInquirer.promptInputNumber(message = "How many print levels do you want to print? (Optional)", default = "0", hint = "0") + KInquirer.promptInputNumber(message = "How many print levels do you want to print?", default = "0", hint = "0") + return arrayOf("--print-levels=$printLevels") + } - val moveFrom: String = KInquirer.promptInput( - message = "What are the nodes to be moved? (Optional)" - ) - var moveTo: String = "" - if (moveFrom.isNotBlank()) { - moveTo = KInquirer.promptInput( - message = "Where to move them?" - ) - } - val remove: String = KInquirer.promptInput( - message = "What are the nodes to be removed? (Optional)" - ) - return listOfNotNull( - inputFolderName, - "--output-file=$outputFileName", - if (printLevels.toInt() != 0) "--print-levels=$printLevels" else null, - if (setRoot.isNotBlank()) "--set-root=$setRoot" else null, - if (moveFrom.isNotBlank()) "--move-from=$moveFrom" else null, - if (moveFrom.isNotBlank()) "--move-to=$moveTo" else null, - if (remove.isNotBlank()) "--remove=$remove" else null, - ) + private fun collectSetRootArguments(): Array { + val setRoot: String = + KInquirer.promptInput(message = "What path within the project should be extracted as the new root?") + val outputFileName = collectOutputFileName() + return arrayOf("--set-root=$setRoot", "--output-file=$outputFileName") + } + + private fun collectMoveNodesArguments(): Array { + val moveFrom: String = + KInquirer.promptInput(message = "What path should be moved (contained children will be moved as well)?") + val moveTo: String = + KInquirer.promptInput(message = "What is the target path to move them?") + val outputFileName = collectOutputFileName() + return arrayOf("--move-from=$moveFrom", "--move-to=$moveTo", "--output-file=$outputFileName") + } + + private fun collectRemoveNodesArguments(): Array { + val remove: String = + KInquirer.promptInput(message = "What are the paths of the nodes to be removed?") + val outputFileName = collectOutputFileName() + return arrayOf("--remove=$remove", "--output-file=$outputFileName") + } + + private fun collectOutputFileName(): String { + return KInquirer.promptInput(message = "What is the name of the output file?") } } } diff --git a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifier.kt b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifier.kt index c009c3af7a..12ad85b8be 100644 --- a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifier.kt +++ b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifier.kt @@ -33,14 +33,14 @@ class StructureModifier( @CommandLine.Parameters(arity = "0..1", paramLabel = "FILE", description = ["input project file"]) private var source: File? = null - @CommandLine.Option(names = ["-s", "--set-root"], description = ["path within project to be extracted"]) + @CommandLine.Option(names = ["-s", "--set-root"], description = ["path within project to be extracted as the new roo"]) private var setRoot: String? = null @CommandLine.Option( names = ["-p", "--print-levels"], description = ["show first x layers of project hierarchy"] ) - private var printLevels: Int = 0 + private var printLevels: Int? = null @CommandLine.Option(names = ["-o", "--output-file"], description = ["output File (or empty for stdout)"]) private var outputFile: String? = null @@ -76,11 +76,16 @@ class StructureModifier( } override fun call(): Unit? { + if (isMoreThanOneActionSpecified()) { + logger.error("More than one action specified - aborting execution.") + return null + } + project = readProject() ?: return null when { - printLevels > 0 -> { - ProjectStructurePrinter(project, output).printProjectStructure(printLevels) + printLevels != null -> { + ProjectStructurePrinter(project, output).printProjectStructure(printLevels!!) return null } @@ -94,6 +99,15 @@ class StructureModifier( return null } + private fun isMoreThanOneActionSpecified(): Boolean { + var actionCount = 0 + actionCount += if (setRoot != null) 1 else 0 + actionCount += if (printLevels != null) 1 else 0 + actionCount += if (moveFrom != null || moveTo != null) 1 else 0 + actionCount += if (remove.isNotEmpty()) 1 else 0 + return actionCount > 1 + } + private fun readProject(): Project? { if (source == null) { return ProjectDeserializer.deserializeProject(input) diff --git a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierAction.kt b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierAction.kt new file mode 100644 index 0000000000..02e895f479 --- /dev/null +++ b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierAction.kt @@ -0,0 +1,8 @@ +package de.maibornwolff.codecharta.filter.structuremodifier + +enum class StructureModifierAction(val descripton: String) { + PRINT_STRUCTURE("Print the structure of the project"), + SET_ROOT("Extract a sub path as the new root"), + MOVE_NODES("Move nodes within the project"), + REMOVE_NODES("Remove nodes") +} diff --git a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/SubProjectExtractor.kt b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/SubProjectExtractor.kt index 2e276298ab..518e1947a0 100644 --- a/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/SubProjectExtractor.kt +++ b/analysis/filter/StructureModifier/src/main/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/SubProjectExtractor.kt @@ -42,7 +42,7 @@ class SubProjectExtractor(private val project: Project) { } private fun addRoot(nodes: MutableList): List { - if (nodes.size == 0) logger.warn("No nodes with the specified path ($path) were fond. The resulting project is therefore empty") + if (nodes.isEmpty()) logger.warn("No nodes with the specified path ($path) were found. The resulting project is therefore empty") val rootNode = project.rootNode.toMutableNode() rootNode.children = nodes.toMutableSet() diff --git a/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialogTest.kt b/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialogTest.kt index 0296b63b1f..c12587c8bf 100644 --- a/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialogTest.kt +++ b/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/ParserDialogTest.kt @@ -3,10 +3,11 @@ package de.maibornwolff.codecharta.filter.structuremodifier import com.github.kinquirer.KInquirer import com.github.kinquirer.components.promptInput import com.github.kinquirer.components.promptInputNumber +import com.github.kinquirer.components.promptList import io.mockk.every import io.mockk.mockkStatic import io.mockk.unmockkAll -import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance @@ -23,100 +24,130 @@ class ParserDialogTest { } @Test - fun `should output correct arguments`() { + fun `should output correct arguments when print structure is selected`() { + // given val inputFolderName = "sampleInputFile" - val outputFileName = "sampleOutputFile" - val printLevels = BigDecimal(25) - val setRoot = "myRoot" - val moveTo = "myMoveTo" - val moveFrom = "myMoveFrom" - val remove = "myRemove" + val printLevels = BigDecimal(5) mockkStatic("com.github.kinquirer.components.InputKt") every { - KInquirer.promptInput(any(), any(), any()) - } returns inputFolderName andThen outputFileName andThen setRoot andThen moveFrom andThen moveTo andThen remove + KInquirer.promptInput(any(), any(), any(), any(), any(), any()) + } returns inputFolderName every { - KInquirer.promptInputNumber(any(), any(), any()) + KInquirer.promptInputNumber(any(), any(), any(), any()) } returns printLevels + mockkStatic("com.github.kinquirer.components.ListKt") + every { + KInquirer.promptList(any(), any(), any(), any(), any()) + } returns StructureModifierAction.PRINT_STRUCTURE.descripton + // when val parserArguments = ParserDialog.collectParserArgs() - println(parserArguments.toString()) - val commandLine = CommandLine(StructureModifier()) val parseResult = commandLine.parseArgs(*parserArguments.toTypedArray()) - println(parseResult.toString()) - assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) - assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) - assertThat(parseResult.matchedOption("print-levels").getValue()).isEqualTo(printLevels.toInt()) - assertThat(parseResult.matchedOption("set-root").getValue()).isEqualTo(setRoot) - assertThat(parseResult.matchedOption("move-to").getValue()).isEqualTo(moveTo) - assertThat(parseResult.matchedOption("move-from").getValue()).isEqualTo(moveFrom) - assertThat(parseResult.matchedOption("remove").getValue>()).isEqualTo(arrayOf(remove)) + + // then + Assertions.assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) + Assertions.assertThat(parseResult.matchedOption("print-levels").getValue()).isEqualTo(5) + Assertions.assertThat(parseResult.matchedOption("output-file")).isNull() + Assertions.assertThat(parseResult.matchedOption("set-root")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-to")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-from")).isNull() + Assertions.assertThat(parseResult.matchedOption("remove")).isNull() } @Test - fun `should output correct arguments if all actions are empty`() { + fun `should output correct arguments when extract path is selected`() { + // given val inputFolderName = "sampleInputFile" - val outputFileName = "sampleOutputFile" - val printLevels = BigDecimal(0) - val setRoot = "" - val moveFrom = "" - val remove = "" + val pathToBeExtracted = "/root/src/main" + val outputFileName = "output" mockkStatic("com.github.kinquirer.components.InputKt") every { - KInquirer.promptInput(any(), any(), any()) - } returns inputFolderName andThen outputFileName andThen setRoot andThen moveFrom andThen remove + KInquirer.promptInput(any(), any(), any(), any(), any(), any()) + } returns inputFolderName andThen pathToBeExtracted andThen outputFileName + mockkStatic("com.github.kinquirer.components.ListKt") every { - KInquirer.promptInputNumber(any(), any(), any()) - } returns printLevels + KInquirer.promptList(any(), any(), any(), any(), any()) + } returns StructureModifierAction.SET_ROOT.descripton + // when val parserArguments = ParserDialog.collectParserArgs() - println(parserArguments.toString()) - val commandLine = CommandLine(StructureModifier()) val parseResult = commandLine.parseArgs(*parserArguments.toTypedArray()) - println(parseResult.toString()) - assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) - assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) - assertThat(parseResult.matchedOption("print-levels")).isNull() - assertThat(parseResult.matchedOption("set-root")).isNull() - assertThat(parseResult.matchedOption("move-to")).isNull() - assertThat(parseResult.matchedOption("move-from")).isNull() - assertThat(parseResult.matchedOption("remove")).isNull() + + // then + Assertions.assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) + Assertions.assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) + Assertions.assertThat(parseResult.matchedOption("set-root").getValue()).isEqualTo(pathToBeExtracted) + Assertions.assertThat(parseResult.matchedOption("print-levels")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-from")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-to")).isNull() + Assertions.assertThat(parseResult.matchedOption("remove")).isNull() } @Test - fun `should output correct arguments if moveTo and moveFrom is set`() { + fun `should output correct arguments when move nodes is selected`() { + // given val inputFolderName = "sampleInputFile" - val outputFileName = "sampleOutputFile" - val printLevels = BigDecimal(0) - val setRoot = "" - val moveTo = "myMoveTo" - val moveFrom = "myMoveFrom" - val remove = "" + val outputFileName = "output" + val moveFrom = "/root/src/main/java" + val moveTo = "/root/src/main/java/subfolder" mockkStatic("com.github.kinquirer.components.InputKt") every { - KInquirer.promptInput(any(), any(), any()) - } returns inputFolderName andThen outputFileName andThen setRoot andThen moveFrom andThen moveTo andThen remove + KInquirer.promptInput(any(), any(), any(), any(), any(), any()) + } returns inputFolderName andThen moveFrom andThen moveTo andThen outputFileName + mockkStatic("com.github.kinquirer.components.ListKt") every { - KInquirer.promptInputNumber(any(), any(), any()) - } returns printLevels + KInquirer.promptList(any(), any(), any(), any(), any()) + } returns StructureModifierAction.MOVE_NODES.descripton + // when val parserArguments = ParserDialog.collectParserArgs() - println(parserArguments.toString()) + val commandLine = CommandLine(StructureModifier()) + val parseResult = commandLine.parseArgs(*parserArguments.toTypedArray()) + + // then + Assertions.assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) + Assertions.assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) + Assertions.assertThat(parseResult.matchedOption("move-from").getValue()).isEqualTo(moveFrom) + Assertions.assertThat(parseResult.matchedOption("move-to").getValue()).isEqualTo(moveTo) + Assertions.assertThat(parseResult.matchedOption("print-levels")).isNull() + Assertions.assertThat(parseResult.matchedOption("set-root")).isNull() + Assertions.assertThat(parseResult.matchedOption("remove")).isNull() + } + + @Test + fun `should output correct arguments when remove nodes is selected`() { + // given + val inputFolderName = "sampleInputFile" + val outputFileName = "output" + val nodeToRemove = "/root/src/main/java" + val nodesToRemove = arrayOf(nodeToRemove) + + mockkStatic("com.github.kinquirer.components.InputKt") + every { + KInquirer.promptInput(any(), any(), any(), any(), any(), any()) + } returns inputFolderName andThen nodeToRemove andThen outputFileName + mockkStatic("com.github.kinquirer.components.ListKt") + every { + KInquirer.promptList(any(), any(), any(), any(), any()) + } returns StructureModifierAction.REMOVE_NODES.descripton + // when + val parserArguments = ParserDialog.collectParserArgs() val commandLine = CommandLine(StructureModifier()) val parseResult = commandLine.parseArgs(*parserArguments.toTypedArray()) - println(parseResult.toString()) - assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) - assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) - assertThat(parseResult.matchedOption("print-levels")).isNull() - assertThat(parseResult.matchedOption("set-root")).isNull() - assertThat(parseResult.matchedOption("move-to").getValue()).isEqualTo(moveTo) - assertThat(parseResult.matchedOption("move-from").getValue()).isEqualTo(moveFrom) - assertThat(parseResult.matchedOption("remove")).isNull() + + // then + Assertions.assertThat(parseResult.matchedPositional(0).getValue().name).isEqualTo(inputFolderName) + Assertions.assertThat(parseResult.matchedOption("output-file").getValue()).isEqualTo(outputFileName) + Assertions.assertThat(parseResult.matchedOption("remove").getValue>()).isEqualTo(nodesToRemove) + Assertions.assertThat(parseResult.matchedOption("print-levels")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-from")).isNull() + Assertions.assertThat(parseResult.matchedOption("set-root")).isNull() + Assertions.assertThat(parseResult.matchedOption("move-to")).isNull() } } diff --git a/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierTest.kt b/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierTest.kt index b7c0b2fe73..6711a2227e 100644 --- a/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierTest.kt +++ b/analysis/filter/StructureModifier/src/test/kotlin/de/maibornwolff/codecharta/filter/structuremodifier/StructureModifierTest.kt @@ -3,8 +3,11 @@ package de.maibornwolff.codecharta.filter.structuremodifier import de.maibornwolff.codecharta.serialization.ProjectDeserializer import de.maibornwolff.codecharta.util.InputHelper import io.mockk.every +import io.mockk.mockk import io.mockk.mockkObject import io.mockk.unmockkAll +import mu.KLogger +import mu.KotlinLogging import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test @@ -176,4 +179,42 @@ class StructureModifierTest { assertThat(cliResult).doesNotContain(file1) assertThat(cliResult).doesNotContain(file2) } + + @Test + fun `should log warning when more than one action is specified`() { + // given + val file1 = "/root/src/main/file1.java" + val file2 = "/root/src/main/file2.java" + val nodesToRemove = listOf(file1, file2) + + val loggerMock = mockk() + val errorMessagesLogged = mutableListOf() + mockkObject(KotlinLogging) + every { KotlinLogging.logger(any<(() -> Unit)>()) } returns loggerMock + every { loggerMock.error(capture(errorMessagesLogged)) } returns Unit + + // when + executeForOutput("", arrayOf("src/test/resources/sample_project.cc.json", "--remove", "$nodesToRemove", "--set-root", "$nodesToRemove")) + + // then + assertThat(errorMessagesLogged).isNotEmpty() + } + + @Test + fun `should log error when move-from but not move-to is specified`() { + // given + val folderToMove = "/root/src/main" + + val loggerMock = mockk() + val errorMessagesLogged = mutableListOf() + mockkObject(KotlinLogging) + every { KotlinLogging.logger(any<(() -> Unit)>()) } returns loggerMock + every { loggerMock.error(capture(errorMessagesLogged)) } returns Unit + + // when + executeForOutput("", arrayOf("src/test/resources/sample_project.cc.json", "--move-from", folderToMove, "--move-to", "")) + + // then + assertThat(errorMessagesLogged).isNotEmpty() + } }