diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 5686c21..a848665 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -17,7 +17,7 @@ jobs: build: strategy: matrix: - java-version: [ 11, 17, 20 ] + java-version: [8, 11, 17, 21] os: - macos-latest - ubuntu-latest @@ -28,27 +28,25 @@ jobs: GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - distribution: 'zulu' + distribution: "zulu" java-version: ${{ matrix.java-version }} - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Cache Kotlin Konan - id: cache-kotlin-konan - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: | - ~/.konan/**/* + path: ~/.konan/**/* key: kotlin-konan-${{ runner.os }} - - name: Test with Gradle - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true - arguments: build check --stacktrace -PtestsBadgeApiKey=${{ secrets.TESTS_BADGE_API_KEY }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Publish + run: ./gradlew check build --stacktrace -PtestsBadgeApiKey=${{ secrets.TESTS_BADGE_API_KEY }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e89e240..a930768 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,90 +4,41 @@ on: workflow_dispatch: env: - JAVA_VERSION: 11 - JAVA_DISTRIBUTION: 'zulu' ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.OSSRH_USERNAME}} ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.OSSRH_PASSWORD}} ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGN_SECRET_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGN_SECRET_PWD }} +concurrency: + group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + # Don't cancel midway through publishing if another workflow is triggered, it might cause partial publications + cancel-in-progress: false + jobs: - publish-base: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: ${{ env.JAVA_DISTRIBUTION }} - - - uses: gradle/gradle-build-action@v2 - - - name: Publish Multiplatform release - run: ./gradlew publishKotlinMultiplatformPublicationToOSSRHRepository - - - name: Publish JVM release - run: ./gradlew publishJvmPublicationToOSSRHRepository - - - name: Publish JS release - run: ./gradlew publishJsPublicationToOSSRHRepository - - publish-linux: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: ${{ env.JAVA_DISTRIBUTION }} - - - uses: gradle/gradle-build-action@v2 - - - name: Publish Linux x64 release - run: ./gradlew publishLinuxX64PublicationToOSSRHRepository - - publish-mac: + publish: runs-on: macos-latest - strategy: - max-parallel: 6 - matrix: - target: - - publishMacosArm64PublicationToOSSRHRepository - - publishMacosX64PublicationToOSSRHRepository + steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3 + - name: Set up JDK + uses: actions/setup-java@v4 with: - java-version: ${{ env.JAVA_VERSION }} - distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: "21" + distribution: "zulu" - - uses: gradle/gradle-build-action@v2 + - name: Validate Gradle wrapper + uses: gradle/wrapper-validation-action@v2 + + - name: Cache Kotlin Konan + uses: actions/cache@v4 + with: + path: ~/.konan/**/* + key: kotlin-konan-${{ runner.os }} + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 - name: Publish - run: ./gradlew ${{ matrix.target }} - - publish-windows: - runs-on: windows-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: ${{ env.JAVA_DISTRIBUTION }} - - - uses: gradle/gradle-build-action@v2 - - - name: Publish MinGW x64 release - run: ./gradlew publishMingwX64PublicationToOSSRHRepository \ No newline at end of file + run: ./gradlew publish --no-parallel --stacktrace diff --git a/README.md b/README.md index d879d1d..5f3a0b6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.0-blue)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.6%2B-blue)](https://kotlinlang.org/) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik.urlencoder/urlencoder-lib?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/urlencoder/) [![Release](https://img.shields.io/github/release/ethauvin/urlencoder.svg)](https://github.com/ethauvin/urlencoder/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik.urlencoder/urlencoder-lib)](https://central.sonatype.com/search?namespace=net.thauvin.erik.urlencoder) @@ -32,18 +32,17 @@ optimizations have a significantly beneficial impact on performance of encoding compared to other solutions like the standard `URLEncoder` in the JDK or `UriUtils` in Spring. - ## Examples (TL;DR) ```kotlin -UrlEncoder.encode("a test &") // -> a%20test%20%26 -UrlEncoder.encode("%#okékÉȢ smile!😁") // -> %25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81 -UrlEncoder.encode("?test=a test", allow = "?=") // -> ?test=a%20test -UrlEncoder.endode("foo bar", spaceToPlus = true) // -> foo+bar +UrlEncoderUtil.encode("a test &") // -> a%20test%20%26 +UrlEncoderUtil.encode("%#okékÉȢ smile!😁") // -> %25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81 +UrlEncoderUtil.encode("?test=a test", allow = "?=") // -> ?test=a%20test +UrlEncoderUtil.endode("foo bar", spaceToPlus = true) // -> foo+bar -UrlEncoder.decode("a%20test%20%26") // -> a test & -UrlEncoder.decode("%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81") // -> %#okékÉȢ smile!😁 -UrlEncoder.decode("foo+bar", plusToSpace = true) // -> foo bar +UrlEncoderUtil.decode("a%20test%20%26") // -> a test & +UrlEncoderUtil.decode("%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81") // -> %#okékÉȢ smile!😁 +UrlEncoderUtil.decode("foo+bar", plusToSpace = true) // -> foo bar ``` ## Gradle, Maven, etc. @@ -61,7 +60,7 @@ repositories { } dependencies { - implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0") + implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.6.0") } ``` @@ -72,11 +71,11 @@ to the artifact URL. net.thauvin.erik.urlencoder urlencoder-lib-jvm - 1.4.0 + 1.6.0 ``` -Instructions for using with Ivy, etc. can be found on +Instructions for using with Ivy, etc. can be found on [Maven Central](https://central.sonatype.com/search?namespace=net.thauvin.erik.urlencoder). ## Standalone usage @@ -90,7 +89,7 @@ You have two options: The usage is as follows: -``` +```console Encode and decode URL components defensively. -e encode (default) -d decode @@ -98,7 +97,7 @@ Encode and decode URL components defensively. ### Running with Gradle -```shell +```console ./gradlew run --quiet --args="-e 'a test &'" # -> a%20test%20%26 ./gradlew run --quiet --args="%#okékÉȢ" # -> %25%23ok%C3%A9k%C3%89%C8%A2 @@ -109,13 +108,13 @@ Encode and decode URL components defensively. First build the jar file: -```shell +```console ./gradlew fatJar ``` Then run it: -```shell +```console java -jar urlencoder-app/build/libs/urlencoder-*all.jar -e "a test &" # -> a%20test%20%26 java -jar urlencoder-app/build/libs/urlencoder-*all.jar "%#okékÉȢ" # -> %25%23ok%C3%A9k%C3%89%C8%A2 diff --git a/build.gradle.kts b/build.gradle.kts index a109e40..5ccf894 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "net.thauvin.erik.urlencoder" -version = "1.4.0" +version = "1.6.0" dependencies { kover(projects.urlencoderLib) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 182d281..1819780 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -3,9 +3,10 @@ plugins { } dependencies { - implementation("com.github.ben-manes:gradle-versions-plugin:0.48.0") - implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.1") - implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.0") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0") - implementation("org.jetbrains.kotlinx:kover-gradle-plugin:0.7.3") -} \ No newline at end of file + implementation("com.github.ben-manes:gradle-versions-plugin:0.51.0") + implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7") + implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24") + implementation("org.jetbrains.kotlinx:kover-gradle-plugin:0.8.3") + implementation("org.apache.httpcomponents:httpclient:4.5.13") +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts index 5665e86..3ceabc1 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts @@ -3,7 +3,9 @@ package buildsrc.conventions.lang import buildsrc.utils.Rife2TestListener import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile @@ -24,39 +26,31 @@ plugins { kotlin { //jvmToolchain(11) - targets.configureEach { - compilations.configureEach { - kotlinOptions { - languageVersion = "1.6" - } - } + applyDefaultHierarchyTemplate() + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + languageVersion = KotlinVersion.KOTLIN_1_6 } // configure all Kotlin/JVM Tests to use JUnit targets.withType().configureEach { testRuns.configureEach { executionTask.configure { - // useJUnitPlatform() + useJUnitPlatform() } } } - - sourceSets.configureEach { - languageSettings { - // languageVersion = - // apiVersion = - } - } } tasks { withType().configureEach { - sourceCompatibility = JavaVersion.VERSION_11.toString() - targetCompatibility = JavaVersion.VERSION_11.toString() + sourceCompatibility = JavaVersion.VERSION_1_8.toString() + targetCompatibility = JavaVersion.VERSION_1_8.toString() } withType().configureEach { - compilerOptions.jvmTarget.set(JvmTarget.JVM_11) + compilerOptions.jvmTarget.set(JvmTarget.JVM_1_8) } withType().configureEach { diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts index 2a0034a..5474801 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts @@ -1,5 +1,7 @@ package buildsrc.conventions.lang +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl + /** conventions for a Kotlin/JS subproject */ plugins { @@ -7,12 +9,38 @@ plugins { } kotlin { - targets { - js(IR) { - browser() - nodejs() - } + js(IR) { + browser() + nodejs() + } + + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + browser() + nodejs() + } + + @OptIn(ExperimentalWasmDsl::class) + wasmWasi { + nodejs() } } relocateKotlinJsStore() + + +//region FIXME: WORKAROUND https://youtrack.jetbrains.com/issue/KT-65864 +rootProject.plugins.withType { + rootProject.extensions.configure { + // Use a Node.js version current enough to support Kotlin/Wasm + nodeVersion = "22.0.0-nightly2024010568c8472ed9" + logger.lifecycle("Using Node.js $nodeVersion to support Kotlin/Wasm") + nodeDownloadBaseUrl = "https://nodejs.org/download/nightly" + } +} + +rootProject.tasks.withType().configureEach { + // Prevent Yarn from complaining about newer Node.js versions. + args.add("--ignore-engines") +} +//endregion diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts index e29ad97..70022cc 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts @@ -7,94 +7,26 @@ plugins { } kotlin { - - // Native targets all extend commonMain and commonTest. - // - // Some targets (ios, tvos, watchos) are shortcuts provided by the Kotlin DSL, that - // provide additional targets, except for 'simulators' which must be defined manually. - // https://kotlinlang.org/docs/multiplatform-share-on-platforms.html#use-target-shortcuts - // - // common/ - // └── native/ - // ├── linuxX64 - // ├── mingwX64 - // ├── macosX64 - // ├── macosArm64 - // ├── ios/ (shortcut) - // │ ├── iosArm64 - // │ ├── iosX64 - // │ └── iosSimulatorArm64 - // ├── tvos/ (shortcut) - // │ ├── tvosArm64 - // │ ├── tvosX64 - // │ └── tvosSimulatorArm64Main - // └── watchos/ (shortcut) - // ├── watchosArm32 - // ├── watchosArm64 - // ├── watchosX64 - // └── watchosSimulatorArm64Main - linuxX64() mingwX64() + linuxArm64() + macosX64() macosArm64() - // https://kotlinlang.org/docs/multiplatform-share-on-platforms.html#use-target-shortcuts - ios() // iosArm64, iosX64 - watchos() // watchosArm32, watchosArm64, watchosX64 - tvos() // tvosArm64, tvosX64 - + iosArm64() + iosX64() iosSimulatorArm64() - tvosSimulatorArm64() + + watchosArm32() + watchosArm64() + watchosX64() watchosSimulatorArm64() + watchosDeviceArm64() - @Suppress("UNUSED_VARIABLE") - sourceSets { - val commonMain by getting {} - val commonTest by getting {} - - val nativeMain by creating { dependsOn(commonMain) } - val nativeTest by creating { dependsOn(commonTest) } - - // Linux - val linuxX64Main by getting { dependsOn(nativeMain) } - val linuxX64Test by getting { dependsOn(nativeTest) } - - // Windows - MinGW - val mingwX64Main by getting { dependsOn(nativeMain) } - val mingwX64Test by getting { dependsOn(nativeTest) } - - // Apple - macOS - val macosArm64Main by getting { dependsOn(nativeMain) } - val macosArm64Test by getting { dependsOn(nativeTest) } - - val macosX64Main by getting { dependsOn(nativeMain) } - val macosX64Test by getting { dependsOn(nativeTest) } - - // Apple - iOS - val iosMain by getting { dependsOn(nativeMain) } - val iosTest by getting { dependsOn(nativeTest) } - - // val iosSimulatorArm64Main by getting { dependsOn(iosMain) } - // val iosSimulatorArm64Test by getting { dependsOn(iosTest) } - - // // Apple - tvOS - // val tvosMain by getting { dependsOn(nativeMain) } - // val tvosTest by getting { dependsOn(nativeTest) } - - // val tvosSimulatorArm64Main by getting { dependsOn(tvosMain) } - // val tvosSimulatorArm64Test by getting { dependsOn(tvosTest) } - - // // Apple - watchOS - // val watchosMain by getting { dependsOn(nativeMain) } - // val watchosTest by getting { dependsOn(nativeTest) } - - // val watchosSimulatorArm64Main by getting { dependsOn(watchosMain) } - // val watchosSimulatorArm64Test by getting { dependsOn(watchosTest) } - - // val iosArm32Main by getting { dependsOn(desktopMain) } - // val iosArm32Test by getting { dependsOn(nativeTest) } - } + tvosArm64() + tvosX64() + tvosSimulatorArm64() } diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt index eefdc94..8525916 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension * version catalog. */ internal fun Project.relocateKotlinJsStore() { - afterEvaluate { - rootProject.extensions.configure { - lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store") - } - } + afterEvaluate { + rootProject.extensions.configure { + lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store") + } + } } diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts index 660d4b1..6afd9e1 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts @@ -1,19 +1,3 @@ -/* - * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) - * - * 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 - * - * http://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. - */ package buildsrc.conventions plugins { @@ -98,9 +82,11 @@ signing { }) } -tasks.withType().configureEach { - val signingRequiredPredicate = provider { signing.isRequired } - onlyIf { signingRequiredPredicate.get() } +tasks { + withType().configureEach { + val signingRequiredPredicate = provider { signing.isRequired } + onlyIf { signingRequiredPredicate.get() } + } } // https://youtrack.jetbrains.com/issue/KT-46466 diff --git a/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt b/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt index 748b064..59df2bd 100644 --- a/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt +++ b/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt @@ -1,12 +1,11 @@ /* - * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2001-2024 the original author or 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -17,14 +16,13 @@ package buildsrc.utils +import org.apache.http.client.methods.HttpPost +import org.apache.http.impl.client.HttpClients +import org.apache.http.util.EntityUtils import org.gradle.api.provider.Provider import org.gradle.api.tasks.testing.TestDescriptor import org.gradle.api.tasks.testing.TestListener import org.gradle.api.tasks.testing.TestResult -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse class Rife2TestListener( private val testBadgeApiKey: Provider @@ -42,23 +40,23 @@ class Rife2TestListener( if (apiKey != null) { println(apiKey) - val response: HttpResponse = HttpClient.newHttpClient() - .send( - HttpRequest.newBuilder() - .uri( - URI( - "https://rife2.com/tests-badge/update/net.thauvin.erik/urlencoder?" + - "apiKey=$apiKey&" + - "passed=$passed&" + - "failed=$failed&" + - "skipped=$skipped" - ) - ) - .POST(HttpRequest.BodyPublishers.noBody()) - .build(), HttpResponse.BodyHandlers.ofString() - ) - println("RESPONSE: ${response.statusCode()}") - println(response.body()) + val url = "https://rife2.com/tests-badge/update/net.thauvin.erik/urlencoder?" + + "apiKey=$apiKey&" + + "passed=$passed&" + + "failed=$failed&" + + "skipped=$skipped" + + val client = HttpClients.createDefault() + val post = HttpPost(url) + + val response = client.execute(post) + val entity = response.entity + + val statusCode = response.statusLine.statusCode + val responseBody = EntityUtils.toString(entity, "UTF-8") + + println("RESPONSE: $statusCode") + println(responseBody) } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # 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 +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # 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 +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -145,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +205,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# 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" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle.kts b/settings.gradle.kts index 03ddb65..9e70d32 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,82 +1,90 @@ rootProject.name = "urlencoder" pluginManagement { - repositories { - mavenCentral() - gradlePluginPortal() - } + repositories { + mavenCentral() + gradlePluginPortal() + } } @Suppress("UnstableApiUsage") dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) - repositories { - mavenCentral() - maven("https://oss.sonatype.org/content/repositories/snapshots") { - name = "Sonatype Snapshots" - mavenContent { snapshotsOnly() } - } - - // Declare the Node.js & Yarn download repositories - exclusiveContent { - forRepository { - ivy("https://nodejs.org/dist/") { - name = "Node Distributions at $url" - patternLayout { artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]") } - metadataSources { artifact() } - content { includeModule("org.nodejs", "node") } + repositories { + mavenCentral() + maven("https://oss.sonatype.org/content/repositories/snapshots") { + name = "Sonatype Snapshots" + mavenContent { snapshotsOnly() } } - } - filter { includeGroup("org.nodejs") } - } - exclusiveContent { - forRepository { - ivy("https://github.com/yarnpkg/yarn/releases/download") { - name = "Yarn Distributions at $url" - patternLayout { artifact("v[revision]/[artifact](-v[revision]).[ext]") } - metadataSources { artifact() } - content { includeModule("com.yarnpkg", "yarn") } + // Declare the Node.js & Yarn download repositories + exclusiveContent { + forRepositories( + ivy("https://nodejs.org/dist/") { + name = "Node Distributions at $url" + patternLayout { artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]") } + metadataSources { artifact() } + }, + ivy("https://nodejs.org/download/v8-canary/") { + name = "Node Canary Distributions at $url" + patternLayout { artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]") } + metadataSources { artifact() } + }, + ivy("https://nodejs.org/download/nightly/") { + name = "Node Nightly Distributions at $url" + patternLayout { artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]") } + metadataSources { artifact() } + }, + ) + filter { includeGroup("org.nodejs") } } - } - filter { includeGroup("com.yarnpkg") } - } - // workaround for https://youtrack.jetbrains.com/issue/KT-51379 - exclusiveContent { - forRepository { - ivy("https://download.jetbrains.com/kotlin/native/builds") { - name = "Kotlin Native" - patternLayout { - // example download URLs: - // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/linux-x86_64/kotlin-native-prebuilt-linux-x86_64-1.7.20.tar.gz - // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/windows-x86_64/kotlin-native-prebuilt-windows-x86_64-1.7.20.zip - // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/macos-x86_64/kotlin-native-prebuilt-macos-x86_64-1.7.20.tar.gz - listOf( - "macos-x86_64", - "macos-aarch64", - "osx-x86_64", - "osx-aarch64", - "linux-x86_64", - "windows-x86_64", - ).forEach { os -> - listOf("dev", "releases").forEach { stage -> - artifact("$stage/[revision]/$os/[artifact]-[revision].[ext]") - } + exclusiveContent { + forRepository { + ivy("https://github.com/yarnpkg/yarn/releases/download") { + name = "Yarn Distributions at $url" + patternLayout { artifact("v[revision]/[artifact](-v[revision]).[ext]") } + metadataSources { artifact() } + } } - } - metadataSources { artifact() } + filter { includeGroup("com.yarnpkg") } + } + + // workaround for https://youtrack.jetbrains.com/issue/KT-51379 + exclusiveContent { + forRepository { + ivy("https://download.jetbrains.com/kotlin/native/builds") { + name = "Kotlin Native" + patternLayout { + // example download URLs: + // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/linux-x86_64/kotlin-native-prebuilt-linux-x86_64-1.7.20.tar.gz + // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/windows-x86_64/kotlin-native-prebuilt-windows-x86_64-1.7.20.zip + // https://download.jetbrains.com/kotlin/native/builds/releases/1.7.20/macos-x86_64/kotlin-native-prebuilt-macos-x86_64-1.7.20.tar.gz + listOf( + "macos-x86_64", + "macos-aarch64", + "osx-x86_64", + "osx-aarch64", + "linux-x86_64", + "windows-x86_64", + ).forEach { os -> + listOf("dev", "releases").forEach { stage -> + artifact("$stage/[revision]/$os/[artifact]-[revision].[ext]") + } + } + } + metadataSources { artifact() } + } + } + filter { includeModuleByRegex(".*", ".*kotlin-native-prebuilt.*") } } - } - filter { includeModuleByRegex(".*", ".*kotlin-native-prebuilt.*") } } - } } enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") include( - ":urlencoder-app", - ":urlencoder-lib", + ":urlencoder-app", + ":urlencoder-lib", ) diff --git a/urlencoder-app/build.gradle.kts b/urlencoder-app/build.gradle.kts index 93a9789..c3fc159 100644 --- a/urlencoder-app/build.gradle.kts +++ b/urlencoder-app/build.gradle.kts @@ -1,17 +1,21 @@ import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { buildsrc.conventions.lang.`kotlin-multiplatform-jvm` -// buildsrc.conventions.lang.`kotlin-multiplatform-js` -// buildsrc.conventions.lang.`kotlin-multiplatform-native` buildsrc.conventions.publishing - id("application") id("com.github.ben-manes.versions") } val urlEncoderMainClass = "net.thauvin.erik.urlencoder.UrlEncoder" kotlin { + jvm { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + mainRun { + mainClass.set(urlEncoderMainClass) + } + } sourceSets { commonMain { dependencies { @@ -32,10 +36,6 @@ base { archivesName.set(rootProject.name) } -application { - mainClass.set(urlEncoderMainClass) -} - tasks { jvmJar { manifest { @@ -45,14 +45,13 @@ tasks { val fatJar by registering(Jar::class) { group = LifecycleBasePlugin.BUILD_GROUP - dependsOn.addAll(listOf("compileJava", "compileKotlinJvm", "processResources")) archiveClassifier.set("all") duplicatesStrategy = DuplicatesStrategy.EXCLUDE - manifest { attributes(mapOf("Main-Class" to application.mainClass)) } - from(sourceSets.main.get().output) + manifest { attributes(mapOf("Main-Class" to urlEncoderMainClass)) } + from(sourceSets.main.map { it.output }) dependsOn(configurations.jvmRuntimeClasspath) from(configurations.jvmRuntimeClasspath.map { classpath -> - classpath.incoming.artifacts.artifactFiles.files.filter { it.name.endsWith("jar") }.map { zipTree(it) } + classpath.filter { it.name.endsWith(".jar") }.map { zipTree(it) } }) } diff --git a/urlencoder-app/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt b/urlencoder-app/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt index df89c28..2c8ff60 100644 --- a/urlencoder-app/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt +++ b/urlencoder-app/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2001-2023 the original author or authors. + * Copyright 2001-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/urlencoder-app/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt b/urlencoder-app/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt index 1b159ed..ecf9356 100644 --- a/urlencoder-app/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt +++ b/urlencoder-app/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2001-2023 the original author or authors. + * Copyright 2001-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ class UrlEncoderTest { val validMap = listOf( "a test &" to "a%20test%20%26", "!abcdefghijklmnopqrstuvwxyz%%ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~=" to - "%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.%7E%3D", + "%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.%7E%3D", "%#okékÉȢ smile!😁" to "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81", "\uD808\uDC00\uD809\uDD00\uD808\uDF00\uD808\uDD00" to "%F0%92%80%80%F0%92%94%80%F0%92%8C%80%F0%92%84%80", ) diff --git a/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/Character.kt b/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/Character.kt index 1ea0db9..e4b4286 100644 --- a/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/Character.kt +++ b/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/Character.kt @@ -1,5 +1,5 @@ /* - * Copyright 2001-2023 the original author or authors. + * Copyright 2001-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,15 +59,15 @@ internal object Character { internal fun lowSurrogateOf(codePoint: Int): Char = ((codePoint and 0x3FF) + MIN_LOW_SURROGATE.code).toChar() -// private const val MIN_CODE_POINT: Int = 0x000000 + // private const val MIN_CODE_POINT: Int = 0x000000 private const val MAX_CODE_POINT: Int = 0x10FFFF private const val MIN_SUPPLEMENTARY_CODE_POINT: Int = 0x10000 private const val SURROGATE_DECODE_OFFSET: Int = MIN_SUPPLEMENTARY_CODE_POINT - - (MIN_HIGH_SURROGATE.code shl 10) - - MIN_LOW_SURROGATE.code + (MIN_HIGH_SURROGATE.code shl 10) - + MIN_LOW_SURROGATE.code private const val HIGH_SURROGATE_ENCODE_OFFSET: Char = MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10) } diff --git a/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtil.kt b/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtil.kt index 0f45bc6..7da63d1 100644 --- a/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtil.kt +++ b/urlencoder-lib/src/commonMain/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2001-2023 the original author or authors. + * Copyright 2001-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/TestData.kt b/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/TestData.kt new file mode 100644 index 0000000..6cbf139 --- /dev/null +++ b/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/TestData.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2001-2024 the original author or 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. + */ + +package net.thauvin.erik.urlencoder + +import kotlin.jvm.JvmField + +const val standardContent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_." + +val invalidContent = listOf("sdkjfh%", "sdkjfh%6", "sdkjfh%xx", "sdfjfh%-1") + +/** + * List of unencoded content paired with the encoded content. + */ +val decodedToEncoded = listOf( + TestData("a test &", "a%20test%20%26"), + TestData( + "!abcdefghijklmnopqrstuvwxyz%%ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~=", + "%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.%7E%3D" + ), + TestData("%#okékÉȢ smile!😁", "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81"), + TestData("\uD808\uDC00\uD809\uDD00\uD808\uDF00\uD808\uDD00", "%F0%92%80%80%F0%92%94%80%F0%92%8C%80%F0%92%84%80"), +) + +data class TestData( + @JvmField + val unencoded: String, + @JvmField + val encoded: String, +) diff --git a/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtilTest.kt b/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtilTest.kt index f6b67de..102bbfa 100644 --- a/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtilTest.kt +++ b/urlencoder-lib/src/commonTest/kotlin/net/thauvin/erik/urlencoder/UrlEncoderUtilTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2001-2023 the original author or authors. + * Copyright 2001-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,30 +23,17 @@ import kotlin.test.DefaultAsserter.assertEquals import kotlin.test.DefaultAsserter.assertSame class UrlEncoderUtilTest { - private val same = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_." - - companion object { - val invalid = listOf("sdkjfh%", "sdkjfh%6", "sdkjfh%xx", "sdfjfh%-1") - - val validMap = listOf( - "a test &" to "a%20test%20%26", - "!abcdefghijklmnopqrstuvwxyz%%ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~=" to - "%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.%7E%3D", - "%#okékÉȢ smile!😁" to "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81", - "\uD808\uDC00\uD809\uDD00\uD808\uDF00\uD808\uDD00" to "%F0%92%80%80%F0%92%94%80%F0%92%8C%80%F0%92%84%80", - ) - } @Test fun decodeURL() { - for (m in validMap) { - assertEquals(m.first, decode(m.second)) + for ((unencoded, encoded) in decodedToEncoded) { + assertEquals(unencoded, decode(encoded)) } } @Test fun decodeWithException() { - for (source in invalid) { + for (source in invalidContent) { assertFailsWith( message = "decode($source)", block = { decode(source) } @@ -56,7 +43,7 @@ class UrlEncoderUtilTest { @Test fun decodeWhenNoneNeeded() { - assertSame(same, decode(same)) + assertSame(standardContent, decode(standardContent)) assertEquals("decode('')", decode(""), "") assertEquals("decode(' ')", decode(" "), " ") } @@ -72,8 +59,8 @@ class UrlEncoderUtilTest { @Test fun encodeURL() { - for (m in validMap) { - assertEquals(m.second, encode(m.first)) + for ((unencoded, encoded) in decodedToEncoded) { + assertEquals(encoded, encode(unencoded)) } } @@ -86,8 +73,8 @@ class UrlEncoderUtilTest { @Test fun encodeWhenNoneNeeded() { - assertSame(encode(same), same) - assertSame("with empty allow", encode(same, allow = ""), same) + assertSame(encode(standardContent), standardContent) + assertSame("with empty allow", encode(standardContent, allow = ""), standardContent) } @Test diff --git a/urlencoder-lib/src/jvmTest/java/net/thauvin/erik/urlencoder/UrlEncoderJavaTest.java b/urlencoder-lib/src/jvmTest/java/net/thauvin/erik/urlencoder/UrlEncoderJavaTest.java new file mode 100644 index 0000000..8fa9561 --- /dev/null +++ b/urlencoder-lib/src/jvmTest/java/net/thauvin/erik/urlencoder/UrlEncoderJavaTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2001-2024 the original author or 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. + */ + +package net.thauvin.erik.urlencoder; + +import org.junit.jupiter.api.Test; + +import static net.thauvin.erik.urlencoder.TestDataKt.getDecodedToEncoded; +import static net.thauvin.erik.urlencoder.UrlEncoderUtil.decode; +import static net.thauvin.erik.urlencoder.UrlEncoderUtil.encode; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class UrlEncoderJavaTest { + + @Test + public void decodeURL() { + assertAll( + getDecodedToEncoded() + .stream() + .map(data -> + () -> assertEquals(data.unencoded, decode(data.encoded)) + ) + ); + } + + @Test + public void encodeURL() { + assertAll( + getDecodedToEncoded() + .stream() + .map(data -> + () -> assertEquals(data.encoded, encode(data.unencoded)) + ) + ); + } +}