From 8bcc50ea1b91bd28ee3116236c8207a719dc4d5e Mon Sep 17 00:00:00 2001 From: Hubert Van De Walle Date: Thu, 8 Oct 2020 16:27:49 +0200 Subject: [PATCH] Add tests --- pom.xml | 6 + src/main/kotlin/starter/Models.kt | 2 +- .../kotlin/starter/modules/PebbleModule.kt | 4 +- .../kotlin/starter/modules/RoutesModule.kt | 3 + .../pebble/DepAsXmlPebbleFunction.kt | 2 +- .../{ => starter}/pebble/HasFeatureFilter.kt | 2 +- .../kotlin/starter/routes/ZipRouteSupplier.kt | 55 +++------ .../kotlin/starter/templates/PomTemplate.kt | 2 - .../kotlin/starter/utils/ProjectExtractor.kt | 44 +++++++ src/test/kotlin/starter/TestProject.kt | 46 ++++++++ .../starter/utils/ProjectExtractorImplTest.kt | 109 ++++++++++++++++++ src/test/resources/junit-platform.properties | 4 + 12 files changed, 231 insertions(+), 48 deletions(-) rename src/main/kotlin/{ => starter}/pebble/DepAsXmlPebbleFunction.kt (98%) rename src/main/kotlin/{ => starter}/pebble/HasFeatureFilter.kt (96%) create mode 100644 src/main/kotlin/starter/utils/ProjectExtractor.kt create mode 100644 src/test/kotlin/starter/TestProject.kt create mode 100644 src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt create mode 100644 src/test/resources/junit-platform.properties diff --git a/pom.xml b/pom.xml index 779057a..69f3ab8 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,12 @@ 5.7.0 test + + org.junit.jupiter + junit-jupiter-params + 5.7.0 + test + org.assertj assertj-core diff --git a/src/main/kotlin/starter/Models.kt b/src/main/kotlin/starter/Models.kt index c02efeb..65255f6 100644 --- a/src/main/kotlin/starter/Models.kt +++ b/src/main/kotlin/starter/Models.kt @@ -32,7 +32,7 @@ data class Project( val inputs: List, val features: List, val dependencies: List, - val repositories: Collection, + val repositories: Set, ) data class Version(val name: String, val value: String) diff --git a/src/main/kotlin/starter/modules/PebbleModule.kt b/src/main/kotlin/starter/modules/PebbleModule.kt index 98b8c2f..7e490b9 100644 --- a/src/main/kotlin/starter/modules/PebbleModule.kt +++ b/src/main/kotlin/starter/modules/PebbleModule.kt @@ -2,8 +2,8 @@ package starter.modules import org.koin.dsl.bind import org.koin.dsl.module -import pebble.DepAsXmlPebbleFunction -import pebble.HasFeatureFilter +import starter.pebble.DepAsXmlPebbleFunction +import starter.pebble.HasFeatureFilter import starter.utils.PebbleEngineBuilder import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap import starter.utils.PebbleFilter diff --git a/src/main/kotlin/starter/modules/RoutesModule.kt b/src/main/kotlin/starter/modules/RoutesModule.kt index e6ebd1d..647ab8b 100644 --- a/src/main/kotlin/starter/modules/RoutesModule.kt +++ b/src/main/kotlin/starter/modules/RoutesModule.kt @@ -11,10 +11,13 @@ import starter.routes.IndexRouteSupplier import starter.routes.RouteSupplier import starter.routes.ZipRouteSupplier import starter.routes.toRouter +import starter.utils.ProjectExtractor +import starter.utils.ProjectExtractorImpl val routesModule = module { single { IndexRouteSupplier(get()) } bind RouteSupplier::class single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class + single { ProjectExtractorImpl(get()) } single { ServerFilters.CatchAll().then( routes( diff --git a/src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt b/src/main/kotlin/starter/pebble/DepAsXmlPebbleFunction.kt similarity index 98% rename from src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt rename to src/main/kotlin/starter/pebble/DepAsXmlPebbleFunction.kt index d63036f..4d59a5d 100644 --- a/src/main/kotlin/pebble/DepAsXmlPebbleFunction.kt +++ b/src/main/kotlin/starter/pebble/DepAsXmlPebbleFunction.kt @@ -1,4 +1,4 @@ -package pebble +package starter.pebble import com.mitchellbosecke.pebble.extension.escaper.SafeString import com.mitchellbosecke.pebble.template.EvaluationContext diff --git a/src/main/kotlin/pebble/HasFeatureFilter.kt b/src/main/kotlin/starter/pebble/HasFeatureFilter.kt similarity index 96% rename from src/main/kotlin/pebble/HasFeatureFilter.kt rename to src/main/kotlin/starter/pebble/HasFeatureFilter.kt index 1b5d5d0..f51ad28 100644 --- a/src/main/kotlin/pebble/HasFeatureFilter.kt +++ b/src/main/kotlin/starter/pebble/HasFeatureFilter.kt @@ -1,4 +1,4 @@ -package pebble +package starter.pebble import com.mitchellbosecke.pebble.template.EvaluationContext import com.mitchellbosecke.pebble.template.PebbleTemplate diff --git a/src/main/kotlin/starter/routes/ZipRouteSupplier.kt b/src/main/kotlin/starter/routes/ZipRouteSupplier.kt index 38ecabf..3798ce7 100644 --- a/src/main/kotlin/starter/routes/ZipRouteSupplier.kt +++ b/src/main/kotlin/starter/routes/ZipRouteSupplier.kt @@ -1,62 +1,35 @@ package starter.routes import org.http4k.core.Method +import org.http4k.core.Request import org.http4k.core.Response -import org.http4k.core.body.form -import org.http4k.core.body.formAsMap import org.http4k.core.with import org.http4k.routing.bind -import starter.Project import starter.ProjectZip -import starter.config.StarterConfig import starter.extensions.attachment import starter.extensions.badRequest import starter.extensions.ok +import starter.utils.ProjectExtractor import java.io.ByteArrayInputStream class ZipRouteSupplier( - private val conf: StarterConfig, + private val projectExtractor: ProjectExtractor, private val projectZip: ProjectZip, ) : RouteSupplier { - override fun get() = "/" bind Method.POST to { req -> + private fun handle(req: Request): Response { + val project = projectExtractor(req) ?: return Response.badRequest() - val deps = conf.dependencies.filter { - req.form(it.name) != null - } + val outputStream = projectZip.createZip(project) - val formMap = req.formAsMap() - - val inputKeys = conf.inputs.map { it.name } - val inputs = formMap - .filter { it.key in inputKeys } - .map { (name, value) -> - conf.inputs.find { it.name == name }!!.copy(value = value.first()) - } - - val features = formMap - .filter { it.key in conf.features.map { it.name } } - .map { (name, _) -> - conf.features.find { it.name == name }!!.copy(value = true) - } - - val projectName = inputs.find { it.name == "name" }!!.value!! - val basePackage = inputs.find { it.name == "basePackage" }!!.value!! - - if (basePackage.contains("/") || basePackage.contains("..")) { - Response.badRequest() - } else { - val repositories = deps.mapNotNull { it.repository }.toSet() - val project = Project(projectName, basePackage, inputs, features, deps, repositories) - val outputStream = projectZip.createZip(project) - - Response.ok().with( - attachment( - value = ByteArrayInputStream(outputStream.toByteArray()), - name = "$projectName.zip", - contentType = "application/zip" - ) + return Response.ok().with( + attachment( + value = ByteArrayInputStream(outputStream.toByteArray()), + name = "${project.name}.zip", + contentType = "application/zip" ) - } + ) } + + override fun get() = "/" bind Method.POST to ::handle } diff --git a/src/main/kotlin/starter/templates/PomTemplate.kt b/src/main/kotlin/starter/templates/PomTemplate.kt index 774912e..66cda6e 100644 --- a/src/main/kotlin/starter/templates/PomTemplate.kt +++ b/src/main/kotlin/starter/templates/PomTemplate.kt @@ -21,8 +21,6 @@ class PomTemplate(private val engine: PebbleEngine) : Template { args[it.name] = it.value } - println(args.entries.joinToString("\n")) - val rendered = engine.render("starter/pom/index", args) return prettyPrintXml(rendered) } diff --git a/src/main/kotlin/starter/utils/ProjectExtractor.kt b/src/main/kotlin/starter/utils/ProjectExtractor.kt new file mode 100644 index 0000000..69450d0 --- /dev/null +++ b/src/main/kotlin/starter/utils/ProjectExtractor.kt @@ -0,0 +1,44 @@ +package starter.utils + +import org.http4k.core.Request +import org.http4k.core.body.form +import org.http4k.core.body.formAsMap +import starter.Project +import starter.config.StarterConfig + +interface ProjectExtractor { + operator fun invoke(request: Request): Project? +} + +class ProjectExtractorImpl(private val conf: StarterConfig) : ProjectExtractor { + override fun invoke(request: Request): Project? { + val deps = conf.dependencies.filter { + request.form(it.name) != null + } + + val formMap = request.formAsMap() + + val inputKeys = conf.inputs.map { it.name } + val inputs = formMap + .filter { it.key in inputKeys } + .map { (name, value) -> + conf.inputs.find { it.name == name }!!.copy(value = value.first()) + } + + val features = formMap + .filter { it.key in conf.features.map { it.name } } + .map { (name, _) -> + conf.features.find { it.name == name }!!.copy(value = true) + } + + val projectName = inputs.find { it.name == "name" }?.value ?: return null + val basePackage = inputs.find { it.name == "basePackage" }?.value ?: return null + + return if (basePackage.contains("/") || basePackage.contains("..")) { + null + } else { + val repositories = deps.mapNotNull { it.repository }.toSet() + Project(projectName, basePackage, inputs, features, deps, repositories) + } + } +} diff --git a/src/test/kotlin/starter/TestProject.kt b/src/test/kotlin/starter/TestProject.kt new file mode 100644 index 0000000..47c4d25 --- /dev/null +++ b/src/test/kotlin/starter/TestProject.kt @@ -0,0 +1,46 @@ +package starter + +import starter.config.StarterConfig + +val testConfig = StarterConfig( + dependencies = listOf( + Dependency( + name = "h2", + groupId = "com.h2database", + artifactId = "h2", + version = Version("h2", "1.4.200"), + default = false, + category = Category.Database, + scope = Scope.Compile, + logger = null, + repository = null, + ), + Dependency( + name = "assertj", + groupId = "org.assertj", + artifactId = "assertj-core", + version = Version("assertj", "3.17.2"), + default = true, + category = Category.Test, + scope = Scope.Test, + logger = null, + repository = null, + ), + Dependency( + name = "koin", + groupId = "org.koin", + artifactId = "koin-core", + version = Version("koin", "2.1.6"), + default = true, + category = Category.Injection, + scope = Scope.Compile, + logger = null, + repository = Repository("jcenter", "https://jcenter.bintray.com"), + ), + ), + inputs = listOf( + Input(name = "name", display = "name", value = "example"), + Input(name = "basePackage", display = "Base package", value = "org.example"), + ), + features = listOf(Feature("ktlint", true)) +) diff --git a/src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt b/src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt new file mode 100644 index 0000000..ca60f63 --- /dev/null +++ b/src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt @@ -0,0 +1,109 @@ +package starter.utils + +import org.assertj.core.api.Assertions.assertThat +import org.http4k.core.Method +import org.http4k.core.Request +import org.http4k.core.body.Form +import org.http4k.core.body.toBody +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.koin.dsl.koinApplication +import org.koin.dsl.module +import starter.Feature +import starter.Input +import starter.Project +import starter.modules.routesModule +import starter.testConfig +import java.util.stream.Stream + +internal class ProjectExtractorImplTest { + + private val fakeModule = module { + single { testConfig } + } + + private val koin = koinApplication { + modules(routesModule, fakeModule) + }.koin + + private val projectExtractor = koin.get() + + @Suppress("unused") + fun invalidProjectsSource(): Stream
= Stream.of( + emptyList(), + listOf( + "basePackage" to "org.example", + ), + listOf( + "basePackage" to "org.example/a", + "name" to "test" + ), + ) + + @ParameterizedTest + @MethodSource("invalidProjectsSource") + fun invalidProjects(form: Form) { + val request = Request(Method.POST, "") + .body(form.toBody()) + + val project = projectExtractor(request) + + assertThat(project).isNull() + } + + @Suppress("unused") + fun validProjectsSource(): Stream> = Stream.of( + listOf( + "name" to "Test", + "basePackage" to "org.example", + "ktlint" to "", + ) to Project( + name = "Test", + basePackage = "org.example", + inputs = listOf( + Input(name = "name", display = "name", value = "Test"), + Input(name = "basePackage", display = "Base package", value = "org.example"), + ), + features = listOf( + Feature(name = "ktlint", value = true) + ), + dependencies = listOf(), + repositories = setOf(), + ), + listOf( + "name" to "Test", + "basePackage" to "org.example", + "ktlint" to "", + "koin" to "", + ) to Project( + name = "Test", + basePackage = "org.example", + inputs = listOf( + Input(name = "name", display = "name", value = "Test"), + Input(name = "basePackage", display = "Base package", value = "org.example"), + ), + features = listOf( + Feature(name = "ktlint", value = true) + ), + dependencies = listOf( + testConfig.dependencies.find { it.name == "koin" }!! + ), + repositories = setOf( + testConfig.dependencies.find { it.name == "koin" }!!.repository!! + ), + ), + ) + + @ParameterizedTest + @MethodSource("validProjectsSource") + fun validProjects(pair: Pair) { + val (form, expected) = pair + + val request = Request(Method.POST, "") + .body(form.toBody()) + + val project = projectExtractor(request) + + assertThat(project).isEqualTo(expected) + } +} diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000..a8416a7 --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1,4 @@ +junit.jupiter.testinstance.lifecycle.default=per_class +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.default=same_thread +junit.jupiter.execution.parallel.mode.classes.default=concurrent