Compare commits

...

4 commits

Author SHA1 Message Date
a689c56e1e
Bumped Gradle to version 8.7 2024-03-26 14:14:08 -07:00
b59d01ec6d
Bumped Dokka to version 1.9.20 2024-03-26 14:13:32 -07:00
Adam
8890fef665
bump Kotlin to 1.9.23, enable additional Kotlin Multiplatform targets (#15)
* bump Kotlin to 1.9.23, enable additional Kotlin Multiplatform targets

* replace soon-to-be-deprecated kotlinOptions with newer compilerOptions
2024-03-26 13:52:11 -07:00
Adam
171570159e
add Java tests for verifying @JvmStatic (#14) 2024-02-25 04:17:08 -08:00
10 changed files with 237 additions and 196 deletions

View file

@ -5,7 +5,7 @@ plugins {
dependencies {
implementation("com.github.ben-manes:gradle-versions-plugin:0.51.0")
implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.1")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.10")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23")
implementation("org.jetbrains.kotlinx:kover-gradle-plugin:0.7.4")
}

View file

@ -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,29 +26,21 @@ 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<KotlinJvmTarget>().configureEach {
testRuns.configureEach {
executionTask.configure {
// useJUnitPlatform()
useJUnitPlatform()
}
}
}
sourceSets.configureEach {
languageSettings {
// languageVersion =
// apiVersion =
}
}
}
tasks {

View file

@ -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()
}
@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<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
rootProject.extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
// 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<org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask>().configureEach {
// Prevent Yarn from complaining about newer Node.js versions.
args.add("--ignore-engines")
}
//endregion

View file

@ -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()
}

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View file

@ -20,14 +20,23 @@ dependencyResolutionManagement {
// Declare the Node.js & Yarn download repositories
exclusiveContent {
forRepository {
forRepositories(
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") }
}
}
},
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") }
}
@ -37,7 +46,6 @@ dependencyResolutionManagement {
name = "Yarn Distributions at $url"
patternLayout { artifact("v[revision]/[artifact](-v[revision]).[ext]") }
metadataSources { artifact() }
content { includeModule("com.yarnpkg", "yarn") }
}
}
filter { includeGroup("com.yarnpkg") }

View file

@ -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) }
})
}

View file

@ -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,
)

View file

@ -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<IllegalArgumentException>(
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

View file

@ -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))
)
);
}
}