From 8c3243fb52d6281612df44d4e395bccc1fdeb7e9 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 3 Oct 2022 11:02:35 -0700 Subject: [PATCH] Cleaned up test with assertk --- README.md | 5 ++ build.gradle.kts | 1 + .../net/thauvin/erik/jokeapi/models/Flag.kt | 2 +- .../net/thauvin/erik/jokeapi/ApiCallTest.kt | 16 ++-- .../thauvin/erik/jokeapi/ExceptionsTest.kt | 48 +++++++----- .../net/thauvin/erik/jokeapi/GetJokeTest.kt | 76 ++++++++++++------- .../thauvin/erik/jokeapi/GetRawJokeTest.kt | 21 ++--- .../thauvin/erik/jokeapi/JokeConfigTest.kt | 21 ++--- 8 files changed, 119 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index ad5223e..cb01051 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,11 @@ class HttpErrorException( To use with [Gradle](https://gradle.org/), include the following dependency in your build file: ```gradle +repositories { + mavenCentral() + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } +} + dependencies { implementation("net.thauvin.erik:jokeapi:0.9-SNAPSHOT") } diff --git a/build.gradle.kts b/build.gradle.kts index 07eee0c..e433258 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") + testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") } tasks.test { diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt index 00715ac..ab2d73e 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt @@ -42,5 +42,5 @@ enum class Flag(val value: String) { RACIST("racist"), SEXIST("sexist"), EXPLICIT("explicit"), - ALL("${NSFW.value},${RELIGIOUS.value},${POLITICAL.value},${RACIST.value},${SEXIST.value},${EXPLICIT.value}"), + ALL("${NSFW.value},${RELIGIOUS.value},${POLITICAL.value},${RACIST.value},${SEXIST.value},${EXPLICIT.value}") } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt index 83d292b..057f4f9 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -32,19 +32,21 @@ package net.thauvin.erik.jokeapi +import assertk.assertThat +import assertk.assertions.isGreaterThan +import assertk.assertions.startsWith import net.thauvin.erik.jokeapi.JokeApi.Companion.apiCall import net.thauvin.erik.jokeapi.JokeApi.Companion.logger import net.thauvin.erik.jokeapi.models.Format -import net.thauvin.erik.jokeapi.models.Language import net.thauvin.erik.jokeapi.models.Parameter import org.json.JSONObject import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import java.util.logging.ConsoleHandler import java.util.logging.Level +import kotlin.test.assertContains internal class ApiCallTest { @Test @@ -53,9 +55,9 @@ internal class ApiCallTest { val response = apiCall(endPoint = "flags") val json = JSONObject(response) assertAll("Validate JSON", - { assertFalse(json.getBoolean("error"), "should not be an error") }, - { assertTrue(json.getJSONArray("flags").length() > 0, "should have flags") }, - { assertTrue(json.getLong("timestamp") > 0, "should have a timestamp") }) + { assertFalse(json.getBoolean("error"), "apiCall(flags).error") }, + { assertThat(json.getJSONArray("flags").length(), "apiCall(flags).flags").isGreaterThan(0) }, + { assertThat(json.getLong("timestamp"), "apiCall(flags).timestamp").isGreaterThan(0) }) } @Test @@ -65,14 +67,14 @@ internal class ApiCallTest { endPoint = "langcode", path = "french", params = mapOf(Parameter.FORMAT to Format.YAML.value) ) - assertTrue(lang.contains("code: \"fr\"")) { "should contain ${Language.FR.value}" } + assertContains(lang, "code: \"fr\"", false, "apiCall(langcode, french, yaml)") } @Test fun `Get Ping Response`() { // See https://v2.jokeapi.dev/#ping-endpoint val ping = apiCall(endPoint = "ping", params = mapOf(Parameter.FORMAT to Format.TXT.value)) - assertTrue(ping.startsWith("Pong!"), "should return pong") + assertThat(ping, "apiCall(ping, txt)").startsWith("Pong!") } companion object { diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index 939fdfb..e28cc7a 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -32,6 +32,14 @@ package net.thauvin.erik.jokeapi +import assertk.assertThat +import assertk.assertions.index +import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThan +import assertk.assertions.isNotEmpty +import assertk.assertions.isNull +import assertk.assertions.size +import assertk.assertions.startsWith import net.thauvin.erik.jokeapi.JokeApi.Companion.fetchUrl import net.thauvin.erik.jokeapi.JokeApi.Companion.getJoke import net.thauvin.erik.jokeapi.JokeApi.Companion.logger @@ -52,45 +60,51 @@ import java.util.logging.ConsoleHandler import java.util.logging.Level internal class ExceptionsTest { + private val httpStat = "https://httpstat.us" + @Test fun `Validate Joke Exception`() { val e = assertThrows { getJoke(categories = setOf(Category.CHRISTMAS), search = "foo") } logger.fine(e.debug()) - assertAll("JokeException Validation", - { assertEquals(106, e.code, "code should be valid") }, - { assertTrue(e.error, "should be an error") }, - { assertFalse(e.internalError, "should not be internal error") }, - { assertEquals("No matching joke found", e.message, "message should match") }, - { assertEquals(1, e.causedBy.size, "causedBy size should be 1") }, - { assertTrue(e.causedBy[0].startsWith("No jokes"), "causedBy should start with no jokes") }, - { assertTrue(e.additionalInfo.isNotEmpty(), "additional info should not be empty") }, - { assertTrue(e.timestamp > 0, "timestamp should be > 0") }) + assertAll( + "JokeException Validation", + { assertEquals(106, e.code) { "getJoke(${Category.CHRISTMAS}, foo).code" } }, + { assertTrue(e.error) { "getJoke(${Category.CHRISTMAS}, foo).error" } }, + { assertFalse(e.internalError) { "getJoke(${Category.CHRISTMAS}, foo).internalError" } }, + { assertEquals("No matching joke found", e.message) { "getJoke(${Category.CHRISTMAS}, foo).message" } }, + { assertThat(e.causedBy, "getJoke(${Category.CHRISTMAS}, foo).causedBy").size().isEqualTo(1) }, + { assertThat(e.causedBy, "getJoke(${Category.CHRISTMAS}, foo).causedBy").index(0).startsWith("No jokes") }, + { assertThat(e.additionalInfo, "getJoke(${Category.CHRISTMAS}, foo).additionalInfo").isNotEmpty() }, + { assertThat(e.timestamp, "getJoke(${Category.CHRISTMAS}, foo).timestamp").isGreaterThan(0) }, + ) } @ParameterizedTest(name = "HTTP Status Code: {0}") @ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523]) fun `Validate HTTP Error Exceptions`(input: Int) { val e = assertThrows { - fetchUrl("https://httpstat.us/$input") + fetchUrl("$httpStat/$input") } assertAll("HttpErrorException Validation", - { assertEquals(input, e.statusCode) { "status code should be $input" } }, - { assertTrue(e.message!!.isNotEmpty()) { "message for $input should not be empty" } }, - { assertTrue(e.cause!!.message!!.isNotEmpty()) { "cause of $input should not be empty" } }) + { assertEquals(input, e.statusCode) { "fetchUrl($httpStat/$input).statusCode" } }, + { assertThat(e.message!!, "fetchUrl($httpStat/$input).message").isNotEmpty() }, + { assertThat(e.cause!!.message!!, "fetchUrl($httpStat/$input).cause.message").isNotEmpty() } + ) } @Test fun `Fetch Invalid URL`() { val statusCode = 999 val e = assertThrows { - fetchUrl("https://httpstat.us/$statusCode") + fetchUrl("$httpStat/$statusCode") } Assertions.assertAll("JokeException Validation", - { assertEquals(statusCode, e.statusCode) { "status code should be $statusCode" } }, - { assertTrue(e.message!!.isNotEmpty(), "message should not be empty") }, - { assertTrue(e.cause == null, "cause should be null") }) + { assertEquals(statusCode, e.statusCode) { "fetchUrl($httpStat/$statusCode).statusCode" } }, + { assertThat(e.message!!, "fetchUrl($httpStat/$statusCode).message").isNotEmpty() }, + { assertThat(e.cause, "fetchUrl($httpStat/$statusCode).statusCode.cause").isNull() } + ) } companion object { diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index 908e80b..edc85ff 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -32,6 +32,15 @@ package net.thauvin.erik.jokeapi +import assertk.all +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.isEmpty +import assertk.assertions.isGreaterThan +import assertk.assertions.isGreaterThanOrEqualTo +import assertk.assertions.isIn +import assertk.assertions.isNotEmpty +import assertk.assertions.size import net.thauvin.erik.jokeapi.JokeApi.Companion.getJoke import net.thauvin.erik.jokeapi.JokeApi.Companion.logger import net.thauvin.erik.jokeapi.exceptions.JokeException @@ -49,6 +58,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.util.logging.ConsoleHandler import java.util.logging.Level +import kotlin.test.assertContains internal class GetJokeTest { @Test @@ -56,24 +66,24 @@ internal class GetJokeTest { val joke = getJoke() logger.fine(joke.toString()) assertAll("No Param Joke", - { assertFalse(joke.error, "error should be false") }, - { assertTrue(joke.joke.isNotEmpty(), "joke should not be empty") }, - { assertTrue(joke.type == Type.TWOPART || joke.type == Type.SINGLE, "type should validate") }, - { assertTrue(joke.id >= 0, "id should be >= 0") }, - { assertEquals(Language.EN, joke.language, "language should be english") }) + { assertFalse(joke.error, "getJoke().error") }, + { assertThat(joke.joke, "getJoke().joke").isNotEmpty() }, + { assertThat(joke.type, "getJoke().type").isIn(Type.SINGLE, Type.TWOPART) }, + { assertThat(joke.id, "getJoke().id").isGreaterThanOrEqualTo(0) }, + { assertEquals(Language.EN, joke.language, "getJoke().language") }) } @Test fun `Get Joke without Blacklist Flags`() { val joke = getJoke(flags = setOf(Flag.ALL)) - assertTrue(joke.flags.isEmpty(), "flags should be empty.") + assertThat(joke.flags, "getJoke(flags=ALL)").isEmpty() } @Test fun `Get Joke without any Blacklist Flags`() { val allFlags = Flag.values().filter { it != Flag.ALL }.toSet() val joke = getJoke(flags = allFlags) - assertTrue(joke.flags.isEmpty(), "flags should be empty.") + assertThat(joke.flags, "getJoke(all flags)").isEmpty() } @Test @@ -82,9 +92,15 @@ internal class GetJokeTest { val joke = getJoke(idRange = IdRange(id)) logger.fine(joke.toString()) assertAll("Joke by ID", - { assertTrue(joke.flags.contains(Flag.NSFW) && joke.flags.contains(Flag.EXPLICIT), "nsfw & explicit") }, - { assertEquals(172, joke.id) { "id is $id" } }, - { assertEquals(Category.PUN, joke.category, "category should be pun") }) + { + assertThat(joke.flags, "getJoke($id).flags").all { + contains(Flag.EXPLICIT) + contains(Flag.NSFW) + } + }, + { assertEquals(172, joke.id) { "getJoke($id).id" } }, + { assertEquals(Category.PUN, joke.category) { "getJoke($id).category" } } + ) } @Test @@ -92,31 +108,34 @@ internal class GetJokeTest { val idRange = IdRange(1, 100) val joke = getJoke(idRange = idRange) logger.fine(joke.toString()) - assertTrue(joke.id >= idRange.start && joke.id <= idRange.end, "id should be in range") + assertContains(IntRange(idRange.start, idRange.end), joke.id, "getJoke(${idRange})") } @Test fun `Get Joke with invalid ID Range`() { - val joke = getJoke(idRange = IdRange(100, 1)) + val idRange = IdRange(100, 1) + val joke = getJoke(idRange = idRange) logger.fine(joke.toString()) - assertFalse(joke.error, "should not be an error") + assertFalse(joke.error) { "getJoke(${idRange}.error" } } @Test fun `Get Joke with max ID Range`() { - val e = assertThrows { getJoke(idRange = IdRange(1, 30000)) } + val idRange = IdRange(1, 30000) + val e = assertThrows { getJoke(idRange = idRange) } assertAll("Joke w/ max ID Range", - { assertTrue(e.error, "should be an error") }, - { assertTrue(e.additionalInfo.contains("ID range"), "should contain ID range") }) + { assertTrue(e.error, "getJoke{${idRange}).error") }, + { assertContains(e.additionalInfo, "ID range", false, "getJoke{${idRange}).additionalInfo") }) } @Test fun `Get Joke with two Categories`() { val joke = getJoke(categories = setOf(Category.PROGRAMMING, Category.MISC)) logger.fine(joke.toString()) - assertTrue(joke.category == Category.PROGRAMMING || joke.category == Category.MISC) { - "category should be ${Category.PROGRAMMING.value} or ${Category.MISC.value}" - } + assertThat(joke.category, "getJoke(${Category.PROGRAMMING},${Category.MISC})").isIn( + Category.PROGRAMMING, + Category.MISC + ) } @Test @@ -124,7 +143,7 @@ internal class GetJokeTest { Category.values().filter { it != Category.ANY }.forEach { val joke = getJoke(categories = setOf(it)) logger.fine(joke.toString()) - assertEquals(it.value, joke.category.value) { "category should be ${it.value}" } + assertEquals(it.value, joke.category.value) { "getJoke($it).category" } } } @@ -132,7 +151,7 @@ internal class GetJokeTest { fun `Get Joke with each Languages`() { Language.values().forEach { val joke = getJoke(language = it) - assertEquals(it.value, joke.language.value) { "language should be ${it.value}" } + assertEquals(it.value, joke.language.value) { "getJoke(${it}).language" } } } @@ -141,7 +160,7 @@ internal class GetJokeTest { val joke = getJoke( categories = setOf(Category.DARK), type = Type.SINGLE, idRange = IdRange(178), splitNewLine = false ) - assertTrue(joke.joke.toString().contains("\n"), "should contain newline") + assertContains(joke.joke.toString(), "\n", false, "getJoke(splitNewLine=false)") } @Test @@ -149,15 +168,15 @@ internal class GetJokeTest { val joke = getJoke(safe = true) logger.fine(joke.toString()) assertAll("Safe Joke", - { assertTrue(joke.safe, "should be safe") }, - { assertTrue(joke.flags.isEmpty(), "flags should be empty") }) + { assertTrue(joke.safe, "getJoke(safe).safe") }, + { assertThat(joke.flags, "getJoke(safe).flags").isEmpty() }) } @Test fun `Get Single Joke`() { val joke = getJoke(type = Type.SINGLE) logger.fine(joke.toString()) - assertEquals(Type.SINGLE, joke.type, "type should be single") + assertEquals(Type.SINGLE, joke.type) { "getJoke(${Type.SINGLE}).type" } } @Test @@ -165,8 +184,9 @@ internal class GetJokeTest { val joke = getJoke(type = Type.TWOPART) logger.fine(joke.toString()) assertAll("Two-Parts Joke", - { assertEquals(Type.TWOPART, joke.type, "type should be two-part") }, - { assertTrue(joke.joke.size > 1, "should have multiple lines") }) + { assertEquals(Type.TWOPART, joke.type) { "getJoke(${Type.TWOPART}).type" } }, + { assertThat(joke.joke, "getJoke(${Type.TWOPART}).joke").size().isGreaterThan(1) } + ) } @Test @@ -175,7 +195,7 @@ internal class GetJokeTest { val joke = getJoke(search = "his wife", categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true) logger.fine(joke.toString()) - assertEquals(id, joke.id) { "id should be $id" } + assertEquals(id, joke.id) { "getJoke(his wife).id" } } companion object { diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt index 77b3e34..b55a2d1 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt @@ -32,50 +32,53 @@ package net.thauvin.erik.jokeapi +import assertk.assertThat +import assertk.assertions.doesNotContain +import assertk.assertions.isNotEmpty +import assertk.assertions.startsWith import net.thauvin.erik.jokeapi.JokeApi.Companion.getRawJoke import net.thauvin.erik.jokeapi.JokeApi.Companion.logger import net.thauvin.erik.jokeapi.models.Format import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import java.util.logging.ConsoleHandler import java.util.logging.Level +import kotlin.test.assertContains internal class GetRawJokeTest { @Test fun `Get Raw Joke with TXT`() { val response = getRawJoke(format = Format.TEXT) assertAll("Plain Text", - { assertTrue(response.isNotEmpty(), "should be not empty") }, - { assertFalse(response.startsWith("Error "), "should not be an error") }) + { assertThat(response, "getRawJoke(txt)").isNotEmpty() }, + { assertFalse(response.startsWith("Error "), "getRawJoke(txt)") } + ) } @Test fun `Get Raw Joke with invalid Amount`() { val response = getRawJoke(amount = 100) - assertFalse(response.contains("\"amount\":"), "should not have amount") + assertThat(response, "getRawJoke(100)").doesNotContain("\"amount\":") } @Test fun `Get Raw Joke with XML`() { val response = getRawJoke(format = Format.XML) - assertTrue( - response.startsWith("\n\n false"), "should be xml" - ) + assertThat(response, "getRawJoke(xml)").startsWith("\n\n false") } @Test fun `Get Raw Joke with YAML`() { val response = getRawJoke(format = Format.YAML) - assertTrue(response.startsWith("error: false"), "should be yaml") + assertThat(response, "getRawJoke(yaml)").startsWith("error: false") } @Test fun `Get Raw Jokes`() { val response = getRawJoke(amount = 2) - assertTrue(response.contains("\"amount\": 2"), "amount should be 2") + assertContains(response, "\"amount\": 2", false, "getRawJoke(2)") } companion object { diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index b11e943..c8959b0 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -32,6 +32,9 @@ package net.thauvin.erik.jokeapi +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.size import net.thauvin.erik.jokeapi.JokeApi.Companion.getJoke import net.thauvin.erik.jokeapi.JokeApi.Companion.getRawJoke import net.thauvin.erik.jokeapi.JokeApi.Companion.logger @@ -48,6 +51,7 @@ import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import java.util.logging.ConsoleHandler import java.util.logging.Level +import kotlin.test.assertContains class JokeConfigTest { @Test @@ -65,12 +69,13 @@ class JokeConfigTest { val joke = getJoke(config) logger.fine(joke.toString()) assertAll("Two-Parts Joke", - { assertEquals(Type.TWOPART, joke.type, "type should be two-part") }, - { assertEquals(joke.category, Category.PROGRAMMING) { "category should be ${Category.PROGRAMMING}" } }, - { assertEquals(joke.joke.size, 2, "should have two lines") }, - { assertEquals(joke.language, Language.EN, "language should be english") }, - { assertTrue(joke.flags.isEmpty(), "flags should empty") }, - { assertTrue(joke.id in id - 2..id + 2) { "id should be $id +- 2" } }) + { assertEquals(Type.TWOPART, joke.type, "config.type") }, + { assertEquals(joke.category, Category.PROGRAMMING) { "config.category" } }, + { assertThat(joke.joke, "config.joke").size().isEqualTo(2) }, + { assertEquals(joke.language, Language.EN, "config.language") }, + { assertTrue(joke.flags.isEmpty(), "config.flags.isEmpty") }, + { assertContains(IntRange(id - 2, id + 2), joke.id, "config.id") } + ) } @Test @@ -83,9 +88,7 @@ class JokeConfigTest { safe(true) }.build() val joke = getRawJoke(config) - assertTrue( - joke.contains("----------------------------------------------"), "should contain -- delimiter" - ) + assertContains(joke, "----------------------------------------------", false, "config.amount(2)") } companion object {