Skip to content

Commit

Permalink
use interface for interactive parsers + implement in ValidatorTool (#…
Browse files Browse the repository at this point in the history
…2822)

* chore: fix editorconfig for gradle files

* refactor: use interface for interactive parsers

this allows us to automatically detect them from the subcommands, and makes a separate map unnecessary

* feat: implement InteractiveParser in ValidationTool

* fix: use same testing framework (Spek) as in the rest of the app

* fix: switch back to JUnit

* fix: interactive dialog inserted unwanted space char at beginning of output file name

* refactor: clean up ParserServiceTest

* fix: use this for CommandLine

* rename callInteractive to executeWithInteractive #2341

* refactor: move executeWithInteractive into ParserService

* add changelog entry
#2341

* add parametrized tests
#2341

Co-authored-by: Mira Weller <mira.weller@maibornwolff.de>
Co-authored-by: IhsenBouallegue <bouallegueihsen@gmail.com>
  • Loading branch information
3 people committed May 31, 2022
1 parent a6a46b3 commit 5acb19e
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 132 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ quote_type = unset

[*.md]
indent_size = 4

[*.gradle]
indent_size = 4
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

### Added 🚀

- Add interactive dialog support for the parsers [#2737](https://github.com/MaibornWolff/codecharta/pull/2737) <br>
- Add interactive dialog support for the parsers [#2737](https://github.com/MaibornWolff/codecharta/pull/2737) [#2822](https://github.com/MaibornWolff/codecharta/pull/2822) <br>
![m](https://user-images.githubusercontent.com/48621967/161549546-1463914e-c223-4912-acb1-db4e357e76c5.png)

### Changed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package de.maibornwolff.codecharta.filter.edgefilter

import de.maibornwolff.codecharta.filter.edgefilter.ParserDialog.Companion.collectParserArgs
import de.maibornwolff.codecharta.serialization.ProjectDeserializer
import de.maibornwolff.codecharta.serialization.ProjectSerializer
import de.maibornwolff.codecharta.tools.interactiveparser.InteractiveParser
import de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterface
import picocli.CommandLine
import java.io.File
import java.util.concurrent.Callable
Expand All @@ -12,7 +13,7 @@ import java.util.concurrent.Callable
description = ["aggregtes edgeAttributes as nodeAttributes into a new cc.json file"],
footer = ["Copyright(c) 2022, MaibornWolff GmbH"]
)
class EdgeFilter : Callable<Void?> {
class EdgeFilter : Callable<Void?>, InteractiveParser {

@CommandLine.Option(names = ["-h", "--help"], usageHelp = true, description = ["displays this help and exits"])
var help: Boolean = false
Expand All @@ -37,12 +38,5 @@ class EdgeFilter : Callable<Void?> {
return null
}

companion object {
@JvmStatic
fun main(args: Array<String>) {
val commandLine = CommandLine(EdgeFilter())
val collectedArgs = collectParserArgs()
commandLine.execute(*collectedArgs.toTypedArray())
}
}
override fun getDialog(): ParserDialogInterface = ParserDialog
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ private val logger = KotlinLogging.logger {}
class ParserDialog {
companion object : ParserDialogInterface {
private const val EXTENSION = "cc.json"
private val extensionPattern = Regex(".($EXTENSION)$")

override fun collectParserArgs(): List<String> {

var inputFileName = KInquirer.promptInput(message = "What is the $EXTENSION file that has to be parsed?")
if (!extensionPattern.containsMatchIn(inputFileName))
inputFileName += ".$EXTENSION"
val inputFileName = KInquirer.promptInput(message = "What is the $EXTENSION file that has to be parsed?")
logger.info { "File path: $inputFileName" }

val defaultOutputFileName = getOutputFileName(inputFileName)
Expand All @@ -33,7 +30,7 @@ class ParserDialog {
default = defaultPathSeparator
)

return listOf(inputFileName, "-o $outputFileName", "--path-separator=$pathSeparator")
return listOf(inputFileName, "--output-file=$outputFileName", "--path-separator=$pathSeparator")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import picocli.CommandLine
import java.io.File

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ParserDialogTest {
Expand All @@ -19,32 +22,29 @@ class ParserDialogTest {
}

@Test
fun `should output correct arguments for file without extension`() {
fun `should output correct arguments`() {
mockkStatic("com.github.kinquirer.components.InputKt")
every {
KInquirer.promptInput(any(), any(), any())
} returns "sampleFile" andThen "sampleOutputFile" andThen "/"
} returns "sampleFile.cc.json" andThen "sampleOutputFile" andThen "/"

val parserArguments = ParserDialog.collectParserArgs()

Assertions.assertThat(parserArguments).isEqualTo(listOf("sampleFile.cc.json", "-o sampleOutputFile", "--path-separator=/"))

every {
KInquirer.promptInput(any(), any(), any())
} returns "sampleFile.cc.json" andThen "sampleOutputFile" andThen "/"

Assertions.assertThat(parserArguments).isEqualTo(listOf("sampleFile.cc.json", "-o sampleOutputFile", "--path-separator=/"))
Assertions.assertThat(parserArguments).isEqualTo(listOf("sampleFile.cc.json", "--output-file=sampleOutputFile", "--path-separator=/"))
}

@Test
fun `should output correct arguments for file with correct extension`() {
fun `should output arguments that are parsed correctly`() {
mockkStatic("com.github.kinquirer.components.InputKt")
every {
KInquirer.promptInput(any(), any(), any())
} returns "sampleFile.cc.json" andThen "sampleOutputFile" andThen "/"

val parserArguments = ParserDialog.collectParserArgs()

Assertions.assertThat(parserArguments).isEqualTo(listOf("sampleFile.cc.json", "-o sampleOutputFile", "--path-separator=/"))
val cmdLine = CommandLine(EdgeFilter())
val parseResult = cmdLine.parseArgs(*parserArguments.toTypedArray())
assertThat(parseResult.matchedOption("output-file").getValue<File>().name).isEqualTo("sampleOutputFile")
assertThat(parseResult.matchedOption("path-separator").getValue<Char>()).isEqualTo('/')
assertThat(parseResult.matchedPositional(0).getValue<String>()).isEqualTo("sampleFile.cc.json")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package de.maibornwolff.codecharta.tools.interactiveparser

interface InteractiveParser {
fun getDialog(): ParserDialogInterface
}
14 changes: 6 additions & 8 deletions analysis/tools/ValidationTool/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ repositories {
}

dependencies {
implementation project(':tools:InteractiveParser')
implementation group: 'com.github.everit-org.json-schema', name: 'org.everit.json.schema', version: json_schema_version
implementation group: 'info.picocli', name: 'picocli', version: picocli_version
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlin_logging_version
implementation "com.github.kotlin-inquirer:kotlin-inquirer:$kotlin_inquirer_version"

testImplementation group: 'org.jetbrains.kotlin', name: 'kotlin-test', version: kotlin_version
testImplementation("org.spekframework.spek2:spek-dsl-jvm:$spek2_version") {
exclude group: 'org.jetbrains.kotlin'
}
testImplementation group: 'org.assertj', name: 'assertj-core', version: assertj_version
testImplementation group: 'io.mockk', name: 'mockk', version: mockk_version

testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:$spek2_version") {
exclude group: 'org.jetbrains.kotlin'
}
testRuntimeOnly group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version
}

test {
useJUnitPlatform {
includeEngines 'spek2'
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.maibornwolff.codecharta.tools.validation

import com.github.kinquirer.KInquirer
import com.github.kinquirer.components.promptInput
import de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterface
import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

class ParserDialog {
companion object : ParserDialogInterface {
private const val EXTENSION = "cc.json"

override fun collectParserArgs(): List<String> {
val inputFileName = KInquirer.promptInput(message = "Which $EXTENSION file do you want to validate?")
logger.info { "File path: $inputFileName" }

return listOf(inputFileName)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.maibornwolff.codecharta.tools.validation

import de.maibornwolff.codecharta.tools.interactiveparser.InteractiveParser
import de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterface
import picocli.CommandLine
import java.io.File
import java.io.FileInputStream
Expand All @@ -10,9 +12,7 @@ import java.util.concurrent.Callable
description = ["validates cc.json files"],
footer = ["Copyright(c) 2020, MaibornWolff GmbH"]
)
class ValidationTool : Callable<Void?> {

private val schemaPath = "cc.json"
class ValidationTool : Callable<Void?>, InteractiveParser {

@CommandLine.Option(names = ["-h", "--help"], usageHelp = true, description = ["displays this help and exits"])
var help: Boolean = false
Expand All @@ -21,17 +21,14 @@ class ValidationTool : Callable<Void?> {
var file: String = ""

override fun call(): Void? {
EveritValidator(schemaPath).validate(FileInputStream(File(file).absoluteFile))
EveritValidator(SCHEMA_PATH).validate(FileInputStream(File(file).absoluteFile))

return null
}

companion object {
var SCHEMA_PATH = "cc.json"

@JvmStatic
fun main(args: Array<String>) {
CommandLine.call(ValidationTool(), System.out, *args)
}
const val SCHEMA_PATH = "cc.json"
}

override fun getDialog(): ParserDialogInterface = ParserDialog
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
package de.maibornwolff.codecharta.tools.validation

import de.maibornwolff.codecharta.tools.validation.ValidationTool.Companion.SCHEMA_PATH
import org.everit.json.schema.ValidationException
import org.json.JSONException
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import org.junit.jupiter.api.Test
import kotlin.test.assertFailsWith

class EveritValidatorTest : Spek({
describe("a validator") {
val validator = EveritValidator(SCHEMA_PATH)
class EveritValidatorTest {

it("should validate valid File") {
validator.validate(this.javaClass.classLoader.getResourceAsStream("validFile.json"))
}
private val validator = EveritValidator(ValidationTool.SCHEMA_PATH)

@Test
fun `should validate valid File`() {
validator.validate(this.javaClass.classLoader.getResourceAsStream("validFile.json"))
}

it("should throw exception on missing node name") {
assertFailsWith(ValidationException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("missingNodeNameFile.json"))
}
@Test
fun `should throw exception on missing node name`() {
assertFailsWith(ValidationException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("missingNodeNameFile.json"))
}
}

it("should throw exception on missing project") {
assertFailsWith(ValidationException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("invalidFile.json"))
}
@Test
fun `should throw exception on missing project`() {
assertFailsWith(ValidationException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("invalidFile.json"))
}
}

it("should throw exception if no json file") {
assertFailsWith(JSONException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("invalidJson.json"))
}
@Test
fun `should throw exception if no json file`() {
assertFailsWith(JSONException::class) {
validator.validate(this.javaClass.classLoader.getResourceAsStream("invalidJson.json"))
}
}
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package de.maibornwolff.codecharta.tools.validation

import com.github.kinquirer.KInquirer
import com.github.kinquirer.components.promptInput
import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ParserDialogTest {

@AfterAll
fun afterTest() {
unmockkAll()
}

@Test
fun `should output correct arguments`() {
mockkStatic("com.github.kinquirer.components.InputKt")
every {
KInquirer.promptInput(any(), any(), any())
} returns "sampleFile.cc.json"

val parserArguments = ParserDialog.collectParserArgs()

Assertions.assertThat(parserArguments).isEqualTo(listOf("sampleFile.cc.json"))
}
}
2 changes: 2 additions & 0 deletions analysis/tools/ccsh/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
def validationTool = project(':tools:ValidationTool')
def csvExporter = project(':export:CSVExporter')
def rawTextParser = project(':parser:RawTextParser')
def interactiveParser = project(':tools:InteractiveParser')

// first implementation is for dependency in main, testImplementation is so our test suite can find all other tests
implementation codeMaatImporter; testImplementation codeMaatImporter.sourceSets.test.output
Expand All @@ -53,6 +54,7 @@ dependencies {
implementation csvExporter; testImplementation csvExporter.sourceSets.test.output
implementation structureModifier; testImplementation structureModifier.sourceSets.test.output
implementation rawTextParser; testImplementation rawTextParser.sourceSets.test.output
implementation interactiveParser; testImplementation interactiveParser.sourceSets.test.output

implementation group: 'info.picocli', name: 'picocli', version: picocli_version
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlin_logging_version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ class Ccsh : Callable<Void?> {
}

private fun executeInteractiveParser(commandLine: CommandLine) {
val selectedParser = ParserService.selectParser(commandLine)
logger.info { "Executing $selectedParser" }
ParserService.executeSelectedParser(selectedParser)
val selectedParser = ParserService.selectParser(commandLine)
logger.info { "Executing $selectedParser" }
ParserService.executeSelectedParser(commandLine, selectedParser)
}

private fun isParserUnknown(args: Array<String>, commandLine: CommandLine): Boolean {
Expand Down

0 comments on commit 5acb19e

Please sign in to comment.