1
0

Add tests

This commit is contained in:
Hubert Van De Walle 2020-10-08 16:27:49 +02:00
parent d063ba1c25
commit 8bcc50ea1b
12 changed files with 231 additions and 48 deletions

View File

@ -64,6 +64,12 @@
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>

View File

@ -32,7 +32,7 @@ data class Project(
val inputs: List<Input>,
val features: List<Feature>,
val dependencies: List<Dependency>,
val repositories: Collection<Repository>,
val repositories: Set<Repository>,
)
data class Version(val name: String, val value: String)

View File

@ -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

View File

@ -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<ProjectExtractor> { ProjectExtractorImpl(get()) }
single {
ServerFilters.CatchAll().then(
routes(

View File

@ -1,4 +1,4 @@
package pebble
package starter.pebble
import com.mitchellbosecke.pebble.extension.escaper.SafeString
import com.mitchellbosecke.pebble.template.EvaluationContext

View File

@ -1,4 +1,4 @@
package pebble
package starter.pebble
import com.mitchellbosecke.pebble.template.EvaluationContext
import com.mitchellbosecke.pebble.template.PebbleTemplate

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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))
)

View File

@ -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<ProjectExtractor>()
@Suppress("unused")
fun invalidProjectsSource(): Stream<Form> = 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<Pair<Form, Project>> = 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<Form, Project>) {
val (form, expected) = pair
val request = Request(Method.POST, "")
.body(form.toBody())
val project = projectExtractor(request)
assertThat(project).isEqualTo(expected)
}
}

View File

@ -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