diff --git a/README.md b/README.md index baab6e8..6eaed1c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ import net.thauvin.erik.jokeapi.getJoke val joke = getJoke() val safe = getJoke(safe = true) -val pun = getJoke(category = Category.PUN) +val pun = getJoke(categories = setOf(Category.PUN)) ``` The parameters match the [joke endpoint](https://v2.jokeapi.dev/#joke-endpoint). @@ -27,7 +27,7 @@ data class Joke( val flags: Set, val id: Int, val safe: Boolean, - val language: Language + val lang: Language ) ``` - View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt)... @@ -35,7 +35,7 @@ data class Joke( To retrieve multiple jokes: ```kotlin -val frenchJokes = getJokes(amount = 2, type = Type.TWOPART, language = Language.FR) +val frenchJokes = getJokes(amount = 2, type = Type.TWOPART, lang = Language.FR) frenchJokes.forEach { println(it.joke.joinToString("\n")) println("-".repeat(46)) @@ -70,6 +70,18 @@ class HttpErrorException( ``` - View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt)... +## Java + +To make it easier to use the library with Java, a configuration builder is available: + +```java +var config = new JokeConfig.Builder() + .type(Type.SINGLE) + .safe(true) + .build(); +var joke = JokeApi.getJoke(config); +joke.getJoke().forEach(System.out::println); +``` ## Gradle, Maven, etc. To use with [Gradle](https://gradle.org/), include the following dependency in your build file: @@ -114,19 +126,6 @@ lang: "en" ``` - View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt)... -## Java - -To make it easier to use the library with Java, a configuration builder is also available: - -```java -var config = new JokeConfig.Builder() - .type(Type.SINGLE) - .safe(true) - .build(); -var joke = JokeApi.getJoke(config); -joke.getJoke().forEach(System.out::println); -``` - ## Extending A generic `apiCall()` function is available to access other [JokeAPI endpoints](https://v2.jokeapi.dev/#endpoints). diff --git a/build.gradle.kts b/build.gradle.kts index d59cc39..8317052 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { id("io.gitlab.arturbosch.detekt") version "1.21.0" id("java") id("maven-publish") - id("org.jetbrains.dokka") version "1.7.10" + id("org.jetbrains.dokka") version "1.7.20" id("org.jetbrains.kotlinx.kover") version "0.6.1" id("org.sonarqube") version "3.4.0.2513" id("signing") diff --git a/detekt-baseline.xml b/detekt-baseline.xml index af692ce..8ca446d 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -2,11 +2,11 @@ - ComplexMethod:JokeApi.kt$fun getRawJokes( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.EN, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ): String - LongParameterList:JokeApi.kt$( amount: Int, categories: Set<Category> = setOf(Category.ANY), language: Language = Language.EN, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, search: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, splitNewLine: Boolean = false, auth: String = "" ) - LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.EN, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ) - LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.EN, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, search: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, splitNewLine: Boolean = false, auth: String = "" ) - LongParameterList:JokeConfig.kt$JokeConfig$( val categories: Set<Category>, val language: Language, val flags: Set<Flag>, val type: Type, val format: Format, val search: String, val idRange: IdRange, val amount: Int, val safe: Boolean, val splitNewLine: Boolean, val auth: String ) + ComplexMethod:JokeApi.kt$fun getRawJokes( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ): String + LongParameterList:JokeApi.kt$( amount: Int, categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) + LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) + LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ) + LongParameterList:JokeConfig.kt$JokeConfig$( val categories: Set<Category>, val language: Language, val flags: Set<Flag>, val type: Type, val format: Format, val contains: String, val idRange: IdRange, val amount: Int, val safe: Boolean, val splitNewLine: Boolean, val auth: String ) LongParameterList:JokeException.kt$JokeException$( val internalError: Boolean, val code: Int, message: String, val causedBy: List<String>, val additionalInfo: String, val timestamp: Long, cause: Throwable? = null ) MagicNumber:util.kt$200 MagicNumber:util.kt$399 @@ -19,5 +19,6 @@ MagicNumber:util.kt$500 MagicNumber:util.kt$523 TooManyFunctions:JokeConfig.kt$JokeConfig$Builder + UnusedPrivateMember:JokeConfig.kt$JokeConfig.Builder$search: String diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index 4967019..849acbb 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -111,11 +111,11 @@ class JokeApi private constructor() { fun getRawJokes(config: JokeConfig): String { return getRawJokes( categories = config.categories, - language = config.language, - flags = config.flags, + lang = config.language, + blacklistFlags = config.flags, type = config.type, format = config.format, - search = config.search, + contains = config.contains, idRange = config.idRange, amount = config.amount, safe = config.safe, @@ -134,14 +134,14 @@ class JokeApi private constructor() { fun getJoke(config: JokeConfig = JokeConfig.Builder().build()): Joke { return getJoke( categories = config.categories, - language = config.language, - flags = config.flags, + lang = config.language, + blacklistFlags = config.flags, type = config.type, - search = config.search, + contains = config.contains, idRange = config.idRange, safe = config.safe, - splitNewLine = config.splitNewLine, - auth = config.auth + auth = config.auth, + splitNewLine = config.splitNewLine ) } @@ -155,15 +155,15 @@ class JokeApi private constructor() { fun getJokes(config: JokeConfig): Array { return getJokes( categories = config.categories, - language = config.language, - flags = config.flags, + lang = config.language, + blacklistFlags = config.flags, type = config.type, - search = config.search, + contains = config.contains, idRange = config.idRange, amount = config.amount, safe = config.safe, - splitNewLine = config.splitNewLine, - auth = config.auth + auth = config.auth, + splitNewLine = config.splitNewLine ) } } @@ -179,22 +179,22 @@ class JokeApi private constructor() { */ fun getJoke( categories: Set = setOf(Category.ANY), - language: Language = Language.EN, - flags: Set = emptySet(), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), type: Type = Type.ALL, - search: String = "", + contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, - splitNewLine: Boolean = false, - auth: String = "" + auth: String = "", + splitNewLine: Boolean = false ): Joke { val json = JSONObject( getRawJokes( categories = categories, - language = language, - flags = flags, + lang = lang, + blacklistFlags = blacklistFlags, type = type, - search = search, + contains = contains, idRange = idRange, safe = safe, auth = auth @@ -218,22 +218,22 @@ fun getJoke( fun getJokes( amount: Int, categories: Set = setOf(Category.ANY), - language: Language = Language.EN, - flags: Set = emptySet(), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), type: Type = Type.ALL, - search: String = "", + contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, - splitNewLine: Boolean = false, - auth: String = "" + auth: String = "", + splitNewLine: Boolean = false ): Array { val json = JSONObject( getRawJokes( categories = categories, - language = language, - flags = flags, + lang = lang, + blacklistFlags = blacklistFlags, type = type, - search = search, + contains = contains, idRange = idRange, amount = amount, safe = safe, @@ -259,11 +259,11 @@ fun getJokes( */ fun getRawJokes( categories: Set = setOf(Category.ANY), - language: Language = Language.EN, - flags: Set = emptySet(), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, - search: String = "", + contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, @@ -279,16 +279,16 @@ fun getRawJokes( } // Language - if (language != Language.EN) { - params[Parameter.LANG] = language.value + if (lang != Language.EN) { + params[Parameter.LANG] = lang.value } // Flags - if (flags.isNotEmpty()) { - if (flags.contains(Flag.ALL)) { + if (blacklistFlags.isNotEmpty()) { + if (blacklistFlags.contains(Flag.ALL)) { params[Parameter.FLAGS] = Flag.ALL.value } else { - params[Parameter.FLAGS] = flags.stream().map(Flag::value).collect(Collectors.joining(",")) + params[Parameter.FLAGS] = blacklistFlags.stream().map(Flag::value).collect(Collectors.joining(",")) } } @@ -303,8 +303,8 @@ fun getRawJokes( } // Contains - if (search.isNotBlank()) { - params[Parameter.CONTAINS] = search + if (contains.isNotBlank()) { + params[Parameter.CONTAINS] = contains } // Range diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index 50f8dc4..cf1a7d8 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -51,7 +51,7 @@ class JokeConfig private constructor( val flags: Set, val type: Type, val format: Format, - val search: String, + val contains: String, val idRange: IdRange, val amount: Int, val safe: Boolean, @@ -67,31 +67,31 @@ class JokeConfig private constructor( */ data class Builder( var categories: Set = setOf(Category.ANY), - var language: Language = Language.EN, - var flags: Set = emptySet(), + var lang: Language = Language.EN, + var blacklistFlags: Set = emptySet(), var type: Type = Type.ALL, var format: Format = Format.JSON, - var search: String = "", + var contains: String = "", var idRange: IdRange = IdRange(), var amount: Int = 1, var safe: Boolean = false, - var splitNewLine: Boolean = false, - var auth: String = "" - ) { + var auth: String = "", + var splitNewLine: Boolean = false + ) { fun categories(categories: Set) = apply { this.categories = categories } - fun language(language: Language) = apply { this.language = language } - fun flags(flags: Set) = apply { this.flags = flags } + fun lang(language: Language) = apply { lang = language } + fun blacklistFlags(flags: Set) = apply { blacklistFlags = flags } fun type(type: Type) = apply { this.type = type } fun format(format: Format) = apply { this.format = format } - fun search(search: String) = apply { this.search = search } + fun contains(search: String) = apply { contains = search } fun idRange(idRange: IdRange) = apply { this.idRange = idRange } fun amount(amount: Int) = apply { this.amount = amount } fun safe(safe: Boolean) = apply { this.safe = safe } - fun splitNewLine(splitNewLine: Boolean) = apply { this.splitNewLine = splitNewLine } fun auth(auth: String) = apply { this.auth = auth } + fun splitNewLine(splitNewLine: Boolean) = apply { this.splitNewLine = splitNewLine } fun build() = JokeConfig( - categories, language, flags, type, format, search, idRange, amount, safe, splitNewLine, auth + categories, lang, blacklistFlags, type, format, contains, idRange, amount, safe, splitNewLine, auth ) } } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt index 57f13b9..fd1984c 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt @@ -37,6 +37,7 @@ package net.thauvin.erik.jokeapi.models */ enum class Format(val value: String) { JSON("json"), + /** Plain Text */ TXT("txt"), XML("xml"), diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt index e9df053..ed5a2b9 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt @@ -42,5 +42,5 @@ data class Joke( val flags: Set, val id: Int, val safe: Boolean, - val language: Language + val lang: Language ) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt index 3abb17f..34fa9bd 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt @@ -38,14 +38,19 @@ package net.thauvin.erik.jokeapi.models enum class Language(val value: String) { /** Czech */ CS("cs"), + /** German */ DE("de"), + /** English */ EN("en"), + /** Spanish */ ES("es"), + /** French */ FR("fr"), + /** Portuguese */ PT("pt") } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/util.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/util.kt index cb3b4b6..a076985 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/util.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/util.kt @@ -166,7 +166,7 @@ internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke { flags = enabledFlags, safe = json.getBoolean("safe"), id = json.getInt("id"), - language = Language.valueOf(json.getString(Parameter.LANG).uppercase()) + lang = Language.valueOf(json.getString(Parameter.LANG).uppercase()) ) } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index cfff0c8..baf9e7f 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -60,7 +60,7 @@ internal class ExceptionsTest { @Test fun `Validate Joke Exception`() { val e = assertThrows { - getJoke(categories = setOf(Category.CHRISTMAS), search = "foo") + getJoke(categories = setOf(Category.CHRISTMAS), contains = "foo") } logger.fine(e.debug()) assertThat(e, "getJoke(${Category.CHRISTMAS},foo)").all { diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index 857949f..a8e7b23 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -72,20 +72,20 @@ internal class GetJokeTest { prop(Joke::joke).isNotEmpty() prop(Joke::type).isIn(Type.SINGLE, Type.TWOPART) prop(Joke::id).isGreaterThanOrEqualTo(0) - prop(Joke::language).isEqualTo(Language.EN) + prop(Joke::lang).isEqualTo(Language.EN) } } @Test fun `Get Joke without Blacklist Flags`() { - val joke = getJoke(flags = setOf(Flag.ALL)) + val joke = getJoke(blacklistFlags = setOf(Flag.ALL)) assertThat(joke::flags).isEmpty() } @Test fun `Get Joke without any Blacklist Flags`() { val allFlags = Flag.values().filter { it != Flag.ALL }.toSet() - val joke = getJoke(flags = allFlags) + val joke = getJoke(blacklistFlags = allFlags) assertThat(joke::flags).isEmpty() } @@ -115,7 +115,7 @@ internal class GetJokeTest { @Test fun `Get Joke with invalid ID Range`() { val idRange = IdRange(100, 1) - val e = assertThrows { getJoke(idRange = idRange, language = Language.DE) } + val e = assertThrows { getJoke(idRange = idRange, lang = Language.DE) } assertThat(e::message).isNotNull().contains("100, 1") } @@ -150,9 +150,9 @@ internal class GetJokeTest { @Test fun `Get Joke with each Languages`() { Language.values().forEach { - val joke = getJoke(language = it) + val joke = getJoke(lang = it) logger.fine(joke.toString()) - assertThat(joke::language, "getJoke($it)").prop(Language::value).isEqualTo(it.value) + assertThat(joke::lang, "getJoke($it)").prop(Language::value).isEqualTo(it.value) } } @@ -202,7 +202,7 @@ internal class GetJokeTest { val id = 265 val search = "his wife" val joke = - getJoke(search = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true) + getJoke(contains = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true) logger.fine(joke.toString()) assertThat(joke, "getJoke($search)").all { prop(Joke::id).isEqualTo(id) diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt index bbc0bd5..3646eb0 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt @@ -57,14 +57,14 @@ internal class GetJokesTest { @Test fun `Get Multiple Jokes`() { val amount = 2 - val jokes = getJokes(amount = amount, safe = true, language = Language.FR) + val jokes = getJokes(amount = amount, safe = true, lang = Language.FR) assertThat(jokes, "jokes").all { size().isEqualTo(amount) each { it.prop(Joke::id).isGreaterThanOrEqualTo(0) it.prop(Joke::safe).isTrue() it.prop(Joke::flags).isEmpty() - it.prop(Joke::language).isEqualTo(Language.FR) + it.prop(Joke::lang).isEqualTo(Language.FR) } } } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt index 770b563..868c296 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -76,7 +76,7 @@ internal class GetRawJokesTest { @Test fun `Get Raw Invalid Jokes`() { - val response = getRawJokes(search = "foo", safe = true, amount = 2, idRange = IdRange(160, 161)) + val response = getRawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161)) assertContains(response, "\"error\": true", false, "getRawJokes(foo)") } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index a1e792e..2110474 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -65,7 +65,7 @@ class JokeConfigTest { val joke = getJoke() assertThat(joke, "joke").all { prop(Joke::id).isGreaterThanOrEqualTo(0) - prop(Joke::language).isEqualTo(Language.EN) + prop(Joke::lang).isEqualTo(Language.EN) } } @@ -74,8 +74,8 @@ class JokeConfigTest { val id = 266 val config = JokeConfig.Builder().apply { categories(setOf(Category.PROGRAMMING)) - language(Language.EN) - flags(setOf(Flag.ALL)) + lang(Language.EN) + blacklistFlags(setOf(Flag.ALL)) type(Type.TWOPART) idRange(IdRange(id - 2, id + 2)) safe(true) @@ -86,7 +86,7 @@ class JokeConfigTest { prop(Joke::type).isEqualTo(Type.TWOPART) prop(Joke::category).isEqualTo(Category.PROGRAMMING) prop(Joke::joke).size().isEqualTo(2) - prop(Joke::language).isEqualTo(Language.EN) + prop(Joke::lang).isEqualTo(Language.EN) prop(Joke::flags).isEmpty() prop(Joke::id).isBetween(id - 2, id + 2) } @@ -113,7 +113,7 @@ class JokeConfigTest { val config = JokeConfig.Builder().apply { categories(setOf(Category.PROGRAMMING)) format(Format.TXT) - search("bar") + contains("bar") amount(2) safe(true) }.build() @@ -127,7 +127,7 @@ class JokeConfigTest { val config = JokeConfig.Builder().apply { amount(amount) safe(true) - language(Language.FR) + lang(Language.FR) }.build() val jokes = getJokes(config) assertThat(jokes, "jokes").all { @@ -136,7 +136,7 @@ class JokeConfigTest { it.prop(Joke::id).isGreaterThanOrEqualTo(0) it.prop(Joke::safe).isTrue() it.prop(Joke::flags).isEmpty() - it.prop(Joke::language).isEqualTo(Language.FR) + it.prop(Joke::lang).isEqualTo(Language.FR) } } } @@ -156,11 +156,11 @@ class JokeConfigTest { val auth = "token" val config = JokeConfig.Builder().apply { categories(categories) - language(language) - flags(flags) + lang(language) + blacklistFlags(flags) type(type) format(format) - search(search) + contains(search) idRange(idRange) amount(amount) safe(safe) @@ -173,7 +173,7 @@ class JokeConfigTest { prop(JokeConfig::flags).isEqualTo(flags) prop(JokeConfig::type).isEqualTo(type) prop(JokeConfig::format).isEqualTo(format) - prop(JokeConfig::search).isEqualTo(search) + prop(JokeConfig::contains).isEqualTo(search) prop(JokeConfig::idRange).isEqualTo(idRange) prop(JokeConfig::amount).isEqualTo(amount) prop(JokeConfig::safe).isEqualTo(safe)