Added httpError function
Renamed apiCall to getRawJoke Added HTTP Error Exception class Added models and exceptions
This commit is contained in:
parent
5ac9e751c3
commit
c27321d31a
13 changed files with 288 additions and 108 deletions
68
README.md
68
README.md
|
@ -26,3 +26,71 @@ data class Joke(
|
|||
val language: Language
|
||||
)
|
||||
```
|
||||
|
||||
If an error occurs, a `JokeException` is thrown:
|
||||
|
||||
```kotlin
|
||||
class JokeException(
|
||||
val error: Boolean,
|
||||
val internalError: Boolean,
|
||||
val code: Int,
|
||||
message: String,
|
||||
val causedBy: List<String>,
|
||||
val additionalInfo: String,
|
||||
val timestamp: Long,
|
||||
cause: Throwable? = null
|
||||
) : Exception(message, cause)
|
||||
```
|
||||
|
||||
If an HTTP error occurs an `HttpErrorException` is thrown, with its message and cause matching the [JokeAPI status codes](https://sv443.net/jokeapi/v2/#status-codes):
|
||||
|
||||
```kotlin
|
||||
class HttpErrorException(
|
||||
val statusCode: Int,
|
||||
message: String,
|
||||
cause: Throwable? = null
|
||||
) : IOException(message, cause)
|
||||
```
|
||||
|
||||
## Gradle, Maven, etc.
|
||||
To use with [Gradle](https://gradle.org/), include the following dependency in your build file:
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation("net.thauvin.erik:jokeapi:0.9-SNAPSHOT")
|
||||
}
|
||||
```
|
||||
|
||||
Instructions for using with Maven, Ivy, etc. can be found on Maven Central.
|
||||
|
||||
## Raw Joke
|
||||
|
||||
You can also retrieve a raw joke in all [supported formats](https://jokeapi.dev/#format-param).
|
||||
|
||||
For example for YAML:
|
||||
```kotlin
|
||||
var joke = getRawJoke(format = Format.YAML, idRange = IdRange(22))
|
||||
println(joke)
|
||||
```
|
||||
```yaml
|
||||
error: false
|
||||
category: "Programming"
|
||||
type: "single"
|
||||
joke: "If Bill Gates had a dime for every time Windows crashed ... Oh wait, he does."
|
||||
flags:
|
||||
nsfw: false
|
||||
religious: false
|
||||
political: false
|
||||
racist: false
|
||||
sexist: false
|
||||
explicit: false
|
||||
id: 22
|
||||
safe: true
|
||||
lang: "en"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>ComplexMethod:JokeApi.kt$JokeApi.Companion$@JvmStatic @JvmOverloads @Throws(IOException::class) fun apiCall( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Set<Type> = emptySet(), format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, ): String</ID>
|
||||
<ID>LongMethod:JokeApi.kt$JokeApi.Companion$@Throws(JokeException::class, IOException::class) private fun fetchUrl(url: String) : String</ID>
|
||||
<ID>LongParameterList:JokeApi.kt$JokeApi.Companion$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Set<Type> = emptySet(), format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, )</ID>
|
||||
<ID>LongParameterList:JokeApi.kt$JokeApi.Companion$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Set<Type> = emptySet(), search: String = "", idRange: IdRange = IdRange(), safe: Boolean = false )</ID>
|
||||
<ID>ComplexMethod:JokeApi.kt$JokeApi.Companion$@JvmStatic @JvmOverloads @Throws(HttpErrorException::class, IOException::class) fun getRawJoke( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, ): String</ID>
|
||||
<ID>LongParameterList:JokeApi.kt$JokeApi.Companion$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, search: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, )</ID>
|
||||
<ID>LongParameterList:JokeApi.kt$JokeApi.Companion$( categories: Set<Category> = setOf(Category.ANY), language: Language = Language.ENGLISH, flags: Set<Flag> = emptySet(), type: Type = Type.ALL, search: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, splitNewLine: Boolean = true )</ID>
|
||||
<ID>LongParameterList:JokeException.kt$JokeException$( val error: Boolean, val internalError: Boolean, val code: Int, message: String, val causedBy: List<String>, val additionalInfo: String, val timestamp: Long, cause: Throwable? = null )</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$10</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$200</ID>
|
||||
|
@ -14,10 +13,10 @@
|
|||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$403</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$404</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$413</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$428</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$414</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$429</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$500</ID>
|
||||
<ID>MagicNumber:JokeApi.kt$JokeApi.Companion$523</ID>
|
||||
<ID>ThrowsCount:JokeApi.kt$JokeApi.Companion$@Throws(JokeException::class, IOException::class) private fun fetchUrl(url: String) : String</ID>
|
||||
<ID>UtilityClassWithPublicConstructor:JokeApi.kt$JokeApi</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
|
@ -32,6 +32,15 @@
|
|||
|
||||
package net.thauvin.erik.jokeapi
|
||||
|
||||
import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
|
||||
import net.thauvin.erik.jokeapi.exceptions.JokeException
|
||||
import net.thauvin.erik.jokeapi.models.Category
|
||||
import net.thauvin.erik.jokeapi.models.Flag
|
||||
import net.thauvin.erik.jokeapi.models.Format
|
||||
import net.thauvin.erik.jokeapi.models.IdRange
|
||||
import net.thauvin.erik.jokeapi.models.Joke
|
||||
import net.thauvin.erik.jokeapi.models.Language
|
||||
import net.thauvin.erik.jokeapi.models.Type
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
|
@ -45,12 +54,14 @@ import java.util.stream.Collectors
|
|||
class JokeApi {
|
||||
companion object {
|
||||
private const val API_URL = "https://v2.jokeapi.dev/joke/"
|
||||
|
||||
@JvmStatic
|
||||
val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) }
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun apiCall(
|
||||
@Throws(HttpErrorException::class, IOException::class)
|
||||
fun getRawJoke(
|
||||
categories: Set<Category> = setOf(Category.ANY),
|
||||
language: Language = Language.ENGLISH,
|
||||
flags: Set<Flag> = emptySet(),
|
||||
|
@ -135,8 +146,8 @@ class JokeApi {
|
|||
return fetchUrl(urlBuilder.toString())
|
||||
}
|
||||
|
||||
@Throws(JokeException::class, IOException::class)
|
||||
private fun fetchUrl(url: String): String {
|
||||
@Throws(HttpErrorException::class, IOException::class)
|
||||
internal fun fetchUrl(url: String): String {
|
||||
logger.log(Level.FINE, url)
|
||||
|
||||
val connection = URL(url).openConnection() as HttpURLConnection
|
||||
|
@ -151,54 +162,72 @@ class JokeApi {
|
|||
}
|
||||
return body
|
||||
} else {
|
||||
when (connection.responseCode) {
|
||||
400 -> throw IOException(
|
||||
"400: Bad Request", IOException(
|
||||
"The request you have sent to JokeAPI is formatted incorrectly and cannot be processed"
|
||||
)
|
||||
)
|
||||
|
||||
403 -> throw IOException(
|
||||
"4o3: Forbidden", IOException(
|
||||
"You have been added to the blacklist due to malicious behavior and are not allowed" + " to send requests to JokeAPI anymore"
|
||||
)
|
||||
)
|
||||
|
||||
404 -> throw IOException(
|
||||
"404: Not Found", IOException("The URL you have requested couldn't be found")
|
||||
)
|
||||
|
||||
413 -> throw IOException(
|
||||
"413: Payload Too Large",
|
||||
IOException("The payload data sent to the server exceeds the maximum size of 5120 bytes")
|
||||
)
|
||||
|
||||
428 -> throw IOException(
|
||||
"429: Too Many Requests", IOException(
|
||||
"You have exceeded the limit of 120 requests per minute and have to wait a bit" + " until you are allowed to send requests again"
|
||||
)
|
||||
)
|
||||
|
||||
500 -> throw IOException(
|
||||
"500: Internal Server Error", IOException(
|
||||
"There was a general internal error within JokeAPI. You can get more info from" + " the properties in the response text"
|
||||
)
|
||||
)
|
||||
|
||||
523 -> throw IOException(
|
||||
"523: Origin Unreachable", IOException(
|
||||
"The server is temporarily offline due to maintenance or a dynamic IP update." + " Please be patient in this case."
|
||||
)
|
||||
)
|
||||
|
||||
else -> throw IOException("${connection.responseCode}: Unknown Error")
|
||||
throw httpError(connection.responseCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun httpError(responseCode: Int): HttpErrorException {
|
||||
val httpException: HttpErrorException
|
||||
when (responseCode) {
|
||||
400 -> httpException = HttpErrorException(
|
||||
responseCode, "Bad Request", IOException(
|
||||
"The request you have sent to JokeAPI is formatted incorrectly and cannot be processed."
|
||||
)
|
||||
)
|
||||
|
||||
403 -> httpException = HttpErrorException(
|
||||
responseCode, "Forbidden", IOException(
|
||||
"You have been added to the blacklist due to malicious behavior and are not allowed"
|
||||
+ " to send requests to JokeAPI anymore."
|
||||
)
|
||||
)
|
||||
|
||||
404 -> httpException = HttpErrorException(
|
||||
responseCode, "Not Found", IOException("The URL you have requested couldn't be found.")
|
||||
)
|
||||
|
||||
413 -> httpException = HttpErrorException(
|
||||
responseCode,
|
||||
"URI Too Long",
|
||||
IOException("The URL exceeds the maximum length of 250 characters.")
|
||||
)
|
||||
|
||||
414 -> httpException = HttpErrorException(
|
||||
responseCode,
|
||||
"Payload Too Large",
|
||||
IOException("The payload data sent to the server exceeds the maximum size of 5120 bytes.")
|
||||
)
|
||||
|
||||
429 -> httpException = HttpErrorException(
|
||||
responseCode, "Too Many Requests", IOException(
|
||||
"You have exceeded the limit of 120 requests per minute and have to wait a bit" +
|
||||
" until you are allowed to send requests again."
|
||||
)
|
||||
)
|
||||
|
||||
500 -> httpException = HttpErrorException(
|
||||
responseCode, "Internal Server Error", IOException(
|
||||
"There was a general internal error within JokeAPI. You can get more info from" +
|
||||
" the properties in the response text."
|
||||
)
|
||||
)
|
||||
|
||||
523 -> httpException = HttpErrorException(
|
||||
responseCode, "Origin Unreachable", IOException(
|
||||
"The server is temporarily offline due to maintenance or a dynamic IP update." +
|
||||
" Please be patient in this case."
|
||||
)
|
||||
)
|
||||
|
||||
else -> httpException = HttpErrorException(responseCode, "Unknown HTTP Error")
|
||||
}
|
||||
|
||||
return httpException
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(JokeException::class, IOException::class)
|
||||
@Throws(JokeException::class, HttpErrorException::class, IOException::class)
|
||||
fun getJoke(
|
||||
categories: Set<Category> = setOf(Category.ANY),
|
||||
language: Language = Language.ENGLISH,
|
||||
|
@ -210,7 +239,17 @@ class JokeApi {
|
|||
splitNewLine: Boolean = true
|
||||
): Joke {
|
||||
val json =
|
||||
JSONObject(apiCall(categories, language, flags, type, search = search, idRange = idRange, safe = safe))
|
||||
JSONObject(
|
||||
getRawJoke(
|
||||
categories,
|
||||
language,
|
||||
flags,
|
||||
type,
|
||||
search = search,
|
||||
idRange = idRange,
|
||||
safe = safe
|
||||
)
|
||||
)
|
||||
if (json.getBoolean("error")) {
|
||||
val causedBy = json.getJSONArray("causedBy")
|
||||
val causes = MutableList<String>(causedBy.length()) { i -> causedBy.getString(i) }
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* HttpErrorException.kt
|
||||
*
|
||||
* Copyright (c) 2022, Erik C. Thauvin (erik@thauvin.net)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi.exceptions
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
class HttpErrorException @JvmOverloads constructor(
|
||||
val statusCode: Int,
|
||||
message: String,
|
||||
cause: Throwable? = null
|
||||
) : IOException(message, cause) {
|
||||
companion object {
|
||||
private const val serialVersionUID = 1L
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.exceptions
|
||||
|
||||
class JokeException @JvmOverloads constructor(
|
||||
val error: Boolean,
|
||||
|
@ -47,8 +47,7 @@ class JokeException @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
fun debug(): String {
|
||||
return "JokeException(message=$message, error=$error, internalError=$internalError, code=$code, causedBy=$causedBy, additionalInfo='$additionalInfo', timestamp=$timestamp)"
|
||||
return "JokeException(message=$message, error=$error, internalError=$internalError, code=$code," +
|
||||
" causedBy=$causedBy, additionalInfo='$additionalInfo', timestamp=$timestamp)"
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
/**
|
||||
* Categories and aliases.
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
/**
|
||||
* Blacklist flags.
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
/**
|
||||
* Response formats.
|
|
@ -30,6 +30,6 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
data class IdRange(val start: Int = -1, val end: Int = -1)
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
data class Joke(
|
||||
val error: Boolean,
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
/**
|
||||
* Supported languages.
|
|
@ -30,7 +30,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
/**
|
||||
* Joke types.
|
|
@ -32,9 +32,18 @@
|
|||
|
||||
package net.thauvin.erik.jokeapi
|
||||
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.apiCall
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.fetchUrl
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.getJoke
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.getRawJoke
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.logger
|
||||
import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
|
||||
import net.thauvin.erik.jokeapi.exceptions.JokeException
|
||||
import net.thauvin.erik.jokeapi.models.Category
|
||||
import net.thauvin.erik.jokeapi.models.Flag
|
||||
import net.thauvin.erik.jokeapi.models.Format
|
||||
import net.thauvin.erik.jokeapi.models.IdRange
|
||||
import net.thauvin.erik.jokeapi.models.Language
|
||||
import net.thauvin.erik.jokeapi.models.Type
|
||||
import org.junit.jupiter.api.Assertions.assertAll
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
|
@ -42,41 +51,12 @@ import org.junit.jupiter.api.Assertions.assertTrue
|
|||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import java.util.logging.ConsoleHandler
|
||||
import java.util.logging.Level
|
||||
|
||||
internal class JokeApiTest {
|
||||
@Test
|
||||
fun `API call with TXT`() {
|
||||
val response = apiCall(format = Format.TEXT)
|
||||
logger.log(Level.FINE, response)
|
||||
assertAll("plain text",
|
||||
{ assertTrue(response.isNotEmpty()) { "should be not empty" } },
|
||||
{ assertFalse(response.startsWith("Error ")) { "should not be an error" } }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `API Call with invalid ID Range`() {
|
||||
val response = apiCall(format = Format.TXT, idRange = IdRange(0, 30000))
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("Error ")) { "should be an error" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `API Call with XML`() {
|
||||
val response = apiCall(format = Format.XML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("<?xml version='1.0'?>\n<data>\n <error>false</error>")) { "should be xml" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `API Call with YAML`() {
|
||||
val response = apiCall(format = Format.YAML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("error: false")) { "should be yaml" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get Joke`() {
|
||||
val joke = getJoke()
|
||||
|
@ -86,8 +66,7 @@ internal class JokeApiTest {
|
|||
{ 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" } }
|
||||
)
|
||||
{ assertEquals(Language.EN, joke.language) { "language should be english" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,8 +77,7 @@ internal class JokeApiTest {
|
|||
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" } }
|
||||
)
|
||||
{ assertEquals(Category.PUN, joke.category) { "category should be pun" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -141,8 +119,7 @@ internal class JokeApiTest {
|
|||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("safe joke",
|
||||
{ assertTrue(joke.safe) { "should be safe" } },
|
||||
{ assertTrue(joke.flags.isEmpty()) { "flags should be empty" } }
|
||||
)
|
||||
{ assertTrue(joke.flags.isEmpty()) { "flags should be empty" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -158,8 +135,7 @@ internal class JokeApiTest {
|
|||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("two-part joke",
|
||||
{ assertEquals(Type.TWOPART, joke.type) { "type should be two-part" } },
|
||||
{ assertTrue(joke.joke.size > 1) { "should have multiple lines" } }
|
||||
)
|
||||
{ assertTrue(joke.joke.size > 1) { "should have multiple lines" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -170,13 +146,55 @@ internal class JokeApiTest {
|
|||
assertEquals(id, joke.id) { "id should be 1" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get Raw Joke with TXT`() {
|
||||
val response = getRawJoke(format = Format.TEXT)
|
||||
logger.log(Level.FINE, response)
|
||||
assertAll("plain text",
|
||||
{ assertTrue(response.isNotEmpty()) { "should be not empty" } },
|
||||
{ assertFalse(response.startsWith("Error ")) { "should not be an error" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get Raw Joke with invalid ID Range`() {
|
||||
val response = getRawJoke(format = Format.TXT, idRange = IdRange(0, 30000))
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("Error ")) { "should be an error" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get Raw Joke with XML`() {
|
||||
val response = getRawJoke(format = Format.XML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("<?xml version='1.0'?>\n<data>\n <error>false</error>")) { "should be xml" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get Raw Joke with YAML`() {
|
||||
val response = getRawJoke(format = Format.YAML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("error: false")) { "should be yaml" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Fetch Invalid URL`() {
|
||||
val statusCode = 999
|
||||
val e = assertThrows<HttpErrorException> {
|
||||
fetchUrl("https://httpstat.us/$statusCode")
|
||||
}
|
||||
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" } })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Validate Joke Exception`() {
|
||||
val e = assertThrows<JokeException> {
|
||||
getJoke(categories = setOf(Category.CHRISTMAS), search = "foo")
|
||||
}
|
||||
logger.log(Level.FINE, e.debug())
|
||||
assertAll("exception validation",
|
||||
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" } },
|
||||
|
@ -184,10 +202,22 @@ internal class JokeApiTest {
|
|||
{ 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" } }
|
||||
)
|
||||
{ assertTrue(e.timestamp > 0) { "timestamp should be > 0" } })
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523])
|
||||
fun `Validate HTTP Error Exceptions`(input: Int) {
|
||||
val e = assertThrows<HttpErrorException> {
|
||||
fetchUrl("https://httpstat.us/$input")
|
||||
}
|
||||
assertAll("JokeException 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" } })
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@BeforeAll
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue