From 7609778c644b9e4be803febc3a8c8122433c363d Mon Sep 17 00:00:00 2001 From: uzzu Date: Sun, 16 Feb 2020 15:36:20 +0900 Subject: [PATCH] Fix dotenv properties as testable --- build.gradle.kts | 15 +-- plugin/build.gradle.kts | 10 -- .../kotlin/co/uzzu/dotenv/EnvProviders.kt | 24 +++++ .../co/uzzu/dotenv/gradle/DotEnvPlugin.kt | 29 +++--- .../co/uzzu/dotenv/gradle/DotEnvProperties.kt | 29 ++++-- .../co/uzzu/dotenv/InMemoryEnvProvider.kt | 8 ++ .../uzzu/dotenv/gradle/DotEnvPropertyTest.kt | 96 +++++++++++++++++++ .../co/uzzu/dotenv/gradle/DotEnvRootTest.kt | 96 +++++++++++++++++++ 8 files changed, 268 insertions(+), 39 deletions(-) create mode 100644 plugin/src/main/kotlin/co/uzzu/dotenv/EnvProviders.kt create mode 100644 plugin/src/test/kotlin/co/uzzu/dotenv/InMemoryEnvProvider.kt create mode 100644 plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvPropertyTest.kt create mode 100644 plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvRootTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5ae6632..c71e937 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,11 +11,14 @@ allprojects { } } -ktlint { - verbose.set(true) - outputToConsole.set(true) - reporters { - reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE) +subprojects { + apply(plugin = "org.jlleitschuh.gradle.ktlint") + ktlint { + verbose.set(true) + outputToConsole.set(true) + reporters { + reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE) + } + ignoreFailures.set(true) } - ignoreFailures.set(true) } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 2c21643..81d3380 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -3,7 +3,6 @@ plugins { `java-gradle-plugin` `maven-publish` kotlin("jvm") - id("org.jlleitschuh.gradle.ktlint") } dependencies { @@ -37,15 +36,6 @@ tasks { } } -ktlint { - verbose.set(true) - outputToConsole.set(true) - reporters { - reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE) - } - ignoreFailures.set(true) -} - // region publishing object Artifact { diff --git a/plugin/src/main/kotlin/co/uzzu/dotenv/EnvProviders.kt b/plugin/src/main/kotlin/co/uzzu/dotenv/EnvProviders.kt new file mode 100644 index 0000000..53335ff --- /dev/null +++ b/plugin/src/main/kotlin/co/uzzu/dotenv/EnvProviders.kt @@ -0,0 +1,24 @@ +package co.uzzu.dotenv + +/** + * Provides environment variable + */ +interface EnvProvider { + /** + * @return A environment variable for name. + */ + fun getenv(name: String): String? + + /** + * @return All environment variables. + */ + fun getenv(): Map +} + +/** + * EnvProvider implementation using System#getenv + */ +class SystemEnvProvider : EnvProvider { + override fun getenv(name: String): String? = System.getenv(name) + override fun getenv(): Map = System.getenv() +} diff --git a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvPlugin.kt b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvPlugin.kt index f374ab0..7280df7 100644 --- a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvPlugin.kt +++ b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvPlugin.kt @@ -1,6 +1,8 @@ package co.uzzu.dotenv.gradle import co.uzzu.dotenv.DotEnvParser +import co.uzzu.dotenv.EnvProvider +import co.uzzu.dotenv.SystemEnvProvider import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.ExtensionAware @@ -9,29 +11,30 @@ import java.nio.charset.Charset @Suppress("unused") class DotEnvPlugin : Plugin { override fun apply(target: Project) { - val envTemplate = target.rootProject.envTemplate() - val envSource = target.rootProject.envSource() - val envMerged = envTemplate.keys - .union(envSource.keys) - .map { it to envSource[it] } + val envProvider = SystemEnvProvider() + val dotenvTemplate = target.rootProject.dotenvTemplate() + val dotenvSource = target.rootProject.dotenvSource() + val dotenvMerged = dotenvTemplate.keys + .union(dotenvSource.keys) + .map { it to dotenvSource[it] } .toMap() - target.applyEnv(envMerged) - target.subprojects { it.applyEnv(envMerged) } + target.applyEnv(envProvider, dotenvMerged) + target.subprojects { it.applyEnv(envProvider, dotenvMerged) } } - private fun Project.applyEnv(envProperties: Map) { + private fun Project.applyEnv(envProvider: EnvProvider, dotenvProperties: Map) { val env = - extensions.create("env", DotEnvRoot::class.java, envProperties) as ExtensionAware - envProperties.forEach { (name, value) -> - env.extensions.create(name, DotEnvProperty::class.java, name, value) + extensions.create("env", DotEnvRoot::class.java, envProvider, dotenvProperties) as ExtensionAware + dotenvProperties.forEach { (name, value) -> + env.extensions.create(name, DotEnvProperty::class.java, envProvider, name, value) } } - private fun Project.envTemplate(filename: String = ".env.template") = + private fun Project.dotenvTemplate(filename: String = ".env.template"): Map = readText(filename).let(DotEnvParser::parse) - private fun Project.envSource(filename: String = ".env") = + private fun Project.dotenvSource(filename: String = ".env"): Map = readText(filename).let(DotEnvParser::parse) private fun Project.readText(filename: String): String { diff --git a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt index f267db8..864f5bb 100644 --- a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt +++ b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt @@ -1,11 +1,16 @@ package co.uzzu.dotenv.gradle -open class DotEnvRoot(private val map: Map) { +import co.uzzu.dotenv.EnvProvider + +open class DotEnvRoot( + private val envProvider: EnvProvider, + private val map: Map +) { /** * @return Indicates an environment variable with specified name is present */ fun isPresent(name: String): Boolean = - System.getenv()[name]?.let { true } + envProvider.getenv()[name]?.let { true } ?: map[name]?.let { true } ?: false @@ -14,7 +19,7 @@ open class DotEnvRoot(private val map: Map) { * @throws IllegalStateException if it was not set */ fun fetch(name: String) = - System.getenv()[name] + envProvider.getenv()[name] ?: map[name] ?: throw IllegalStateException("""Environment variable $name was not set.""") @@ -23,7 +28,7 @@ open class DotEnvRoot(private val map: Map) { * @throws IllegalStateException if it was not set */ fun fetch(name: String, defaultValue: String) = - System.getenv()[name] + envProvider.getenv()[name] ?: map[name] ?: defaultValue @@ -31,17 +36,21 @@ open class DotEnvRoot(private val map: Map) { * @return An environment variable. If it was not set, returns specified default value */ fun fetchOrNull(name: String): String? = - System.getenv()[name] + envProvider.getenv()[name] ?: map[name] } -open class DotEnvProperty(private val name: String, private val dotenvValue: String?) { +open class DotEnvProperty( + private val envProvider: EnvProvider, + private val name: String, + private val dotenvValue: String? +) { /** * @return Indicates an environment variable is present */ val isPresent: Boolean - get() = System.getenv()[name]?.let { true } + get() = envProvider.getenv()[name]?.let { true } ?: dotenvValue?.let { true } ?: false @@ -51,7 +60,7 @@ open class DotEnvProperty(private val name: String, private val dotenvValue: Str */ val value: String get() = - System.getenv()[name] + envProvider.getenv()[name] ?: dotenvValue ?: throw IllegalStateException("""Environment variable $name was not set.""") @@ -59,7 +68,7 @@ open class DotEnvProperty(private val name: String, private val dotenvValue: Str * @return An environment variable. If it was not set, returns specified default value */ fun orElse(defaultValue: String): String = - System.getenv()[name] + envProvider.getenv()[name] ?: dotenvValue ?: defaultValue @@ -67,6 +76,6 @@ open class DotEnvProperty(private val name: String, private val dotenvValue: Str * @return An environment variable. If it was not set, returns null. */ fun orNull(): String? = - System.getenv()[name] + envProvider.getenv()[name] ?: dotenvValue } diff --git a/plugin/src/test/kotlin/co/uzzu/dotenv/InMemoryEnvProvider.kt b/plugin/src/test/kotlin/co/uzzu/dotenv/InMemoryEnvProvider.kt new file mode 100644 index 0000000..8dd3414 --- /dev/null +++ b/plugin/src/test/kotlin/co/uzzu/dotenv/InMemoryEnvProvider.kt @@ -0,0 +1,8 @@ +package co.uzzu.dotenv + +class InMemoryEnvProvider( + private val map: Map +) : EnvProvider { + override fun getenv(name: String): String? = map[name] + override fun getenv(): Map = map +} diff --git a/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvPropertyTest.kt b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvPropertyTest.kt new file mode 100644 index 0000000..340c3c6 --- /dev/null +++ b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvPropertyTest.kt @@ -0,0 +1,96 @@ +package co.uzzu.dotenv.gradle + +import co.uzzu.dotenv.InMemoryEnvProvider +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class DotEnvPropertyTest { + + @Test + fun isPresentByEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val property = DotEnvProperty(envProvider, "FOO", null) + assertTrue(property.isPresent) + } + + @Test + fun isPresentByDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertTrue(property.isPresent) + } + + @Test + fun isNotPresent() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", null) + assertFalse(property.isPresent) + } + + @Test + fun valueFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("env", property.value) + } + + @Test + fun valueFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("dotenv", property.value) + } + + @Test + fun throwIfNoVariables() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", null) + assertThrows(IllegalStateException::class.java) { property.value } + } + + @Test + fun valueOrElseFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("env", property.value) + } + + @Test + fun valueOrElseFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("dotenv", property.value) + } + + @Test + fun valueOrElse() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", null) + assertEquals("default", property.orElse("default")) + } + + @Test + fun fetchOrNullFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("env", property.orNull()) + } + + @Test + fun fetchOrNullFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", "dotenv") + assertEquals("dotenv", property.orNull()) + } + + @Test + fun fetchOrNull() { + val envProvider = InMemoryEnvProvider(mapOf()) + val property = DotEnvProperty(envProvider, "FOO", null) + assertNull(property.orNull()) + } +} diff --git a/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvRootTest.kt b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvRootTest.kt new file mode 100644 index 0000000..371dca9 --- /dev/null +++ b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/DotEnvRootTest.kt @@ -0,0 +1,96 @@ +package co.uzzu.dotenv.gradle + +import co.uzzu.dotenv.InMemoryEnvProvider +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class DotEnvRootTest { + + @Test + fun isPresentByEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val root = DotEnvRoot(envProvider, mapOf()) + assertTrue(root.isPresent("FOO")) + } + + @Test + fun isPresentByDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertTrue(root.isPresent("FOO")) + } + + @Test + fun isNotPresent() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf()) + assertFalse(root.isPresent("FOO")) + } + + @Test + fun fetchFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("env", root.fetch("FOO")) + } + + @Test + fun fetchFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("dotenv", root.fetch("FOO")) + } + + @Test + fun throwIfNoVariables() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf()) + assertThrows(IllegalStateException::class.java) { root.fetch("FOO") } + } + + @Test + fun fetchOrElseFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("env", root.fetch("FOO", "default")) + } + + @Test + fun fetchOrElseFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("dotenv", root.fetch("FOO", "default")) + } + + @Test + fun fetchOrElse() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf()) + assertEquals("default", root.fetch("FOO", "default")) + } + + @Test + fun fetchOrNullFromEnv() { + val envProvider = InMemoryEnvProvider(mapOf("FOO" to "env")) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("env", root.fetch("FOO", "default")) + } + + @Test + fun fetchOrNullFromDotEnv() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf("FOO" to "dotenv")) + assertEquals("dotenv", root.fetch("FOO", "default")) + } + + @Test + fun fetchOrNull() { + val envProvider = InMemoryEnvProvider(mapOf()) + val root = DotEnvRoot(envProvider, mapOf()) + assertNull(root.fetchOrNull("FOO")) + } +}