Switched from Gradle to bld
This commit is contained in:
parent
4c031d7a61
commit
f613b8cdfc
58 changed files with 2344 additions and 760 deletions
|
@ -4,50 +4,41 @@ defaults: &defaults
|
|||
environment:
|
||||
JVM_OPTS: -Xmx3200m
|
||||
TERM: dumb
|
||||
CI: true
|
||||
CI_NAME: "CircleCI"
|
||||
|
||||
defaults_gradle: &defaults_gradle
|
||||
defaults_gradle: &defaults_bld
|
||||
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" }}
|
||||
name: Download the bld dependencies
|
||||
command: ./bld download
|
||||
- run:
|
||||
name: Run All Checks
|
||||
command: ./gradlew check
|
||||
- store_artifacts:
|
||||
path: build/reports/
|
||||
destination: reports
|
||||
- store_test_results:
|
||||
path: build/reports/
|
||||
name: Compile source with bld
|
||||
command: ./bld compile
|
||||
- run:
|
||||
name: Run tests with bld
|
||||
command: ./bld test
|
||||
|
||||
jobs:
|
||||
build_gradle_jdk17:
|
||||
bld_jdk17:
|
||||
<<: *defaults
|
||||
|
||||
docker:
|
||||
- image: cimg/openjdk:17.0
|
||||
|
||||
<<: *defaults_gradle
|
||||
<<: *defaults_bld
|
||||
|
||||
build_gradle_jdk11:
|
||||
bld_jdk20:
|
||||
<<: *defaults
|
||||
|
||||
docker:
|
||||
- image: cimg/openjdk:11.0
|
||||
- image: cimg/openjdk:20.0
|
||||
|
||||
<<: *defaults_gradle
|
||||
<<: *defaults_bld
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
gradle:
|
||||
bld:
|
||||
jobs:
|
||||
- build_gradle_jdk11
|
||||
- build_gradle_jdk17
|
||||
- bld_jdk17
|
||||
- bld_jdk20
|
||||
|
|
44
.github/workflows/gradle.yml
vendored
44
.github/workflows/gradle.yml
vendored
|
@ -1,21 +1,21 @@
|
|||
name: gradle-ci
|
||||
name: bld-ci
|
||||
|
||||
on: [ push, pull_request, workflow_dispatch ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-bld-project:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m"
|
||||
SONAR_JDK: "17"
|
||||
COVERAGE_SDK: "17"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [ 11, 17, 20 ]
|
||||
java-version: [ 17, 20 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout source repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
@ -25,25 +25,25 @@ jobs:
|
|||
distribution: 'zulu'
|
||||
java-version: ${{ matrix.java-version }}
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Grant bld execute permission
|
||||
run: chmod +x bld
|
||||
|
||||
- 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: Download the bld dependencies
|
||||
run: ./bld download
|
||||
|
||||
- name: Test with Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: build check --stacktrace --scan
|
||||
- name: Compile source with bld
|
||||
run: ./bld compile
|
||||
|
||||
- name: SonarCloud
|
||||
if: success() && matrix.java-version == env.SONAR_JDK
|
||||
- name: Run tests with bld
|
||||
run: ./bld jacoco
|
||||
|
||||
- name: Remove pom.xml
|
||||
if: success() && matrix.java-version == env.COVERAGE_SDK
|
||||
run: rm -rf pom.xml
|
||||
|
||||
- name: SonarCloud Scan
|
||||
uses: sonarsource/sonarcloud-github-action@master
|
||||
if: success() && matrix.java-version == env.COVERAGE_SDK
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
run: ./gradlew sonar --info
|
||||
|
|
135
.gitignore
vendored
135
.gitignore
vendored
|
@ -1,84 +1,57 @@
|
|||
!.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
|
||||
.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__
|
||||
.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
|
||||
atlassian-ide-plugin.xml
|
||||
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/
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
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
|
||||
|
|
30
.idea/app.iml
generated
Normal file
30
.idea/app.iml
generated
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/build/main" />
|
||||
<output-test url="file://$MODULE_DIR$/build/test" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" relativeOutputPath="resources" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library" scope="RUNTIME">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="file://$MODULE_DIR$/src/main/resources/templates" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="library" name="compile" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="runtime" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="test" level="project" />
|
||||
</component>
|
||||
</module>
|
14
.idea/bld.iml
generated
Normal file
14
.idea/bld.iml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/build/bld" />
|
||||
<output-test url="file://$MODULE_DIR$/build/bld" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$/src/bld">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/bld/java" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="bld" level="project" />
|
||||
</component>
|
||||
</module>
|
17
.idea/libraries/bld.xml
generated
Normal file
17
.idea/libraries/bld.xml
generated
Normal file
|
@ -0,0 +1,17 @@
|
|||
<component name="libraryTable">
|
||||
<library name="bld">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/lib/bld" />
|
||||
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.5.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.5-sources.jar!/" />
|
||||
</SOURCES>
|
||||
<excluded>
|
||||
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />
|
||||
</excluded>
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" type="SOURCES" />
|
||||
</library>
|
||||
</component>
|
13
.idea/libraries/compile.xml
generated
Normal file
13
.idea/libraries/compile.xml
generated
Normal file
|
@ -0,0 +1,13 @@
|
|||
<component name="libraryTable">
|
||||
<library name="compile">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/lib/compile" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$PROJECT_DIR$/lib/compile" />
|
||||
</SOURCES>
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
|
||||
</library>
|
||||
</component>
|
14
.idea/libraries/runtime.xml
generated
Normal file
14
.idea/libraries/runtime.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<component name="libraryTable">
|
||||
<library name="runtime">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/lib/runtime" />
|
||||
<root url="file://$PROJECT_DIR$/src/main/resources" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$PROJECT_DIR$/lib/runtime" />
|
||||
</SOURCES>
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
|
||||
</library>
|
||||
</component>
|
14
.idea/libraries/test.xml
generated
Normal file
14
.idea/libraries/test.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<component name="libraryTable">
|
||||
<library name="test">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/lib/test" />
|
||||
<root url="file://$PROJECT_DIR$/src/test/resources" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$PROJECT_DIR$/lib/test" />
|
||||
</SOURCES>
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
|
||||
</library>
|
||||
</component>
|
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="PDMPlugin">
|
||||
<option name="skipTestSources" value="false" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="19" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build" />
|
||||
</component>
|
||||
</project>
|
9
.idea/modules.xml
generated
Normal file
9
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/app.iml" filepath="$PROJECT_DIR$/.idea/app.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/bld.iml" filepath="$PROJECT_DIR$/.idea/bld.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
9
.idea/runConfigurations/Run Tests.xml
generated
Normal file
9
.idea/runConfigurations/Run Tests.xml
generated
Normal file
|
@ -0,0 +1,9 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Tests" type="Application" factoryName="Application" nameIsGenerated="true">
|
||||
<option name="MAIN_CLASS_NAME" value="net.thauvin.erik.JokeapiTest" />
|
||||
<module name="app" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Run Tests",
|
||||
"request": "launch",
|
||||
"mainClass": "net.thauvin.erik.JokeapiTest"
|
||||
}
|
||||
]
|
||||
}
|
15
.vscode/settings.json
vendored
Normal file
15
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"java.project.sourcePaths": [
|
||||
"src/main/java",
|
||||
"src/main/resources",
|
||||
"src/test/java",
|
||||
"src/bld/java"
|
||||
],
|
||||
"java.configuration.updateBuildConfiguration": "automatic",
|
||||
"java.project.referencedLibraries": [
|
||||
"${HOME}/.bld/dist/bld-1.7.5.jar",
|
||||
"lib/compile/*.jar",
|
||||
"lib/runtime/*.jar",
|
||||
"lib/test/*.jar"
|
||||
]
|
||||
}
|
17
README.md
17
README.md
|
@ -1,8 +1,8 @@
|
|||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
[](https://kotlinlang.org/)
|
||||
[](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/)
|
||||
[](https://kotlinlang.org/)
|
||||
[](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/gradle.yml)
|
||||
|
@ -88,6 +88,19 @@ 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);
|
||||
|
||||
scope(compile)
|
||||
.include(dependency("net.thauvin.erik:cryptoprice:1.0.1"));
|
||||
```
|
||||
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:
|
||||
|
||||
|
|
318
bin/main/net/thauvin/erik/jokeapi/JokeApi.kt
Normal file
318
bin/main/net/thauvin/erik/jokeapi/JokeApi.kt
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* 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<String, String> = 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<Joke> {
|
||||
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<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
|
||||
): 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<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
|
||||
): Array<Joke> {
|
||||
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<Category> = setOf(Category.ANY),
|
||||
lang: Language = Language.EN,
|
||||
blacklistFlags: Set<Flag> = emptySet(),
|
||||
type: Type = Type.ALL,
|
||||
format: Format = Format.JSON,
|
||||
contains: String = "",
|
||||
idRange: IdRange = IdRange(),
|
||||
amount: Int = 1,
|
||||
safe: Boolean = false,
|
||||
auth: String = ""
|
||||
): String {
|
||||
val params = mutableMapOf<String, String>()
|
||||
|
||||
// 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)
|
||||
}
|
96
bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt
Normal file
96
bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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<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
|
||||
) {
|
||||
/**
|
||||
* [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<Category> = setOf(Category.ANY),
|
||||
var lang: Language = Language.EN,
|
||||
var blacklistFlags: Set<Flag> = 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<Category>) = apply { this.categories = categories }
|
||||
fun lang(language: Language) = apply { lang = language }
|
||||
fun blacklistFlags(flags: Set<Flag>) = 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
|
||||
)
|
||||
}
|
||||
}
|
173
bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt
Normal file
173
bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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<String>(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<String>()
|
||||
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<Flag>()
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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<String>,
|
||||
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)"
|
||||
}
|
||||
}
|
45
bin/main/net/thauvin/erik/jokeapi/models/Category.kt
Normal file
45
bin/main/net/thauvin/erik/jokeapi/models/Category.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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")
|
||||
}
|
45
bin/main/net/thauvin/erik/jokeapi/models/Flag.kt
Normal file
45
bin/main/net/thauvin/erik/jokeapi/models/Flag.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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}")
|
||||
}
|
44
bin/main/net/thauvin/erik/jokeapi/models/Format.kt
Normal file
44
bin/main/net/thauvin/erik/jokeapi/models/Format.kt
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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")
|
||||
}
|
37
bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt
Normal file
37
bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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)
|
45
bin/main/net/thauvin/erik/jokeapi/models/Joke.kt
Normal file
45
bin/main/net/thauvin/erik/jokeapi/models/Joke.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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<String>,
|
||||
val flags: Set<Flag>,
|
||||
val id: Int,
|
||||
val safe: Boolean,
|
||||
val lang: Language
|
||||
)
|
55
bin/main/net/thauvin/erik/jokeapi/models/Language.kt
Normal file
55
bin/main/net/thauvin/erik/jokeapi/models/Language.kt
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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")
|
||||
}
|
51
bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt
Normal file
51
bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
41
bin/main/net/thauvin/erik/jokeapi/models/Type.kt
Normal file
41
bin/main/net/thauvin/erik/jokeapi/models/Type.kt
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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}")
|
||||
}
|
87
bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt
Normal file
87
bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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("<?xml version='1.0'?>")
|
||||
}
|
||||
}
|
47
bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt
Normal file
47
bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
90
bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt
Normal file
90
bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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<JokeException> {
|
||||
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<HttpErrorException> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
211
bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt
Normal file
211
bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* 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<IllegalArgumentException> { 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<JokeException> { 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
84
bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt
Normal file
84
bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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<IllegalArgumentException> { 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
Normal file
79
bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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("<?xml version='1.0'?>\n<data>\n <error>false</error>")
|
||||
}
|
||||
|
||||
@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)")
|
||||
}
|
||||
}
|
182
bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt
Normal file
182
bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
}
|
60
bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt
Normal file
60
bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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<JSONException> { parseError(JSONObject("{}")) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Invalid JSON Joke`() {
|
||||
assertThrows<JSONException> { 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\"")
|
||||
}
|
||||
}
|
2
bld
Executable file
2
bld
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env sh
|
||||
java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build net.thauvin.erik.JokeApiBuild "$@"
|
4
bld.bat
Normal file
4
bld.bat
Normal file
|
@ -0,0 +1,4 @@
|
|||
@echo off
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build net.thauvin.erik.JokeApiBuild %*
|
185
build.gradle.kts
185
build.gradle.kts
|
@ -1,185 +0,0 @@
|
|||
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.49.0"
|
||||
id("io.gitlab.arturbosch.detekt") version "1.23.1"
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("org.jetbrains.dokka") version "1.9.10"
|
||||
id("org.jetbrains.kotlinx.kover") version "0.7.4"
|
||||
id("org.sonarqube") version "4.4.1.3373"
|
||||
id("signing")
|
||||
kotlin("jvm") version "1.9.10"
|
||||
}
|
||||
|
||||
description = "Retrieve jokes from Sv443's JokeAPI"
|
||||
group = "net.thauvin.erik"
|
||||
version = "0.9.1-SNAPSHOT"
|
||||
|
||||
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:20231013")
|
||||
|
||||
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", "${layout.buildDirectory.get()}/reports/kover/report.xml")
|
||||
}
|
||||
}
|
||||
|
||||
val javadocJar by tasks.creating(Jar::class) {
|
||||
dependsOn(tasks.dokkaJavadoc)
|
||||
from(tasks.dokkaJavadoc)
|
||||
archiveClassifier.set("javadoc")
|
||||
}
|
||||
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions.jvmTarget = java.targetCompatibility.toString()
|
||||
}
|
||||
|
||||
withType<Test> {
|
||||
testLogging {
|
||||
exceptionFormat = TestExceptionFormat.FULL
|
||||
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
|
||||
}
|
||||
}
|
||||
|
||||
withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
|
||||
this.jvmTarget = java.targetCompatibility.toString()
|
||||
}
|
||||
|
||||
withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach {
|
||||
this.jvmTarget = java.targetCompatibility.toString()
|
||||
}
|
||||
|
||||
withType<GenerateMavenPom> {
|
||||
destination = file("$projectDir/pom.xml")
|
||||
}
|
||||
|
||||
clean {
|
||||
doLast {
|
||||
project.delete(fileTree(deployDir))
|
||||
}
|
||||
}
|
||||
|
||||
withType<DokkaTask>().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<MavenPublication>(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])
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
kotlin.code.style=official
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
7
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +0,0 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
gradlew
vendored
249
gradlew
vendored
|
@ -1,249 +0,0 @@
|
|||
#!/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=SC2039,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=SC2039,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, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
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" "$@"
|
92
gradlew.bat
vendored
92
gradlew.bat
vendored
|
@ -1,92 +0,0 @@
|
|||
@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
|
BIN
lib/bld/bld-wrapper.jar
Normal file
BIN
lib/bld/bld-wrapper.jar
Normal file
Binary file not shown.
8
lib/bld/bld-wrapper.properties
Normal file
8
lib/bld/bld-wrapper.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
bld.downloadExtensionJavadoc=false
|
||||
bld.downloadExtensionSources=true
|
||||
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1
|
||||
bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT
|
||||
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
|
||||
bld.downloadLocation=
|
||||
bld.sourceDirectories=
|
||||
bld.version=1.7.5
|
|
@ -1,18 +0,0 @@
|
|||
plugins {
|
||||
id("com.gradle.enterprise").version("3.15")
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
link("GitHub", "https://github.com/ethauvin/jokeapi/tree/master")
|
||||
if (!System.getenv("CI").isNullOrEmpty()) {
|
||||
isUploadInBackground = false
|
||||
publishOnFailure()
|
||||
tag("CI")
|
||||
}
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "jokeapi"
|
7
sonar-project.properties
Normal file
7
sonar-project.properties
Normal file
|
@ -0,0 +1,7 @@
|
|||
sonar.organization=ethauvin-github
|
||||
sonar.projectKey=ethauvin_readingtime
|
||||
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
|
153
src/bld/java/net/thauvin/erik/JokeApiBuild.java
Normal file
153
src/bld/java/net/thauvin/erik/JokeApiBuild.java
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* JokeApiBuild.java
|
||||
*
|
||||
* 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;
|
||||
|
||||
import rife.bld.BuildCommand;
|
||||
import rife.bld.Project;
|
||||
import rife.bld.extension.CompileKotlinOperation;
|
||||
import rife.bld.extension.CompileKotlinOptions;
|
||||
import rife.bld.extension.JacocoReportOperation;
|
||||
import rife.bld.extension.dokka.DokkaOperation;
|
||||
import rife.bld.extension.dokka.LoggingLevel;
|
||||
import rife.bld.extension.dokka.OutputFormat;
|
||||
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 static rife.bld.dependencies.Repository.*;
|
||||
import static rife.bld.dependencies.Scope.compile;
|
||||
import static rife.bld.dependencies.Scope.test;
|
||||
|
||||
public class JokeApiBuild extends Project {
|
||||
public JokeApiBuild() {
|
||||
pkg = "net.thauvin.erik";
|
||||
name = "jokeapi";
|
||||
version = version(0, 9, 1, "SNAPSHOT");
|
||||
|
||||
javaRelease = 11;
|
||||
downloadSources = true;
|
||||
autoDownloadPurge = true;
|
||||
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL);
|
||||
|
||||
scope(compile)
|
||||
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 20)))
|
||||
.include(dependency("org.json", "json", "20231013"))
|
||||
.include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0)));
|
||||
scope(test)
|
||||
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 20)))
|
||||
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1)))
|
||||
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1)))
|
||||
.include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0)));
|
||||
|
||||
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")))
|
||||
.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)
|
||||
.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(new File(srcMainDirectory(), "kotlin"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new JokeApiBuild().start(args);
|
||||
}
|
||||
|
||||
@BuildCommand(summary = "Compiles the Kotlin project")
|
||||
@Override
|
||||
public void compile() throws IOException {
|
||||
new CompileKotlinOperation()
|
||||
.fromProject(this)
|
||||
.compileOptions(
|
||||
new CompileKotlinOptions()
|
||||
.jdkRelease(javaRelease)
|
||||
.verbose(true)
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
|
||||
@BuildCommand(summary = "Generates JaCoCo Reports")
|
||||
public void jacoco() throws IOException {
|
||||
new JacocoReportOperation()
|
||||
.fromProject(this)
|
||||
.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();
|
||||
}
|
||||
|
||||
@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"));
|
||||
}
|
||||
}
|
|
@ -32,12 +32,7 @@
|
|||
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
|
||||
import net.thauvin.erik.jokeapi.models.*
|
||||
|
||||
/**
|
||||
* Joke Configuration.
|
||||
|
|
|
@ -35,12 +35,7 @@ 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 net.thauvin.erik.jokeapi.models.*
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
|
@ -155,7 +150,7 @@ internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke {
|
|||
}
|
||||
val enabledFlags = mutableSetOf<Flag>()
|
||||
val jsonFlags = json.getJSONObject("flags")
|
||||
Flag.values().filter { it != Flag.ALL }.forEach {
|
||||
Flag.entries.filter { it != Flag.ALL }.forEach {
|
||||
if (jsonFlags.has(it.value) && jsonFlags.getBoolean(it.value)) {
|
||||
enabledFlags.add(it)
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ class HttpErrorException @JvmOverloads constructor(
|
|||
cause: Throwable? = null
|
||||
) : IOException(message, cause) {
|
||||
companion object {
|
||||
@Suppress("ConstPropertyName")
|
||||
private const val serialVersionUID = 1L
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
@file:Suppress("ConstPropertyName")
|
||||
|
||||
package net.thauvin.erik.jokeapi.exceptions
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,16 +33,7 @@ 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 assertk.assertions.*
|
||||
import net.thauvin.erik.jokeapi.JokeApi.logger
|
||||
import net.thauvin.erik.jokeapi.exceptions.HttpErrorException
|
||||
import net.thauvin.erik.jokeapi.exceptions.JokeException
|
||||
|
|
|
@ -33,29 +33,10 @@ 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 assertk.assertions.*
|
||||
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 net.thauvin.erik.jokeapi.models.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
@ -82,7 +63,7 @@ internal class GetJokeTest {
|
|||
|
||||
@Test
|
||||
fun `Get Joke without any Blacklist Flags`() {
|
||||
val allFlags = Flag.values().filter { it != Flag.ALL }.toSet()
|
||||
val allFlags = Flag.entries.filter { it != Flag.ALL }.toSet()
|
||||
val joke = joke(blacklistFlags = allFlags)
|
||||
assertThat(joke::flags).isEmpty()
|
||||
}
|
||||
|
@ -138,7 +119,7 @@ internal class GetJokeTest {
|
|||
|
||||
@Test
|
||||
fun `Get Joke with each Categories`() {
|
||||
Category.values().filter { it != Category.ANY }.forEach {
|
||||
Category.entries.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)
|
||||
|
@ -147,7 +128,7 @@ internal class GetJokeTest {
|
|||
|
||||
@Test
|
||||
fun `Get Joke with each Languages`() {
|
||||
Language.values().forEach {
|
||||
Language.entries.forEach {
|
||||
val joke = joke(lang = it)
|
||||
logger.fine(joke.toString())
|
||||
assertThat(joke::lang, "joke($it)").prop(Language::value).isEqualTo(it.value)
|
||||
|
|
|
@ -33,15 +33,7 @@ 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 assertk.assertions.*
|
||||
import net.thauvin.erik.jokeapi.models.Joke
|
||||
import net.thauvin.erik.jokeapi.models.Language
|
||||
import org.junit.jupiter.api.Test
|
||||
|
|
|
@ -33,25 +33,12 @@ 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 assertk.assertions.*
|
||||
import net.thauvin.erik.jokeapi.JokeApi.getRawJokes
|
||||
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 net.thauvin.erik.jokeapi.models.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import kotlin.test.assertContains
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* UtilTest.kt
|
||||
* JokeUtilTest.kt
|
||||
*
|
||||
* Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue