diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8dabc3f..2922277 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,62 +1,53 @@
-version: 2.1
-
-orbs:
- sdkman: joshdholtz/sdkman@0.2.0
-
+version: 2
defaults: &defaults
working_directory: ~/repo
environment:
JVM_OPTS: -Xmx3200m
TERM: dumb
- CI_NAME: "CircleCI"
-
-commands:
- build_and_test:
- parameters:
- reports-dir:
- type: string
- default: "build/reports/test_results"
- steps:
- - checkout
- - sdkman/setup-sdkman
- - sdkman/sdkman-install:
- candidate: kotlin
- version: 2.0.20
- - run:
- name: Download dependencies
- command: ./bld download
- - run:
- name: Compile source
- command: ./bld compile
- - run:
- name: Run tests
- command: ./bld jacoco -reports-dir=<< parameters.reports-dir >>
- - store_test_results:
- path: << parameters.reports-dir >>
- - store_artifacts:
- path: build/reports/jacoco/test/html
+ CI: true
+defaults_gradle: &defaults_gradle
+ steps:
+ - checkout
+ - restore_cache:
+ keys:
+ - gradle-dependencies-{{ checksum "build.gradle.kts" }}
+ # fallback to using the latest cache if no exact match is found
+ - gradle-dependencies-
+ - run:
+ name: Gradle Dependencies
+ command: ./gradlew dependencies
+ - save_cache:
+ paths: ~/.m2
+ key: gradle-dependencies-{{ checksum "build.gradle.kts" }}
+ - run:
+ name: Run All Checks
+ command: ./gradlew check
+ - store_artifacts:
+ path: build/reports/
+ destination: reports
+ - store_test_results:
+ path: build/reports/
jobs:
- bld_jdk17:
+ build_gradle_jdk17:
<<: *defaults
docker:
- image: cimg/openjdk:17.0
- steps:
- - build_and_test
+ <<: *defaults_gradle
- bld_jdk20:
+ build_gradle_jdk11:
<<: *defaults
docker:
- - image: cimg/openjdk:20.0
+ - image: cimg/openjdk:11.0
- steps:
- - build_and_test
+ <<: *defaults_gradle
workflows:
- bld:
+ version: 2
+ gradle:
jobs:
- - bld_jdk17
- - bld_jdk20
+ - build_gradle_jdk11
+ - build_gradle_jdk17
diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml
deleted file mode 100644
index 007e63a..0000000
--- a/.github/workflows/bld.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-name: bld-ci
-
-on: [ push, pull_request, workflow_dispatch ]
-
-env:
- COVERAGE_JDK: "21"
- COVERAGE_KOTLIN: "2.1.20"
-
-jobs:
- build-bld-project:
- strategy:
- matrix:
- java-version: [ 17, 21, 24 ]
- kotlin-version: [ 1.9.25, 2.0.21, 2.1.20 ]
- os: [ ubuntu-latest, windows-latest, macos-latest ]
-
- runs-on: ${{ matrix.os }}
-
- steps:
- - name: Checkout source repository
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up JDK ${{ matrix.java-version }} with Kotlin ${{ matrix.kotlin-version }}
- uses: actions/setup-java@v4
- with:
- distribution: "zulu"
- java-version: ${{ matrix.java-version }}
-
- - name: Download dependencies
- run: ./bld download
-
- - name: Compile source
- run: ./bld compile
-
- - name: Run tests
- run: ./bld jacoco
-
- - name: Remove pom.xml
- if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN
- && matrix.os == 'ubuntu-latest'
- run: rm -rf pom.xml
-
- - name: SonarCloud Scan
- uses: sonarsource/sonarcloud-github-action@master
- if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN
- && matrix.os == 'ubuntu-latest'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
new file mode 100644
index 0000000..42bc1da
--- /dev/null
+++ b/.github/workflows/gradle.yml
@@ -0,0 +1,49 @@
+name: gradle-ci
+
+on: [ push, pull_request, workflow_dispatch ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ env:
+ GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m"
+ SONAR_JDK: "17"
+
+ strategy:
+ matrix:
+ java-version: [ 11, 17, 20 ]
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Set up JDK ${{ matrix.java-version }}
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: ${{ matrix.java-version }}
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ - name: Cache SonarCloud packages
+ if: matrix.java-version == env.SONAR_JDK
+ uses: actions/cache@v3
+ with:
+ path: ~/.sonar/cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+
+ - name: Test with Gradle
+ uses: gradle/gradle-build-action@v2
+ with:
+ arguments: build check --stacktrace
+
+ - name: SonarCloud
+ if: success() && matrix.java-version == env.SONAR_JDK
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ run: ./gradlew sonar --info
diff --git a/.gitignore b/.gitignore
index ea86fe8..0742f86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,57 +1,84 @@
-.gradle
+!.vscode/extensions.json
+!.vscode/launch.json
+!.vscode/settings.json
+!.vscode/tasks.json
+*.class
+*.code-workspace
+*.ctxt
+*.iws
+*.log
+*.nar
+*.rar
+*.sublime-*
+*.tar.gz
+*.zip
.DS_Store
-build
-lib/bld/**
-!lib/bld/bld-wrapper.jar
-!lib/bld/bld-wrapper.properties
-lib/compile/
-lib/runtime/
-lib/standalone/
-lib/test/
-
-# IDEA ignores
-
-# User-specific
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# AWS User-specific
-.idea/**/aws.xml
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
+.classpath
+.gradle
+.history
+.kobalt
+.mtj.tmp/
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.nb-gradle
+.project
+.scannerwork
+.settings
+.vscode/*
+/**/.idea/$CACHE_FILE$
+/**/.idea/$PRODUCT_WORKSPACE_FILE$
+/**/.idea/**/caches/build_file_checksums.ser
+/**/.idea/**/contentModel.xml
+/**/.idea/**/dataSources.ids
+/**/.idea/**/dataSources.local.xml
+/**/.idea/**/dataSources/
+/**/.idea/**/dbnavigator.xml
+/**/.idea/**/dictionaries
+/**/.idea/**/dynamic.xml
+/**/.idea/**/gradle.xml
+/**/.idea/**/httpRequests
+/**/.idea/**/libraries
+/**/.idea/**/mongoSettings.xml
+/**/.idea/**/replstate.xml
+/**/.idea/**/shelf
+/**/.idea/**/shelf/
+/**/.idea/**/sqlDataSources.xml
+/**/.idea/**/tasks.xml
+/**/.idea/**/uiDesigner.xml
+/**/.idea/**/usage.statistics.xml
+/**/.idea/**/workspace.xml
+/**/.idea/sonarlint*
+/**/.idea_modules/
+Thumbs.db
+__pycache__
atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# SonarLint plugin
-.idea/sonarlint/
-
-# Editor-based Rest Client
-.idea/httpRequests
-
+bin/
+build/
+cmake-build-*/
+com_crashlytics_export_strings.xml
+crashlytics-build.properties
+crashlytics.properties
+dependency-reduced-pom.xml
+deploy/
+dist/
+ehthumbs.db
+fabric.properties
+gen/
+hs_err_pid*
+kobaltBuild
+kobaltw*-test
+lib/kotlin*
+libs/
local.properties
+out/
+pom.xml.asc
+pom.xml.next
+pom.xml.releaseBackup
+pom.xml.tag
+pom.xml.versionsBackup
+proguard-project.txt
+project.properties
+release.properties
+target/
+test-output
+venv
diff --git a/.idea/app.iml b/.idea/app.iml
deleted file mode 100644
index 2c1fe21..0000000
--- a/.idea/app.iml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/bld.iml b/.idea/bld.iml
deleted file mode 100644
index e63e11e..0000000
--- a/.idea/bld.iml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/bld.xml b/.idea/bld.xml
deleted file mode 100644
index 6600cee..0000000
--- a/.idea/bld.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/intellij-javadocs-4.0.1.xml b/.idea/intellij-javadocs-4.0.1.xml
deleted file mode 100644
index 4b17413..0000000
--- a/.idea/intellij-javadocs-4.0.1.xml
+++ /dev/null
@@ -1,204 +0,0 @@
-
-
-
-
- UPDATE
- false
- true
-
- TYPE
- METHOD
- FIELD
-
-
- DEFAULT
- PROTECTED
- PUBLIC
-
-
-
-
-
- ^.*(public|protected|private)*.+interface\s+\w+.*
- /**\n
- * The interface ${name}.\n
-<#if element.typeParameters?has_content> * \n
-</#if>
-<#list element.typeParameters as typeParameter>
- * @param <${typeParameter.name}> the type parameter\n
-</#list>
- */
-
-
- ^.*(public|protected|private)*.+enum\s+\w+.*
- /**\n
- * The enum ${name}.\n
- */
-
-
- ^.*(public|protected|private)*.+class\s+\w+.*
- /**\n
- * The type ${name}.\n
-<#if element.typeParameters?has_content> * \n
-</#if>
-<#list element.typeParameters as typeParameter>
- * @param <${typeParameter.name}> the type parameter\n
-</#list>
- */
-
-
- .+
- /**\n
- * The type ${name}.\n
- */
-
-
-
-
- .+
- /**\n
- * Instantiates a new ${name}.\n
-<#if element.parameterList.parameters?has_content>
- *\n
-</#if>
-<#list element.parameterList.parameters as parameter>
- * @param ${parameter.name} the ${paramNames[parameter.name]}\n
-</#list>
-<#if element.throwsList.referenceElements?has_content>
- *\n
-</#if>
-<#list element.throwsList.referenceElements as exception>
- * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
-</#list>
- */
-
-
-
-
- ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+
- /**\n
- * Gets ${partName}.\n
-<#if element.typeParameters?has_content> * \n
-</#if>
-<#list element.typeParameters as typeParameter>
- * @param <${typeParameter.name}> the type parameter\n
-</#list>
-<#if element.parameterList.parameters?has_content>
- *\n
-</#if>
-<#list element.parameterList.parameters as parameter>
- * @param ${parameter.name} the ${paramNames[parameter.name]}\n
-</#list>
-<#if isNotVoid>
- *\n
- * @return the ${partName}\n
-</#if>
-<#if element.throwsList.referenceElements?has_content>
- *\n
-</#if>
-<#list element.throwsList.referenceElements as exception>
- * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
-</#list>
- */
-
-
- ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+
- /**\n
- * Sets ${partName}.\n
-<#if element.typeParameters?has_content> * \n
-</#if>
-<#list element.typeParameters as typeParameter>
- * @param <${typeParameter.name}> the type parameter\n
-</#list>
-<#if element.parameterList.parameters?has_content>
- *\n
-</#if>
-<#list element.parameterList.parameters as parameter>
- * @param ${parameter.name} the ${paramNames[parameter.name]}\n
-</#list>
-<#if isNotVoid>
- *\n
- * @return the ${partName}\n
-</#if>
-<#if element.throwsList.referenceElements?has_content>
- *\n
-</#if>
-<#list element.throwsList.referenceElements as exception>
- * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
-</#list>
- */
-
-
- ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+
- /**\n
- * The entry point of application.\n
-
- <#if element.parameterList.parameters?has_content>
- *\n
-</#if>
- * @param ${element.parameterList.parameters[0].name} the input arguments\n
-<#if element.throwsList.referenceElements?has_content>
- *\n
-</#if>
-<#list element.throwsList.referenceElements as exception>
- * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
-</#list>
- */
-
-
- .+
- /**\n
- * ${name}<#if isNotVoid> ${return}</#if>.\n
-<#if element.typeParameters?has_content> * \n
-</#if>
-<#list element.typeParameters as typeParameter>
- * @param <${typeParameter.name}> the type parameter\n
-</#list>
-<#if element.parameterList.parameters?has_content>
- *\n
-</#if>
-<#list element.parameterList.parameters as parameter>
- * @param ${parameter.name} the ${paramNames[parameter.name]}\n
-</#list>
-<#if isNotVoid>
- *\n
- * @return the ${return}\n
-</#if>
-<#if element.throwsList.referenceElements?has_content>
- *\n
-</#if>
-<#list element.throwsList.referenceElements as exception>
- * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
-</#list>
- */
-
-
-
-
- ^.*(public|protected|private)*.+static.*(\w\s\w)+.+
- /**\n
- * The constant ${element.getName()}.\n
- */
-
-
- ^.*(public|protected|private)*.*(\w\s\w)+.+
- /**\n
- <#if element.parent.isInterface()>
- * The constant ${element.getName()}.\n
-<#else>
- * The ${name}.\n
-</#if> */
-
-
- .+
- /**\n
- <#if element.parent.isEnum()>
- *${name} ${typeName}.\n
-<#else>
- * The ${name}.\n
-</#if>*/
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index a8d9757..f8467b4 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
-
+
\ No newline at end of file
diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml
deleted file mode 100644
index 153a060..0000000
--- a/.idea/libraries/bld.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml
deleted file mode 100644
index 99cc0c0..0000000
--- a/.idea/libraries/compile.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml
deleted file mode 100644
index d4069f2..0000000
--- a/.idea/libraries/runtime.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml
deleted file mode 100644
index 57ed5ef..0000000
--- a/.idea/libraries/test.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index f2b4c1e..caf34dd 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,21 +1,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 55adcb9..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
index 82ecd17..4331a4d 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
index bb86972..3627830 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,11 @@
[](https://opensource.org/licenses/BSD-3-Clause)
-[](https://kotlinlang.org/)
-[](https://rife2.com/bld)
+[](https://kotlinlang.org/)
+[](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/)
[](https://github.com/ethauvin/jokeapi/releases/latest)
[](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi)
-[](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/)
[](https://sonarcloud.io/dashboard?id=ethauvin_jokeapi)
-[](https://github.com/ethauvin/jokeapi/actions/workflows/bld.yml)
+[](https://github.com/ethauvin/jokeapi/actions/workflows/gradle.yml)
[](https://circleci.com/gh/ethauvin/jokeapi/tree/master)
# JokeAPI for Kotlin, Java and Android
@@ -16,7 +15,7 @@ A simple library to retrieve jokes from [Sv443's JokeAPI](https://v2.jokeapi.dev
## Examples (TL;DR)
```kotlin
-import net.thauvin.erik.jokeapi.joke
+import net.thauvin.erik.jokeapi.getJoke
val joke = joke()
val safe = joke(safe = true)
@@ -89,19 +88,6 @@ var config = new JokeConfig.Builder()
var joke = JokeApi.joke(config);
joke.getJoke().forEach(System.out::println);
```
-
-## bld
-
-To use with [bld](https://rife2.com/bld), include the following dependency in your build file:
-
-```java
-repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS_LEGACY);
-
-scope(compile)
- .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0"));
-```
-Be sure to use the [bld Kotlin extension](https://github.com/rife2/bld-kotlin) in your project.
-
## Gradle, Maven, etc.
To use with [Gradle](https://gradle.org/), include the following dependency in your build file:
@@ -112,7 +98,7 @@ repositories {
}
dependencies {
- implementation("net.thauvin.erik:jokeapi:1.0.0")
+ implementation("net.thauvin.erik:jokeapi:0.9.0")
}
```
@@ -124,10 +110,9 @@ You can also retrieve one or more raw (unprocessed) jokes in all [supported form
For example for YAML:
```kotlin
-var jokes = getRawJokes(format = Format.YAML, idRange = IdRange(22))
-println(jokes.data)
+var joke = getRawJokes(format = Format.YAML, idRange = IdRange(22))
+println(joke)
```
-
```yaml
error: false
category: "Programming"
@@ -143,8 +128,8 @@ flags:
id: 22
safe: true
lang: "en"
-```
+```
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt#L46)...
## Extending
@@ -154,37 +139,15 @@ A generic `apiCall()` function is available to access other [JokeAPI endpoints](
For example to retrieve the French [language code](https://v2.jokeapi.dev/#langcode-endpoint):
```kotlin
-val response = JokeApi.apiCall(
+val lang = JokeApi.apiCall(
endPoint = "langcode",
path = "french",
params = mapOf(Parameter.FORMAT to Format.YAML.value)
)
-if (response.statusCode == 200) {
- println(response.data)
-}
+println(lang)
```
-
```yaml
error: false
code: "fr"
```
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt#L48)...
-
-## Contributing
-
-If you want to contribute to this project, all you have to do is clone the GitHub
-repository:
-
-```console
-git clone git@github.com:ethauvin/jokeapi.git
-```
-
-Then use [bld](https://rife2.com/bld) to build:
-
-```console
-cd jokeapi
-./bld compile
-```
-
-The project has an [IntelliJ IDEA](https://www.jetbrains.com/idea/) project structure. You can just open it after all
-the dependencies were downloaded and peruse the code.
diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt b/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt
deleted file mode 100644
index b4df9aa..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * JokeApi.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
-import net.thauvin.erik.jokeapi.exceptions.JokeException
-import net.thauvin.erik.jokeapi.models.*
-import net.thauvin.erik.urlencoder.UrlEncoderUtil
-import org.json.JSONObject
-import java.util.logging.Logger
-import java.util.stream.Collectors
-
-/**
- * Implements the [Sv443's JokeAPI](https://jokeapi.dev/).
- */
-object JokeApi {
- private const val API_URL = "https://v2.jokeapi.dev/"
-
- @JvmStatic
- val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) }
-
- /**
- * Makes a direct API call.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details.
- */
- @JvmStatic
- @JvmOverloads
- @Throws(HttpErrorException::class)
- fun apiCall(
- endPoint: String,
- path: String = "",
- params: Map = emptyMap(),
- auth: String = ""
- ): String {
- val urlBuilder = StringBuilder("$API_URL$endPoint")
-
- if (path.isNotEmpty()) {
- if (!urlBuilder.endsWith(('/'))) {
- urlBuilder.append('/')
- }
- urlBuilder.append(path)
- }
-
- if (params.isNotEmpty()) {
- urlBuilder.append('?')
- val it = params.iterator()
- while (it.hasNext()) {
- val param = it.next()
- urlBuilder.append(param.key)
- if (param.value.isNotEmpty()) {
- urlBuilder.append("=").append(UrlEncoderUtil.encode(param.value))
- }
- if (it.hasNext()) {
- urlBuilder.append("&")
- }
- }
- }
- return fetchUrl(urlBuilder.toString(), auth)
- }
-
- /**
- * Returns one or more jokes using a [configuration][JokeConfig].
- *
- * See the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- */
- @JvmStatic
- @Throws(HttpErrorException::class)
- fun getRawJokes(config: JokeConfig): String {
- return rawJokes(
- categories = config.categories,
- lang = config.language,
- blacklistFlags = config.flags,
- type = config.type,
- format = config.format,
- contains = config.contains,
- idRange = config.idRange,
- amount = config.amount,
- safe = config.safe,
- auth = config.auth
- )
- }
-
- /**
- * Retrieve a [Joke] instance using a [configuration][JokeConfig].
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- */
- @JvmStatic
- @JvmOverloads
- @Throws(HttpErrorException::class, JokeException::class)
- fun joke(config: JokeConfig = JokeConfig.Builder().build()): Joke {
- return joke(
- categories = config.categories,
- lang = config.language,
- blacklistFlags = config.flags,
- type = config.type,
- contains = config.contains,
- idRange = config.idRange,
- safe = config.safe,
- auth = config.auth,
- splitNewLine = config.splitNewLine
- )
- }
-
- /**
- * Returns an array of [Joke] instances using a [configuration][JokeConfig].
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- */
- @JvmStatic
- @Throws(HttpErrorException::class, JokeException::class)
- fun jokes(config: JokeConfig): Array {
- return jokes(
- categories = config.categories,
- lang = config.language,
- blacklistFlags = config.flags,
- type = config.type,
- contains = config.contains,
- idRange = config.idRange,
- amount = config.amount,
- safe = config.safe,
- auth = config.auth,
- splitNewLine = config.splitNewLine
- )
- }
-}
-
-
-/**
- * Returns a [Joke] instance.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- *
- * @param splitNewLine Split newline within [Type.SINGLE] joke.
- */
-fun joke(
- categories: Set = setOf(Category.ANY),
- lang: Language = Language.EN,
- blacklistFlags: Set = emptySet(),
- type: Type = Type.ALL,
- contains: String = "",
- idRange: IdRange = IdRange(),
- safe: Boolean = false,
- auth: String = "",
- splitNewLine: Boolean = false
-): Joke {
- val json = JSONObject(
- rawJokes(
- categories = categories,
- lang = lang,
- blacklistFlags = blacklistFlags,
- type = type,
- contains = contains,
- idRange = idRange,
- safe = safe,
- auth = auth
- )
- )
- if (json.getBoolean("error")) {
- throw parseError(json)
- } else {
- return parseJoke(json, splitNewLine)
- }
-}
-
-/**
- * Returns an array of [Joke] instances.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- *
- * @param amount The required amount of jokes to return.
- * @param splitNewLine Split newline within [Type.SINGLE] joke.
- */
-fun jokes(
- amount: Int,
- categories: Set = setOf(Category.ANY),
- lang: Language = Language.EN,
- blacklistFlags: Set = emptySet(),
- type: Type = Type.ALL,
- contains: String = "",
- idRange: IdRange = IdRange(),
- safe: Boolean = false,
- auth: String = "",
- splitNewLine: Boolean = false
-): Array {
- val json = JSONObject(
- rawJokes(
- categories = categories,
- lang = lang,
- blacklistFlags = blacklistFlags,
- type = type,
- contains = contains,
- idRange = idRange,
- amount = amount,
- safe = safe,
- auth = auth
- )
- )
- if (json.getBoolean("error")) {
- throw parseError(json)
- } else {
- return if (json.has("amount")) {
- val jokes = json.getJSONArray("jokes")
- Array(jokes.length()) { i -> parseJoke(jokes.getJSONObject(i), splitNewLine) }
- } else {
- arrayOf(parseJoke(json, splitNewLine))
- }
- }
-}
-
-/**
- * Returns one or more jokes.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- */
-fun rawJokes(
- categories: Set = setOf(Category.ANY),
- lang: Language = Language.EN,
- blacklistFlags: Set = emptySet(),
- type: Type = Type.ALL,
- format: Format = Format.JSON,
- contains: String = "",
- idRange: IdRange = IdRange(),
- amount: Int = 1,
- safe: Boolean = false,
- auth: String = ""
-): String {
- val params = mutableMapOf()
-
- // Categories
- val path = if (categories.isEmpty() || categories.contains(Category.ANY)) {
- Category.ANY.value
- } else {
- categories.stream().map(Category::value).collect(Collectors.joining(","))
- }
-
- // Language
- if (lang != Language.EN) {
- params[Parameter.LANG] = lang.value
- }
-
- // Flags
- if (blacklistFlags.isNotEmpty()) {
- if (blacklistFlags.contains(Flag.ALL)) {
- params[Parameter.FLAGS] = Flag.ALL.value
- } else {
- params[Parameter.FLAGS] = blacklistFlags.stream().map(Flag::value).collect(Collectors.joining(","))
- }
- }
-
- // Type
- if (type != Type.ALL) {
- params[Parameter.TYPE] = type.value
- }
-
- // Format
- if (format != Format.JSON) {
- params[Parameter.FORMAT] = format.value
- }
-
- // Contains
- if (contains.isNotBlank()) {
- params[Parameter.CONTAINS] = contains
- }
-
- // Range
- if (idRange.start >= 0) {
- if (idRange.end == -1 || idRange.start == idRange.end) {
- params[Parameter.RANGE] = idRange.start.toString()
- } else {
- require(idRange.end > idRange.start) { "Invalid ID Range: ${idRange.start}, ${idRange.end}" }
- params[Parameter.RANGE] = "${idRange.start}-${idRange.end}"
- }
- }
-
- // Amount
- require(amount > 0) { "Invalid Amount: $amount" }
- if (amount > 1) {
- params[Parameter.AMOUNT] = amount.toString()
- }
-
- // Safe
- if (safe) {
- params[Parameter.SAFE] = ""
- }
-
- return JokeApi.apiCall("joke", path, params, auth)
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt b/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt
deleted file mode 100644
index 544383c..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * JokeConfig.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import net.thauvin.erik.jokeapi.JokeConfig.Builder
-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
-
-/**
- * Joke Configuration.
- *
- * Use the [Builder] to create a new configuration.
- */
-class JokeConfig private constructor(
- val categories: Set,
- val language: Language,
- val flags: Set,
- val type: Type,
- val format: Format,
- val contains: String,
- val idRange: IdRange,
- val amount: Int,
- val safe: Boolean,
- val splitNewLine: Boolean,
- val auth: String
-) {
- /**
- * [Builds][build] a new configuration.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- *
- * @param splitNewLine Split newline within [Type.SINGLE] joke.
- */
- data class Builder(
- var categories: Set = setOf(Category.ANY),
- var lang: Language = Language.EN,
- var blacklistFlags: Set = emptySet(),
- var type: Type = Type.ALL,
- var format: Format = Format.JSON,
- var contains: String = "",
- var idRange: IdRange = IdRange(),
- var amount: Int = 1,
- var safe: Boolean = false,
- var splitNewLine: Boolean = false,
- var auth: String = ""
- ) {
- fun categories(categories: Set) = apply { this.categories = categories }
- 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 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 build() = JokeConfig(
- categories, lang, blacklistFlags, type, format, contains, idRange, amount, safe, splitNewLine, auth
- )
- }
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt b/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt
deleted file mode 100644
index 9d838f8..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * JokeUtil.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.
- */
-
-@file:JvmName("JokeUtil")
-
-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.Joke
-import net.thauvin.erik.jokeapi.models.Language
-import net.thauvin.erik.jokeapi.models.Parameter
-import net.thauvin.erik.jokeapi.models.Type
-import org.json.JSONObject
-import java.io.IOException
-import java.net.HttpURLConnection
-import java.net.URL
-import java.util.logging.Level
-
-internal fun fetchUrl(url: String, auth: String = ""): String {
- if (JokeApi.logger.isLoggable(Level.FINE)) {
- JokeApi.logger.fine(url)
- }
-
- val connection = URL(url).openConnection() as HttpURLConnection
- connection.setRequestProperty(
- "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"
- )
- if (auth.isNotEmpty()) {
- connection.setRequestProperty("Authentication", auth)
- }
-
- if (connection.responseCode in 200..399) {
- val body = connection.inputStream.bufferedReader().use { it.readText() }
- if (JokeApi.logger.isLoggable(Level.FINE)) {
- JokeApi.logger.fine(body)
- }
- return body
- } else {
- 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
-}
-
-internal fun parseError(json: JSONObject): JokeException {
- val causedBy = json.getJSONArray("causedBy")
- val causes = List(causedBy.length()) { i -> causedBy.getString(i) }
- return JokeException(
- internalError = json.getBoolean("internalError"),
- code = json.getInt("code"),
- message = json.getString("message"),
- causedBy = causes,
- additionalInfo = json.getString("additionalInfo"),
- timestamp = json.getLong("timestamp")
- )
-}
-
-internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke {
- val jokes = mutableListOf()
- if (json.has("setup")) {
- jokes.add(json.getString("setup"))
- jokes.add(json.getString(("delivery")))
- } else {
- if (splitNewLine) {
- jokes.addAll(json.getString("joke").split("\n"))
- } else {
- jokes.add(json.getString("joke"))
- }
- }
- val enabledFlags = mutableSetOf()
- val jsonFlags = json.getJSONObject("flags")
- Flag.values().filter { it != Flag.ALL }.forEach {
- if (jsonFlags.has(it.value) && jsonFlags.getBoolean(it.value)) {
- enabledFlags.add(it)
- }
- }
- return Joke(
- category = Category.valueOf(json.getString("category").uppercase()),
- type = Type.valueOf(json.getString(Parameter.TYPE).uppercase()),
- joke = jokes,
- flags = enabledFlags,
- safe = json.getBoolean("safe"),
- id = json.getInt("id"),
- lang = Language.valueOf(json.getString(Parameter.LANG).uppercase())
- )
-}
-
diff --git a/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt
deleted file mode 100644
index cd17ca8..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * HttpErrorException.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-/**
- * Signals that a server error has occurred.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#status-codes) for more details.
- */
-class HttpErrorException @JvmOverloads constructor(
- val statusCode: Int,
- message: String,
- cause: Throwable? = null
-) : IOException(message, cause) {
- companion object {
- private const val serialVersionUID = 1L
- }
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt
deleted file mode 100644
index 919216e..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * JokeException.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-/**
- * Signals that an error has occurred.
- *
- * Sse the [JokeAPI Documentation](https://jokeapi.dev/#errors) for more details.
- */
-class JokeException @JvmOverloads constructor(
- val internalError: Boolean,
- val code: Int,
- message: String,
- val causedBy: List,
- val additionalInfo: String,
- val timestamp: Long,
- cause: Throwable? = null
-) : RuntimeException(message, cause) {
- companion object {
- private const val serialVersionUID = 1L
- }
-
- fun debug(): String {
- return "JokeException(message=$message, internalError=$internalError, code=$code," +
- " causedBy=$causedBy, additionalInfo='$additionalInfo', timestamp=$timestamp)"
- }
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Category.kt b/bin/main/net/thauvin/erik/jokeapi/models/Category.kt
deleted file mode 100644
index 4951d4a..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Category.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Category.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The supported [categories](https://jokeapi.dev/#categories), use [ANY] for all.
- */
-enum class Category(val value: String) {
- ANY("Any"),
- CHRISTMAS("Christmas"),
- DARK("Dark"),
- MISC("Misc"),
- PROGRAMMING("Programming"),
- PUN("Pun"),
- SPOOKY("Spooky")
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt b/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt
deleted file mode 100644
index af92e90..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Flag.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The supported [blacklist flags](https://jokeapi.dev/#flags-param), use [ALL] to prevent all.
- */
-enum class Flag(val value: String) {
- EXPLICIT("explicit"),
- NSFW("nsfw"),
- POLITICAL("political"),
- RACIST("racist"),
- RELIGIOUS("religious"),
- SEXIST("sexist"),
- ALL("${NSFW.value},${RELIGIOUS.value},${POLITICAL.value},${RACIST.value},${SEXIST.value},${EXPLICIT.value}")
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Format.kt b/bin/main/net/thauvin/erik/jokeapi/models/Format.kt
deleted file mode 100644
index 2678a21..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Format.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Format.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The supported response [formats](https://jokeapi.dev/#format-param).
- */
-enum class Format(val value: String) {
- JSON("json"),
-
- /** Plain Text */
- TXT("txt"),
- XML("xml"),
- YAML("yaml")
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt b/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt
deleted file mode 100644
index 62a6eb6..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * IdRange.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * Specifies a joke [ID or range of IDs](https://jokeapi.dev/#idrange-param).
- */
-data class IdRange(val start: Int = -1, val end: Int = -1)
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt b/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt
deleted file mode 100644
index 0309977..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Joke.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * Stores a joke's data.
- */
-data class Joke(
- val category: Category,
- val type: Type,
- val joke: List,
- val flags: Set,
- val id: Int,
- val safe: Boolean,
- val lang: Language
-)
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Language.kt b/bin/main/net/thauvin/erik/jokeapi/models/Language.kt
deleted file mode 100644
index 10c00fb..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Language.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Language.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The supported [languages](https://jokeapi.dev/#lang).
- */
-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/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt b/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt
deleted file mode 100644
index b9e1106..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Parameter.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The available [URL Parameters](https://jokeapi.dev/#url-parameters).
- */
-object Parameter {
- const val AMOUNT = "amount"
- const val CONTAINS = "contains"
- const val FLAGS = "blacklistFlags"
- const val FORMAT = "format"
- const val RANGE = "idRange"
- const val LANG = "lang"
- const val SAFE = "safe-mode"
- const val TYPE = "type"
-
- const val BLACKLIST_FLAGS = FLAGS
- const val ID_RANGE = RANGE
- const val SAFE_MODE = SAFE
- const val SEARCH = CONTAINS
-}
diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Type.kt b/bin/main/net/thauvin/erik/jokeapi/models/Type.kt
deleted file mode 100644
index 59126b4..0000000
--- a/bin/main/net/thauvin/erik/jokeapi/models/Type.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Type.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The supported [types](https://jokeapi.dev/#type-param), use [ALL] for all.
- */
-enum class Type(val value: String) {
- SINGLE("single"),
- TWOPART("twopart"),
- ALL("${SINGLE.value},${TWOPART.value}")
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt b/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt
deleted file mode 100644
index d9f9b30..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * ApiCallTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.assertThat
-import assertk.assertions.isGreaterThan
-import assertk.assertions.startsWith
-import net.thauvin.erik.jokeapi.JokeApi.apiCall
-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.Test
-import org.junit.jupiter.api.assertAll
-import org.junit.jupiter.api.extension.ExtendWith
-import kotlin.test.assertContains
-
-@ExtendWith(BeforeAllTests::class)
-internal class ApiCallTest {
- @Test
- fun `Get Flags`() {
- // See https://v2.jokeapi.dev/#flags-endpoint
- val response = apiCall(endPoint = "flags")
- val json = JSONObject(response)
- assertAll("Validate JSON",
- { 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
- fun `Get Language Code`() {
- // See https://v2.jokeapi.dev/#langcode-endpoint
- val lang = apiCall(
- endPoint = "langcode", path = "french",
- params = mapOf(Parameter.FORMAT to Format.YAML.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))
- assertThat(ping, "apiCall(ping, txt)").startsWith("Pong!")
- }
-
- @Test
- fun `Get Supported Language`() {
- // See https://v2.jokeapi.dev/languages
- val lang = apiCall(
- endPoint = "languages",
- params = mapOf(Parameter.FORMAT to Format.XML.value, Parameter.LANG to Language.FR.value)
- )
- assertThat(lang).startsWith("")
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt b/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt
deleted file mode 100644
index de9d48a..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * BeforeAllTests.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import org.junit.jupiter.api.extension.BeforeAllCallback
-import org.junit.jupiter.api.extension.ExtensionContext
-import java.util.logging.ConsoleHandler
-import java.util.logging.Level
-
-class BeforeAllTests : BeforeAllCallback {
- override fun beforeAll(context: ExtensionContext?) {
- with(JokeApi.logger) {
- addHandler(ConsoleHandler().apply { level = Level.FINE })
- level = Level.FINE
- }
- }
-}
-
diff --git a/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt
deleted file mode 100644
index adacf75..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * ExceptionsTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.all
-import assertk.assertThat
-import assertk.assertions.index
-import assertk.assertions.isEqualTo
-import assertk.assertions.isFalse
-import assertk.assertions.isGreaterThan
-import assertk.assertions.isNotEmpty
-import assertk.assertions.isNotNull
-import assertk.assertions.isNull
-import assertk.assertions.prop
-import assertk.assertions.size
-import assertk.assertions.startsWith
-import net.thauvin.erik.jokeapi.JokeApi.logger
-import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
-import net.thauvin.erik.jokeapi.exceptions.JokeException
-import net.thauvin.erik.jokeapi.models.Category
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.junit.jupiter.api.extension.ExtendWith
-import org.junit.jupiter.params.ParameterizedTest
-import org.junit.jupiter.params.provider.ValueSource
-
-@ExtendWith(BeforeAllTests::class)
-internal class ExceptionsTest {
- @Test
- fun `Validate Joke Exception`() {
- val e = assertThrows {
- joke(categories = setOf(Category.CHRISTMAS), contains = "foo")
- }
- logger.fine(e.debug())
- assertThat(e, "joke(${Category.CHRISTMAS},foo)").all {
- prop(JokeException::code).isEqualTo(106)
- prop(JokeException::internalError).isFalse()
- prop(JokeException::message).isEqualTo("No matching joke found")
- prop(JokeException::causedBy).size().isEqualTo(1)
- prop(JokeException::causedBy).index(0).startsWith("No jokes")
- prop(JokeException::additionalInfo).isNotEmpty()
- prop(JokeException::timestamp).isGreaterThan(0)
- }
- }
-
- @ParameterizedTest
- @ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523, 666])
- fun `Validate HTTP Exceptions`(code: Int) {
- val e = assertThrows {
- fetchUrl("https://httpstat.us/$code")
- }
- assertThat(e, "fetchUrl($code)").all {
- prop(HttpErrorException::statusCode).isEqualTo(code)
- prop(HttpErrorException::message).isNotNull().isNotEmpty()
- if (code < 600)
- prop(HttpErrorException::cause).isNotNull().assertThat(Throwable::message).isNotNull()
- else
- prop(HttpErrorException::cause).isNull()
- }
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt
deleted file mode 100644
index a2b06db..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * GetJokeTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.all
-import assertk.assertThat
-import assertk.assertions.any
-import assertk.assertions.contains
-import assertk.assertions.containsNone
-import assertk.assertions.each
-import assertk.assertions.isBetween
-import assertk.assertions.isEmpty
-import assertk.assertions.isEqualTo
-import assertk.assertions.isGreaterThan
-import assertk.assertions.isGreaterThanOrEqualTo
-import assertk.assertions.isIn
-import assertk.assertions.isNotEmpty
-import assertk.assertions.isNotNull
-import assertk.assertions.isTrue
-import assertk.assertions.prop
-import assertk.assertions.size
-import net.thauvin.erik.jokeapi.JokeApi.logger
-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.IdRange
-import net.thauvin.erik.jokeapi.models.Joke
-import net.thauvin.erik.jokeapi.models.Language
-import net.thauvin.erik.jokeapi.models.Type
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.junit.jupiter.api.extension.ExtendWith
-
-@ExtendWith(BeforeAllTests::class)
-internal class GetJokeTest {
- @Test
- fun `Get Joke`() {
- val joke = joke()
- logger.fine(joke.toString())
- assertThat(joke, "joke()").all {
- prop(Joke::joke).isNotEmpty()
- prop(Joke::type).isIn(Type.SINGLE, Type.TWOPART)
- prop(Joke::id).isGreaterThanOrEqualTo(0)
- prop(Joke::lang).isEqualTo(Language.EN)
- }
- }
-
- @Test
- fun `Get Joke without Blacklist Flags`() {
- val joke = joke(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 = joke(blacklistFlags = allFlags)
- assertThat(joke::flags).isEmpty()
- }
-
- @Test
- fun `Get Joke with ID`() {
- val id = 172
- val joke = joke(idRange = IdRange(id))
- logger.fine(joke.toString())
- assertThat(joke, "joke($id)").all {
- prop(Joke::flags).all {
- contains(Flag.EXPLICIT)
- contains(Flag.NSFW)
- }
- prop(Joke::id).isEqualTo(172)
- prop(Joke::category).isEqualTo(Category.PUN)
- }
- }
-
- @Test
- fun `Get Joke with ID Range`() {
- val idRange = IdRange(1, 100)
- val joke = joke(idRange = idRange)
- logger.fine(joke.toString())
- assertThat(joke::id).isBetween(idRange.start, idRange.end)
- }
-
- @Test
- fun `Get Joke with invalid ID Range`() {
- val idRange = IdRange(100, 1)
- val e = assertThrows { joke(idRange = idRange, lang = Language.DE) }
- assertThat(e::message).isNotNull().contains("100, 1")
- }
-
- @Test
- fun `Get Joke with max ID Range`() {
- val idRange = IdRange(1, 30000)
- val e = assertThrows { joke(idRange = idRange) }
- assertThat(e, "joke{${idRange})").all {
- prop(JokeException::additionalInfo).contains("ID range")
- }
- }
-
- @Test
- fun `Get Joke with two Categories`() {
- val joke = joke(categories = setOf(Category.PROGRAMMING, Category.MISC))
- logger.fine(joke.toString())
- assertThat(joke.category, "joke(${Category.PROGRAMMING},${Category.MISC})").isIn(
- Category.PROGRAMMING,
- Category.MISC
- )
- }
-
- @Test
- fun `Get Joke with each Categories`() {
- Category.values().filter { it != Category.ANY }.forEach {
- val joke = joke(categories = setOf(it))
- logger.fine(joke.toString())
- assertThat(joke::category, "joke($it)").prop(Category::value).isEqualTo(it.value)
- }
- }
-
- @Test
- fun `Get Joke with each Languages`() {
- Language.values().forEach {
- val joke = joke(lang = it)
- logger.fine(joke.toString())
- assertThat(joke::lang, "joke($it)").prop(Language::value).isEqualTo(it.value)
- }
- }
-
- @Test
- fun `Get Joke with Split Newline`() {
- val joke = joke(
- categories = setOf(Category.DARK), type = Type.SINGLE, idRange = IdRange(178), splitNewLine = true
- )
- logger.fine(joke.toString())
- assertThat(joke::joke, "joke(splitNewLine=true)").all {
- size().isEqualTo(2)
- each {
- containsNone("\n")
- }
- }
- }
-
- @Test
- fun `Get Safe Joke`() {
- val joke = joke(safe = true)
- logger.fine(joke.toString())
- assertThat(joke, "joke(safe)").all {
- prop(Joke::safe).isTrue()
- }
- }
-
- @Test
- fun `Get Single Joke`() {
- val joke = joke(type = Type.SINGLE)
- logger.fine(joke.toString())
- assertThat(joke::type).assertThat(Type.SINGLE)
- }
-
- @Test
- fun `Get Two-Parts Joke`() {
- val joke = joke(type = Type.TWOPART)
- logger.fine(joke.toString())
- assertThat(joke, "joke(${Type.TWOPART})").all {
- prop(Joke::type).isEqualTo(Type.TWOPART)
- prop(Joke::joke).size().isGreaterThan(1)
- }
- }
-
- @Test
- fun `Get Joke using Search`() {
- val id = 265
- val search = "his wife"
- val joke =
- joke(contains = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true)
- logger.fine(joke.toString())
- assertThat(joke, "joke($search)").all {
- prop(Joke::id).isEqualTo(id)
- prop(Joke::joke).any {
- it.contains(search)
- }
- }
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt
deleted file mode 100644
index 1ab8b60..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * GetJokesTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.all
-import assertk.assertThat
-import assertk.assertions.contains
-import assertk.assertions.each
-import assertk.assertions.index
-import assertk.assertions.isEqualTo
-import assertk.assertions.isGreaterThanOrEqualTo
-import assertk.assertions.isNotNull
-import assertk.assertions.isTrue
-import assertk.assertions.prop
-import assertk.assertions.size
-import net.thauvin.erik.jokeapi.models.Joke
-import net.thauvin.erik.jokeapi.models.Language
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.junit.jupiter.api.extension.ExtendWith
-
-@ExtendWith(BeforeAllTests::class)
-internal class GetJokesTest {
- @Test
- fun `Get Multiple Jokes`() {
- val amount = 2
- val jokes = jokes(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::lang).isEqualTo(Language.FR)
- }
- }
- }
-
- @Test
- fun `Get Jokes with Invalid Amount`() {
- val e = assertThrows { jokes(amount = -1) }
- assertThat(e::message).isNotNull().contains("-1")
- }
-
- @Test
- fun `Get One Joke as Multiple`() {
- val jokes = jokes(amount = 1, safe = true)
- assertThat(jokes, "jokes").all {
- size().isEqualTo(1)
- index(0).all {
- prop(Joke::id).isGreaterThanOrEqualTo(0)
- prop(Joke::safe).isTrue()
- }
- }
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
deleted file mode 100644
index 7bcf1c6..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * GetRawJokesTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.all
-import assertk.assertThat
-import assertk.assertions.doesNotContain
-import assertk.assertions.isNotEmpty
-import assertk.assertions.startsWith
-import net.thauvin.erik.jokeapi.models.Format
-import net.thauvin.erik.jokeapi.models.IdRange
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
-import kotlin.test.assertContains
-
-@ExtendWith(BeforeAllTests::class)
-internal class GetRawJokesTest {
- @Test
- fun `Get Raw Joke with TXT`() {
- val response = rawJokes(format = Format.TXT)
- assertThat(response, "rawJoke(txt)").all {
- isNotEmpty()
- doesNotContain("Error")
- }
- }
-
- @Test
- fun `Get Raw Joke with XML`() {
- val response = rawJokes(format = Format.XML)
- assertThat(response, "rawJoke(xml)").startsWith("\n\n false")
- }
-
- @Test
- fun `Get Raw Joke with YAML`() {
- val response = rawJokes(format = Format.YAML)
- assertThat(response, "rawJoke(yaml)").startsWith("error: false")
- }
-
- @Test
- fun `Get Raw Jokes`() {
- val response = rawJokes(amount = 2)
- assertContains(response, "\"amount\": 2", false, "rawJoke(2)")
- }
-
- @Test
- fun `Get Raw Invalid Jokes`() {
- val response = rawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161))
- assertContains(response, "\"error\": true", false, "getRawJokes(foo)")
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt
deleted file mode 100644
index 92de2e0..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * JokeConfigTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.all
-import assertk.assertThat
-import assertk.assertions.each
-import assertk.assertions.isBetween
-import assertk.assertions.isEmpty
-import assertk.assertions.isEqualTo
-import assertk.assertions.isGreaterThanOrEqualTo
-import assertk.assertions.isTrue
-import assertk.assertions.prop
-import assertk.assertions.size
-import net.thauvin.erik.jokeapi.JokeApi.joke
-import net.thauvin.erik.jokeapi.JokeApi.jokes
-import net.thauvin.erik.jokeapi.JokeApi.getRawJokes
-import net.thauvin.erik.jokeapi.JokeApi.logger
-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.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
-import kotlin.test.assertContains
-
-@ExtendWith(BeforeAllTests::class)
-internal class JokeConfigTest {
- @Test
- fun `Get Joke with Default Builder`() {
- val joke = joke()
- assertThat(joke, "joke").all {
- prop(Joke::id).isGreaterThanOrEqualTo(0)
- prop(Joke::lang).isEqualTo(Language.EN)
- }
- }
-
- @Test
- fun `Get Joke with Builder`() {
- val id = 266
- val config = JokeConfig.Builder().apply {
- categories(setOf(Category.PROGRAMMING))
- lang(Language.EN)
- blacklistFlags(setOf(Flag.ALL))
- type(Type.TWOPART)
- idRange(IdRange(id - 2, id + 2))
- safe(true)
- }.build()
- val joke = joke(config)
- logger.fine(joke.toString())
- assertThat(joke, "config").all {
- prop(Joke::type).isEqualTo(Type.TWOPART)
- prop(Joke::category).isEqualTo(Category.PROGRAMMING)
- prop(Joke::joke).size().isEqualTo(2)
- prop(Joke::lang).isEqualTo(Language.EN)
- prop(Joke::flags).isEmpty()
- prop(Joke::id).isBetween(id - 2, id + 2)
- }
- }
-
- @Test
- fun `Get joke with Builder and Split Newline`() {
- val id = 5
- val config = JokeConfig.Builder().apply {
- categories(setOf(Category.PROGRAMMING))
- idRange(IdRange(id))
- splitNewLine(true)
- }.build()
- val joke = joke(config)
- logger.fine(joke.toString())
- assertThat(joke, "config").all {
- prop(Joke::id).isEqualTo(id)
- prop(Joke::joke).size().isEqualTo(2)
- }
- }
-
- @Test
- fun `Get Raw Joke with Builder`() {
- val config = JokeConfig.Builder().apply {
- categories(setOf(Category.PROGRAMMING))
- format(Format.TXT)
- contains("bar")
- amount(2)
- safe(true)
- }.build()
- val joke = getRawJokes(config)
- assertContains(joke, "----------------------------------------------", false, "config.amount(2)")
- }
-
- @Test
- fun `Get Multiple Jokes with Builder`() {
- val amount = 2
- val config = JokeConfig.Builder().apply {
- amount(amount)
- safe(true)
- lang(Language.FR)
- }.build()
- val jokes = jokes(config)
- 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::lang).isEqualTo(Language.FR)
- }
- }
- }
-
- @Test
- fun `Validate Config`() {
- val categories = setOf(Category.ANY)
- val language = Language.CS
- val flags = setOf(Flag.POLITICAL, Flag.RELIGIOUS)
- val type = Type.TWOPART
- val format = Format.XML
- val search = "foo"
- val idRange = IdRange(1, 20)
- val amount = 10
- val safe = true
- val splitNewLine = true
- val auth = "token"
- val config = JokeConfig.Builder().apply {
- categories(categories)
- lang(language)
- blacklistFlags(flags)
- type(type)
- format(format)
- contains(search)
- idRange(idRange)
- amount(amount)
- safe(safe)
- splitNewLine(splitNewLine)
- auth(auth)
- }.build()
- assertThat(config, "config").all {
- prop(JokeConfig::categories).isEqualTo(categories)
- prop(JokeConfig::language).isEqualTo(language)
- prop(JokeConfig::flags).isEqualTo(flags)
- prop(JokeConfig::type).isEqualTo(type)
- prop(JokeConfig::format).isEqualTo(format)
- prop(JokeConfig::contains).isEqualTo(search)
- prop(JokeConfig::idRange).isEqualTo(idRange)
- prop(JokeConfig::amount).isEqualTo(amount)
- prop(JokeConfig::safe).isEqualTo(safe)
- prop(JokeConfig::splitNewLine).isEqualTo(splitNewLine)
- prop(JokeConfig::auth).isEqualTo(auth)
- }
- }
-}
diff --git a/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt
deleted file mode 100644
index 8f8d936..0000000
--- a/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * UtilTest.kt
- *
- * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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
-
-import assertk.assertThat
-import assertk.assertions.contains
-import org.json.JSONException
-import org.json.JSONObject
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.junit.jupiter.api.extension.ExtendWith
-
-@ExtendWith(BeforeAllTests::class)
-internal class JokeUtilTest {
- @Test
- fun `Invalid JSON Error`() {
- assertThrows { parseError(JSONObject("{}")) }
- }
-
- @Test
- fun `Invalid JSON Joke`() {
- assertThrows { parseJoke(JSONObject("{}"), false) }
- }
-
- @Test
- fun `Validate Authentication Header`() {
- val token = "AUTH-TOKEN"
- val body = fetchUrl("https://postman-echo.com/get", token)
- assertThat(body, "body").contains("\"authentication\": \"$token\"")
- }
-}
diff --git a/bld b/bld
deleted file mode 100755
index bfff52f..0000000
--- a/bld
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env sh
-java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build net.thauvin.erik.JokeApiBuild "$@"
diff --git a/bld.bat b/bld.bat
deleted file mode 100644
index 9f7473c..0000000
--- a/bld.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-@echo off
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build net.thauvin.erik.JokeApiBuild %*
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..fbea59b
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,185 @@
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+import org.gradle.api.tasks.testing.logging.TestLogEvent
+import org.jetbrains.dokka.gradle.DokkaTask
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ id("com.github.ben-manes.versions") version "0.48.0"
+ id("io.gitlab.arturbosch.detekt") version "1.23.1"
+ id("java")
+ id("maven-publish")
+ id("org.jetbrains.dokka") version "1.9.0"
+ id("org.jetbrains.kotlinx.kover") version "0.7.3"
+ id("org.sonarqube") version "4.3.1.3277"
+ id("signing")
+ kotlin("jvm") version "1.9.10"
+}
+
+description = "Retrieve jokes from Sv443's JokeAPI"
+group = "net.thauvin.erik"
+version = "0.9.0"
+
+val deployDir = "deploy"
+val gitHub = "ethauvin/$name"
+val mavenUrl = "https://github.com/$gitHub"
+val publicationName = "mavenJava"
+
+repositories {
+ mavenCentral()
+ maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
+}
+
+dependencies {
+ implementation(platform(kotlin("bom")))
+
+ implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0")
+ implementation("org.json:json:20230618")
+
+ testImplementation(kotlin("test"))
+ testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
+ testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.27.0")
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ withSourcesJar()
+}
+
+koverReport {
+ defaults {
+ xml {
+ onCheck = true
+ }
+ html {
+ onCheck = true
+ }
+ }
+}
+
+sonarqube {
+ properties {
+ property("sonar.projectKey", "ethauvin_$name")
+ property("sonar.organization", "ethauvin-github")
+ property("sonar.host.url", "https://sonarcloud.io")
+ property("sonar.sourceEncoding", "UTF-8")
+ property("sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/kover/report.xml")
+ }
+}
+
+val javadocJar by tasks.creating(Jar::class) {
+ dependsOn(tasks.dokkaJavadoc)
+ from(tasks.dokkaJavadoc)
+ archiveClassifier.set("javadoc")
+}
+
+tasks {
+ test {
+ useJUnitPlatform()
+ }
+
+ withType().configureEach {
+ kotlinOptions.jvmTarget = java.targetCompatibility.toString()
+ }
+
+ withType {
+ testLogging {
+ exceptionFormat = TestExceptionFormat.FULL
+ events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
+ }
+ }
+
+ withType().configureEach {
+ this.jvmTarget = java.targetCompatibility.toString()
+ }
+
+ withType().configureEach {
+ this.jvmTarget = java.targetCompatibility.toString()
+ }
+
+ withType {
+ destination = file("$projectDir/pom.xml")
+ }
+
+ clean {
+ doLast {
+ project.delete(fileTree(deployDir))
+ }
+ }
+
+ withType().configureEach {
+ dokkaSourceSets {
+ named("main") {
+ moduleName.set("Joke API")
+ }
+ }
+ }
+
+ val copyToDeploy by registering(Copy::class) {
+ from(configurations.runtimeClasspath) {
+ exclude("annotations-*.jar")
+ }
+ from(jar)
+ into(deployDir)
+ }
+
+ register("deploy") {
+ description = "Copies all needed files to the $deployDir directory."
+ group = PublishingPlugin.PUBLISH_TASK_GROUP
+ dependsOn(clean, build, jar)
+ outputs.dir(deployDir)
+ inputs.files(copyToDeploy)
+ mustRunAfter(clean)
+ }
+}
+
+publishing {
+ publications {
+ create(publicationName) {
+ from(components["java"])
+ artifact(javadocJar)
+ pom {
+ name.set(project.name)
+ description.set(project.description)
+ url.set(mavenUrl)
+ licenses {
+ license {
+ name.set("BSD 3-Clause")
+ url.set("https://opensource.org/licenses/BSD-3-Clause")
+ }
+ }
+ developers {
+ developer {
+ id.set("ethauvin")
+ name.set("Erik C. Thauvin")
+ email.set("erik@thauvin.net")
+ url.set("https://erik.thauvin.net/")
+ }
+ }
+ scm {
+ connection.set("scm:git:https://github.com/$gitHub.git")
+ developerConnection.set("scm:git:git@github.com:$gitHub.git")
+ url.set(mavenUrl)
+ }
+ issueManagement {
+ system.set("GitHub")
+ url.set("$mavenUrl/issues")
+ }
+ }
+ }
+ }
+ repositories {
+ maven {
+ name = "ossrh"
+ url = if (project.version.toString().contains("SNAPSHOT"))
+ uri("https://oss.sonatype.org/content/repositories/snapshots/") else
+ uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
+ credentials(PasswordCredentials::class)
+ }
+ }
+}
+
+signing {
+ useGpgCmd()
+ sign(publishing.publications[publicationName])
+}
diff --git a/detekt-baseline.xml b/detekt-baseline.xml
index 1a99819..a53ce7c 100644
--- a/detekt-baseline.xml
+++ b/detekt-baseline.xml
@@ -1,12 +1,12 @@
-
+
-
+
- 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 )
+ 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:JokeUtil.kt$200
MagicNumber:JokeUtil.kt$399
MagicNumber:JokeUtil.kt$400
@@ -18,15 +18,6 @@
MagicNumber:JokeUtil.kt$500
MagicNumber:JokeUtil.kt$523
TooManyFunctions:JokeConfig.kt$JokeConfig$Builder
- WildcardImport:ExceptionsTest.kt$import assertk.assertions.*
- WildcardImport:GetJokeTest.kt$import assertk.assertions.*
- WildcardImport:GetJokeTest.kt$import net.thauvin.erik.jokeapi.models.*
- WildcardImport:GetJokesTest.kt$import assertk.assertions.*
- WildcardImport:GetRawJokesTest.kt$import assertk.assertions.*
WildcardImport:JokeApi.kt$import net.thauvin.erik.jokeapi.models.*
- WildcardImport:JokeConfig.kt$import net.thauvin.erik.jokeapi.models.*
- WildcardImport:JokeConfigTest.kt$import assertk.assertions.*
- WildcardImport:JokeConfigTest.kt$import net.thauvin.erik.jokeapi.models.*
- WildcardImport:JokeUtil.kt$import net.thauvin.erik.jokeapi.models.*
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..7fc6f1f
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7f93135
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..ac72c34
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..0adc8e1
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar
deleted file mode 100644
index 1eb86cf..0000000
Binary files a/lib/bld/bld-wrapper.jar and /dev/null differ
diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties
deleted file mode 100644
index fc9463a..0000000
--- a/lib/bld/bld-wrapper.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-bld.downloadExtensionJavadoc=false
-bld.downloadExtensionSources=true
-bld.downloadLocation=
-bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT
-bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.4-SNAPSHOT
-bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10-SNAPSHOT
-bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT
-bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
-bld.sourceDirectories=
-bld.version=2.2.1
diff --git a/pom.xml b/pom.xml
index e480d48..31a633b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,12 +1,16 @@
-
+
+
+
+
+
+
4.0.0
net.thauvin.erik
jokeapi
- 1.0.1-SNAPSHOT
+ 0.9.0
jokeapi
- Retrieve jokes from Sv443's JokeAPI
+ Retrieve jokes from Sv443's JokeAPI
https://github.com/ethauvin/jokeapi
@@ -14,26 +18,6 @@
https://opensource.org/licenses/BSD-3-Clause
-
-
- org.jetbrains.kotlin
- kotlin-stdlib
- 2.1.20
- compile
-
-
- org.json
- json
- 20250107
- compile
-
-
- net.thauvin.erik.urlencoder
- urlencoder-lib-jvm
- 1.6.0
- compile
-
-
ethauvin
@@ -47,4 +31,39 @@
scm:git:git@github.com:ethauvin/jokeapi.git
https://github.com/ethauvin/jokeapi
+
+ GitHub
+ https://github.com/ethauvin/jokeapi/issues
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-bom
+ 1.9.10
+ pom
+ import
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ 1.9.10
+ compile
+
+
+ net.thauvin.erik.urlencoder
+ urlencoder-lib-jvm
+ 1.4.0
+ runtime
+
+
+ org.json
+ json
+ 20230618
+ runtime
+
+
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..dc0111b
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,3 @@
+
+rootProject.name = "jokeapi"
+
diff --git a/sonar-project.properties b/sonar-project.properties
deleted file mode 100644
index 5fe9b51..0000000
--- a/sonar-project.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-sonar.organization=ethauvin-github
-sonar.projectKey=ethauvin_jokeapi
-sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml
-sonar.sources=src/main/kotlin/
-sonar.tests=src/test/kotlin/
-sonar.java.binaries=build/main,build/test
-sonar.java.libraries=lib/compile/*.jar
diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java
deleted file mode 100644
index 62b9d9a..0000000
--- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * JokeApiBuild.java
- *
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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;
-
-import rife.bld.BuildCommand;
-import rife.bld.Project;
-import rife.bld.extension.CompileKotlinOperation;
-import rife.bld.extension.DetektOperation;
-import rife.bld.extension.DokkaOperation;
-import rife.bld.extension.JacocoReportOperation;
-import rife.bld.extension.dokka.LoggingLevel;
-import rife.bld.extension.dokka.OutputFormat;
-import rife.bld.extension.kotlin.CompileOptions;
-import rife.bld.operations.exceptions.ExitStatusException;
-import rife.bld.publish.PomBuilder;
-import rife.bld.publish.PublishDeveloper;
-import rife.bld.publish.PublishLicense;
-import rife.bld.publish.PublishScm;
-import rife.tools.exceptions.FileUtilsErrorException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static rife.bld.dependencies.Repository.*;
-import static rife.bld.dependencies.Scope.compile;
-import static rife.bld.dependencies.Scope.test;
-
-public class JokeApiBuild extends Project {
- final File srcMainKotlin = new File(srcMainDirectory(), "kotlin");
-
- public JokeApiBuild() {
- pkg = "net.thauvin.erik";
- name = "jokeapi";
- version = version(1, 0, 1, "SNAPSHOT");
-
- javaRelease = 11;
- downloadSources = true;
- autoDownloadPurge = true;
- repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL);
-
- final var kotlin = version(2, 1, 20);
- scope(compile)
- .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))
- .include(dependency("org.json", "json", "20250107"))
- .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 6, 0)));
- scope(test)
- .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
- .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1)))
- .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1)))
- .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 1)))
- .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1)));
-
- publishOperation()
- .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location())
- .withCredentials(property("sonatype.user"), property("sonatype.password"))
- : repository(SONATYPE_RELEASES_LEGACY.location())
- .withCredentials(property("sonatype.user"), property("sonatype.password")))
- .repository(repository("github"))
- .info()
- .groupId(pkg)
- .artifactId(name)
- .description("Retrieve jokes from Sv443's JokeAPI")
- .url("https://github.com/ethauvin/" + name)
- .developer(
- new PublishDeveloper()
- .id("ethauvin")
- .name("Erik C. Thauvin")
- .email("erik@thauvin.net")
- .url("https://erik.thauvin.net/")
- )
- .license(
- new PublishLicense()
- .name("BSD 3-Clause")
- .url("https://opensource.org/licenses/BSD-3-Clause")
- )
- .scm(
- new PublishScm()
- .connection("scm:git:https://github.com/ethauvin/" + name + ".git")
- .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git")
- .url("https://github.com/ethauvin/" + name)
- )
- .signKey(property("sign.key"))
- .signPassphrase(property("sign.passphrase"));
-
- jarSourcesOperation().sourceDirectories(srcMainKotlin);
- }
-
- public static void main(String[] args) {
- // Enable detailed logging for the extensions
- var level = Level.ALL;
- var logger = Logger.getLogger("rife.bld.extension");
- var consoleHandler = new ConsoleHandler();
-
- consoleHandler.setLevel(level);
- logger.addHandler(consoleHandler);
- logger.setLevel(level);
- logger.setUseParentHandlers(false);
-
- new JokeApiBuild().start(args);
- }
-
- @BuildCommand(summary = "Compiles the Kotlin project")
- @Override
- public void compile() throws Exception {
- new CompileKotlinOperation()
- .fromProject(this)
- .compileOptions(new CompileOptions().verbose(true))
- .execute();
- }
-
- @BuildCommand(summary = "Checks source with Detekt")
- public void detekt() throws ExitStatusException, IOException, InterruptedException {
- new DetektOperation()
- .fromProject(this)
- .execute();
- }
-
- @BuildCommand(value = "detekt-baseline", summary = "Creates the Detekt baseline")
- public void detektBaseline() throws ExitStatusException, IOException, InterruptedException {
- new DetektOperation()
- .fromProject(this)
- .baseline("detekt-baseline.xml")
- .createBaseline(true)
- .execute();
- }
-
- @BuildCommand(summary = "Generates JaCoCo Reports")
- public void jacoco() throws Exception {
- new JacocoReportOperation()
- .fromProject(this)
- .sourceFiles(srcMainKotlin)
- .execute();
- }
-
- @Override
- public void javadoc() throws ExitStatusException, IOException, InterruptedException {
- new DokkaOperation()
- .fromProject(this)
- .loggingLevel(LoggingLevel.INFO)
- .moduleName("JokeApi")
- .moduleVersion(version.toString())
- .outputDir(new File(buildDirectory(), "javadoc"))
- .outputFormat(OutputFormat.JAVADOC)
- .execute();
- }
-
- @Override
- public void publish() throws Exception {
- super.publish();
- pomRoot();
- }
-
- @Override
- public void publishLocal() throws Exception {
- super.publishLocal();
- pomRoot();
- }
-
- @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory")
- public void pomRoot() throws FileUtilsErrorException {
- PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
- new File(workDirectory, "pom.xml"));
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt
index 474aa27..b4df9aa 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt
@@ -1,7 +1,7 @@
/*
* JokeApi.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,16 +45,13 @@ import java.util.stream.Collectors
object JokeApi {
private const val API_URL = "https://v2.jokeapi.dev/"
- /**
- * The logger instance.
- */
@JvmStatic
val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) }
/**
* Makes a direct API call.
*
- * See the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details.
+ * Sse the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details.
*/
@JvmStatic
@JvmOverloads
@@ -64,7 +61,7 @@ object JokeApi {
path: String = "",
params: Map = emptyMap(),
auth: String = ""
- ): JokeResponse {
+ ): String {
val urlBuilder = StringBuilder("$API_URL$endPoint")
if (path.isNotEmpty()) {
@@ -98,11 +95,11 @@ object JokeApi {
*/
@JvmStatic
@Throws(HttpErrorException::class)
- fun getRawJokes(config: JokeConfig): JokeResponse {
+ fun getRawJokes(config: JokeConfig): String {
return rawJokes(
categories = config.categories,
- lang = config.lang,
- blacklistFlags = config.blacklistFlags,
+ lang = config.language,
+ blacklistFlags = config.flags,
type = config.type,
format = config.format,
contains = config.contains,
@@ -124,8 +121,8 @@ object JokeApi {
fun joke(config: JokeConfig = JokeConfig.Builder().build()): Joke {
return joke(
categories = config.categories,
- lang = config.lang,
- blacklistFlags = config.blacklistFlags,
+ lang = config.language,
+ blacklistFlags = config.flags,
type = config.type,
contains = config.contains,
idRange = config.idRange,
@@ -145,8 +142,8 @@ object JokeApi {
fun jokes(config: JokeConfig): Array {
return jokes(
categories = config.categories,
- lang = config.lang,
- blacklistFlags = config.blacklistFlags,
+ lang = config.language,
+ blacklistFlags = config.flags,
type = config.type,
contains = config.contains,
idRange = config.idRange,
@@ -164,32 +161,6 @@ object JokeApi {
*
* Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
*
- * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is
- * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark
- * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use
- * [Category.ANY], which will make JokeAPI randomly choose a category.
- * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other.
- * All system messages like errors can have a certain system language, while jokes can only have a joke language.
- * It is possible, that system languages don't yet exist for your language while jokes already do.
- * If no suitable system language is found, JokeAPI will default to English.
- * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be
- * set on each joke, and they tell you something about the offensiveness of each joke.
- * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type
- * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated
- * because you might want to present the users the delivery after a timeout or in a different section of the UI.
- * A joke of type [Type.SINGLE] only has a single string, which is the entire joke.
- * @param contains If the search string filter is used, only jokes that contain the specified string will be returned.
- * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs.
- * You don't necessarily need to provide an ID range though, a single ID will work just fine as well.
- * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will
- * mean you will only get the 6th joke.
- * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for
- * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its
- * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as
- * unsafe.
- * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token.
- * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business
- * and need more than 120 requests per minute.
* @param splitNewLine Split newline within [Type.SINGLE] joke.
*/
fun joke(
@@ -213,7 +184,7 @@ fun joke(
idRange = idRange,
safe = safe,
auth = auth
- ).data
+ )
)
if (json.getBoolean("error")) {
throw parseError(json)
@@ -227,35 +198,7 @@ fun joke(
*
* Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
*
- * @param amount This filter allows you to set a certain amount of jokes to receive in a single call. Setting the
- * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a number
- * larger than 10 will make JokeAPI default to the maximum (10).
- * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is
- * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark
- * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use
- * [Category.ANY], which will make JokeAPI randomly choose a category.
- * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other.
- * All system messages like errors can have a certain system language, while jokes can only have a joke language.
- * It is possible, that system languages don't yet exist for your language while jokes already do.
- * If no suitable system language is found, JokeAPI will default to English.
- * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be
- * set on each joke, and they tell you something about the offensiveness of each joke.
- * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type
- * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated
- * because you might want to present the users the delivery after a timeout or in a different section of the UI.
- * A joke of type [Type.SINGLE] only has a single string, which is the entire joke.
- * @param contains If the search string filter is used, only jokes that contain the specified string will be returned.
- * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs.
- * You don't necessarily need to provide an ID range though, a single ID will work just fine as well.
- * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will
- * mean you will only get the 6th joke.
- * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for
- * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its
- * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as
- * unsafe.
- * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token.
- * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business
- * and need more than 120 requests per minute.
+ * @param amount The required amount of jokes to return.
* @param splitNewLine Split newline within [Type.SINGLE] joke.
*/
fun jokes(
@@ -281,7 +224,7 @@ fun jokes(
amount = amount,
safe = safe,
auth = auth
- ).data
+ )
)
if (json.getBoolean("error")) {
throw parseError(json)
@@ -298,42 +241,8 @@ fun jokes(
/**
* Returns one or more jokes.
*
- * See the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
- *
- * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is
- * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark
- * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use
- * [Category.ANY], which will make JokeAPI randomly choose a category.
- * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other.
- * All system messages like errors can have a certain system language, while jokes can only have a joke language.
- * It is possible, that system languages don't yet exist for your language while jokes already do.
- * If no suitable system language is found, JokeAPI will default to English.
- * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be
- * set on each joke, and they tell you something about the offensiveness of each joke.
- * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type
- * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated
- * because you might want to present the users the delivery after a timeout or in a different section of the UI.
- * A joke of type [Type.SINGLE] only has a single string, which is the entire joke.
- * @param contains If the search string filter is used, only jokes that contain the specified string will be returned.
- * @param format Response Formats (or just "Formats") are a way to get your data in a different file format.
- * Maybe your environment or language doesn't support JSON natively. In that case, JokeAPI is able to convert the
- * JSON-formatted joke to a different format for you.
- * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs.
- * You don't necessarily need to provide an ID range though, a single ID will work just fine as well.
- * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will
- * mean you will only get the 6th joke.
- * @param amount This filter allows you to set a certain amount of jokes to receive in a single call. Setting the
- * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a number
- * larger than 10 will make JokeAPI default to the maximum (10).
- * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for
- * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its
- * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as
- * unsafe.
- * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token.
- * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business
- * and need more than 120 requests per minute.
+ * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details.
*/
-@Throws(HttpErrorException::class)
fun rawJokes(
categories: Set = setOf(Category.ANY),
lang: Language = Language.EN,
@@ -345,7 +254,7 @@ fun rawJokes(
amount: Int = 1,
safe: Boolean = false,
auth: String = ""
-): JokeResponse {
+): String {
val params = mutableMapOf()
// Categories
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt
index a4d4901..544383c 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt
@@ -1,7 +1,7 @@
/*
* JokeConfig.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,26 +32,31 @@
package net.thauvin.erik.jokeapi
import net.thauvin.erik.jokeapi.JokeConfig.Builder
-import net.thauvin.erik.jokeapi.models.*
+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
/**
* Joke Configuration.
*
* Use the [Builder] to create a new configuration.
*/
-class JokeConfig private constructor(builder: Builder) {
- val categories = builder.categories
- val lang = builder.lang
- val blacklistFlags = builder.blacklistFlags
- val type = builder.type
- val format = builder.format
- val contains = builder.contains
- val idRange = builder.idRange
- val amount = builder.amount
- val safe = builder.safe
- val splitNewLine = builder.splitNewLine
- val auth = builder.auth
-
+class JokeConfig private constructor(
+ val categories: Set,
+ val language: Language,
+ val flags: Set,
+ val type: Type,
+ val format: Format,
+ val contains: String,
+ val idRange: IdRange,
+ val amount: Int,
+ val safe: Boolean,
+ val splitNewLine: Boolean,
+ val auth: String
+) {
/**
* [Builds][build] a new configuration.
*
@@ -72,86 +77,20 @@ class JokeConfig private constructor(builder: Builder) {
var splitNewLine: Boolean = false,
var auth: String = ""
) {
- /**
- * JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is
- * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING]
- * category, dark humor will be in the [Category.DARK] category and so on. If you want jokes from all
- * categories, you can instead use [Category.ANY], which will make JokeAPI randomly choose a category.
- */
- fun categories(categories: Set): Builder = apply { this.categories = categories }
+ fun categories(categories: Set) = apply { this.categories = categories }
+ 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 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 }
- /**
- * There are two types of languages; system languages and joke languages. Both are separate from each other.
- * All system messages like errors can have a certain system language, while jokes can only have a joke
- * language. It is possible, that system languages don't yet exist for your language while jokes already do.
- * If no suitable system language is found, JokeAPI will default to English.
- */
- fun lang(language: Language): Builder = apply { lang = language }
-
- /**
- * Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be
- * set on each joke, and they tell you something about the offensiveness of each joke.
- */
- fun blacklistFlags(flags: Set): Builder = apply { blacklistFlags = flags }
-
- /**
- * Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type
- * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are
- * separated because you might want to present the users the delivery after a timeout or in a different section
- * of the UI. A joke of type [Type.SINGLE] only has a single string, which is the entire joke.
- */
- fun type(type: Type): Builder = apply { this.type = type }
-
- /**
- * Response Formats (or just "Formats") are a way to get your data in a different file format.
- * Maybe your environment or language doesn't support JSON natively. In that case, JokeAPI is able to convert
- * the JSON-formatted joke to a different format for you.
- */
- fun format(format: Format): Builder = apply { this.format = format }
-
- /**
- * If the search string filter is used, only jokes that contain the specified string will be returned.
- */
- fun contains(search: String): Builder = apply { contains = search }
-
- /**
- * If this filter is used, you will only get jokes that are within the provided range of IDs.
- * You don't necessarily need to provide an ID range though, a single ID will work just fine as well.
- * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range
- * of 5 will mean you will only get the 6th joke.
- */
- fun idRange(idRange: IdRange): Builder = apply { this.idRange = idRange }
-
- /**
- * This filter allows you to set a certain amount of jokes to receive in a single call. Setting the
- * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a
- * number larger than 10 will make JokeAPI default to the maximum (10).
- */
- fun amount(amount: Int): Builder = apply { this.amount = amount }
-
- /**
- * Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for
- * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language,
- * its references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally
- * marked as unsafe.
- */
- fun safe(safe: Boolean): Builder = apply { this.safe = safe }
-
- /**
- * Split newline within [Type.SINGLE] joke.
- */
- fun splitNewLine(splitNewLine: Boolean): Builder = apply { this.splitNewLine = splitNewLine }
-
- /**
- * JokeAPI has a way of whitelisting certain clients. This is achieved through an API token.
- * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a
- * business and need more than 120 requests per minute.
- */
- fun auth(auth: String): Builder = apply { this.auth = auth }
-
- /**
- * Builds a new configuration.
- */
- fun build() = JokeConfig(this)
+ fun build() = JokeConfig(
+ categories, lang, blacklistFlags, type, format, contains, idRange, amount, safe, splitNewLine, auth
+ )
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt
index 651844c..9d838f8 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt
@@ -1,7 +1,7 @@
/*
* JokeUtil.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,41 +35,39 @@ 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.*
+import net.thauvin.erik.jokeapi.models.Category
+import net.thauvin.erik.jokeapi.models.Flag
+import net.thauvin.erik.jokeapi.models.Joke
+import net.thauvin.erik.jokeapi.models.Language
+import net.thauvin.erik.jokeapi.models.Parameter
+import net.thauvin.erik.jokeapi.models.Type
import org.json.JSONObject
import java.io.IOException
import java.net.HttpURLConnection
-import java.net.URI
+import java.net.URL
import java.util.logging.Level
-/**
- * Fetch a URL.
- */
-internal fun fetchUrl(url: String, auth: String = ""): JokeResponse {
+internal fun fetchUrl(url: String, auth: String = ""): String {
if (JokeApi.logger.isLoggable(Level.FINE)) {
JokeApi.logger.fine(url)
}
- val connection = URI(url).toURL().openConnection() as HttpURLConnection
- try {
- connection.setRequestProperty(
- "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0"
- )
- if (auth.isNotEmpty()) {
- connection.setRequestProperty("Authentication", auth)
- }
+ val connection = URL(url).openConnection() as HttpURLConnection
+ connection.setRequestProperty(
+ "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"
+ )
+ if (auth.isNotEmpty()) {
+ connection.setRequestProperty("Authentication", auth)
+ }
- val isSuccess = connection.responseCode in 200..399
- val stream = if (isSuccess) connection.inputStream else connection.errorStream
- val body = stream.bufferedReader().use { it.readText() }
- if (!isSuccess && (body.isBlank() || connection.contentType.contains("text/html"))) {
- throw httpError(connection.responseCode)
- } else if (JokeApi.logger.isLoggable(Level.FINE)) {
+ if (connection.responseCode in 200..399) {
+ val body = connection.inputStream.bufferedReader().use { it.readText() }
+ if (JokeApi.logger.isLoggable(Level.FINE)) {
JokeApi.logger.fine(body)
}
- return JokeResponse(connection.responseCode, body)
- } finally {
- connection.disconnect()
+ return body
+ } else {
+ throw httpError(connection.responseCode)
}
}
@@ -130,9 +128,6 @@ private fun httpError(responseCode: Int): HttpErrorException {
return httpException
}
-/**
- * Parse Error.
- */
internal fun parseError(json: JSONObject): JokeException {
val causedBy = json.getJSONArray("causedBy")
val causes = List(causedBy.length()) { i -> causedBy.getString(i) }
@@ -146,9 +141,6 @@ internal fun parseError(json: JSONObject): JokeException {
)
}
-/**
- * Parse Joke.
- */
internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke {
val jokes = mutableListOf()
if (json.has("setup")) {
@@ -163,7 +155,7 @@ internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke {
}
val enabledFlags = mutableSetOf()
val jsonFlags = json.getJSONObject("flags")
- Flag.entries.filter { it != Flag.ALL }.forEach {
+ Flag.values().filter { it != Flag.ALL }.forEach {
if (jsonFlags.has(it.value) && jsonFlags.getBoolean(it.value)) {
enabledFlags.add(it)
}
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt
index f2e8529..cd17ca8 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt
@@ -1,7 +1,7 @@
/*
* HttpErrorException.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt
index ac77344..919216e 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt
@@ -1,7 +1,7 @@
/*
* JokeException.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,8 +29,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-@file:Suppress("ConstPropertyName")
-
package net.thauvin.erik.jokeapi.exceptions
/**
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt
index cfb008e..4951d4a 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt
@@ -1,7 +1,7 @@
/*
* Category.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
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 be2e21f..af92e90 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt
@@ -1,7 +1,7 @@
/*
* Flag.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
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 1beb9d3..2678a21 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt
@@ -1,7 +1,7 @@
/*
* Format.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt
index 73d45ec..62a6eb6 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt
@@ -1,7 +1,7 @@
/*
* IdRange.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
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 c2124ae..0309977 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt
@@ -1,7 +1,7 @@
/*
* Joke.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt
deleted file mode 100644
index d34f2c3..0000000
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * JokeResponse.kt
- *
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
- *
- * 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.models
-
-/**
- * The Joke API response.
- *
- * @property statusCode The HTTP status code.
- * @property data The response body text.
- */
-data class JokeResponse(val statusCode: Int, val data: String)
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 3ee166e..10c00fb 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt
@@ -1,7 +1,7 @@
/*
* Language.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt
index 8962b2a..b9e1106 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt
@@ -1,7 +1,7 @@
/*
* Parameter.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,6 @@ package net.thauvin.erik.jokeapi.models
/**
* The available [URL Parameters](https://jokeapi.dev/#url-parameters).
*/
-@Suppress("unused")
object Parameter {
const val AMOUNT = "amount"
const val CONTAINS = "contains"
diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt
index 4fd80fe..59126b4 100644
--- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt
+++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt
@@ -1,7 +1,7 @@
/*
* Type.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt
index 6153825..d9f9b30 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt
@@ -1,7 +1,7 @@
/*
* ApiCallTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@
package net.thauvin.erik.jokeapi
import assertk.assertThat
-import assertk.assertions.isEqualTo
import assertk.assertions.isGreaterThan
import assertk.assertions.startsWith
import net.thauvin.erik.jokeapi.JokeApi.apiCall
@@ -52,9 +51,8 @@ internal class ApiCallTest {
fun `Get Flags`() {
// See https://v2.jokeapi.dev/#flags-endpoint
val response = apiCall(endPoint = "flags")
- val json = JSONObject(response.data)
- assertAll(
- "Validate JSON",
+ val json = JSONObject(response)
+ assertAll("Validate JSON",
{ 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) })
@@ -67,16 +65,14 @@ internal class ApiCallTest {
endPoint = "langcode", path = "french",
params = mapOf(Parameter.FORMAT to Format.YAML.value)
)
- assertThat(lang.statusCode).isEqualTo(200)
- assertContains(lang.data, "code: \"fr\"", false, "apiCall(langcode, french, yaml)")
+ 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))
- assertThat(ping.statusCode).isEqualTo(200)
- assertThat(ping.data).startsWith("Pong!")
+ assertThat(ping, "apiCall(ping, txt)").startsWith("Pong!")
}
@Test
@@ -86,7 +82,6 @@ internal class ApiCallTest {
endPoint = "languages",
params = mapOf(Parameter.FORMAT to Format.XML.value, Parameter.LANG to Language.FR.value)
)
- assertThat(lang.statusCode).isEqualTo(200)
- assertThat(lang.data).startsWith("")
+ assertThat(lang).startsWith("")
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt
index 50ce4b2..de9d48a 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt
@@ -1,7 +1,7 @@
/*
* BeforeAllTests.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt
index eb6837a..adacf75 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt
@@ -1,7 +1,7 @@
/*
* ExceptionsTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,16 @@ package net.thauvin.erik.jokeapi
import assertk.all
import assertk.assertThat
-import assertk.assertions.*
+import assertk.assertions.index
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFalse
+import assertk.assertions.isGreaterThan
+import assertk.assertions.isNotEmpty
+import assertk.assertions.isNotNull
+import assertk.assertions.isNull
+import assertk.assertions.prop
+import assertk.assertions.size
+import assertk.assertions.startsWith
import net.thauvin.erik.jokeapi.JokeApi.logger
import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
import net.thauvin.erik.jokeapi.exceptions.JokeException
@@ -41,6 +50,8 @@ import net.thauvin.erik.jokeapi.models.Category
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ValueSource
@ExtendWith(BeforeAllTests::class)
internal class ExceptionsTest {
@@ -61,20 +72,19 @@ internal class ExceptionsTest {
}
}
- @Test
- fun `Validate HTTP Exceptions`() {
- val locs = ArrayList>()
- locs.add(Pair("https://apichallenges.herokuapp.com/secret/note", 401))
- locs.add(Pair("https://apichallenges.herokuapp.com/todo", 404))
-
- for ((url, code) in locs) {
- val e = assertThrows {
- fetchUrl(url)
- }
- assertThat(e, "fetchUrl($code)").all {
- prop(HttpErrorException::statusCode).isEqualTo(code)
- prop(HttpErrorException::message).isNotNull().isNotEmpty()
- }
+ @ParameterizedTest
+ @ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523, 666])
+ fun `Validate HTTP Exceptions`(code: Int) {
+ val e = assertThrows {
+ fetchUrl("https://httpstat.us/$code")
+ }
+ assertThat(e, "fetchUrl($code)").all {
+ prop(HttpErrorException::statusCode).isEqualTo(code)
+ prop(HttpErrorException::message).isNotNull().isNotEmpty()
+ if (code < 600)
+ prop(HttpErrorException::cause).isNotNull().assertThat(Throwable::message).isNotNull()
+ else
+ prop(HttpErrorException::cause).isNull()
}
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt
index e5a7d39..a2b06db 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt
@@ -1,7 +1,7 @@
/*
* GetJokeTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,10 +33,29 @@ package net.thauvin.erik.jokeapi
import assertk.all
import assertk.assertThat
-import assertk.assertions.*
+import assertk.assertions.any
+import assertk.assertions.contains
+import assertk.assertions.containsNone
+import assertk.assertions.each
+import assertk.assertions.isBetween
+import assertk.assertions.isEmpty
+import assertk.assertions.isEqualTo
+import assertk.assertions.isGreaterThan
+import assertk.assertions.isGreaterThanOrEqualTo
+import assertk.assertions.isIn
+import assertk.assertions.isNotEmpty
+import assertk.assertions.isNotNull
+import assertk.assertions.isTrue
+import assertk.assertions.prop
+import assertk.assertions.size
import net.thauvin.erik.jokeapi.JokeApi.logger
import net.thauvin.erik.jokeapi.exceptions.JokeException
-import net.thauvin.erik.jokeapi.models.*
+import net.thauvin.erik.jokeapi.models.Category
+import net.thauvin.erik.jokeapi.models.Flag
+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.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
@@ -63,19 +82,22 @@ internal class GetJokeTest {
@Test
fun `Get Joke without any Blacklist Flags`() {
- val allFlags = Flag.entries.filter { it != Flag.ALL }.toSet()
+ val allFlags = Flag.values().filter { it != Flag.ALL }.toSet()
val joke = joke(blacklistFlags = allFlags)
assertThat(joke::flags).isEmpty()
}
@Test
fun `Get Joke with ID`() {
- val id = 201
+ val id = 172
val joke = joke(idRange = IdRange(id))
logger.fine(joke.toString())
assertThat(joke, "joke($id)").all {
- prop(Joke::flags).contains(Flag.RELIGIOUS);
- prop(Joke::id).isEqualTo(id)
+ prop(Joke::flags).all {
+ contains(Flag.EXPLICIT)
+ contains(Flag.NSFW)
+ }
+ prop(Joke::id).isEqualTo(172)
prop(Joke::category).isEqualTo(Category.PUN)
}
}
@@ -116,7 +138,7 @@ internal class GetJokeTest {
@Test
fun `Get Joke with each Categories`() {
- Category.entries.filter { it != Category.ANY }.forEach {
+ Category.values().filter { it != Category.ANY }.forEach {
val joke = joke(categories = setOf(it))
logger.fine(joke.toString())
assertThat(joke::category, "joke($it)").prop(Category::value).isEqualTo(it.value)
@@ -125,7 +147,7 @@ internal class GetJokeTest {
@Test
fun `Get Joke with each Languages`() {
- Language.entries.forEach {
+ Language.values().forEach {
val joke = joke(lang = it)
logger.fine(joke.toString())
assertThat(joke::lang, "joke($it)").prop(Language::value).isEqualTo(it.value)
@@ -134,10 +156,12 @@ internal class GetJokeTest {
@Test
fun `Get Joke with Split Newline`() {
- val joke = joke(type = Type.SINGLE, idRange = IdRange(18), splitNewLine = true)
+ val joke = joke(
+ categories = setOf(Category.DARK), type = Type.SINGLE, idRange = IdRange(178), splitNewLine = true
+ )
logger.fine(joke.toString())
assertThat(joke::joke, "joke(splitNewLine=true)").all {
- size().isGreaterThanOrEqualTo(2)
+ size().isEqualTo(2)
each {
containsNone("\n")
}
@@ -172,12 +196,13 @@ internal class GetJokeTest {
@Test
fun `Get Joke using Search`() {
- val search = "UDP joke"
+ val id = 265
+ val search = "his wife"
val joke =
- joke(contains = search, categories = setOf(Category.PROGRAMMING), safe = true)
+ joke(contains = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true)
logger.fine(joke.toString())
assertThat(joke, "joke($search)").all {
- prop(Joke::id).isEqualTo(0)
+ prop(Joke::id).isEqualTo(id)
prop(Joke::joke).any {
it.contains(search)
}
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt
index ea49211..1ab8b60 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt
@@ -1,7 +1,7 @@
/*
* GetJokesTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,15 @@ package net.thauvin.erik.jokeapi
import assertk.all
import assertk.assertThat
-import assertk.assertions.*
+import assertk.assertions.contains
+import assertk.assertions.each
+import assertk.assertions.index
+import assertk.assertions.isEqualTo
+import assertk.assertions.isGreaterThanOrEqualTo
+import assertk.assertions.isNotNull
+import assertk.assertions.isTrue
+import assertk.assertions.prop
+import assertk.assertions.size
import net.thauvin.erik.jokeapi.models.Joke
import net.thauvin.erik.jokeapi.models.Language
import org.junit.jupiter.api.Test
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
index aa85337..7bcf1c6 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
@@ -1,7 +1,7 @@
/*
* GetRawJokesTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,60 +33,47 @@ package net.thauvin.erik.jokeapi
import assertk.all
import assertk.assertThat
-import assertk.assertions.*
+import assertk.assertions.doesNotContain
+import assertk.assertions.isNotEmpty
+import assertk.assertions.startsWith
import net.thauvin.erik.jokeapi.models.Format
import net.thauvin.erik.jokeapi.models.IdRange
-import net.thauvin.erik.jokeapi.models.JokeResponse
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
+import kotlin.test.assertContains
@ExtendWith(BeforeAllTests::class)
internal class GetRawJokesTest {
@Test
fun `Get Raw Joke with TXT`() {
val response = rawJokes(format = Format.TXT)
- assertThat(response).all {
- prop("statusCode", JokeResponse::statusCode).isEqualTo(200)
- prop("data", JokeResponse::data).all {
- isNotEmpty()
- doesNotContain("Error")
- }
+ assertThat(response, "rawJoke(txt)").all {
+ isNotEmpty()
+ doesNotContain("Error")
}
}
@Test
fun `Get Raw Joke with XML`() {
val response = rawJokes(format = Format.XML)
- assertThat(response).all {
- prop("statusCode", JokeResponse::statusCode).isEqualTo(200)
- prop("data", JokeResponse::data).startsWith("\n\n false")
- }
+ assertThat(response, "rawJoke(xml)").startsWith("\n\n false")
}
@Test
fun `Get Raw Joke with YAML`() {
val response = rawJokes(format = Format.YAML)
- assertThat(response).all {
- prop("statusCode", JokeResponse::statusCode).isEqualTo(200)
- prop("data", JokeResponse::data).startsWith("error: false")
- }
+ assertThat(response, "rawJoke(yaml)").startsWith("error: false")
}
@Test
fun `Get Raw Jokes`() {
val response = rawJokes(amount = 2)
- assertThat(response).all {
- prop("statusCode", JokeResponse::statusCode).isEqualTo(200)
- prop("data", JokeResponse::data).isNotEmpty()
- }
+ assertContains(response, "\"amount\": 2", false, "rawJoke(2)")
}
@Test
fun `Get Raw Invalid Jokes`() {
val response = rawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161))
- assertThat(response).all {
- prop("statusCode", JokeResponse::statusCode).isEqualTo(400)
- prop("data", JokeResponse::data).contains("\"error\": true")
- }
+ 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 a4d4e0c..92de2e0 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt
@@ -1,7 +1,7 @@
/*
* JokeConfigTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,12 +33,25 @@ package net.thauvin.erik.jokeapi
import assertk.all
import assertk.assertThat
-import assertk.assertions.*
-import net.thauvin.erik.jokeapi.JokeApi.getRawJokes
+import assertk.assertions.each
+import assertk.assertions.isBetween
+import assertk.assertions.isEmpty
+import assertk.assertions.isEqualTo
+import assertk.assertions.isGreaterThanOrEqualTo
+import assertk.assertions.isTrue
+import assertk.assertions.prop
+import assertk.assertions.size
import net.thauvin.erik.jokeapi.JokeApi.joke
import net.thauvin.erik.jokeapi.JokeApi.jokes
+import net.thauvin.erik.jokeapi.JokeApi.getRawJokes
import net.thauvin.erik.jokeapi.JokeApi.logger
-import net.thauvin.erik.jokeapi.models.*
+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.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import kotlin.test.assertContains
@@ -102,9 +115,8 @@ internal class JokeConfigTest {
amount(2)
safe(true)
}.build()
- val jokes = getRawJokes(config)
- assertThat(jokes.statusCode).isEqualTo(200)
- assertContains(jokes.data, "----------------------------------------------", false, "config.amount(2)")
+ val joke = getRawJokes(config)
+ assertContains(joke, "----------------------------------------------", false, "config.amount(2)")
}
@Test
@@ -155,8 +167,8 @@ internal class JokeConfigTest {
}.build()
assertThat(config, "config").all {
prop(JokeConfig::categories).isEqualTo(categories)
- prop(JokeConfig::lang).isEqualTo(language)
- prop(JokeConfig::blacklistFlags).isEqualTo(flags)
+ prop(JokeConfig::language).isEqualTo(language)
+ prop(JokeConfig::flags).isEqualTo(flags)
prop(JokeConfig::type).isEqualTo(type)
prop(JokeConfig::format).isEqualTo(format)
prop(JokeConfig::contains).isEqualTo(search)
diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt
index d50b97a..8f8d936 100644
--- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt
@@ -1,7 +1,7 @@
/*
- * JokeUtilTest.kt
+ * UtilTest.kt
*
- * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net)
+ * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,6 @@ package net.thauvin.erik.jokeapi
import assertk.assertThat
import assertk.assertions.contains
-import assertk.assertions.isEqualTo
import org.json.JSONException
import org.json.JSONObject
import org.junit.jupiter.api.Test
@@ -55,8 +54,7 @@ internal class JokeUtilTest {
@Test
fun `Validate Authentication Header`() {
val token = "AUTH-TOKEN"
- val response = fetchUrl("https://postman-echo.com/get", token)
- assertThat(response.statusCode).isEqualTo(200)
- assertThat(response.data, "body").contains("\"authentication\": \"$token\"")
+ val body = fetchUrl("https://postman-echo.com/get", token)
+ assertThat(body, "body").contains("\"authentication\": \"$token\"")
}
}