Run spotless apply

This commit is contained in:
Dan Chao
2024-07-01 09:08:06 -07:00
committed by Daniel Chao
parent 7a9b571f6e
commit 8c1c10528f
127 changed files with 5325 additions and 3450 deletions

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklJavaLibrary
@@ -25,7 +40,8 @@ jmh {
// "-Dgraal.Dump=Truffle,TruffleTree -Dgraal.TraceTruffleCompilation=true " +
// "-Dgraal.TruffleFunctionInlining=false"
jvm.set("${buildInfo.graalVmAmd64.baseDir}/bin/java")
// see: https://docs.oracle.com/en/graalvm/enterprise/20/docs/graalvm-as-a-platform/implement-language/#disable-class-path-separation
// see:
// https://docs.oracle.com/en/graalvm/enterprise/20/docs/graalvm-as-a-platform/implement-language/#disable-class-path-separation
jvmArgs.set(
listOf(
// one JVM arg per list element doesn't work, but the following does
@@ -37,12 +53,9 @@ jmh {
// synchronizeIterations = false
}
tasks.named("jmh") {
dependsOn(":installGraalVmAmd64")
}
tasks.named("jmh") { dependsOn(":installGraalVmAmd64") }
// Prevent this error which occurs when building in IntelliJ:
// "Entry org/pkl/core/fib_class_typed.pkl is a duplicate but no duplicate handling strategy has been set."
tasks.processJmhResources {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// "Entry org/pkl/core/fib_class_typed.pkl is a duplicate but no duplicate handling strategy has
// been set."
tasks.processJmhResources { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
// https://youtrack.jetbrains.com/issue/KTIJ-19369
@file:Suppress("DSL_SCOPE_VIOLATION")
@@ -40,15 +55,12 @@ idea {
}
}
val clean by tasks.existing {
delete(layout.buildDirectory)
}
val clean by tasks.existing { delete(layout.buildDirectory) }
val printVersion by tasks.registering {
doFirst { println(buildInfo.pklVersion) }
}
val printVersion by tasks.registering { doFirst { println(buildInfo.pklVersion) } }
val message = """
val message =
"""
====
Gradle version : ${gradle.gradleVersion}
Java version : ${System.getProperty("java.version")}
@@ -63,5 +75,7 @@ Git Commit ID : ${buildInfo.commitId}
====
"""
val formattedMessage = message.replace("\n====", "\n" + "=".repeat(message.lines().maxByOrNull { it.length }!!.length))
val formattedMessage =
message.replace("\n====", "\n" + "=".repeat(message.lines().maxByOrNull { it.length }!!.length))
logger.info(formattedMessage)

View File

@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
`kotlin-dsl`
}
plugins { `kotlin-dsl` }
dependencies {
implementation(libs.downloadTaskPlugin)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
@file:Suppress("UnstableApiUsage")
rootProject.name = "buildSrc"
@@ -12,11 +27,7 @@ pluginManagement {
// makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional
dependencyResolutionManagement {
// use same version catalog as main build
versionCatalogs {
register("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
versionCatalogs { register("libs") { from(files("../gradle/libs.versions.toml")) } }
repositories {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
import java.io.File
@@ -14,13 +29,9 @@ open class BuildInfo(project: Project) {
System.getenv("GRAALVM_HOME") ?: "${System.getProperty("user.home")}/.graalvm"
}
val version: String by lazy {
libs.findVersion("graalVm").get().toString()
}
val version: String by lazy { libs.findVersion("graalVm").get().toString() }
val graalVmJdkVersion: String by lazy {
libs.findVersion("graalVmJdkVersion").get().toString()
}
val graalVmJdkVersion: String by lazy { libs.findVersion("graalVmJdkVersion").get().toString() }
val osName: String by lazy {
when {
@@ -31,9 +42,7 @@ open class BuildInfo(project: Project) {
}
}
val baseName: String by lazy {
"graalvm-jdk-${graalVmJdkVersion}_${osName}-${arch}_bin"
}
val baseName: String by lazy { "graalvm-jdk-${graalVmJdkVersion}_${osName}-${arch}_bin" }
val downloadUrl: String by lazy {
val jdkMajor = graalVmJdkVersion.takeWhile { it != '.' }
@@ -41,18 +50,14 @@ open class BuildInfo(project: Project) {
"https://download.oracle.com/graalvm/$jdkMajor/archive/$baseName.$extension"
}
val installDir: File by lazy {
File(homeDir, baseName)
}
val installDir: File by lazy { File(homeDir, baseName) }
val baseDir: String by lazy {
if (os.isMacOsX) "$installDir/Contents/Home" else installDir.toString()
}
}
/**
* Same logic as [org.gradle.internal.os.OperatingSystem#arch], which is protected.
*/
/** Same logic as [org.gradle.internal.os.OperatingSystem#arch], which is protected. */
val arch: String by lazy {
when (val arch = System.getProperty("os.arch")) {
"x86" -> "i386"
@@ -66,13 +71,9 @@ open class BuildInfo(project: Project) {
val graalVmAmd64: GraalVm = GraalVm("x64")
val isCiBuild: Boolean by lazy {
System.getenv("CI") != null
}
val isCiBuild: Boolean by lazy { System.getenv("CI") != null }
val isReleaseBuild: Boolean by lazy {
java.lang.Boolean.getBoolean("releaseBuild")
}
val isReleaseBuild: Boolean by lazy { java.lang.Boolean.getBoolean("releaseBuild") }
val hasMuslToolchain: Boolean by lazy {
// see "install musl" in .circleci/jobs/BuildNativeJob.pkl
@@ -87,7 +88,8 @@ open class BuildInfo(project: Project) {
val commitId: String by lazy {
// only run command once per build invocation
if (project === project.rootProject) {
val process = ProcessBuilder()
val process =
ProcessBuilder()
.command("git", "rev-parse", "--short", "HEAD")
.directory(project.rootDir)
.start()
@@ -100,9 +102,7 @@ open class BuildInfo(project: Project) {
}
}
val commitish: String by lazy {
if (isReleaseBuild) project.version.toString() else commitId
}
val commitish: String by lazy { if (isReleaseBuild) project.version.toString() else commitId }
val pklVersion: String by lazy {
if (isReleaseBuild) {

View File

@@ -1,39 +1,52 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
/**
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix
* and executable with `java -jar` on Windows.
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix and executable with `java
* -jar` on Windows.
*
* For direct execution, the `java` command must be on the PATH.
*
* https://skife.org/java/unix/2011/06/20/really_executable_jars.html
*/
abstract class ExecutableJar : DefaultTask() {
@get:InputFile
abstract val inJar: RegularFileProperty
@get:InputFile abstract val inJar: RegularFileProperty
@get:OutputFile
abstract val outJar: RegularFileProperty
@get:OutputFile abstract val outJar: RegularFileProperty
@get:Input
abstract val jvmArgs: ListProperty<String>
@get:Input abstract val jvmArgs: ListProperty<String>
@TaskAction
fun buildJar() {
val inFile = inJar.get().asFile
val outFile = outJar.get().asFile
val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" }
val startScript = """
val startScript =
"""
#!/bin/sh
exec java $escapedJvmArgs -jar $0 "$@"
""".trimIndent() + "\n\n\n"
"""
.trimIndent() + "\n\n\n"
outFile.outputStream().use { outStream ->
startScript.byteInputStream().use { it.copyTo(outStream) }
inFile.inputStream().use { it.copyTo(outStream) }

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.util.GradleVersion
open class GradlePluginTests {

View File

@@ -1,6 +1,21 @@
import org.gradle.util.GradleVersion
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import groovy.json.JsonSlurper
import java.net.URI
import org.gradle.util.GradleVersion
@Suppress("unused")
class GradleVersionInfo(json: Map<String, Any>) {
@@ -38,15 +53,19 @@ class GradleVersionInfo(json: Map<String, Any>) {
val wrapperChecksumUrl: String by json
companion object {
private fun fetchAll(): List<GradleVersionInfo> = fetchMultiple("https://services.gradle.org/versions/all")
private fun fetchAll(): List<GradleVersionInfo> =
fetchMultiple("https://services.gradle.org/versions/all")
fun fetchReleases(): List<GradleVersionInfo> = fetchAll().filter { it.isReleaseVersion }
fun fetchCurrent(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/current")
fun fetchCurrent(): GradleVersionInfo =
fetchSingle("https://services.gradle.org/versions/current")
fun fetchRc(): GradleVersionInfo? = fetchSingleOrNull("https://services.gradle.org/versions/release-candidate")
fun fetchRc(): GradleVersionInfo? =
fetchSingleOrNull("https://services.gradle.org/versions/release-candidate")
fun fetchNightly(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/nightly")
fun fetchNightly(): GradleVersionInfo =
fetchSingle("https://services.gradle.org/versions/nightly")
private fun fetchSingle(url: String): GradleVersionInfo {
@Suppress("UNCHECKED_CAST")
@@ -61,8 +80,9 @@ class GradleVersionInfo(json: Map<String, Any>) {
private fun fetchMultiple(url: String): List<GradleVersionInfo> {
@Suppress("UNCHECKED_CAST")
return (JsonSlurper().parse(URI(url).toURL()) as List<Map<String, Any>>)
.map { GradleVersionInfo(it) }
return (JsonSlurper().parse(URI(url).toURL()) as List<Map<String, Any>>).map {
GradleVersionInfo(it)
}
}
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.api.Project
import org.gradle.api.file.FileCollection

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import java.io.File
import java.util.regex.Matcher
import java.util.regex.Pattern
@@ -15,21 +30,18 @@ import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.mapProperty
open class MergeSourcesJars : DefaultTask() {
@get:InputFiles
val inputJars: ConfigurableFileCollection = project.objects.fileCollection()
@get:InputFiles val inputJars: ConfigurableFileCollection = project.objects.fileCollection()
@get:InputFiles
val mergedBinaryJars: ConfigurableFileCollection = project.objects.fileCollection()
@get:Input
val relocatedPackages: MapProperty<String, String> = project.objects.mapProperty()
@get:Input val relocatedPackages: MapProperty<String, String> = project.objects.mapProperty()
@get:Input
var sourceFileExtensions: ListProperty<String> = project.objects.listProperty<String>()
.convention(listOf(".java", ".kt"))
var sourceFileExtensions: ListProperty<String> =
project.objects.listProperty<String>().convention(listOf(".java", ".kt"))
@get:OutputFile
val outputJar: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile val outputJar: RegularFileProperty = project.objects.fileProperty()
@TaskAction
@Suppress("unused")
@@ -38,12 +50,15 @@ open class MergeSourcesJars : DefaultTask() {
val relocatedPkgs = relocatedPackages.get()
val relocatedPaths = relocatedPkgs.entries.associate { (key, value) -> toPath(key) to toPath(value) }
val relocatedPaths =
relocatedPkgs.entries.associate { (key, value) -> toPath(key) to toPath(value) }
// use negative lookbehind to match any that don't precede with
// a word or a period character. should catch most cases.
val importPattern = Pattern.compile("(?<!(\\w|\\.))(" +
relocatedPkgs.keys.joinToString("|") { it.replace(".", "\\.") } + ")")
val importPattern =
Pattern.compile(
"(?<!(\\w|\\.))(" + relocatedPkgs.keys.joinToString("|") { it.replace(".", "\\.") } + ")"
)
val sourceFileExts = sourceFileExtensions.get()

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.result.ResolvedArtifactResult
@@ -12,25 +27,27 @@ import org.gradle.kotlin.dsl.property
import org.gradle.language.base.artifact.SourcesArtifact
open class ResolveSourcesJars : DefaultTask() {
@get:InputFiles
val configuration: Property<Configuration> = project.objects.property()
@get:InputFiles val configuration: Property<Configuration> = project.objects.property()
@get:OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty()
@get:OutputDirectory val outputDir: DirectoryProperty = project.objects.directoryProperty()
@TaskAction
@Suppress("UnstableApiUsage", "unused")
fun resolve() {
val componentIds = configuration.get().incoming.resolutionResult.allDependencies.map {
val componentIds =
configuration.get().incoming.resolutionResult.allDependencies.map {
(it as ResolvedDependencyResult).selected.id
}
val resolutionResult = project.dependencies.createArtifactResolutionQuery()
val resolutionResult =
project.dependencies
.createArtifactResolutionQuery()
.forComponents(componentIds)
.withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java)
.execute()
val resolvedJars = resolutionResult.resolvedComponents
val resolvedJars =
resolutionResult.resolvedComponents
.flatMap { it.getArtifacts(SourcesArtifact::class.java) }
.map { (it as ResolvedArtifactResult).file }

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.api.GradleException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.component.AdhocComponentWithVariants
@@ -18,9 +33,11 @@ val fatJarConfiguration: Configuration = configurations.create("fatJar")
val fatJarPublication: MavenPublication = publishing.publications.create<MavenPublication>("fatJar")
// ideally we'd configure this automatically based on project dependencies
val firstPartySourcesJarsConfiguration: Configuration = configurations.create("firstPartySourcesJars")
val firstPartySourcesJarsConfiguration: Configuration =
configurations.create("firstPartySourcesJars")
val relocations = mapOf(
val relocations =
mapOf(
// pkl-core dependencies
"org.antlr.v4." to "org.pkl.thirdparty.antlr.v4.",
"com.oracle.truffle" to "org.pkl.thirdparty.truffle",
@@ -82,12 +99,11 @@ tasks.shadowJar {
// workaround for https://github.com/johnrengelman/shadow/issues/651
components.withType(AdhocComponentWithVariants::class.java).forEach { c ->
c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) {
skip()
}
c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) { skip() }
}
val testFatJar by tasks.registering(Test::class) {
val testFatJar by
tasks.registering(Test::class) {
testClassesDirs = files(tasks.test.get().testClassesDirs)
classpath =
// compiled test classes
@@ -100,11 +116,10 @@ val testFatJar by tasks.registering(Test::class) {
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
}
tasks.check {
dependsOn(testFatJar)
}
tasks.check { dependsOn(testFatJar) }
val validateFatJar by tasks.registering {
val validateFatJar by
tasks.registering {
val outputFile = layout.buildDirectory.file("validateFatJar/result.txt")
inputs.files(tasks.shadowJar)
inputs.property("nonRelocations", nonRelocations)
@@ -115,10 +130,12 @@ val validateFatJar by tasks.registering {
zipTree(tasks.shadowJar.get().outputs.files.singleFile).visit {
val fileDetails = this
val path = fileDetails.relativePath.pathString
if (!(fileDetails.isDirectory ||
if (
!(fileDetails.isDirectory ||
path.startsWith("org/pkl/") ||
path.startsWith("META-INF/") ||
nonRelocations.any { path.startsWith(it) })) {
nonRelocations.any { path.startsWith(it) })
) {
// don't throw exception inside `visit`
// as this gives a misleading "Could not expand ZIP" error message
unshadowedFiles.add(path)
@@ -132,32 +149,31 @@ val validateFatJar by tasks.registering {
}
}
}
tasks.check {
dependsOn(validateFatJar)
}
val resolveSourcesJars by tasks.registering(ResolveSourcesJars::class) {
tasks.check { dependsOn(validateFatJar) }
val resolveSourcesJars by
tasks.registering(ResolveSourcesJars::class) {
configuration.set(configurations.runtimeClasspath)
outputDir.set(layout.buildDirectory.dir("resolveSourcesJars"))
}
val fatSourcesJar by tasks.registering(MergeSourcesJars::class) {
plugins.withId("pklJavaLibrary") {
inputJars.from(tasks.named("sourcesJar"))
}
val fatSourcesJar by
tasks.registering(MergeSourcesJars::class) {
plugins.withId("pklJavaLibrary") { inputJars.from(tasks.named("sourcesJar")) }
inputJars.from(firstPartySourcesJarsConfiguration)
inputJars.from(resolveSourcesJars.map { fileTree(it.outputDir) })
mergedBinaryJars.from(tasks.shadowJar)
relocatedPackages.set(relocations)
outputJar.fileProvider(provider {
outputJar.fileProvider(
provider {
file(tasks.shadowJar.get().archiveFile.get().asFile.path.replace(".jar", "-sources.jar"))
})
}
)
}
artifacts {
add("fatJar", tasks.shadowJar)
}
artifacts { add("fatJar", tasks.shadowJar) }
publishing {
publications {
@@ -165,16 +181,12 @@ publishing {
project.shadow.component(this)
// sources Jar is fat
artifact(fatSourcesJar.flatMap { it.outputJar.asFile }) {
classifier = "sources"
}
artifact(fatSourcesJar.flatMap { it.outputJar.asFile }) { classifier = "sources" }
plugins.withId("pklJavaLibrary") {
val javadocJar by tasks.existing(Jar::class)
// Javadoc Jar is not fat (didn't invest effort)
artifact(javadocJar.flatMap { it.archiveFile }) {
classifier = "javadoc"
}
artifact(javadocJar.flatMap { it.archiveFile }) { classifier = "javadoc" }
}
}
}

View File

@@ -1,36 +1,44 @@
import java.nio.file.*
import java.util.UUID
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
import java.nio.file.*
import java.util.UUID
import kotlin.io.path.createDirectories
plugins {
id("de.undercouch.download")
}
plugins { id("de.undercouch.download") }
val buildInfo = project.extensions.getByType<BuildInfo>()
val BuildInfo.GraalVm.downloadFile get(): File {
val BuildInfo.GraalVm.downloadFile
get(): File {
val extension = if (buildInfo.os.isWindows) "zip" else "tar.gz"
return file(homeDir).resolve("${baseName}.$extension")
}
// tries to minimize chance of corruption by download-to-temp-file-and-move
val downloadGraalVmAarch64 by tasks.registering(Download::class) {
configureDownloadGraalVm(buildInfo.graalVmAarch64)
}
val downloadGraalVmAarch64 by
tasks.registering(Download::class) { configureDownloadGraalVm(buildInfo.graalVmAarch64) }
val downloadGraalVmAmd64 by tasks.registering(Download::class) {
configureDownloadGraalVm(buildInfo.graalVmAmd64)
}
val downloadGraalVmAmd64 by
tasks.registering(Download::class) { configureDownloadGraalVm(buildInfo.graalVmAmd64) }
fun Download.configureDownloadGraalVm(graalvm: BuildInfo.GraalVm) {
onlyIf {
!graalvm.installDir.exists()
}
doLast {
println("Downloaded GraalVm to ${graalvm.downloadFile}")
}
onlyIf { !graalvm.installDir.exists() }
doLast { println("Downloaded GraalVm to ${graalvm.downloadFile}") }
src(graalvm.downloadUrl)
dest(graalvm.downloadFile)
@@ -38,42 +46,44 @@ fun Download.configureDownloadGraalVm(graalvm: BuildInfo.GraalVm) {
tempAndMove(true)
}
val verifyGraalVmAarch64 by tasks.registering(Verify::class) {
val verifyGraalVmAarch64 by
tasks.registering(Verify::class) {
configureVerifyGraalVm(buildInfo.graalVmAarch64)
dependsOn(downloadGraalVmAarch64)
}
val verifyGraalVmAmd64 by tasks.registering(Verify::class) {
val verifyGraalVmAmd64 by
tasks.registering(Verify::class) {
configureVerifyGraalVm(buildInfo.graalVmAmd64)
dependsOn(downloadGraalVmAmd64)
}
fun Verify.configureVerifyGraalVm(graalvm: BuildInfo.GraalVm) {
onlyIf {
!graalvm.installDir.exists()
}
onlyIf { !graalvm.installDir.exists() }
src(graalvm.downloadFile)
checksum(buildInfo.libs.findVersion("graalVmSha256-${graalvm.osName}-${graalvm.arch}").get().toString())
checksum(
buildInfo.libs.findVersion("graalVmSha256-${graalvm.osName}-${graalvm.arch}").get().toString()
)
algorithm("SHA-256")
}
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
val installGraalVmAarch64 by tasks.registering {
val installGraalVmAarch64 by
tasks.registering {
dependsOn(verifyGraalVmAarch64)
configureInstallGraalVm(buildInfo.graalVmAarch64)
}
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
val installGraalVmAmd64 by tasks.registering {
val installGraalVmAmd64 by
tasks.registering {
dependsOn(verifyGraalVmAmd64)
configureInstallGraalVm(buildInfo.graalVmAmd64)
}
fun Task.configureInstallGraalVm(graalVm: BuildInfo.GraalVm) {
onlyIf {
!graalVm.installDir.exists()
}
onlyIf { !graalVm.installDir.exists() }
doLast {
val distroDir = Paths.get(graalVm.homeDir, UUID.randomUUID().toString())
@@ -88,7 +98,9 @@ fun Task.configureInstallGraalVm(graalVm: BuildInfo.GraalVm) {
args("--strip-components=1", "-xzf", graalVm.downloadFile)
}
val distroBinDir = if (buildInfo.os.isMacOsX) distroDir.resolve("Contents/Home/bin") else distroDir.resolve("bin")
val distroBinDir =
if (buildInfo.os.isMacOsX) distroDir.resolve("Contents/Home/bin")
else distroDir.resolve("bin")
println("Installing native-image into $distroDir")
exec {
@@ -103,11 +115,15 @@ fun Task.configureInstallGraalVm(graalVm: BuildInfo.GraalVm) {
try {
Files.move(tempLink, graalVm.installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
} catch (e: Exception) {
try { delete(tempLink.toFile()) } catch (ignored: Exception) {}
try {
delete(tempLink.toFile())
} catch (ignored: Exception) {}
throw e
}
} catch (e: Exception) {
try { delete(distroDir) } catch (ignored: Exception) {}
try {
delete(distroDir)
} catch (ignored: Exception) {}
throw e
}
}

View File

@@ -1,19 +1,19 @@
/**
* Allows to run Gradle plugin tests against different Gradle versions.
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Adds a `compatibilityTestX` task for every Gradle version X
* between `ext.minSupportedGradleVersion` and `ext.maxSupportedGradleVersion`
* that is not in `ext.gradleVersionsExcludedFromTesting`.
* The list of available Gradle versions is obtained from services.gradle.org.
* Adds lifecycle tasks to test against multiple Gradle versions at once, for example all Gradle release versions.
* Compatibility test tasks run the same tests and use the same task configuration as the project's `test` task.
* They set system properties for the Gradle version and distribution URL to be used.
* These properties are consumed by the `AbstractTest` class.
* 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.
*/
plugins {
java
}
plugins { java }
val gradlePluginTests = extensions.create<GradlePluginTests>("gradlePluginTests")
@@ -24,13 +24,18 @@ tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|
when (val taskNameSuffix = matchResult.groupValues[1]) {
"All" ->
task("compatibilityTestAll") {
dependsOn("compatibilityTestReleases", "compatibilityTestCandidate", "compatibilityTestNightly")
dependsOn(
"compatibilityTestReleases",
"compatibilityTestCandidate",
"compatibilityTestNightly"
)
}
// releases in configured range
"Releases" ->
task("compatibilityTestReleases") {
val versionInfos = GradleVersionInfo.fetchReleases()
val versionsToTestAgainst = versionInfos.filter { versionInfo ->
val versionsToTestAgainst =
versionInfos.filter { versionInfo ->
val v = versionInfo.gradleVersion
!versionInfo.broken &&
v in gradlePluginTests.minGradleVersion..gradlePluginTests.maxGradleVersion &&
@@ -45,8 +50,10 @@ tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|
val versionInfo = GradleVersionInfo.fetchCurrent()
if (versionInfo.version == gradle.gradleVersion) {
doLast {
println("No new Gradle release available. " +
"(Run `gradlew test` to test against ${versionInfo.version}.)")
println(
"No new Gradle release available. " +
"(Run `gradlew test` to test against ${versionInfo.version}.)"
)
}
} else {
dependsOn(createCompatibilityTestTask(versionInfo))
@@ -59,9 +66,7 @@ tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|
if (versionInfo?.activeRc == true) {
dependsOn(createCompatibilityTestTask(versionInfo))
} else {
doLast {
println("No active Gradle release candidate available.")
}
doLast { println("No active Gradle release candidate available.") }
}
}
// latest nightly

View File

@@ -1,16 +1,29 @@
plugins {
base
}
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins { base }
val htmlValidator = extensions.create<HtmlValidator>("htmlValidator", project)
val buildInfo = project.extensions.getByType<BuildInfo>()
val validatorConfiguration: Configuration = configurations.create("validator") {
val validatorConfiguration: Configuration =
configurations.create("validator") {
resolutionStrategy.eachDependency {
if (requested.group == "log4j" && requested.name == "log4j") {
@Suppress("UnstableApiUsage")
useTarget(buildInfo.libs.findLibrary("log4j12Api").get())
@Suppress("UnstableApiUsage") useTarget(buildInfo.libs.findLibrary("log4j12Api").get())
because("mitigate critical security vulnerabilities")
}
}
@@ -32,14 +45,17 @@ dependencies {
}
}
val validateHtml by tasks.registering(JavaExec::class) {
val validateHtml by
tasks.registering(JavaExec::class) {
val resultFile = layout.buildDirectory.file("validateHtml/result.txt")
inputs.files(htmlValidator.sources)
outputs.file(resultFile)
classpath = validatorConfiguration
mainClass.set("nu.validator.client.SimpleCommandLineValidator")
args("--skip-non-html") // --also-check-css doesn't work (still checks css as html), so limit to html files
args(
"--skip-non-html"
) // --also-check-css doesn't work (still checks css as html), so limit to html files
args("--filterpattern", "(.*)Consider adding “lang=(.*)")
args("--filterpattern", "(.*)Consider adding a “lang” attribute(.*)")
args("--filterpattern", "(.*)unrecognized media “amzn-kf8”(.*)") // kindle
@@ -48,11 +64,10 @@ val validateHtml by tasks.registering(JavaExec::class) {
args(htmlValidator.sources)
// write a basic result file s.t. gradle can consider task up-to-date
// writing a result file in case validation fails is not easily possible with JavaExec, but also not strictly necessary
// writing a result file in case validation fails is not easily possible with JavaExec, but also
// not strictly necessary
doFirst { project.delete(resultFile) }
doLast { resultFile.get().asFile.writeText("Success.") }
}
tasks.check {
dependsOn(validateHtml)
}
tasks.check { dependsOn(validateHtml) }

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.gradle.accessors.dm.LibrariesForLibs
plugins {

View File

@@ -1,9 +1,22 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import java.net.URI
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
plugins {
kotlin("jvm")
}
plugins { kotlin("jvm") }
val buildInfo = project.extensions.getByType<BuildInfo>()
@@ -27,17 +40,16 @@ tasks.withType<Test>().configureEach {
// Disable colour output in tests
systemProperty("org.fusesource.jansi.Ansi.disable", "true")
reports.named("html") {
enabled = true
}
reports.named("html") { enabled = true }
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
testLogging { exceptionFormat = TestExceptionFormat.FULL }
addTestListener(object : TestListener {
addTestListener(
object : TestListener {
override fun beforeSuite(suite: TestDescriptor) {}
override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {}
// print report link at end of task, not just at end of build
@@ -45,7 +57,9 @@ tasks.withType<Test>().configureEach {
if (descriptor.parent != null) return // only interested in overall result
if (result.resultType == TestResult.ResultType.FAILURE) {
println("\nThere were failing tests. See the report at: ${fixFileUri(testTask.reports.html.entryPoint.toURI())}")
println(
"\nThere were failing tests. See the report at: ${fixFileUri(testTask.reports.html.entryPoint.toURI())}"
)
}
}
@@ -56,5 +70,6 @@ tasks.withType<Test>().configureEach {
}
return uri
}
})
}
)
}

View File

@@ -1,11 +1,22 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
val assembleNative by tasks.registering {}
val testNative by tasks.registering {}
val checkNative by tasks.registering {
dependsOn(testNative)
}
val checkNative by tasks.registering { dependsOn(testNative) }
val buildNative by tasks.registering {
dependsOn(assembleNative, checkNative)
}
val buildNative by tasks.registering { dependsOn(assembleNative, checkNative) }

View File

@@ -1,6 +1,21 @@
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import java.nio.charset.StandardCharsets
import java.util.Base64
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
plugins {
`maven-publish`
@@ -10,9 +25,7 @@ plugins {
publishing {
publications {
components.findByName("java")?.let { javaComponent ->
create<MavenPublication>("library") {
from(javaComponent)
}
create<MavenPublication>("library") { from(javaComponent) }
}
withType<MavenPublication>().configureEach {
pom {
@@ -49,12 +62,14 @@ publishing {
}
}
val validatePom by tasks.registering {
val validatePom by
tasks.registering {
if (tasks.findByName("generatePomFileForLibraryPublication") == null) {
return@registering
}
val generatePomFileForLibraryPublication by tasks.existing(GenerateMavenPom::class)
val outputFile = layout.buildDirectory.file("validatePom") // dummy output to satisfy up-to-date check
val outputFile =
layout.buildDirectory.file("validatePom") // dummy output to satisfy up-to-date check
dependsOn(generatePomFileForLibraryPublication)
inputs.file(generatePomFileForLibraryPublication.get().destination)
@@ -76,7 +91,8 @@ val validatePom by tasks.registering {
"""
Found unresolved version selector(s) in generated POM:
${matches.joinToString("\n") { it.groupValues[0] }}
""".trimIndent()
"""
.trimIndent()
)
}
}
@@ -90,7 +106,8 @@ val validatePom by tasks.registering {
"""
Found snapshot version(s) in generated POM of Pkl release version:
${matches.joinToString("\n") { it.groupValues[0] }}
""".trimIndent()
"""
.trimIndent()
)
}
}
@@ -99,13 +116,12 @@ val validatePom by tasks.registering {
}
}
tasks.publish {
dependsOn(validatePom)
}
tasks.publish { dependsOn(validatePom) }
// Workaround for maven publish plugin not setting up dependencies correctly.
// Taken from https://github.com/gradle/gradle/issues/26091#issuecomment-1798137734
val dependsOnTasks = mutableListOf<String>()
tasks.withType<AbstractPublishToMaven>().configureEach {
dependsOnTasks.add(name.replace("publish", "sign").replaceAfter("Publication", ""))
dependsOn(dependsOnTasks)
@@ -114,8 +130,10 @@ tasks.withType<AbstractPublishToMaven>().configureEach {
signing {
// provided as env vars `ORG_GRADLE_PROJECT_signingKey` and `ORG_GRADLE_PROJECT_signingPassword`
// in CI.
val signingKey = (findProperty("signingKey") as String?)
?.let { Base64.getDecoder().decode(it).toString(StandardCharsets.US_ASCII) }
val signingKey =
(findProperty("signingKey") as String?)?.let {
Base64.getDecoder().decode(it).toString(StandardCharsets.US_ASCII)
}
val signingPassword = findProperty("signingPassword") as String?
if (signingKey != null && signingPassword != null) {
useInMemoryPgpKeys(signingKey, signingPassword)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
plugins {
@@ -12,10 +27,7 @@ sourceSets {
srcDir(file("modules/pkl-config-java/examples"))
srcDir(file("modules/java-binding/examples"))
}
val kotlin = project.extensions
.getByType<KotlinJvmProjectExtension>()
.sourceSets[name]
.kotlin
val kotlin = project.extensions.getByType<KotlinJvmProjectExtension>().sourceSets[name].kotlin
kotlin.srcDir(file("modules/kotlin-binding/examples"))
}
}
@@ -30,7 +42,8 @@ dependencies {
}
tasks.test {
inputs.files(fileTree("modules").matching {
include("**/pages/*.adoc")
}).withPropertyName("asciiDocFiles").withPathSensitivity(PathSensitivity.RELATIVE)
inputs
.files(fileTree("modules").matching { include("**/pages/*.adoc") })
.withPropertyName("asciiDocFiles")
.withPathSensitivity(PathSensitivity.RELATIVE)
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary
@@ -7,11 +22,9 @@ plugins {
// already on build script class path (see buildSrc/build.gradle.kts),
// hence must only specify plugin ID here
@Suppress("DSL_SCOPE_VIOLATION")
id(libs.plugins.shadow.get().pluginId)
@Suppress("DSL_SCOPE_VIOLATION") id(libs.plugins.shadow.get().pluginId)
@Suppress("DSL_SCOPE_VIOLATION")
alias(libs.plugins.checksum)
@Suppress("DSL_SCOPE_VIOLATION") alias(libs.plugins.checksum)
}
// make Java executable available to other subprojects
@@ -69,17 +82,13 @@ dependencies {
}
tasks.jar {
manifest {
attributes += mapOf("Main-Class" to "org.pkl.cli.Main")
}
manifest { attributes += mapOf("Main-Class" to "org.pkl.cli.Main") }
// not required at runtime
exclude("org/pkl/cli/svm/**")
}
tasks.javadoc {
enabled = false
}
tasks.javadoc { enabled = false }
tasks.shadowJar {
archiveFileName.set("jpkl")
@@ -93,7 +102,8 @@ tasks.shadowJar {
exclude("module-info.*")
}
val javaExecutable by tasks.registering(ExecutableJar::class) {
val javaExecutable by
tasks.registering(ExecutableJar::class) {
inJar.set(tasks.shadowJar.flatMap { it.archiveFile })
outJar.set(layout.buildDirectory.file("executable/jpkl"))
@@ -101,7 +111,8 @@ val javaExecutable by tasks.registering(ExecutableJar::class) {
// jvmArgs.addAll("-ea", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")
}
val testJavaExecutable by tasks.registering(Test::class) {
val testJavaExecutable by
tasks.registering(Test::class) {
testClassesDirs = tasks.test.get().testClassesDirs
classpath =
// compiled test classes
@@ -109,21 +120,23 @@ val testJavaExecutable by tasks.registering(Test::class) {
// java executable
javaExecutable.get().outputs.files +
// test-only dependencies
// (test dependencies that are also main dependencies must already be contained in java executable;
// (test dependencies that are also main dependencies must already be contained in java
// executable;
// to verify that, we don't want to include them here)
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
}
tasks.check {
dependsOn(testJavaExecutable)
}
tasks.check { dependsOn(testJavaExecutable) }
// 0.14 Java executable was broken because javaExecutable.jvmArgs wasn't commented out.
// To catch this and similar problems, test that Java executable starts successfully.
val testStartJavaExecutable by tasks.registering(Exec::class) {
val testStartJavaExecutable by
tasks.registering(Exec::class) {
dependsOn(javaExecutable)
val outputFile =
layout.buildDirectory.file("testStartJavaExecutable") // dummy output to satisfy up-to-date check
layout.buildDirectory.file(
"testStartJavaExecutable"
) // dummy output to satisfy up-to-date check
outputs.file(outputFile)
if (buildInfo.os.isWindows) {
@@ -139,26 +152,24 @@ val testStartJavaExecutable by tasks.registering(Exec::class) {
doLast { outputFile.get().asFile.writeText("OK") }
}
tasks.check {
dependsOn(testStartJavaExecutable)
}
tasks.check { dependsOn(testStartJavaExecutable) }
fun Exec.configureExecutable(
graalVm: BuildInfo.GraalVm,
outputFile: Provider<RegularFile>,
extraArgs: List<String> = listOf()
) {
inputs.files(sourceSets.main.map { it.output })
inputs
.files(sourceSets.main.map { it.output })
.withPropertyName("mainSourceSets")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs.files(configurations.runtimeClasspath)
inputs
.files(configurations.runtimeClasspath)
.withPropertyName("runtimeClasspath")
.withNormalizer(ClasspathNormalizer::class)
val nativeImageCommandName = if (buildInfo.os.isWindows) "native-image.cmd" else "native-image"
inputs.files(
file(graalVm.baseDir)
.resolve("bin/$nativeImageCommandName")
)
inputs
.files(file(graalVm.baseDir).resolve("bin/$nativeImageCommandName"))
.withPropertyName("graalVmNativeImage")
.withPathSensitivity(PathSensitivity.ABSOLUTE)
outputs.file(outputFile)
@@ -170,14 +181,18 @@ fun Exec.configureExecutable(
// JARs to exclude from the class path for the native-image build.
val exclusions = listOf(libs.truffleApi, libs.graalSdk).map { it.get().module.name }
// https://www.graalvm.org/22.0/reference-manual/native-image/Options/
argumentProviders.add(CommandLineArgumentProvider {
argumentProviders.add(
CommandLineArgumentProvider {
buildList {
// currently gives a deprecation warning, but we've been told
// that the "initialize everything at build time" *CLI* option is likely here to stay
add("--initialize-at-build-time=")
// needed for messagepack-java (see https://github.com/msgpack/msgpack-java/issues/600)
// needed for jansi (see https://github.com/fusesource/jansi/issues/199#issuecomment-1252268229)
add("--initialize-at-run-time=org.msgpack.core.buffer.DirectBufferAccess,org.fusesource.jansi.internal")
// needed for jansi (see
// https://github.com/fusesource/jansi/issues/199#issuecomment-1252268229)
add(
"--initialize-at-run-time=org.msgpack.core.buffer.DirectBufferAccess,org.fusesource.jansi.internal"
)
add("--no-fallback")
add("-H:IncludeResources=org/pkl/core/stdlib/.*\\.pkl")
add("-H:IncludeResources=org/jline/utils/.*")
@@ -186,38 +201,46 @@ fun Exec.configureExecutable(
add("--macro:truffle")
add("-H:Class=org.pkl.cli.Main")
add("-H:Name=${outputFile.get().asFile.name}")
// the actual limit (currently) used by native-image is this number + 1400 (idea is to compensate for Truffle's own nodes)
// the actual limit (currently) used by native-image is this number + 1400 (idea is to
// compensate for Truffle's own nodes)
add("-H:MaxRuntimeCompileMethods=1800")
add("-H:+EnforceMaxRuntimeCompileMethods")
add("--enable-url-protocols=http,https")
add("-H:+ReportExceptionStackTraces")
// disable automatic support for JVM CLI options (puts our main class in full control of argument parsing)
// disable automatic support for JVM CLI options (puts our main class in full control of
// argument parsing)
add("-H:-ParseRuntimeOptions")
// quick build mode: 40% faster compilation, 20% smaller (but presumably also slower) executable
// quick build mode: 40% faster compilation, 20% smaller (but presumably also slower)
// executable
if (!buildInfo.isReleaseBuild) {
add("-Ob")
}
add("-march=compatibility")
// native-image rejects non-existing class path entries -> filter
add("--class-path")
val pathInput = sourceSets.main.get().output + configurations.runtimeClasspath.get()
.filter { it.exists() && !exclusions.any { exclude -> it.name.contains(exclude) } }
val pathInput =
sourceSets.main.get().output +
configurations.runtimeClasspath.get().filter {
it.exists() && !exclusions.any { exclude -> it.name.contains(exclude) }
}
add(pathInput.asPath)
// make sure dev machine stays responsive (15% slowdown on my laptop)
val processors = Runtime.getRuntime().availableProcessors() /
val processors =
Runtime.getRuntime().availableProcessors() /
if (buildInfo.os.isMacOsX && !buildInfo.isCiBuild) 4 else 1
add("-J-XX:ActiveProcessorCount=${processors}")
// Pass through all `HOMEBREW_` prefixed environment variables to allow build with shimmed tools.
// Pass through all `HOMEBREW_` prefixed environment variables to allow build with shimmed
// tools.
addAll(environment.keys.filter { it.startsWith("HOMEBREW_") }.map { "-E$it" })
addAll(extraArgs)
}
})
}
)
}
/**
* Builds the pkl CLI for macOS/amd64.
*/
val macExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
/** Builds the pkl CLI for macOS/amd64. */
val macExecutableAmd64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAmd64")
configureExecutable(
buildInfo.graalVmAmd64,
@@ -225,24 +248,20 @@ val macExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
)
}
/**
* Builds the pkl CLI for macOS/aarch64.
*/
val macExecutableAarch64: TaskProvider<Exec> by tasks.registering(Exec::class) {
/** Builds the pkl CLI for macOS/aarch64. */
val macExecutableAarch64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAarch64")
configureExecutable(
buildInfo.graalVmAarch64,
layout.buildDirectory.file("executable/pkl-macos-aarch64"),
listOf(
"-H:+AllowDeprecatedBuilderClassesOnImageClasspath"
)
listOf("-H:+AllowDeprecatedBuilderClassesOnImageClasspath")
)
}
/**
* Builds the pkl CLI for linux/amd64.
*/
val linuxExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
/** Builds the pkl CLI for linux/amd64. */
val linuxExecutableAmd64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAmd64")
configureExecutable(
buildInfo.graalVmAmd64,
@@ -253,10 +272,11 @@ val linuxExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
/**
* Builds the pkl CLI for linux/aarch64.
*
* Right now, this is built within a container on Mac using emulation because CI does not have
* ARM instances.
* Right now, this is built within a container on Mac using emulation because CI does not have ARM
* instances.
*/
val linuxExecutableAarch64: TaskProvider<Exec> by tasks.registering(Exec::class) {
val linuxExecutableAarch64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAarch64")
configureExecutable(
buildInfo.graalVmAarch64,
@@ -270,7 +290,8 @@ val linuxExecutableAarch64: TaskProvider<Exec> by tasks.registering(Exec::class)
* Note: we don't publish the same for linux/aarch64 because native-image doesn't support this.
* Details: https://www.graalvm.org/22.0/reference-manual/native-image/ARM64/
*/
val alpineExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
val alpineExecutableAmd64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAmd64")
configureExecutable(
buildInfo.graalVmAmd64,
@@ -279,7 +300,8 @@ val alpineExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class)
)
}
val windowsExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
val windowsExecutableAmd64: TaskProvider<Exec> by
tasks.registering(Exec::class) {
dependsOn(":installGraalVmAmd64")
configureExecutable(
buildInfo.graalVmAmd64,
@@ -296,15 +318,12 @@ tasks.assembleNative {
dependsOn(macExecutableAarch64)
}
}
buildInfo.os.isWindows -> {
dependsOn(windowsExecutableAmd64)
}
buildInfo.os.isLinux && buildInfo.arch == "aarch64" -> {
dependsOn(linuxExecutableAarch64)
}
buildInfo.os.isLinux && buildInfo.arch == "amd64" -> {
dependsOn(linuxExecutableAmd64)
if (buildInfo.hasMuslToolchain) {
@@ -315,7 +334,8 @@ tasks.assembleNative {
}
// make Java executable available to other subprojects
// (we don't do the same for native executables because we don't want tasks assemble/build to build them)
// (we don't do the same for native executables because we don't want tasks assemble/build to build
// them)
artifacts {
add("javaExecutable", javaExecutable.map { it.outputs.files.singleFile }) {
name = "pkl-cli-java"
@@ -344,7 +364,8 @@ publishing {
Pkl CLI executable for Java.
Can be executed directly on *nix (if the `java` command is found on the PATH) and with `java -jar` otherwise.
Requires Java 17 or higher.
""".trimIndent()
"""
.trimIndent()
)
}
}
@@ -438,5 +459,4 @@ signing {
sign(publishing.publications["macExecutableAmd64"])
sign(publishing.publications["alpineLinuxExecutableAmd64"])
sign(publishing.publications["windowsExecutableAmd64"])
}
//endregion
} // endregion

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary
@@ -19,25 +34,22 @@ dependencies {
// with `org.gradle.parallel=true` and without the line below, `test` strangely runs into:
// java.lang.NoClassDefFoundError: Lorg/pkl/config/java/ConfigEvaluator;
// perhaps somehow related to InMemoryJavaCompiler?
tasks.test {
mustRunAfter(":pkl-config-java:testFatJar")
}
tasks.test { mustRunAfter(":pkl-config-java:testFatJar") }
tasks.jar {
manifest {
attributes += mapOf("Main-Class" to "org.pkl.codegen.java.Main")
}
}
tasks.jar { manifest { attributes += mapOf("Main-Class" to "org.pkl.codegen.java.Main") } }
publishing {
publications {
named<MavenPublication>("library") {
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-codegen-java")
description.set("""
description.set(
"""
Java source code generator that generates corresponding Java classes for Pkl classes,
simplifying consumption of Pkl configuration as statically typed Java objects.
""".trimIndent())
"""
.trimIndent()
)
}
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary
@@ -9,20 +24,19 @@ publishing {
named<MavenPublication>("library") {
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-codegen-kotlin")
description.set("""
description.set(
"""
Kotlin source code generator that generates corresponding Kotlin classes for Pkl classes,
simplifying consumption of Pkl configuration as statically typed Kotlin objects.
""".trimIndent())
"""
.trimIndent()
)
}
}
}
}
tasks.jar {
manifest {
attributes += mapOf("Main-Class" to "org.pkl.codegen.kotlin.Main")
}
}
tasks.jar { manifest { attributes += mapOf("Main-Class" to "org.pkl.codegen.kotlin.Main") } }
dependencies {
implementation(projects.pklCommons)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import java.security.MessageDigest
plugins {
@@ -19,8 +34,8 @@ dependencies {
/**
* Creates test packages from the `src/test/files/packages` directory.
*
* These packages are used by PackageServer to serve assets when running
* LanguageSnippetTests and PackageResolversTest.
* These packages are used by PackageServer to serve assets when running LanguageSnippetTests and
* PackageResolversTest.
*/
val createTestPackages by tasks.registering
@@ -38,7 +53,8 @@ for (packageDir in file("src/main/files/packages").listFiles()!!) {
val zipFileName = "${packageDir.name}.zip"
val archiveFile = destinationDir.map { it.file(zipFileName) }
val zipTask = tasks.register("zip-${packageDir.name}", Zip::class) {
val zipTask =
tasks.register("zip-${packageDir.name}", Zip::class) {
destinationDirectory.set(destinationDir)
archiveFileName.set(zipFileName)
from(packageContents)
@@ -47,7 +63,8 @@ for (packageDir in file("src/main/files/packages").listFiles()!!) {
isReproducibleFileOrder = true
}
val copyTask = tasks.register("copy-${packageDir.name}", Copy::class) {
val copyTask =
tasks.register("copy-${packageDir.name}", Copy::class) {
dependsOn(zipTask)
from(metadataJson)
into(destinationDir)
@@ -67,9 +84,7 @@ for (packageDir in file("src/main/files/packages").listFiles()!!) {
}
}
createTestPackages.configure {
dependsOn(copyTask)
}
createTestPackages.configure { dependsOn(copyTask) }
}
val keystoreDir = layout.buildDirectory.dir("keystore")
@@ -77,16 +92,23 @@ val keystoreName = "localhost.p12"
val keystoreFile = keystoreDir.map { it.file(keystoreName) }
val certsFileName = "localhost.pem"
val generateKeys by tasks.registering(JavaExec::class) {
val generateKeys by
tasks.registering(JavaExec::class) {
outputs.file(keystoreFile)
mainClass.set("sun.security.tools.keytool.Main")
args = listOf(
args =
listOf(
"-genkeypair",
"-keyalg", "RSA",
"-alias", "integ_tests",
"-keystore", keystoreName,
"-storepass", "password",
"-dname", "CN=localhost"
"-keyalg",
"RSA",
"-alias",
"integ_tests",
"-keystore",
keystoreName,
"-storepass",
"password",
"-dname",
"CN=localhost"
)
workingDir(keystoreDir)
doFirst {
@@ -95,19 +117,25 @@ val generateKeys by tasks.registering(JavaExec::class) {
}
}
val exportCerts by tasks.registering(JavaExec::class) {
val exportCerts by
tasks.registering(JavaExec::class) {
val outputFile = keystoreDir.map { it.file(certsFileName) }
dependsOn(generateKeys)
inputs.file(keystoreFile)
outputs.file(outputFile)
mainClass.set("sun.security.tools.keytool.Main")
args = listOf(
args =
listOf(
"-exportcert",
"-alias", "integ_tests",
"-storepass", "password",
"-keystore", keystoreName,
"-alias",
"integ_tests",
"-storepass",
"password",
"-keystore",
keystoreName,
"-rfc",
"-file", certsFileName
"-file",
certsFileName
)
workingDir(keystoreDir)
doFirst {
@@ -117,7 +145,8 @@ val exportCerts by tasks.registering(JavaExec::class) {
}
fun toHex(hash: ByteArray): String {
val hexDigitTable = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
val hexDigitTable =
charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
return buildString(hash.size * 2) {
for (b in hash) {
append(hexDigitTable[b.toInt() shr 4 and 0xF])

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklJavaLibrary
@@ -9,36 +24,33 @@ plugins {
val pklCodegenJava: Configuration by configurations.creating
val firstPartySourcesJars by configurations.existing
val generateTestConfigClasses by tasks.registering(JavaExec::class) {
val generateTestConfigClasses by
tasks.registering(JavaExec::class) {
val outputDir = layout.buildDirectory.dir("testConfigClasses")
outputs.dir(outputDir)
inputs.dir("src/test/resources/codegenPkl")
classpath = pklCodegenJava
mainClass.set("org.pkl.codegen.java.Main")
argumentProviders.add(CommandLineArgumentProvider {
listOf(
"--output-dir", outputDir.get().asFile.path,
"--generate-javadoc"
) + fileTree("src/test/resources/codegenPkl").map { it.path }
})
argumentProviders.add(
CommandLineArgumentProvider {
listOf("--output-dir", outputDir.get().asFile.path, "--generate-javadoc") +
fileTree("src/test/resources/codegenPkl").map { it.path }
}
)
}
tasks.processTestResources {
dependsOn(generateTestConfigClasses)
}
tasks.processTestResources { dependsOn(generateTestConfigClasses) }
tasks.compileTestKotlin {
dependsOn(generateTestConfigClasses)
}
tasks.compileTestKotlin { dependsOn(generateTestConfigClasses) }
val bundleTests by tasks.registering(Jar::class) {
from(sourceSets.test.get().output)
}
val bundleTests by tasks.registering(Jar::class) { from(sourceSets.test.get().output) }
// Runs unit tests using jar'd class files as a source.
// This is to test loading the ClassRegistry from within a jar, as opposed to directly from the file system.
val testFromJar by tasks.registering(Test::class) {
// This is to test loading the ClassRegistry from within a jar, as opposed to directly from the file
// system.
val testFromJar by
tasks.registering(Test::class) {
dependsOn(bundleTests)
testClassesDirs = files(tasks.test.get().testClassesDirs)
@@ -54,7 +66,8 @@ val testFromJar by tasks.registering(Test::class) {
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
}
// TODO: the below snippet causes `./gradlew check` to fail specifically on `pkl-codegen-java:check`. Why?
// TODO: the below snippet causes `./gradlew check` to fail specifically on
// `pkl-codegen-java:check`. Why?
// tasks.test {
// dependsOn(testFromJar)
// }
@@ -77,9 +90,7 @@ dependencies {
pklCodegenJava(projects.pklCodegenJava)
}
tasks.shadowJar {
archiveBaseName.set("pkl-config-java-all")
}
tasks.shadowJar { archiveBaseName.set("pkl-config-java-all") }
publishing {
publications {
@@ -94,12 +105,12 @@ publishing {
artifactId = "pkl-config-java-all"
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-config-java")
description.set("Shaded fat Jar for pkl-config-java, a Java config library based on the Pkl config language.")
description.set(
"Shaded fat Jar for pkl-config-java, a Java config library based on the Pkl config language."
)
}
}
}
}
signing {
sign(publishing.publications["fatJar"])
}
signing { sign(publishing.publications["fatJar"]) }

View File

@@ -1,19 +1,37 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.config.java.mapper
import org.pkl.config.java.ConfigEvaluator
import org.pkl.core.ModuleSource
import com.example.Lib
import com.example.PolymorphicModuleTest
import com.example.PolymorphicModuleTest.Strudel
import com.example.PolymorphicModuleTest.TurkishDelight
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.config.java.ConfigEvaluator
import org.pkl.core.ModuleSource
class PolymorphicTest {
@Test
fun `deserializing polymorphic objects`() {
val evaluator = ConfigEvaluator.preconfigured()
val module = evaluator.evaluate(ModuleSource.modulePath("/codegenPkl/PolymorphicModuleTest.pkl")).`as`(PolymorphicModuleTest::class.java)
val module =
evaluator
.evaluate(ModuleSource.modulePath("/codegenPkl/PolymorphicModuleTest.pkl"))
.`as`(PolymorphicModuleTest::class.java)
assertThat(module.desserts[0]).isInstanceOf(Strudel::class.java)
assertThat(module.desserts[1]).isInstanceOf(TurkishDelight::class.java)
assertThat(module.planes[0]).isInstanceOf(Lib.Jet::class.java)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
plugins {
pklAllProjects
pklKotlinLibrary
@@ -27,17 +42,20 @@ dependencies {
testImplementation(libs.geantyref)
}
val generateTestConfigClasses by tasks.registering(JavaExec::class) {
val generateTestConfigClasses by
tasks.registering(JavaExec::class) {
val outputDir = layout.buildDirectory.dir("testConfigClasses")
outputs.dir(outputDir)
inputs.dir("src/test/resources/codegenPkl")
classpath = pklCodegenKotlin
mainClass.set("org.pkl.codegen.kotlin.Main")
argumentProviders.add(CommandLineArgumentProvider {
argumentProviders.add(
CommandLineArgumentProvider {
listOf("--output-dir", outputDir.get().asFile.absolutePath) +
fileTree("src/test/resources/codegenPkl").map { it.absolutePath }
})
}
)
}
sourceSets.getByName("test") {
@@ -45,39 +63,36 @@ sourceSets.getByName("test") {
resources.srcDir(layout.buildDirectory.dir("testConfigClasses/resources"))
}
tasks.processTestResources {
dependsOn(generateTestConfigClasses)
}
tasks.processTestResources { dependsOn(generateTestConfigClasses) }
tasks.compileTestKotlin {
dependsOn(generateTestConfigClasses)
}
tasks.compileTestKotlin { dependsOn(generateTestConfigClasses) }
// use pkl-config-java-all for testing (same as for publishing)
tasks.test {
classpath = classpath - pklConfigJava + pklConfigJavaAll
}
tasks.test { classpath = classpath - pklConfigJava + pklConfigJavaAll }
// disable publishing of .module until we find a way to manipulate it like POM (or ideally both together)
tasks.withType<GenerateModuleMetadata> {
enabled = false
}
// disable publishing of .module until we find a way to manipulate it like POM (or ideally both
// together)
tasks.withType<GenerateModuleMetadata> { enabled = false }
publishing {
publications {
named<MavenPublication>("library") {
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-config-kotlin")
description.set("Kotlin extensions for pkl-config-java, a Java config library based on the Pkl config language.")
description.set(
"Kotlin extensions for pkl-config-java, a Java config library based on the Pkl config language."
)
// change dependency pkl-config-java to pkl-config-java-all
withXml {
val projectElement = asElement()
val dependenciesElement = projectElement.getElementsByTagName("dependencies").item(0) as org.w3c.dom.Element
val dependenciesElement =
projectElement.getElementsByTagName("dependencies").item(0) as org.w3c.dom.Element
val dependencyElements = dependenciesElement.getElementsByTagName("dependency")
for (idx in 0 until dependencyElements.length) {
val dependencyElement = dependencyElements.item(idx) as org.w3c.dom.Element
val artifactIdElement = dependencyElement.getElementsByTagName("artifactId").item(0) as org.w3c.dom.Element
val artifactIdElement =
dependencyElement.getElementsByTagName("artifactId").item(0) as org.w3c.dom.Element
if (artifactIdElement.textContent == "pkl-config-java") {
artifactIdElement.textContent = "pkl-config-java-all"
return@withXml

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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.
*/
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
@@ -12,13 +27,7 @@ plugins {
val generatorSourceSet = sourceSets.register("generator")
sourceSets {
main {
java {
srcDir(file("generated/antlr"))
}
}
}
sourceSets { main { java { srcDir(file("generated/antlr")) } } }
idea {
module {
@@ -51,9 +60,7 @@ dependencies {
implementation(libs.truffleApi)
implementation(libs.graalSdk)
implementation(libs.paguro) {
exclude(group = "org.jetbrains", module = "annotations")
}
implementation(libs.paguro) { exclude(group = "org.jetbrains", module = "annotations") }
implementation(libs.snakeYaml)
@@ -73,11 +80,14 @@ publishing {
named<MavenPublication>("library") {
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-core")
description.set("""
description.set(
"""
Core implementation of the Pkl configuration language.
Includes Java APIs for embedding the language into JVM applications,
and for building libraries and tools on top of the language.
""".trimIndent())
"""
.trimIndent()
)
}
}
}
@@ -97,29 +107,21 @@ tasks.generateGrammarSource {
outputDirectory = file("generated/antlr/org/pkl/core/parser/antlr")
}
tasks.compileJava {
dependsOn(tasks.generateGrammarSource)
}
tasks.compileJava { dependsOn(tasks.generateGrammarSource) }
tasks.sourcesJar {
dependsOn(tasks.generateGrammarSource)
}
tasks.sourcesJar { dependsOn(tasks.generateGrammarSource) }
tasks.generateTestGrammarSource {
enabled = false
}
tasks.named("generateGeneratorGrammarSource") {
enabled = false
}
tasks.generateTestGrammarSource { enabled = false }
tasks.named("generateGeneratorGrammarSource") { enabled = false }
// Satisfy expectations of IntelliJ ANTLR plugin,
// which can't otherwise cope with our ANTLR setup.
val makeIntelliJAntlrPluginHappy by tasks.registering(Copy::class) {
val makeIntelliJAntlrPluginHappy by
tasks.registering(Copy::class) {
dependsOn(tasks.generateGrammarSource)
into("src/main/antlr")
from("generated/antlr/org/pkl/core/parser/antlr") {
include("PklLexer.tokens")
}
from("generated/antlr/org/pkl/core/parser/antlr") { include("PklLexer.tokens") }
}
tasks.processResources {
@@ -127,33 +129,30 @@ tasks.processResources {
inputs.property("commitId", buildInfo.commitId)
filesMatching("org/pkl/core/Release.properties") {
val stdlibModules = fileTree("$rootDir/stdlib") {
val stdlibModules =
fileTree("$rootDir/stdlib") {
include("*.pkl")
exclude("doc-package-info.pkl")
}.map { "pkl:" + it.nameWithoutExtension }
}
.map { "pkl:" + it.nameWithoutExtension }
.sortedBy { it.lowercase() }
filter<ReplaceTokens>("tokens" to mapOf(
filter<ReplaceTokens>(
"tokens" to
mapOf(
"version" to buildInfo.pklVersion,
"commitId" to buildInfo.commitId,
"stdlibModules" to stdlibModules.joinToString(",")
))
)
)
}
into("org/pkl/core/stdlib") {
from("$rootDir/stdlib") {
include("*.pkl")
}
}
into("org/pkl/core/stdlib") { from("$rootDir/stdlib") { include("*.pkl") } }
}
tasks.compileJava {
options.generatedSourceOutputDirectory.set(file("generated/truffle"))
}
tasks.compileJava { options.generatedSourceOutputDirectory.set(file("generated/truffle")) }
tasks.compileKotlin {
enabled = false
}
tasks.compileKotlin { enabled = false }
tasks.test {
configureTest()
@@ -166,7 +165,8 @@ tasks.test {
}
}
val testJavaExecutable by tasks.registering(Test::class) {
val testJavaExecutable by
tasks.registering(Test::class) {
configureExecutableTest("LanguageSnippetTestsEngine")
classpath =
// compiled test classes
@@ -174,41 +174,46 @@ val testJavaExecutable by tasks.registering(Test::class) {
// java executable
javaExecutableConfiguration +
// test-only dependencies
// (test dependencies that are also main dependencies must already be contained in java executable;
// (test dependencies that are also main dependencies must already be contained in java
// executable;
// to verify that we don't want to include them here)
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
}
tasks.check {
dependsOn(testJavaExecutable)
}
tasks.check { dependsOn(testJavaExecutable) }
val testMacExecutableAmd64 by tasks.registering(Test::class) {
val testMacExecutableAmd64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:macExecutableAmd64")
configureExecutableTest("MacAmd64LanguageSnippetTestsEngine")
}
val testMacExecutableAarch64 by tasks.registering(Test::class) {
val testMacExecutableAarch64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:macExecutableAarch64")
configureExecutableTest("MacAarch64LanguageSnippetTestsEngine")
}
val testLinuxExecutableAmd64 by tasks.registering(Test::class) {
val testLinuxExecutableAmd64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:linuxExecutableAmd64")
configureExecutableTest("LinuxAmd64LanguageSnippetTestsEngine")
}
val testLinuxExecutableAarch64 by tasks.registering(Test::class) {
val testLinuxExecutableAarch64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:linuxExecutableAarch64")
configureExecutableTest("LinuxAarch64LanguageSnippetTestsEngine")
}
val testAlpineExecutableAmd64 by tasks.registering(Test::class) {
val testAlpineExecutableAmd64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:alpineExecutableAmd64")
configureExecutableTest("AlpineLanguageSnippetTestsEngine")
}
val testWindowsExecutableAmd64 by tasks.registering(Test::class) {
val testWindowsExecutableAmd64 by
tasks.registering(Test::class) {
dependsOn(":pkl-cli:windowsExecutableAmd64")
configureExecutableTest("WindowsLanguageSnippetTestsEngine")
}
@@ -249,13 +254,16 @@ spotless {
}
private fun Test.configureTest() {
inputs.dir("src/test/files/LanguageSnippetTests/input")
inputs
.dir("src/test/files/LanguageSnippetTests/input")
.withPropertyName("languageSnippetTestsInput")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs.dir("src/test/files/LanguageSnippetTests/input-helper")
inputs
.dir("src/test/files/LanguageSnippetTests/input-helper")
.withPropertyName("languageSnippetTestsInputHelper")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs.dir("src/test/files/LanguageSnippetTests/output")
inputs
.dir("src/test/files/LanguageSnippetTests/output")
.withPropertyName("languageSnippetTestsOutput")
.withPathSensitivity(PathSensitivity.RELATIVE)
}
@@ -264,7 +272,5 @@ private fun Test.configureExecutableTest(engineName: String) {
configureTest()
testClassesDirs = files(tasks.test.get().testClassesDirs)
classpath = tasks.test.get().classpath
useJUnitPlatform {
includeEngines(engineName)
}
useJUnitPlatform { includeEngines(engineName) }
}

View File

@@ -1,26 +1,41 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.generator
import com.oracle.truffle.api.dsl.GeneratedBy
import com.squareup.javapoet.ClassName
import javax.lang.model.SourceVersion
import javax.annotation.processing.RoundEnvironment
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.JavaFile
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.TypeSpec
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.SourceVersion
import javax.lang.model.element.*
import javax.lang.model.type.TypeMirror
/**
* Generates a subclass of `org.pkl.core.stdlib.registry.ExternalMemberRegistry`
* for each stdlib module and a factory to instantiate them.
* Generated classes are written to `generated/truffle/org/pkl/core/stdlib/registry`.
* Generates a subclass of `org.pkl.core.stdlib.registry.ExternalMemberRegistry` for each stdlib
* module and a factory to instantiate them. Generated classes are written to
* `generated/truffle/org/pkl/core/stdlib/registry`.
*
* Inputs:
* - Generated Truffle node classes for stdlib members.
* These classes are located in subpackages of `org.pkl.core.stdlib`
* and identified via their `@GeneratedBy` annotations.
* - `@PklName` annotations on handwritten node classes from which Truffle node classes are generated.
* - Generated Truffle node classes for stdlib members. These classes are located in subpackages of
* `org.pkl.core.stdlib` and identified via their `@GeneratedBy` annotations.
* - `@PklName` annotations on handwritten node classes from which Truffle node classes are
* generated.
*/
class MemberRegistryGenerator : AbstractProcessor() {
private val truffleNodeClassSuffix = "NodeGen"
@@ -35,10 +50,8 @@ class MemberRegistryGenerator : AbstractProcessor() {
ClassName.get(registryPackageName, "EmptyMemberRegistry")
private val memberRegistryFactoryClassName: ClassName =
ClassName.get(registryPackageName, "MemberRegistryFactory")
private val moduleKeyClassName: ClassName =
ClassName.get(modulePackageName, "ModuleKey")
private val moduleKeysClassName: ClassName =
ClassName.get(modulePackageName, "ModuleKeys")
private val moduleKeyClassName: ClassName = ClassName.get(modulePackageName, "ModuleKey")
private val moduleKeysClassName: ClassName = ClassName.get(modulePackageName, "ModuleKeys")
override fun getSupportedAnnotationTypes(): Set<String> = setOf(GeneratedBy::class.java.name)
@@ -54,19 +67,27 @@ class MemberRegistryGenerator : AbstractProcessor() {
return true
}
private fun collectNodeClasses(roundEnv: RoundEnvironment) = roundEnv
private fun collectNodeClasses(roundEnv: RoundEnvironment) =
roundEnv
.getElementsAnnotatedWith(GeneratedBy::class.java)
.asSequence()
.filterIsInstance<TypeElement>()
.filter { it.qualifiedName.toString().startsWith(stdLibPackageName) }
.filter { it.simpleName.toString().endsWith(truffleNodeClassSuffix) }
.sortedWith(compareBy(
{ if (it.enclosingElement.kind == ElementKind.PACKAGE) "" else it.enclosingElement.simpleName.toString() },
.sortedWith(
compareBy(
{
if (it.enclosingElement.kind == ElementKind.PACKAGE) ""
else it.enclosingElement.simpleName.toString()
},
{ it.simpleName.toString() }
))
)
)
.groupBy { processingEnv.elementUtils.getPackageOf(it) }
private fun generateRegistryClasses(nodeClassesByPackage: Map<PackageElement, List<TypeElement>>) {
private fun generateRegistryClasses(
nodeClassesByPackage: Map<PackageElement, List<TypeElement>>
) {
for ((pkg, nodeClasses) in nodeClassesByPackage) {
generateRegistryClass(pkg, nodeClasses)
}
@@ -75,9 +96,11 @@ class MemberRegistryGenerator : AbstractProcessor() {
private fun generateRegistryClass(pkg: PackageElement, nodeClasses: List<TypeElement>) {
val pklModuleName = getAnnotatedPklName(pkg) ?: pkg.simpleName.toString()
val pklModuleNameCapitalized = pklModuleName.capitalize()
val registryClassName = ClassName.get(registryPackageName, "${pklModuleNameCapitalized}MemberRegistry")
val registryClassName =
ClassName.get(registryPackageName, "${pklModuleNameCapitalized}MemberRegistry")
val registryClass = TypeSpec.classBuilder(registryClassName)
val registryClass =
TypeSpec.classBuilder(registryClassName)
.addJavadoc("Generated by {@link ${this::class.qualifiedName}}.")
.addModifiers(Modifier.FINAL)
.superclass(externalMemberRegistryClassName)
@@ -85,22 +108,26 @@ class MemberRegistryGenerator : AbstractProcessor() {
for (nodeClass in nodeClasses) {
val enclosingClass = nodeClass.enclosingElement
val pklClassName = getAnnotatedPklName(enclosingClass)
val pklClassName =
getAnnotatedPklName(enclosingClass)
?: enclosingClass.simpleName.toString().removeSuffix(truffleNodeFactorySuffix)
val pklMemberName = getAnnotatedPklName(nodeClass)
val pklMemberName =
getAnnotatedPklName(nodeClass)
?: nodeClass.simpleName.toString().removeSuffix(truffleNodeClassSuffix)
val pklMemberNameQualified = when (pklClassName) {
val pklMemberNameQualified =
when (pklClassName) {
// By convention, the top-level class containing node classes
// for *module* members is named `<SimpleModuleName>Nodes`.
// Example: `BaseNodes` for pkl.base
pklModuleNameCapitalized ->
"pkl.$pklModuleName#$pklMemberName"
else ->
"pkl.$pklModuleName#$pklClassName.$pklMemberName"
pklModuleNameCapitalized -> "pkl.$pklModuleName#$pklMemberName"
else -> "pkl.$pklModuleName#$pklClassName.$pklMemberName"
}
registryClass.addOriginatingElement(nodeClass)
registryClassConstructor
.addStatement("register(\$S, \$T::create)", pklMemberNameQualified, nodeClass)
registryClassConstructor.addStatement(
"register(\$S, \$T::create)",
pklMemberNameQualified,
nodeClass
)
}
registryClass.addMethod(registryClassConstructor.build())
@@ -109,13 +136,14 @@ class MemberRegistryGenerator : AbstractProcessor() {
}
private fun generateRegistryFactoryClass(packages: Collection<PackageElement>) {
val registryFactoryClass = TypeSpec.classBuilder(memberRegistryFactoryClassName)
val registryFactoryClass =
TypeSpec.classBuilder(memberRegistryFactoryClassName)
.addJavadoc("Generated by {@link ${this::class.qualifiedName}}.")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
val registryFactoryConstructor = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
val registryFactoryConstructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE)
registryFactoryClass.addMethod(registryFactoryConstructor.build())
val registryFactoryGetMethod = MethodSpec.methodBuilder("get")
val registryFactoryGetMethod =
MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(moduleKeyClassName, "moduleKey")
.returns(externalMemberRegistryClassName)
@@ -127,7 +155,8 @@ class MemberRegistryGenerator : AbstractProcessor() {
for (pkg in packages) {
val pklModuleName = getAnnotatedPklName(pkg) ?: pkg.simpleName.toString()
val pklModuleNameCapitalized = pklModuleName.capitalize()
val registryClassName = ClassName.get(registryPackageName, "${pklModuleNameCapitalized}MemberRegistry")
val registryClassName =
ClassName.get(registryPackageName, "${pklModuleNameCapitalized}MemberRegistry")
// declare dependency on package-info.java (for `@PklName`)
registryFactoryClass.addOriginatingElement(pkg)
@@ -148,8 +177,7 @@ class MemberRegistryGenerator : AbstractProcessor() {
private fun getAnnotatedPklName(element: Element): String? {
for (annotation in element.annotationMirrors) {
when (annotation.annotationType.asElement().simpleName.toString()) {
"PklName" ->
return annotation.elementValues.values.iterator().next().value.toString()
"PklName" -> return annotation.elementValues.values.iterator().next().value.toString()
"GeneratedBy" -> {
val annotationValue = annotation.elementValues.values.first().value as TypeMirror
return getAnnotatedPklName(processingEnv.typeUtils.asElement(annotationValue))

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
@@ -8,7 +23,8 @@ class ClassInheritanceTest {
@Test
fun `property override without type annotation is considered an object property definition`() {
val module = evaluator.evaluateSchema(
val module =
evaluator.evaluateSchema(
ModuleSource.text(
"""
class Thing
@@ -18,7 +34,8 @@ class ClassInheritanceTest {
class Derived extends Base {
thing {}
}
""".trimIndent()
"""
.trimIndent()
)
)
@@ -33,7 +50,8 @@ class ClassInheritanceTest {
@Test
fun `property override with type annotation is considered a class property definition`() {
val module = evaluator.evaluateSchema(
val module =
evaluator.evaluateSchema(
ModuleSource.text(
"""
class Thing
@@ -43,7 +61,8 @@ class ClassInheritanceTest {
class Derived extends Base {
thing: Thing = new {}
}
""".trimIndent()
"""
.trimIndent()
)
)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import kotlin.math.nextDown
@@ -68,8 +83,7 @@ class DurationTest {
assertThat(duration1.convertTo(MILLIS)).isEqualTo(duration2)
assertThat(duration2.convertTo(SECONDS)).isEqualTo(duration1)
assertThat(duration4.convertTo(NANOS))
.isEqualTo(Duration(0.0, NANOS))
assertThat(duration4.convertTo(NANOS)).isEqualTo(Duration(0.0, NANOS))
}
@Test
@@ -79,8 +93,10 @@ class DurationTest {
assertThat(duration3.toIsoString()).isEqualTo("PT0.3001S")
assertThat(duration4.toIsoString()).isEqualTo("PT0S")
assertThat(Duration(1.0, NANOS).toIsoString()).isEqualTo("PT0.000000001S")
// Although ISO8601 allows for durations (P) denoted in days, months and years, it is not recommended.
// The day notation can express an hour more or less, depending on whether it crosses a daylight savings transition,
// Although ISO8601 allows for durations (P) denoted in days, months and years, it is not
// recommended.
// The day notation can express an hour more or less, depending on whether it crosses a daylight
// savings transition,
// when added to "now" (at the time of evaluation).
assertThat(Duration(100.0, DAYS).toIsoString()).isEqualTo("PT2400H")
}
@@ -96,165 +112,132 @@ class DurationTest {
@Test
fun `toJavaDuration() - positive`() {
assertThat(Duration(999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(999))
assertThat(Duration(999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(999999))
assertThat(Duration(999999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(999999999))
assertThat(Duration(999999999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(999999999999))
assertThat(
Duration(
999999999999999.0,
NANOS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofNanos(999999999999999))
assertThat(Duration(9999999999999999.0, NANOS).toJavaDuration()).isNotEqualTo(
java.time.Duration.ofNanos(
9999999999999999
)
)
assertThat(Duration(999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(999999))
assertThat(Duration(999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(999999999))
assertThat(Duration(999999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(999999999999))
assertThat(Duration(999999999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(999999999999999))
assertThat(Duration(9999999999999999.0, NANOS).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofNanos(9999999999999999))
assertThat(Duration(999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(999))
assertThat(Duration(999999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(999999))
assertThat(Duration(999999999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(999999999))
assertThat(Duration(999999999999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(999999999999))
assertThat(Duration(999999999999999.0, SECONDS).toJavaDuration()).isEqualTo(
java.time.Duration.ofSeconds(
999999999999999
)
)
assertThat(Duration(9999999999999999.0, SECONDS).toJavaDuration()).isNotEqualTo(
java.time.Duration.ofSeconds(
9999999999999999
)
)
assertThat(Duration(999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(999))
assertThat(Duration(999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(999999))
assertThat(Duration(999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(999999999))
assertThat(Duration(999999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(999999999999))
assertThat(Duration(999999999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(999999999999999))
assertThat(Duration(9999999999999999.0, SECONDS).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofSeconds(9999999999999999))
assertThat(Duration(999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(999))
assertThat(Duration(999999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(999999))
assertThat(Duration(999999999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(999999999))
assertThat(Duration(999999999999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(999999999999))
assertThat(Duration(999999999999999.0, MINUTES).toJavaDuration()).isEqualTo(
java.time.Duration.ofMinutes(
999999999999999
)
)
assertThat(Duration(9999999999999999.0, MINUTES).toJavaDuration()).isNotEqualTo(
java.time.Duration.ofMinutes(
9999999999999999
)
)
assertThat(Duration(999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(999))
assertThat(Duration(999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(999999))
assertThat(Duration(999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(999999999))
assertThat(Duration(999999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(999999999999))
assertThat(Duration(999999999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(999999999999999))
assertThat(Duration(9999999999999999.0, MINUTES).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofMinutes(9999999999999999))
assertThat(Duration(999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(999))
assertThat(Duration(999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(999999))
assertThat(Duration(999999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(999999999))
assertThat(Duration(999999999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(999999999999))
assertThat(
Duration(
999999999999999.0,
HOURS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofHours(999999999999999))
assertThat(Duration(999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(999999))
assertThat(Duration(999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(999999999))
assertThat(Duration(999999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(999999999999))
assertThat(Duration(999999999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(999999999999999))
assertThrows<ArithmeticException> { Duration(9999999999999999.0, HOURS).toJavaDuration() }
assertThat(Duration(999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(999))
assertThat(Duration(999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(999999))
assertThat(Duration(999999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(999999999))
assertThat(Duration(999999999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(999999999999))
assertThat(Duration(999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(999999))
assertThat(Duration(999999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(999999999))
assertThat(Duration(999999999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(999999999999))
assertThrows<ArithmeticException> { Duration(999999999999999.0, DAYS).toJavaDuration() }
}
@Test
fun `toJavaDuration() - negative`() {
assertThat(Duration(-999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(-999))
assertThat(Duration(-999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(-999999))
assertThat(Duration(-999999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(-999999999))
assertThat(Duration(-999999999999.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(-999999999999))
assertThat(
Duration(
-999999999999999.0,
NANOS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofNanos(-999999999999999))
assertThat(
Duration(
-9999999999999999.0,
NANOS
).toJavaDuration()
).isNotEqualTo(java.time.Duration.ofNanos(-9999999999999999))
assertThat(Duration(-999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(-999999))
assertThat(Duration(-999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(-999999999))
assertThat(Duration(-999999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(-999999999999))
assertThat(Duration(-999999999999999.0, NANOS).toJavaDuration())
.isEqualTo(java.time.Duration.ofNanos(-999999999999999))
assertThat(Duration(-9999999999999999.0, NANOS).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofNanos(-9999999999999999))
assertThat(Duration(-999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(-999))
assertThat(Duration(-999999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(-999999))
assertThat(Duration(-999999999.0, SECONDS).toJavaDuration()).isEqualTo(java.time.Duration.ofSeconds(-999999999))
assertThat(
Duration(
-999999999999.0,
SECONDS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofSeconds(-999999999999))
assertThat(
Duration(
-999999999999999.0,
SECONDS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofSeconds(-999999999999999))
assertThat(
Duration(
-9999999999999999.0,
SECONDS
).toJavaDuration()
).isNotEqualTo(java.time.Duration.ofSeconds(-9999999999999999))
assertThat(Duration(-999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(-999))
assertThat(Duration(-999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(-999999))
assertThat(Duration(-999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(-999999999))
assertThat(Duration(-999999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(-999999999999))
assertThat(Duration(-999999999999999.0, SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(-999999999999999))
assertThat(Duration(-9999999999999999.0, SECONDS).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofSeconds(-9999999999999999))
assertThat(Duration(-999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(-999))
assertThat(Duration(-999999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(-999999))
assertThat(Duration(-999999999.0, MINUTES).toJavaDuration()).isEqualTo(java.time.Duration.ofMinutes(-999999999))
assertThat(
Duration(
-999999999999.0,
MINUTES
).toJavaDuration()
).isEqualTo(java.time.Duration.ofMinutes(-999999999999))
assertThat(
Duration(
-999999999999999.0,
MINUTES
).toJavaDuration()
).isEqualTo(java.time.Duration.ofMinutes(-999999999999999))
assertThat(
Duration(
-9999999999999999.0,
MINUTES
).toJavaDuration()
).isNotEqualTo(java.time.Duration.ofMinutes(-9999999999999999))
assertThat(Duration(-999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(-999))
assertThat(Duration(-999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(-999999))
assertThat(Duration(-999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(-999999999))
assertThat(Duration(-999999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(-999999999999))
assertThat(Duration(-999999999999999.0, MINUTES).toJavaDuration())
.isEqualTo(java.time.Duration.ofMinutes(-999999999999999))
assertThat(Duration(-9999999999999999.0, MINUTES).toJavaDuration())
.isNotEqualTo(java.time.Duration.ofMinutes(-9999999999999999))
assertThat(Duration(-999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(-999))
assertThat(Duration(-999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(-999999))
assertThat(Duration(-999999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(-999999999))
assertThat(Duration(-999999999999.0, HOURS).toJavaDuration()).isEqualTo(java.time.Duration.ofHours(-999999999999))
assertThat(
Duration(
-999999999999999.0,
HOURS
).toJavaDuration()
).isEqualTo(java.time.Duration.ofHours(-999999999999999))
assertThat(Duration(-999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(-999999))
assertThat(Duration(-999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(-999999999))
assertThat(Duration(-999999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(-999999999999))
assertThat(Duration(-999999999999999.0, HOURS).toJavaDuration())
.isEqualTo(java.time.Duration.ofHours(-999999999999999))
assertThrows<ArithmeticException> { Duration(-9999999999999999.0, HOURS).toJavaDuration() }
assertThat(Duration(-999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(-999))
assertThat(Duration(-999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(-999999))
assertThat(Duration(-999999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(-999999999))
assertThat(Duration(-999999999999.0, DAYS).toJavaDuration()).isEqualTo(java.time.Duration.ofDays(-999999999999))
assertThat(Duration(-999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(-999999))
assertThat(Duration(-999999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(-999999999))
assertThat(Duration(-999999999999.0, DAYS).toJavaDuration())
.isEqualTo(java.time.Duration.ofDays(-999999999999))
assertThrows<ArithmeticException> { Duration(-999999999999999.0, DAYS).toJavaDuration() }
}
@Test
fun `toJavaDuration() - edge cases`() {
assertThat(Duration(0.0, NANOS).toJavaDuration()).isEqualTo(java.time.Duration.ofNanos(0))
assertThat(Duration(Long.MAX_VALUE.toDouble(), SECONDS).toJavaDuration()).isEqualTo(
java.time.Duration.ofSeconds(
Long.MAX_VALUE
)
)
assertThat(Duration(Long.MIN_VALUE.toDouble(), SECONDS).toJavaDuration()).isEqualTo(
java.time.Duration.ofSeconds(
Long.MIN_VALUE
)
)
assertThat(Duration(Long.MAX_VALUE.toDouble(), SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(Long.MAX_VALUE))
assertThat(Duration(Long.MIN_VALUE.toDouble(), SECONDS).toJavaDuration())
.isEqualTo(java.time.Duration.ofSeconds(Long.MIN_VALUE))
val justTooLarge = Duration(Long.MAX_VALUE.toDouble().nextUp(), SECONDS)
assertThrows<ArithmeticException> { justTooLarge.toJavaDuration() }

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.time.temporal.ChronoUnit

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.junit.jupiter.api.Test
@@ -5,13 +20,15 @@ import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
class DynamicTest {
private fun brokenInput(value: String): String = """
private fun brokenInput(value: String): String =
"""
class Person { name: String; age: Int }
person: Person = new { name = 42; age = "Pigeon" } // oops
output { value = $value }
""".trimIndent()
"""
.trimIndent()
@Test
fun `property access respects type`() {

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
@@ -35,7 +50,8 @@ class ErrorColoringTest {
fun `simple error`() {
val error = assertThrows<PklException> { evaluate("bar = 2", "bar = 15") }
assertThat(error).message()
assertThat(error)
.message()
.contains("\u001B[31m Pkl Error \u001B[m")
.contains("\u001B[94m1 | \u001B[m")
.contains("\u001B[0;31m^")
@@ -43,8 +59,15 @@ class ErrorColoringTest {
@Test
fun `repeated error`() {
val error = assertThrows<PklException> { evaluate("""self: String = "Strings; if they were lazy, you could tie the knot on \(self.take(7))"""", "self") }
assertThat(error).message()
val error =
assertThrows<PklException> {
evaluate(
"""self: String = "Strings; if they were lazy, you could tie the knot on \(self.take(7))"""",
"self"
)
}
assertThat(error)
.message()
.contains("A stack overflow occurred.")
.contains("┌─ ")
.contains(" repetitions of:")

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
@@ -22,13 +37,15 @@ class EvaluateExpressionTest {
@Test
fun `evaluate expression`() {
val program = """
val program =
"""
res1 = 1
res2 {
res3 = 3
res4 = 4
}
""".trimIndent()
"""
.trimIndent()
assertThat(evaluate(program, "res1")).isEqualTo(1L)
val res2 = evaluate(program, "res2")
assertThat(res2).isInstanceOf(PObject::class.java)
@@ -39,18 +56,25 @@ class EvaluateExpressionTest {
@Test
fun `evaluate subpath`() {
val resp = evaluate("""
val resp =
evaluate(
"""
foo {
bar = 2
}
""".trimIndent(), "foo.bar")
"""
.trimIndent(),
"foo.bar"
)
assertThat(resp).isEqualTo(2L)
}
@Test
fun `evaluate output text`() {
val result = evaluate("""
val result =
evaluate(
"""
foo {
bar = 2
}
@@ -58,13 +82,20 @@ class EvaluateExpressionTest {
output {
renderer = new YamlRenderer {}
}
""".trimIndent(), "output.text")
"""
.trimIndent(),
"output.text"
)
assertThat(result).isEqualTo("""
assertThat(result)
.isEqualTo(
"""
foo:
bar: 2
""".trimIndent())
"""
.trimIndent()
)
}
@Test
@@ -76,10 +107,7 @@ class EvaluateExpressionTest {
@Test
fun `evaluate import expression`() {
val result = evaluate(
"",
"""import("pkl:release").current.documentation.homepage"""
)
val result = evaluate("", """import("pkl:release").current.documentation.homepage""")
assertThat(result as String).startsWith("https://pkl-lang.org/")
}

View File

@@ -1,9 +1,24 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.core.ModuleSource.text
import org.assertj.core.api.Assertions.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.core.ModuleSource.text
class EvaluateMultipleFileOutputTest {
@@ -11,7 +26,8 @@ class EvaluateMultipleFileOutputTest {
@Test
fun `output files`() {
val program = """
val program =
"""
output {
files {
["foo.yml"] {
@@ -28,14 +44,10 @@ class EvaluateMultipleFileOutputTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
val output = evaluator.evaluateOutputFiles(text(program))
assertThat(output.keys).isEqualTo(setOf(
"foo.yml",
"bar.yml",
"bar/biz.yml",
"bar/../bark.yml"
))
assertThat(output.keys).isEqualTo(setOf("foo.yml", "bar.yml", "bar/biz.yml", "bar/../bark.yml"))
assertThat(output["foo.yml"]?.text).isEqualTo("foo: foo text")
assertThat(output["bar.yml"]?.text).isEqualTo("bar: bar text")
assertThat(output["bar/biz.yml"]?.text).isEqualTo("biz: bar biz")
@@ -45,7 +57,8 @@ class EvaluateMultipleFileOutputTest {
@Test
fun `using a renderer`() {
val evaluator = Evaluator.preconfigured()
val program = """
val program =
"""
output {
files {
["foo.json"] {
@@ -57,21 +70,27 @@ class EvaluateMultipleFileOutputTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
val output = evaluator.evaluateOutputFiles(text(program))
assertThat(output["foo.json"]?.text).isEqualTo("""
assertThat(output["foo.json"]?.text)
.isEqualTo(
"""
{
"foo": "fooey",
"bar": "barrey"
}
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `reading files after the evaluator is closed`() {
val evaluator = Evaluator.preconfigured()
val program = """
val program =
"""
output {
files {
["foo.json"] {
@@ -83,7 +102,8 @@ class EvaluateMultipleFileOutputTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
val output = evaluator.evaluateOutputFiles(text(program))
evaluator.close()
assertThrows<PklException> { output["foo.json"]!!.text }

View File

@@ -1,8 +1,23 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.core.util.IoUtils
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.util.IoUtils
// tests language-internal renderers
// uses same input/output files as Pcf/Json/Yaml/PListRendererTest
@@ -28,13 +43,10 @@ class EvaluateOutputTextTest {
}
private fun checkRenderedOutput(format: OutputFormat) {
val evaluator = EvaluatorBuilder.preconfigured()
.setOutputFormat(format)
.build()
val evaluator = EvaluatorBuilder.preconfigured().setOutputFormat(format).build()
val output = evaluator.evaluateOutputText(
ModuleSource.modulePath("org/pkl/core/rendererTest.pkl")
)
val output =
evaluator.evaluateOutputText(ModuleSource.modulePath("org/pkl/core/rendererTest.pkl"))
val expected = IoUtils.readClassPathResourceAsString(javaClass, "rendererTest.$format")
assertThat(output.trim()).isEqualTo(expected.trim())

View File

@@ -1,10 +1,25 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.core.ModuleSource.*
import java.net.URI
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.pkl.core.ModuleSource.*
import org.pkl.core.runtime.BaseModule
class EvaluateSchemaTest {
@@ -17,9 +32,7 @@ class EvaluateSchemaTest {
@Test
fun `evaluate test schema`() {
val module = evaluator.evaluateSchema(
modulePath("org/pkl/core/EvaluateSchemaTest.pkl")
)
val module = evaluator.evaluateSchema(modulePath("org/pkl/core/EvaluateSchemaTest.pkl"))
checkModuleMetadata(module)
@@ -35,28 +48,27 @@ class EvaluateSchemaTest {
@Test
fun `evaluate pkl_base schema`() {
val module = evaluator.evaluateSchema(uri(URI("pkl:base")))
assertThat(module.moduleClass.superclass)
.isEqualTo(BaseModule.getModuleClass().export())
assertThat(module.moduleClass.superclass).isEqualTo(BaseModule.getModuleClass().export())
}
@Test
fun `does not export local classes`() {
val module = evaluator.evaluateSchema(
val module =
evaluator.evaluateSchema(
text(
"""
class Foo {}
local class Baz {}
""".trimIndent()
"""
.trimIndent()
)
)
assertThat(module.classes.keys)
.containsExactly("Foo")
assertThat(module.classes.keys).containsExactly("Foo")
}
private fun checkModuleMetadata(module: ModuleSchema) {
assertThat(module.moduleUri)
.isEqualTo(URI("modulepath:/org/pkl/core/EvaluateSchemaTest.pkl"))
assertThat(module.moduleUri).isEqualTo(URI("modulepath:/org/pkl/core/EvaluateSchemaTest.pkl"))
assertThat(module.moduleName).isEqualTo("test")
@@ -79,8 +91,7 @@ class EvaluateSchemaTest {
val paramType = propertyb2.type
assertThat(paramType).isInstanceOf(PType.Class::class.java)
paramType as PType.Class
assertThat(paramType.pClass)
.isEqualTo(BaseModule.getIntClass().export())
assertThat(paramType.pClass).isEqualTo(BaseModule.getIntClass().export())
val propertyb3 = properties.getValue("propertyb3")
assertThat(propertyb3.sourceLocation.startLine).isEqualTo(24)
@@ -106,10 +117,8 @@ class EvaluateSchemaTest {
val paramBaseType = paramType.baseType
assertThat(paramBaseType).isInstanceOf(PType.Class::class.java)
paramBaseType as PType.Class
assertThat(paramBaseType.pClass)
.isEqualTo(BaseModule.getStringClass().export())
assertThat(paramType.constraints)
.isEqualTo(listOf("!isEmpty", "startsWith(\"a\")"))
assertThat(paramBaseType.pClass).isEqualTo(BaseModule.getStringClass().export())
assertThat(paramType.constraints).isEqualTo(listOf("!isEmpty", "startsWith(\"a\")"))
val returnType = methodb2.returnType
assertThat(returnType).isInstanceOf(PType.Constrained::class.java)
@@ -141,10 +150,8 @@ class EvaluateSchemaTest {
assertThat(supermodule).isNotNull
assertThat(supermodule!!.supermodule).isNull()
assertThat(module.moduleClass.superclass)
.isEqualTo(supermodule.moduleClass)
assertThat(supermodule.moduleClass.superclass)
.isEqualTo(BaseModule.getModuleClass().export())
assertThat(module.moduleClass.superclass).isEqualTo(supermodule.moduleClass)
assertThat(supermodule.moduleClass.superclass).isEqualTo(BaseModule.getModuleClass().export())
assertThat(supermodule.moduleUri)
.isEqualTo(URI("modulepath:/org/pkl/core/EvaluateSchemaTestBaseModule.pkl"))

View File

@@ -1,15 +1,30 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.commons.createTempFile
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.createFile
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.createTempFile
import org.pkl.commons.writeString
import org.pkl.core.ModuleSource.*
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.createFile
class EvaluateTestsTest {
@@ -17,7 +32,10 @@ class EvaluateTestsTest {
@Test
fun `test successful module`() {
val results = evaluator.evaluateTest(text("""
val results =
evaluator.evaluateTest(
text(
"""
amends "pkl:test"
facts {
@@ -26,7 +44,11 @@ class EvaluateTestsTest {
"foo" == "foo"
}
}
""".trimIndent()), true)
"""
.trimIndent()
),
true
)
assertThat(results.moduleName).isEqualTo("text")
assertThat(results.displayUri).isEqualTo("repl:text")
@@ -38,7 +60,8 @@ class EvaluateTestsTest {
@Test
fun `test module failure`() {
val results = evaluator.evaluateTest(
val results =
evaluator.evaluateTest(
text(
"""
amends "pkl:test"
@@ -49,7 +72,8 @@ class EvaluateTestsTest {
"foo" == "bar"
}
}
""".trimIndent()
"""
.trimIndent()
),
true
)
@@ -71,7 +95,8 @@ class EvaluateTestsTest {
@Test
fun `test module error`() {
val results = evaluator.evaluateTest(
val results =
evaluator.evaluateTest(
text(
"""
amends "pkl:test"
@@ -82,7 +107,8 @@ class EvaluateTestsTest {
throw("got an error")
}
}
""".trimIndent()
"""
.trimIndent()
),
true
)
@@ -98,7 +124,9 @@ class EvaluateTestsTest {
val error = res.errors[0]
assertThat(error.message).isEqualTo("got an error")
assertThat(error.exception.message).isEqualTo("""
assertThat(error.exception.message)
.isEqualTo(
"""
Pkl Error
got an error
@@ -110,13 +138,17 @@ class EvaluateTestsTest {
^^^^^^^
at text#facts (repl:text)
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `test successful example`(@TempDir tempDir: Path) {
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
Files.writeString(file, """
Files.writeString(
file,
"""
amends "pkl:test"
examples {
@@ -127,9 +159,13 @@ class EvaluateTestsTest {
}
}
}
""".trimIndent())
"""
.trimIndent()
)
Files.writeString(createExpected(file), """
Files.writeString(
createExpected(file),
"""
examples {
["user"] {
new {
@@ -138,7 +174,9 @@ class EvaluateTestsTest {
}
}
}
""".trimIndent())
"""
.trimIndent()
)
val results = evaluator.evaluateTest(path(file), false)
assertThat(results.moduleName).startsWith("example")
@@ -151,7 +189,9 @@ class EvaluateTestsTest {
@Test
fun `test example failure`(@TempDir tempDir: Path) {
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
Files.writeString(file, """
Files.writeString(
file,
"""
amends "pkl:test"
examples {
@@ -162,9 +202,13 @@ class EvaluateTestsTest {
}
}
}
""".trimIndent())
"""
.trimIndent()
)
Files.writeString(createExpected(file), """
Files.writeString(
createExpected(file),
"""
examples {
["user"] {
new {
@@ -173,7 +217,9 @@ class EvaluateTestsTest {
}
}
}
""".trimIndent())
"""
.trimIndent()
)
val results = evaluator.evaluateTest(path(file), false)
assertThat(results.moduleName).startsWith("example")
@@ -187,7 +233,9 @@ class EvaluateTestsTest {
assertThat(res.errors.isEmpty()).isTrue
val fail1 = res.failures[0]
assertThat(fail1.rendered.stripFileAndLines(tempDir)).isEqualTo("""
assertThat(fail1.rendered.stripFileAndLines(tempDir))
.isEqualTo(
"""
(/tempDir/example.pkl)
Expected: (/tempDir/example.pkl-expected.pcf)
new {
@@ -199,13 +247,17 @@ class EvaluateTestsTest {
name = "Bob"
age = 33
}
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `written examples use custom string delimiters`(@TempDir tempDir: Path) {
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
Files.writeString(file, """
Files.writeString(
file,
"""
amends "pkl:test"
examples {
@@ -213,25 +265,33 @@ class EvaluateTestsTest {
"my \"string\""
}
}
""".trimIndent())
"""
.trimIndent()
)
evaluator.evaluateTest(path(file), false)
val expectedFile = file.parent.resolve(file.fileName.toString() + "-expected.pcf")
assertThat(expectedFile).exists()
assertThat(expectedFile).hasContent("""
assertThat(expectedFile)
.hasContent(
"""
examples {
["myStr"] {
#"my "string""#
}
}
""".trimIndent())
"""
.trimIndent()
)
}
// test for backwards compatibility
@Test
fun `examples that don't use custom string delimiters still pass`(@TempDir tempDir: Path) {
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
Files.writeString(file, """
Files.writeString(
file,
"""
amends "pkl:test"
examples {
@@ -239,25 +299,28 @@ class EvaluateTestsTest {
"my \"string\""
}
}
""".trimIndent())
createExpected(file).writeString("""
"""
.trimIndent()
)
createExpected(file)
.writeString(
"""
examples {
["myStr"] {
"my \"string\""
}
}
""".trimIndent())
"""
.trimIndent()
)
val result = evaluator.evaluateTest(path(file), false)
assertFalse(result.failed())
}
companion object {
private fun createExpected(path: Path): Path {
return path
.parent
.resolve(path.fileName.toString() + "-expected.pcf")
.createFile()
return path.parent.resolve(path.fileName.toString() + "-expected.pcf").createFile()
}
private fun String.stripFileAndLines(tmpDir: Path) =

View File

@@ -1,11 +1,26 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.nio.file.Path
import java.time.Duration
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.core.project.Project
import java.nio.file.Path
import java.time.Duration
class EvaluatorBuilderTest {
@Test
@@ -34,7 +49,8 @@ class EvaluatorBuilderTest {
@Test
fun `enforces that security manager is set`() {
val e1 = assertThrows<IllegalStateException> {
val e1 =
assertThrows<IllegalStateException> {
EvaluatorBuilder.unconfigured()
.setStackFrameTransformer(StackFrameTransformers.empty)
.build()
@@ -44,10 +60,9 @@ class EvaluatorBuilderTest {
@Test
fun `enforces that stack frame transformer is set`() {
val e1 = assertThrows<IllegalStateException> {
EvaluatorBuilder.unconfigured()
.setSecurityManager(SecurityManagers.defaultManager)
.build()
val e1 =
assertThrows<IllegalStateException> {
EvaluatorBuilder.unconfigured().setSecurityManager(SecurityManagers.defaultManager).build()
}
assertThat(e1).hasMessage("No stack frame transformer set.")
}
@@ -55,19 +70,11 @@ class EvaluatorBuilderTest {
@Test
fun `sets evaluator settings from project`() {
val projectPath = Path.of(javaClass.getResource("project/project1/PklProject")!!.toURI())
val project = Project.loadFromPath(
projectPath,
SecurityManagers.defaultManager,
null
)
val project = Project.loadFromPath(projectPath, SecurityManagers.defaultManager, null)
val projectDir = Path.of(javaClass.getResource("project/project1/PklProject")!!.toURI()).parent
val builder = EvaluatorBuilder
.unconfigured()
.applyFromProject(project)
assertThat(builder.allowedResources.map { it.pattern() })
.isEqualTo(listOf("foo:", "bar:"))
assertThat(builder.allowedModules.map { it.pattern() })
.isEqualTo(listOf("baz:", "biz:"))
val builder = EvaluatorBuilder.unconfigured().applyFromProject(project)
assertThat(builder.allowedResources.map { it.pattern() }).isEqualTo(listOf("foo:", "bar:"))
assertThat(builder.allowedModules.map { it.pattern() }).isEqualTo(listOf("baz:", "biz:"))
assertThat(builder.externalProperties).isEqualTo(mapOf("one" to "1"))
assertThat(builder.environmentVariables).isEqualTo(mapOf("two" to "2"))
assertThat(builder.moduleCacheDir).isEqualTo(projectDir.resolve("my-cache-dir/"))

View File

@@ -1,32 +1,47 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.commons.createParentDirectories
import java.io.File
import java.net.URI
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import java.util.regex.Pattern
import kotlin.io.path.writeText
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.createParentDirectories
import org.pkl.commons.createTempFile
import org.pkl.commons.test.PackageServer
import org.pkl.commons.toPath
import org.pkl.commons.writeString
import org.pkl.core.ModuleSource.*
import org.pkl.core.util.IoUtils
import org.junit.jupiter.api.AfterAll
import org.pkl.commons.test.PackageServer
import org.pkl.core.module.ModuleKey
import org.pkl.core.module.ModuleKeyFactories
import org.pkl.core.module.ModuleKeyFactory
import org.pkl.core.module.ResolvedModuleKey
import org.pkl.core.project.Project
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.util.*
import java.util.regex.Pattern
import kotlin.io.path.writeText
import org.pkl.core.util.IoUtils
class EvaluatorTest {
companion object {
@@ -50,8 +65,10 @@ class EvaluatorTest {
override fun getUri(): URI = uri
override fun loadSource(): String = javaClass.classLoader.getResourceAsStream(uri.path.drop(1))!!.use { it.readAllBytes().toString(
StandardCharsets.UTF_8) }
override fun loadSource(): String =
javaClass.classLoader.getResourceAsStream(uri.path.drop(1))!!.use {
it.readAllBytes().toString(StandardCharsets.UTF_8)
}
override fun resolve(securityManager: SecurityManager): ResolvedModuleKey = this
}
@@ -71,28 +88,20 @@ class EvaluatorTest {
@Test
fun `evaluate text with relative import`() {
val e = assertThrows<PklException> {
evaluator.evaluate(text("import \"foo.bar\""))
}
assertThat(e)
.hasMessageContaining("Module `repl:text` cannot have a relative import URI.")
val e = assertThrows<PklException> { evaluator.evaluate(text("import \"foo.bar\"")) }
assertThat(e).hasMessageContaining("Module `repl:text` cannot have a relative import URI.")
}
@Test
fun `evaluate named module`() {
val module = evaluator.evaluate(
modulePath("org/pkl/core/EvaluatorTest.pkl")
)
val module = evaluator.evaluate(modulePath("org/pkl/core/EvaluatorTest.pkl"))
checkModule(module)
}
@Test
fun `evaluate non-existing named module`() {
val e = assertThrows<PklException> {
evaluator.evaluate(modulePath("non/existing.pkl"))
}
assertThat(e)
.hasMessageContaining("Cannot find module `modulepath:/non/existing.pkl`.")
val e = assertThrows<PklException> { evaluator.evaluate(modulePath("non/existing.pkl")) }
assertThat(e).hasMessageContaining("Cannot find module `modulepath:/non/existing.pkl`.")
}
@Test
@@ -107,11 +116,8 @@ class EvaluatorTest {
@Test
fun `evaluate non-existing file`() {
val file = File("/non/existing")
val e = assertThrows<PklException> {
evaluator.evaluate(file(file))
}
assertThat(e)
.hasMessageContaining("Cannot find module `${file.toPath().toUri()}`.")
val e = assertThrows<PklException> { evaluator.evaluate(file(file)) }
assertThat(e).hasMessageContaining("Cannot find module `${file.toPath().toUri()}`.")
}
@Test
@@ -126,11 +132,8 @@ class EvaluatorTest {
@Test
fun `evaluate non-existing path`() {
val path = "/non/existing".toPath()
val e = assertThrows<PklException> {
evaluator.evaluate(path(path))
}
assertThat(e)
.hasMessageContaining("Cannot find module `${path.toUri()}`.")
val e = assertThrows<PklException> { evaluator.evaluate(path(path)) }
assertThat(e).hasMessageContaining("Cannot find module `${path.toUri()}`.")
}
@Test
@@ -150,9 +153,7 @@ class EvaluatorTest {
// cast required to compile on JDK 14+ (which adds new overload)
FileSystems.newFileSystem(zipFile, null as ClassLoader?).use { zipFs ->
val file = zipFs.getPath("non/existing")
val e = assertThrows<PklException> {
evaluator.evaluate(path(file))
}
val e = assertThrows<PklException> { evaluator.evaluate(path(file)) }
assertThat(e)
.hasMessageContaining("Cannot find module `jar:file:")
.hasMessageContaining("non/existing")
@@ -170,11 +171,9 @@ class EvaluatorTest {
@Test
fun `evaluate non-existing URI`() {
val e = assertThrows<PklException> {
evaluator.evaluate(uri(URI("https://localhost/non/existing")))
}
assertThat(e)
.hasMessageContaining("I/O error loading module `https://localhost/non/existing`.")
val e =
assertThrows<PklException> { evaluator.evaluate(uri(URI("https://localhost/non/existing"))) }
assertThat(e).hasMessageContaining("I/O error loading module `https://localhost/non/existing`.")
}
@Test
@@ -187,48 +186,43 @@ class EvaluatorTest {
@Test
fun `evaluate jar URI with non-existing archive`() {
val moduleUri = URI("jar:file:///non/existing!/bar.pkl")
val e = assertThrows<PklException> {
evaluator.evaluate(uri(moduleUri))
}
assertThat(e)
.hasMessageContaining("Cannot find module `$moduleUri`.")
val e = assertThrows<PklException> { evaluator.evaluate(uri(moduleUri)) }
assertThat(e).hasMessageContaining("Cannot find module `$moduleUri`.")
}
@Test
fun `evaluate jar URI with non-existing archive path`(@TempDir tempDir: Path) {
val zipFile = createModulesZip(tempDir)
val moduleUri = URI("jar:${zipFile.toUri()}!/non/existing")
val e = assertThrows<PklException> {
evaluator.evaluate(uri(moduleUri))
}
assertThat(e)
.hasMessageContaining("Cannot find module `$moduleUri`.")
val e = assertThrows<PklException> { evaluator.evaluate(uri(moduleUri)) }
assertThat(e).hasMessageContaining("Cannot find module `$moduleUri`.")
}
@Test
fun `evaluate module with relative URI`() {
val e = assertThrows<PklException> {
evaluator.evaluate(create(URI("foo.bar"), ""))
}
val e = assertThrows<PklException> { evaluator.evaluate(create(URI("foo.bar"), "")) }
assertThat(e)
.hasMessageContaining("Cannot evaluate relative module URI `foo.bar`.")
assertThat(e).hasMessageContaining("Cannot evaluate relative module URI `foo.bar`.")
}
@Test
fun `evaluating a broken module multiple times results in the same error every time`() {
val e1 = assertThrows<PklException> {
val e1 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
val e2 = assertThrows<PklException> {
val e2 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
assertThat(e2.message).isEqualTo(e1.message)
val e3 = assertThrows<PklException> {
val e3 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
val e4 = assertThrows<PklException> {
val e4 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
assertThat(e4.message).isEqualTo(e3.message)
@@ -236,16 +230,19 @@ class EvaluatorTest {
@Test
fun `evaluation timeout`() {
val evaluator = EvaluatorBuilder.preconfigured()
.setTimeout(java.time.Duration.ofMillis(100))
.build()
val e = assertThrows<PklException> {
evaluator.evaluate(text(
val evaluator =
EvaluatorBuilder.preconfigured().setTimeout(java.time.Duration.ofMillis(100)).build()
val e =
assertThrows<PklException> {
evaluator.evaluate(
text(
"""
function fib(n) = if (n < 2) 0 else fib(n - 1) + fib(n - 2)
x = fib(100)
""".trimIndent()
))
"""
.trimIndent()
)
)
}
assertThat(e.message).contains("timed out")
}
@@ -253,19 +250,26 @@ class EvaluatorTest {
@Test
fun `stack overflow`() {
val evaluator = Evaluator.preconfigured()
val e = assertThrows<PklException> {
evaluator.evaluate(text("""
val e =
assertThrows<PklException> {
evaluator.evaluate(
text(
"""
a = b
b = c
c = a
""".trimIndent()))
"""
.trimIndent()
)
)
}
assertThat(e.message).contains("A stack overflow occurred.")
}
@Test
fun `cannot import module located outside root dir`(@TempDir tempDir: Path) {
val evaluator = EvaluatorBuilder.preconfigured()
val evaluator =
EvaluatorBuilder.preconfigured()
.setSecurityManager(
SecurityManagers.standard(
SecurityManagers.defaultAllowedModules,
@@ -280,19 +284,19 @@ class EvaluatorTest {
module.writeString(
"""
amends "/non/existing.pkl"
""".trimIndent()
"""
.trimIndent()
)
val e = assertThrows<PklException> {
evaluator.evaluate(path(module))
}
val e = assertThrows<PklException> { evaluator.evaluate(path(module)) }
assertThat(e.message).contains("Refusing to load module `file:///non/existing.pkl`")
}
@Test
fun `multiple-file output`() {
val evaluator = Evaluator.preconfigured()
val program = """
val program =
"""
output {
files {
["foo.yml"] {
@@ -309,14 +313,10 @@ class EvaluatorTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
val output = evaluator.evaluateOutputFiles(ModuleSource.text(program))
assertThat(output.keys).isEqualTo(setOf(
"foo.yml",
"bar.yml",
"bar/biz.yml",
"bar/../bark.yml"
))
assertThat(output.keys).isEqualTo(setOf("foo.yml", "bar.yml", "bar/biz.yml", "bar/../bark.yml"))
assertThat(output["foo.yml"]?.text).isEqualTo("foo: foo text")
assertThat(output["bar.yml"]?.text).isEqualTo("bar: bar text")
assertThat(output["bar/biz.yml"]?.text).isEqualTo("biz: bar biz")
@@ -328,10 +328,13 @@ class EvaluatorTest {
PackageServer.populateCacheDir(cacheDir)
val evaluatorBuilder = EvaluatorBuilder.preconfigured().setModuleCacheDir(cacheDir)
val project = Project.load(modulePath("/org/pkl/core/project/project5/PklProject"))
val result = evaluatorBuilder.setProjectDependencies(project.dependencies).build().use { evaluator ->
val result =
evaluatorBuilder.setProjectDependencies(project.dependencies).build().use { evaluator ->
evaluator.evaluateOutputText(modulePath("/org/pkl/core/project/project5/main.pkl"))
}
assertThat(result).isEqualTo("""
assertThat(result)
.isEqualTo(
"""
prop1 {
name = "Apple"
}
@@ -339,13 +342,16 @@ class EvaluatorTest {
res = 1
}
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `project set from custom ModuleKeyFactory`(@TempDir cacheDir: Path) {
PackageServer.populateCacheDir(cacheDir)
val evaluatorBuilder = with(EvaluatorBuilder.preconfigured()) {
val evaluatorBuilder =
with(EvaluatorBuilder.preconfigured()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("custom:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("custom:"))
setModuleCacheDir(cacheDir)
@@ -359,10 +365,14 @@ class EvaluatorTest {
)
)
}
val project = evaluatorBuilder.build().use { Project.load(it, uri("custom:/org/pkl/core/project/project5/PklProject")) }
val project =
evaluatorBuilder.build().use {
Project.load(it, uri("custom:/org/pkl/core/project/project5/PklProject"))
}
val evaluator = evaluatorBuilder.setProjectDependencies(project.dependencies).build()
val output = evaluator.use { it.evaluateOutputText(uri("custom:/org/pkl/core/project/project5/main.pkl")) }
val output =
evaluator.use { it.evaluateOutputText(uri("custom:/org/pkl/core/project/project5/main.pkl")) }
assertThat(output)
.isEqualTo(
"""
@@ -382,28 +392,36 @@ class EvaluatorTest {
fun `project base path set to non-hierarchical scheme`() {
class FooBarModuleKey(val moduleUri: URI) : ModuleKey, ResolvedModuleKey {
override fun hasHierarchicalUris(): Boolean = false
override fun isGlobbable(): Boolean = false
override fun getOriginal(): ModuleKey = this
override fun getUri(): URI = moduleUri
override fun loadSource(): String =
if (uri.schemeSpecificPart.endsWith("PklProject")) {
"""
amends "pkl:Project"
""".trimIndent()
} else """
"""
.trimIndent()
} else
"""
birds = import("@birds/catalog/Ostritch.pkl")
""".trimIndent()
"""
.trimIndent()
override fun resolve(securityManager: SecurityManager): ResolvedModuleKey {
return this
}
}
val fooBayModuleKeyFactory = ModuleKeyFactory { uri ->
if (uri.scheme == "foobar") Optional.of(FooBarModuleKey(uri))
else Optional.empty()
if (uri.scheme == "foobar") Optional.of(FooBarModuleKey(uri)) else Optional.empty()
}
val evaluatorBuilder = with(EvaluatorBuilder.preconfigured()) {
val evaluatorBuilder =
with(EvaluatorBuilder.preconfigured()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("foobar:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("foobar:"))
setModuleKeyFactories(
@@ -420,7 +438,9 @@ class EvaluatorTest {
val project = evaluatorBuilder.build().use { Project.load(it, uri("foobar:foo/PklProject")) }
val evaluator = evaluatorBuilder.setProjectDependencies(project.dependencies).build()
assertThatCode { evaluator.use { it.evaluateOutputText(uri("foobar:baz")) } }
.hasMessageContaining("Cannot import dependency because project URI `foobar:foo/PklProject` does not have a hierarchical path.")
.hasMessageContaining(
"Cannot import dependency because project URI `foobar:foo/PklProject` does not have a hierarchical path."
)
}
@Test
@@ -430,22 +450,34 @@ class EvaluatorTest {
val project = Project.load(modulePath("/org/pkl/core/project/project6/PklProject"))
evaluatorBuilder.setProjectDependencies(project.dependencies).build().use { evaluator ->
assertThatCode {
evaluator.evaluateOutputText(modulePath("/org/pkl/core/project/project6/globWithinDependency.pkl"))
}.hasMessageContaining("""
evaluator.evaluateOutputText(
modulePath("/org/pkl/core/project/project6/globWithinDependency.pkl")
)
}
.hasMessageContaining(
"""
Cannot resolve import in local dependency because scheme `modulepath` is not globbable.
1 | res = import*("*.pkl")
^^^^^^^^^^^^^^^^
""".trimIndent())
"""
.trimIndent()
)
assertThatCode {
evaluator.evaluateOutputText(modulePath("/org/pkl/core/project/project6/globIntoDependency.pkl"))
}.hasMessageContaining("""
evaluator.evaluateOutputText(
modulePath("/org/pkl/core/project/project6/globIntoDependency.pkl")
)
}
.hasMessageContaining(
"""
Pkl Error
Cannot resolve import in local dependency because scheme `modulepath` is not globbable.
1 | import* "@project7/*.pkl" as proj7Files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
""".trimIndent())
"""
.trimIndent()
)
}
}
@@ -460,13 +492,16 @@ class EvaluatorTest {
val module1 = modulesDir.resolve("foo/bar/module1.pkl").createParentDirectories()
val module2 = modulesDir.resolve("foo/baz/module2.pkl").createParentDirectories()
module1.writeText("""
module1.writeText(
"""
// verify that relative import is resolved correctly
import "../baz/module2.pkl"
name = module2.name
age = module2.age
""".trimIndent())
"""
.trimIndent()
)
module2.writeText(sourceText)

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.StringWriter
@@ -12,9 +27,7 @@ class JsonRendererTest {
@Test
fun `render document`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
ModuleSource.modulePath("org/pkl/core/rendererTest.pkl")
)
val module = evaluator.evaluate(ModuleSource.modulePath("org/pkl/core/rendererTest.pkl"))
val writer = StringWriter()
val renderer = ValueRenderers.json(writer, " ", true)
@@ -23,14 +36,13 @@ class JsonRendererTest {
val expected = IoUtils.readClassPathResourceAsString(javaClass, "rendererTest.json")
assertThat(output).isEqualTo(expected)
assertThatCode { JsonParser(object : JsonHandler<Any, Any>() {}).parse(output) }.doesNotThrowAnyException()
assertThatCode { JsonParser(object : JsonHandler<Any, Any>() {}).parse(output) }
.doesNotThrowAnyException()
}
@Test
fun `rendered document ends in newline`() {
val module: PModule = Evaluator
.preconfigured()
.evaluate(ModuleSource.text("foo { bar = 0 }"))
val module: PModule = Evaluator.preconfigured().evaluate(ModuleSource.text("foo { bar = 0 }"))
for (omitNullProperties in listOf(false, true)) {
val writer = StringWriter()

View File

@@ -1,18 +1,28 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.junit.platform.commons.annotation.Testable
@Testable
class LanguageSnippetTests
@Testable class LanguageSnippetTests
@Testable
class MacLanguageSnippetTests
@Testable class MacLanguageSnippetTests
@Testable
class LinuxLanguageSnippetTests
@Testable class LinuxLanguageSnippetTests
@Testable
class AlpineLanguageSnippetTests
@Testable class AlpineLanguageSnippetTests
@Testable
class WindowsLanguageSnippetTests
@Testable class WindowsLanguageSnippetTests

View File

@@ -1,5 +1,27 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.PrintWriter
import java.io.StringWriter
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isRegularFile
import kotlin.reflect.KClass
import org.junit.platform.engine.EngineDiscoveryRequest
import org.junit.platform.engine.TestDescriptor
import org.junit.platform.engine.UniqueId
@@ -11,13 +33,6 @@ import org.pkl.commons.test.PklExecutablePaths
import org.pkl.core.http.HttpClient
import org.pkl.core.project.Project
import org.pkl.core.util.IoUtils
import java.io.PrintWriter
import java.io.StringWriter
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isRegularFile
import kotlin.reflect.KClass
abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
private val lineNumberRegex = Regex("(?m)^(( ║ )*)(\\d+) \\|")
@@ -31,8 +46,8 @@ abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
private val expectedOutputDir: Path = snippetsDir.resolve("output")
/**
* Convenience for development; this selects which snippet test(s) to run.
* There is a (non-language-snippet) test to make sure this is `""` before commit.
* Convenience for development; this selects which snippet test(s) to run. There is a
* (non-language-snippet) test to make sure this is `""` before commit.
*/
// language=regexp
internal val selection: String = ""
@@ -53,8 +68,7 @@ abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
override val isInputFile: (Path) -> Boolean = { it.isRegularFile() }
protected tailrec fun Path.getProjectDir(): Path? =
if (Files.exists(this.resolve("PklProject"))) this
else parent?.getProjectDir()
if (Files.exists(this.resolve("PklProject"))) this else parent?.getProjectDir()
override fun expectedOutputFileFor(inputFile: Path): Path {
val relativePath = IoUtils.relativize(inputFile, inputDir).toString()
@@ -80,12 +94,14 @@ abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
protected fun String.stripFilePaths(): String =
replace(IoUtils.toNormalizedPathString(snippetsDir), replacement)
protected fun String.stripLineNumbers() = replace(lineNumberRegex) { result ->
protected fun String.stripLineNumbers() =
replace(lineNumberRegex) { result ->
// replace line number with equivalent number of 'x' characters to keep formatting intact
(result.groups[1]!!.value) + "x".repeat(result.groups[3]!!.value.length) + " |"
}
protected fun String.stripWebsite() = replace(Release.current().documentation().homepage(), "https://\$pklWebsite/")
protected fun String.stripWebsite() =
replace(Release.current().documentation().homepage(), "https://\$pklWebsite/")
// can't think of a better solution right now
protected fun String.stripVersionCheckErrorMessage() =
@@ -103,8 +119,7 @@ abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
}
protected fun String.withUnixLineEndings(): String {
return if (System.lineSeparator() == "\r\n") replace("\r\n", "\n")
else this
return if (System.lineSeparator() == "\r\n") replace("\r\n", "\n") else this
}
}
@@ -123,16 +138,16 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
"file:///foo/bar" to "file:///foo/bar"
)
)
.setExternalProperties(mapOf(
"name1" to "value1",
"name2" to "value2",
"/foo/bar" to "foobar"
))
.setExternalProperties(
mapOf("name1" to "value1", "name2" to "value2", "/foo/bar" to "foobar")
)
.setModuleCacheDir(null)
.setHttpClient(HttpClient.builder()
.setHttpClient(
HttpClient.builder()
.setTestPort(packageServer.port)
.addCertificates(FileTestUtils.selfSignedCertificate)
.buildLazily())
.buildLazily()
)
}
override val testClass: KClass<*> = LanguageSnippetTests::class
@@ -140,13 +155,16 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
override fun generateOutputFor(inputFile: Path): kotlin.Pair<Boolean, String> {
val logWriter = StringWriter()
val (success, output) = try {
val evaluator = evaluatorBuilder()
val (success, output) =
try {
val evaluator =
evaluatorBuilder()
.setLogger(Loggers.writer(PrintWriter(logWriter)))
.apply {
if (inputFile.startsWith(projectsDir)) {
val projectDir = inputFile.getProjectDir() ?: return@apply
val project = Project.loadFromPath(
val project =
Project.loadFromPath(
projectDir.resolve("PklProject"),
SecurityManagers.defaultManager,
null,
@@ -162,30 +180,32 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
} catch (e: PklBugException) {
false to e.stackTraceToString()
} catch (e: PklException) {
false to e.message!!
.stripLineNumbers()
.stripVersionCheckErrorMessage()
false to e.message!!.stripLineNumbers().stripVersionCheckErrorMessage()
}
val stderr = logWriter.toString().withUnixLineEndings()
return (success && stderr.isBlank()) to (output + stderr).stripFilePaths().stripWebsite().stripStdlibLocationSha()
return (success && stderr.isBlank()) to
(output + stderr).stripFilePaths().stripWebsite().stripStdlibLocationSha()
}
}
abstract class AbstractNativeLanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
abstract val pklExecutablePath: Path
override val excludedTests: List<Regex> = listOf(
// exclude test that loads module from class path (there is no class path when using native executable)
override val excludedTests: List<Regex> =
listOf(
// exclude test that loads module from class path (there is no class path when using native
// executable)
// on the other hand, don't exclude /native/
Regex(".*/import1b\\.pkl"),
)
/**
* Avoid running tests for native binaries when those native binaries have not been built.
*/
override fun discover(discoveryRequest: EngineDiscoveryRequest, uniqueId: UniqueId): TestDescriptor {
/** Avoid running tests for native binaries when those native binaries have not been built. */
override fun discover(
discoveryRequest: EngineDiscoveryRequest,
uniqueId: UniqueId
): TestDescriptor {
if (!pklExecutablePath.exists()) {
// return empty descriptor w/o children
return EngineDescriptor(uniqueId, javaClass.simpleName)
@@ -234,15 +254,17 @@ abstract class AbstractNativeLanguageSnippetTestsEngine : AbstractLanguageSnippe
add(inputFile.toString())
}
val builder = ProcessBuilder()
.command(args)
val builder = ProcessBuilder().command(args)
val process = builder.start()
return try {
val (out, err) = listOf(process.inputStream, process.errorStream)
.map { it.reader().readText().withUnixLineEndings() }
val (out, err) =
listOf(process.inputStream, process.errorStream).map {
it.reader().readText().withUnixLineEndings()
}
val success = process.waitFor() == 0 && err.isBlank()
success to (out + err)
success to
(out + err)
.stripFilePaths()
.stripLineNumbers()
.stripWebsite()
@@ -280,7 +302,8 @@ class AlpineLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngin
}
// error message contains different file path on Windows
private val windowsExcludedTests get() = listOf(Regex(".*missingProjectDeps/bug\\.pkl"))
private val windowsExcludedTests
get() = listOf(Regex(".*missingProjectDeps/bug\\.pkl"))
class WindowsLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = PklExecutablePaths.windowsAmd64

View File

@@ -1,8 +1,23 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.net.URI
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.net.URI
class PClassInfoTest {
@Test

View File

@@ -1,13 +1,28 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.StringWriter
import javax.xml.parsers.DocumentBuilderFactory
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.util.IoUtils
import org.xml.sax.ErrorHandler
import org.xml.sax.InputSource
import org.xml.sax.SAXParseException
import org.pkl.core.util.IoUtils
class PListRendererTest {
@Test
@@ -28,8 +43,7 @@ class PListRendererTest {
@Test
fun `rendered document ends in newline`() {
val module = Evaluator.preconfigured()
.evaluate(ModuleSource.text("foo { bar = 0 }"))
val module = Evaluator.preconfigured().evaluate(ModuleSource.text("foo { bar = 0 }"))
val writer = StringWriter()
ValueRenderers.plist(writer, " ").renderDocument(module)
@@ -37,15 +51,15 @@ class PListRendererTest {
}
private fun parseAndValidateRenderedDocument(output: String) {
val builderFactory = DocumentBuilderFactory.newInstance().apply {
isValidating = true
}
val builderFactory = DocumentBuilderFactory.newInstance().apply { isValidating = true }
val builder = builderFactory.newDocumentBuilder().apply {
val builder =
builderFactory.newDocumentBuilder().apply {
setEntityResolver { _, _ ->
InputSource(PListRendererTest::class.java.getResourceAsStream("PropertyList-1.0.dtd"))
}
setErrorHandler(object : ErrorHandler {
setErrorHandler(
object : ErrorHandler {
override fun warning(exception: SAXParseException) {
throw exception
}
@@ -57,7 +71,8 @@ class PListRendererTest {
override fun fatalError(exception: SAXParseException) {
throw exception
}
})
}
)
}
builder.parse(output.byteInputStream())

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.net.URI
@@ -25,9 +40,7 @@ class PModuleTest {
@Test
fun `get unknown property`() {
val e = assertThrows<NoSuchPropertyException> {
pigeon.getProperty("other")
}
val e = assertThrows<NoSuchPropertyException> { pigeon.getProperty("other") }
assertThat(e)
.hasMessage(
@@ -48,7 +61,8 @@ class PModuleTest {
var objectVisited = false
var moduleVisited = false
val visitor = object : ValueVisitor {
val visitor =
object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
@@ -69,12 +83,7 @@ class PModuleTest {
assertThat(pigeon).isEqualTo(pigeon)
assertThat(pigeon.hashCode()).isEqualTo(pigeon.hashCode())
val pigeon2 = PModule(
moduleUri,
moduleName,
classInfo,
HashMap(properties)
)
val pigeon2 = PModule(moduleUri, moduleName, classInfo, HashMap(properties))
assertThat(pigeon2).isEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isEqualTo(pigeon.hashCode())
@@ -82,12 +91,7 @@ class PModuleTest {
@Test
fun `non-equal - different module uri`() {
val pigeon2 = PModule(
URI("other/module"),
moduleName,
classInfo,
properties
)
val pigeon2 = PModule(URI("other/module"), moduleName, classInfo, properties)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -95,12 +99,7 @@ class PModuleTest {
@Test
fun `non-equal - different module name`() {
val pigeon2 = PModule(
moduleUri,
"other.module",
classInfo,
properties
)
val pigeon2 = PModule(moduleUri, "other.module", classInfo, properties)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -108,12 +107,7 @@ class PModuleTest {
@Test
fun `non-equal - different property value`() {
val pigeon2 = PModule(
moduleUri,
moduleName,
classInfo,
mapOf("name" to "Pigeon", "age" to 21)
)
val pigeon2 = PModule(moduleUri, moduleName, classInfo, mapOf("name" to "Pigeon", "age" to 21))
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -121,12 +115,7 @@ class PModuleTest {
@Test
fun `non-equal - missing property`() {
val pigeon2 = PModule(
moduleUri,
moduleName,
classInfo,
mapOf("name" to "Pigeon")
)
val pigeon2 = PModule(moduleUri, moduleName, classInfo, mapOf("name" to "Pigeon"))
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -134,7 +123,8 @@ class PModuleTest {
@Test
fun `non-equal - extra property`() {
val pigeon2 = PModule(
val pigeon2 =
PModule(
moduleUri,
moduleName,
classInfo,
@@ -147,7 +137,6 @@ class PModuleTest {
@Test
fun `toString()`() {
assertThat(pigeon.toString())
.isEqualTo("test.module { name = Pigeon; age = 42 }")
assertThat(pigeon.toString()).isEqualTo("test.module { name = Pigeon; age = 42 }")
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,9 +1,24 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.net.URI
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import java.net.URI
class PObjectTest {
private val testUri = URI("repl:test")
@@ -29,9 +44,7 @@ class PObjectTest {
@Test
fun `get unknown property`() {
val e = assertThrows<NoSuchPropertyException> {
pigeon.getProperty("other")
}
val e = assertThrows<NoSuchPropertyException> { pigeon.getProperty("other") }
assertThat(e)
.hasMessage(
@@ -52,7 +65,8 @@ class PObjectTest {
var objectVisited = false
var moduleVisited = false
val visitor = object : ValueVisitor {
val visitor =
object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
@@ -73,10 +87,7 @@ class PObjectTest {
assertThat(pigeon).isEqualTo(pigeon)
assertThat(pigeon.hashCode()).isEqualTo(pigeon.hashCode())
val pigeon2 = PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
HashMap(properties)
)
val pigeon2 = PObject(PClassInfo.get("test", "Person", URI("repl:test")), HashMap(properties))
assertThat(pigeon2).isEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isEqualTo(pigeon.hashCode())
@@ -84,10 +95,7 @@ class PObjectTest {
@Test
fun `non-equal - different type`() {
val pigeon2 = PObject(
PClassInfo.get("test", "Other", URI("repl:Other")),
properties
)
val pigeon2 = PObject(PClassInfo.get("test", "Other", URI("repl:Other")), properties)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -95,7 +103,8 @@ class PObjectTest {
@Test
fun `non-equal - different property value`() {
val pigeon2 = PObject(
val pigeon2 =
PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 21)
)
@@ -106,10 +115,8 @@ class PObjectTest {
@Test
fun `non-equal - missing property`() {
val pigeon2 = PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon")
)
val pigeon2 =
PObject(PClassInfo.get("test", "Person", URI("repl:test")), mapOf("name" to "Pigeon"))
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -117,7 +124,8 @@ class PObjectTest {
@Test
fun `non-equal - extra property`() {
val pigeon2 = PObject(
val pigeon2 =
PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 42, "other" to true)
)
@@ -128,7 +136,6 @@ class PObjectTest {
@Test
fun `toString()`() {
assertThat(pigeon.toString())
.isEqualTo("test#Person { name = Pigeon; age = 42 }")
assertThat(pigeon.toString()).isEqualTo("test#Person { name = Pigeon; age = 42 }")
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.StringWriter
@@ -26,9 +41,8 @@ class PcfRendererTest {
@Test
fun `rendered document ends in newline`() {
val module = EvaluatorBuilder.preconfigured()
.build()
.evaluate(ModuleSource.text("foo { bar = 0 }"))
val module =
EvaluatorBuilder.preconfigured().build().evaluate(ModuleSource.text("foo { bar = 0 }"))
val writer = StringWriter()
ValueRenderers.pcf(writer, " ", false, false).renderDocument(module)
@@ -37,16 +51,19 @@ class PcfRendererTest {
@Test
fun `rendering with and without null properties`() {
val cases = listOf(
true to """
val cases =
listOf(
true to
"""
baz {
qux = 42
corge = List(null, 1337, null, "Hello World")
grault = Map("garply", null, "waldo", 42, "pigeon", null)
}
""".trimIndent(),
false to """
"""
.trimIndent(),
false to
"""
foo = null
bar = null
baz {
@@ -55,10 +72,13 @@ class PcfRendererTest {
corge = List(null, 1337, null, "Hello World")
grault = Map("garply", null, "waldo", 42, "pigeon", null)
}
""".trimIndent()
"""
.trimIndent()
)
val module = Evaluator.preconfigured().evaluate(
val module =
Evaluator.preconfigured()
.evaluate(
ModuleSource.text(
"""
foo = null
@@ -78,7 +98,8 @@ class PcfRendererTest {
["pigeon"] = null
}
}
""".trimIndent()
"""
.trimIndent()
)
)
for ((omitNullProperties, expected) in cases) {

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.*

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.*

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.StringWriter
@@ -10,22 +25,30 @@ class PropertiesRendererTest {
@Test
fun `render document`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(ModuleSource.modulePath("org/pkl/core/propertiesRendererTest.pkl"))
val module =
evaluator.evaluate(ModuleSource.modulePath("org/pkl/core/propertiesRendererTest.pkl"))
val writer = StringWriter()
val renderer = ValueRenderers.properties(writer, true, false)
renderer.renderDocument(module)
val output = writer.toString()
val expected = IoUtils.readClassPathResourceAsString(javaClass, "propertiesRendererTest.properties")
val expected =
IoUtils.readClassPathResourceAsString(javaClass, "propertiesRendererTest.properties")
assertThat(output).isEqualTo(expected)
}
@Test
fun `render unsupported document values`() {
val unsupportedValues = listOf(
"List()", "new Listing {}", "Map()", "new Mapping {}", "Set()",
"new PropertiesRenderer {}", "new Dynamic {}"
val unsupportedValues =
listOf(
"List()",
"new Listing {}",
"Map()",
"new Mapping {}",
"Set()",
"new PropertiesRenderer {}",
"new Dynamic {}"
)
unsupportedValues.forEach {
@@ -39,13 +62,13 @@ class PropertiesRendererTest {
@Test
fun `rendered document ends in newline`() {
val module = Evaluator.preconfigured()
.evaluate(ModuleSource.text("foo { bar = 0 }"))
val module = Evaluator.preconfigured().evaluate(ModuleSource.text("foo { bar = 0 }"))
for (omitNullProperties in listOf(false, true)) {
for (restrictCharSet in listOf(false, true)) {
val writer = StringWriter()
ValueRenderers.properties(writer, omitNullProperties, restrictCharSet).renderDocument(module)
ValueRenderers.properties(writer, omitNullProperties, restrictCharSet)
.renderDocument(module)
assertThat(writer.toString()).endsWith("\n")
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.*

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
@@ -11,7 +26,8 @@ import org.pkl.core.repl.ReplServer
import org.pkl.core.resource.ResourceReaders
class ReplServerTest {
private val server = ReplServer(
private val server =
ReplServer(
SecurityManagers.defaultManager,
HttpClient.dummyClient(),
Loggers.stdErr(),
@@ -20,10 +36,7 @@ class ReplServerTest {
ModuleKeyFactories.classPath(this::class.java.classLoader),
ModuleKeyFactories.file
),
listOf(
ResourceReaders.environmentVariable(),
ResourceReaders.externalProperty()
),
listOf(ResourceReaders.environmentVariable(), ResourceReaders.externalProperty()),
mapOf("NAME1" to "value1", "NAME2" to "value2"),
mapOf("name1" to "value1", "name2" to "value2"),
null,
@@ -35,12 +48,8 @@ class ReplServerTest {
@Test
fun `complete members of local property`() {
server.handleRequest(
ReplRequest.Eval("id", "local foo = new { bar = 10 }", false, false)
)
val responses = server.handleRequest(
ReplRequest.Completion("id", "foo")
)
server.handleRequest(ReplRequest.Eval("id", "local foo = new { bar = 10 }", false, false))
val responses = server.handleRequest(ReplRequest.Completion("id", "foo"))
assertThat(responses.size).isEqualTo(1)
@@ -51,9 +60,18 @@ class ReplServerTest {
assertThat(completionResponse.members.toSortedSet())
.isEqualTo(
sortedSetOf(
"default", "bar", "toList()", "toMap()", "getProperty(",
"getPropertyOrNull(", "hasProperty(", "ifNonNull(",
"length()", "getClass()", "toString()", "toTyped("
"default",
"bar",
"toList()",
"toMap()",
"getProperty(",
"getPropertyOrNull(",
"hasProperty(",
"ifNonNull(",
"length()",
"getClass()",
"toString()",
"toTyped("
)
)
}
@@ -61,9 +79,7 @@ class ReplServerTest {
@Test
fun `complete members of module import`() {
server.handleRequest(ReplRequest.Eval("id", "import \"pkl:test\"", false, false))
val responses = server.handleRequest(
ReplRequest.Completion("id", "test")
)
val responses = server.handleRequest(ReplRequest.Completion("id", "test"))
assertThat(responses.size).isEqualTo(1)
@@ -79,14 +95,11 @@ class ReplServerTest {
@Test
fun `complete members of 'this' expression`() {
val responses1 = server.handleRequest(
ReplRequest.Eval("id", "x = 1; function f() = 3", false, false)
)
val responses1 =
server.handleRequest(ReplRequest.Eval("id", "x = 1; function f() = 3", false, false))
assertThat(responses1.size).isEqualTo(0)
val responses2 = server.handleRequest(
ReplRequest.Completion("id", "this")
)
val responses2 = server.handleRequest(ReplRequest.Completion("id", "this"))
assertThat(responses2.size).isEqualTo(1)
val response = responses2[0]
@@ -96,8 +109,18 @@ class ReplServerTest {
assertThat(completionResponse.members.toSortedSet())
.isEqualTo(
sortedSetOf(
"output", "toDynamic()", "toMap()", "f()", "x", "ifNonNull(", "getClass()",
"getProperty(", "getPropertyOrNull(", "hasProperty(", "relativePathTo(", "toString()"
"output",
"toDynamic()",
"toMap()",
"f()",
"x",
"ifNonNull(",
"getClass()",
"getProperty(",
"getPropertyOrNull(",
"hasProperty(",
"relativePathTo(",
"toString()"
)
)
}
@@ -156,7 +179,10 @@ class ReplServerTest {
val result2 = makeEvalRequest("""greet(42)""")
assertThat(result2).isEqualTo("\"Hello, 42!\"")
val result3 = makeEvalRequest("function greet(name: String): String = \"Hello, \\(name)!\"; greet(\"Pigeon\") ")
val result3 =
makeEvalRequest(
"function greet(name: String): String = \"Hello, \\(name)!\"; greet(\"Pigeon\") "
)
assertThat(result3).isEqualTo("\"Hello, Pigeon!\"")
val result4 = makeFailingEvalRequest("""greet(44)""")
@@ -164,8 +190,7 @@ class ReplServerTest {
}
private fun makeEvalRequest(text: String): String {
val responses =
server.handleRequest(ReplRequest.Eval("id", text, false, false))
val responses = server.handleRequest(ReplRequest.Eval("id", text, false, false))
assertThat(responses).hasSize(1)
val response = responses[0]
@@ -176,8 +201,7 @@ class ReplServerTest {
}
private fun makeFailingEvalRequest(text: String): String {
val responses =
server.handleRequest(ReplRequest.Eval("id", text, false, false))
val responses = server.handleRequest(ReplRequest.Eval("id", text, false, false))
assertThat(responses).hasSize(1)
val response = responses[0]

View File

@@ -1,13 +1,28 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.walk
import java.nio.file.Path
import java.util.stream.Collectors
import kotlin.io.path.extension
import kotlin.io.path.isRegularFile
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.walk
/**
* These tests don't assert Pkl's implementation correctness, but rather that no debugging settings
@@ -22,15 +37,21 @@ class RepositoryHygiene {
@Test
fun `no output files exists for language snippets without an input`() {
val input = snippetsFolder.resolve("input")
val inputs = input.walk().filter {
it.extension == "pkl"
}.map {
val inputs =
input
.walk()
.filter { it.extension == "pkl" }
.map {
val path = input.relativize(it).toString()
inputRegex.replace(path, "$1$2")
}.collect(Collectors.toSet())
}
.collect(Collectors.toSet())
val output = snippetsFolder.resolve("output")
output.walk().filter { it.isRegularFile() }.forEach {
output
.walk()
.filter { it.isRegularFile() }
.forEach {
val out = output.relativize(it).toString()
checkOutputHasInput(inputs, out)
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.net.URI
@@ -12,7 +27,8 @@ import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.toPath
class SecurityManagersTest {
private val manager = SecurityManagers.standard(
private val manager =
SecurityManagers.standard(
listOf(Pattern.compile("test:foo/bar")),
listOf(Pattern.compile("env:FOO_BAR")),
{ uri -> if (uri.scheme == "one") 1 else if (uri.scheme == "two") 2 else 0 },
@@ -21,107 +37,74 @@ class SecurityManagersTest {
@Test
fun `checkResolveModule() - complete match`() {
val e = catchThrowable {
manager.checkResolveModule(URI("test:foo/bar"))
}
val e = catchThrowable { manager.checkResolveModule(URI("test:foo/bar")) }
assertThat(e).doesNotThrowAnyException()
}
@Test
fun `checkResolveModule() - partial match from start`() {
val e = catchThrowable {
manager.checkResolveModule(URI("test:foo/bar/baz"))
}
val e = catchThrowable { manager.checkResolveModule(URI("test:foo/bar/baz")) }
assertThat(e).doesNotThrowAnyException()
}
@Test
fun `checkResolveModule() - partial match not from start`() {
assertThrows<SecurityManagerException> {
manager.checkResolveModule(URI("other:test:foo/bar"))
}
assertThrows<SecurityManagerException> { manager.checkResolveModule(URI("other:test:foo/bar")) }
}
@Test
fun `checkResolveModule() - no match`() {
assertThrows<SecurityManagerException> {
manager.checkResolveModule(URI("other:uri"))
}
assertThrows<SecurityManagerException> { manager.checkResolveModule(URI("other:uri")) }
}
@Test
fun `checkResolveModule() - no match #2`() {
assertThrows<SecurityManagerException> {
manager.checkResolveModule(URI("test:foo/baz"))
}
assertThrows<SecurityManagerException> { manager.checkResolveModule(URI("test:foo/baz")) }
}
@Test
fun `checkReadResource() - complete match`() {
val e = catchThrowable {
manager.checkReadResource(URI("env:FOO_BAR"))
}
val e = catchThrowable { manager.checkReadResource(URI("env:FOO_BAR")) }
assertThat(e).doesNotThrowAnyException()
}
@Test
fun `checkReadResource() - partial match from start`() {
val e = catchThrowable {
manager.checkReadResource(URI("env:FOO_BAR_BAZ"))
}
val e = catchThrowable { manager.checkReadResource(URI("env:FOO_BAR_BAZ")) }
assertThat(e).doesNotThrowAnyException()
}
@Test
fun `checkReadResource() - partial match not from start`() {
assertThrows<SecurityManagerException> {
manager.checkReadResource(URI("other:env:FOO_BAR"))
}
assertThrows<SecurityManagerException> { manager.checkReadResource(URI("other:env:FOO_BAR")) }
}
@Test
fun `checkReadResource() - no match`() {
assertThrows<SecurityManagerException> {
manager.checkReadResource(URI("other:uri"))
}
assertThrows<SecurityManagerException> { manager.checkReadResource(URI("other:uri")) }
}
@Test
fun `checkReadResource() - no match #2`() {
assertThrows<SecurityManagerException> {
manager.checkReadResource(URI("env:FOO_BAZ"))
}
assertThrows<SecurityManagerException> { manager.checkReadResource(URI("env:FOO_BAZ")) }
}
@Test
fun `checkImportModule() - same trust level`() {
val e = catchThrowable {
manager.checkImportModule(
URI("one:foo"),
URI("one:bar")
)
}
val e = catchThrowable { manager.checkImportModule(URI("one:foo"), URI("one:bar")) }
assertThat(e).doesNotThrowAnyException()
}
@Test
fun `checkImportModule() - higher trust level`() {
assertThrows<SecurityManagerException> {
manager.checkImportModule(
URI("one:foo"),
URI("two:bar")
)
manager.checkImportModule(URI("one:foo"), URI("two:bar"))
}
}
@Test
fun `checkImportModule() - lower trust level`() {
val e = catchThrowable {
manager.checkImportModule(
URI("two:foo"),
URI("one:bar")
)
}
val e = catchThrowable { manager.checkImportModule(URI("two:foo"), URI("one:bar")) }
assertThat(e).doesNotThrowAnyException()
}
@@ -154,7 +137,8 @@ class SecurityManagersTest {
val rootDir = tempDir.resolve("root")
Files.createDirectory(rootDir)
val manager = SecurityManagers.standard(
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
@@ -174,7 +158,8 @@ class SecurityManagersTest {
fun `can resolve modules and resources under root dir - files don't exist`() {
val rootDir = "/foo/bar".toPath()
val manager = SecurityManagers.standard(
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
@@ -189,11 +174,14 @@ class SecurityManagersTest {
}
@Test
fun `cannot resolve modules and resources outside root dir - files do exist`(@TempDir tempDir: Path) {
fun `cannot resolve modules and resources outside root dir - files do exist`(
@TempDir tempDir: Path
) {
val rootDir = tempDir.resolve("root")
Files.createDirectory(rootDir)
val manager = SecurityManagers.standard(
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
@@ -202,30 +190,23 @@ class SecurityManagersTest {
val path = rootDir.resolve("../baz.pkl")
Files.createFile(path)
assertThrows<SecurityManagerException> {
manager.checkResolveModule(path.toUri())
}
assertThrows<SecurityManagerException> {
manager.checkReadResource(path.toUri())
}
assertThrows<SecurityManagerException> { manager.checkResolveModule(path.toUri()) }
assertThrows<SecurityManagerException> { manager.checkReadResource(path.toUri()) }
val symlink = rootDir.resolve("qux")
Files.createSymbolicLink(symlink, tempDir)
val path2 = symlink.resolve("baz2.pkl")
Files.createFile(path2)
assertThrows<SecurityManagerException> {
manager.checkResolveModule(path2.toUri())
}
assertThrows<SecurityManagerException> {
manager.checkReadResource(path2.toUri())
}
assertThrows<SecurityManagerException> { manager.checkResolveModule(path2.toUri()) }
assertThrows<SecurityManagerException> { manager.checkReadResource(path2.toUri()) }
}
@Test
fun `cannot resolve modules and resources outside root dir - files don't exist`() {
val rootDir = "/foo/bar".toPath()
val manager = SecurityManagers.standard(
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,

View File

@@ -1,9 +1,24 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.pkl.commons.test.PackageServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.pkl.commons.test.PackageServer
import org.pkl.core.http.HttpClient
class StackFrameTransformersTest {
@@ -13,20 +28,12 @@ class StackFrameTransformersTest {
fun replacePackageUriWithSourceCodeUrl() {
PackageServer().use { server ->
val httpClient = HttpClient.builder().setTestPort(server.port).build()
EvaluatorBuilder.preconfigured()
.setHttpClient(httpClient)
.build().use {
val frame = StackFrame(
"package://localhost:0/birds@0.5.0#/Bird.pkl",
null,
listOf(),
1,
1,
2,
2)
val transformed =
StackFrameTransformers.replacePackageUriWithSourceCodeUrl.apply(frame)
assertThat(transformed.moduleUri).isEqualTo("https://example.com/birds/v0.5.0/blob/Bird.pkl#L1-L2")
EvaluatorBuilder.preconfigured().setHttpClient(httpClient).build().use {
val frame =
StackFrame("package://localhost:0/birds@0.5.0#/Bird.pkl", null, listOf(), 1, 1, 2, 2)
val transformed = StackFrameTransformers.replacePackageUriWithSourceCodeUrl.apply(frame)
assertThat(transformed.moduleUri)
.isEqualTo("https://example.com/birds/v0.5.0/blob/Bird.pkl#L1-L2")
}
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import org.assertj.core.api.Assertions.assertThat
@@ -37,23 +52,16 @@ class VersionTest {
@Test
fun `parse invalid version`() {
assertThat(Version.parseOrNull("not a version number"))
.isNull()
assertThat(Version.parseOrNull("not a version number")).isNull()
assertThrows<IllegalArgumentException> {
Version.parse("not a version number")
}
assertThrows<IllegalArgumentException> { Version.parse("not a version number") }
}
@Test
fun `parse too large version`() {
assertThrows<IllegalArgumentException> {
Version.parse("not a version number")
}
assertThrows<IllegalArgumentException> { Version.parse("not a version number") }
assertThrows<IllegalArgumentException> {
Version.parse("999999999999999.0.0")
}
assertThrows<IllegalArgumentException> { Version.parse("999999999999999.0.0") }
}
@Test
@@ -66,7 +74,8 @@ class VersionTest {
@Test
fun withMethods() {
val version = Version.parse("0.0.0")
val version =
Version.parse("0.0.0")
.withMajor(1)
.withMinor(2)
.withPatch(3)
@@ -75,7 +84,8 @@ class VersionTest {
assertThat(version).isEqualTo(Version.parse("1.2.3-rc.1+456.789"))
val version2 = Version.parse("0.0.0")
val version2 =
Version.parse("0.0.0")
.withBuild("456.789")
.withPreRelease("rc.1")
.withPatch(3)
@@ -87,116 +97,57 @@ class VersionTest {
@Test
fun `compareTo()`() {
assertThat(
Version(1, 2, 3, null, null).compareTo(
Version(1, 2, 3, null, null)
)
).isEqualTo(0)
assertThat(
Version(1, 2, 3, "SNAPSHOT", null).compareTo(
Version(1, 2, 3, "SNAPSHOT", null)
)
).isEqualTo(0)
assertThat(
Version(1, 2, 3, "alpha", null).compareTo(
Version(1, 2, 3, "alpha", null)
)
).isEqualTo(0)
assertThat(
Version(1, 2, 3, "alpha", null).compareTo(
Version(1, 2, 3, "alpha", "build123")
)
).isEqualTo(0)
assertThat(Version(1, 2, 3, null, null).compareTo(Version(1, 2, 3, null, null))).isEqualTo(0)
assertThat(Version(1, 2, 3, "SNAPSHOT", null).compareTo(Version(1, 2, 3, "SNAPSHOT", null)))
.isEqualTo(0)
assertThat(Version(1, 2, 3, "alpha", null).compareTo(Version(1, 2, 3, "alpha", null)))
.isEqualTo(0)
assertThat(Version(1, 2, 3, "alpha", null).compareTo(Version(1, 2, 3, "alpha", "build123")))
.isEqualTo(0)
assertThat(
Version(1, 2, 3, null, null).compareTo(
Version(2, 2, 3, null, null)
)
).isLessThan(0)
assertThat(
Version(1, 2, 3, null, null).compareTo(
Version(1, 3, 3, null, null)
)
).isLessThan(0)
assertThat(
Version(1, 2, 3, null, null).compareTo(
Version(1, 2, 4, null, null)
)
).isLessThan(0)
assertThat(Version(1, 2, 3, null, null).compareTo(Version(2, 2, 3, null, null))).isLessThan(0)
assertThat(Version(1, 2, 3, null, null).compareTo(Version(1, 3, 3, null, null))).isLessThan(0)
assertThat(Version(1, 2, 3, null, null).compareTo(Version(1, 2, 4, null, null))).isLessThan(0)
assertThat(
Version(2, 2, 3, null, null).compareTo(
Version(1, 2, 3, null, null)
)
).isGreaterThan(0)
assertThat(
Version(1, 3, 3, null, null).compareTo(
Version(1, 2, 3, null, null)
)
).isGreaterThan(0)
assertThat(
Version(1, 2, 4, null, null).compareTo(
Version(1, 2, 3, null, null)
)
).isGreaterThan(0)
assertThat(Version(2, 2, 3, null, null).compareTo(Version(1, 2, 3, null, null)))
.isGreaterThan(0)
assertThat(Version(1, 3, 3, null, null).compareTo(Version(1, 2, 3, null, null)))
.isGreaterThan(0)
assertThat(Version(1, 2, 4, null, null).compareTo(Version(1, 2, 3, null, null)))
.isGreaterThan(0)
assertThat(
Version(1, 2, 3, "SNAPSHOT", null).compareTo(
Version(1, 2, 3, null, null)
)
).isLessThan(0)
assertThat(
Version(1, 2, 3, "alpha", null).compareTo(
Version(1, 2, 3, "beta", null)
)
).isLessThan(0)
assertThat(
Version(1, 2, 3, "alpha", "build123").compareTo(
Version(1, 2, 3, "beta", null)
)
).isLessThan(0)
assertThat(Version(1, 2, 3, "SNAPSHOT", null).compareTo(Version(1, 2, 3, null, null)))
.isLessThan(0)
assertThat(Version(1, 2, 3, "alpha", null).compareTo(Version(1, 2, 3, "beta", null)))
.isLessThan(0)
assertThat(Version(1, 2, 3, "alpha", "build123").compareTo(Version(1, 2, 3, "beta", null)))
.isLessThan(0)
assertThat(
Version(1, 2, 3, null, null).compareTo(
Version(1, 2, 3, "SNAPSHOT", null)
)
).isGreaterThan(0)
assertThat(
Version(1, 2, 3, "beta", null).compareTo(
Version(1, 2, 3, "alpha", "build123")
)
).isGreaterThan(0)
assertThat(Version(1, 2, 3, null, null).compareTo(Version(1, 2, 3, "SNAPSHOT", null)))
.isGreaterThan(0)
assertThat(Version(1, 2, 3, "beta", null).compareTo(Version(1, 2, 3, "alpha", "build123")))
.isGreaterThan(0)
}
@Test
fun `compare version with too large numeric pre-release identifier`() {
// error is deferred until compareTo(), but should be good enough
assertThrows<IllegalArgumentException> {
Version(1, 2, 3, "999", null).compareTo(
Version(1, 2, 3, "9999999999999999999", null)
)
Version(1, 2, 3, "999", null).compareTo(Version(1, 2, 3, "9999999999999999999", null))
}
}
@Test
fun `equals()`() {
assertThat(Version(1, 2, 3, null, null))
.isEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "SNAPSHOT", null))
.isEqualTo(Version(1, 2, 3, "SNAPSHOT", null))
assertThat(Version(1, 2, 3, "alpha", null))
.isEqualTo(Version(1, 2, 3, "alpha", null))
assertThat(Version(1, 2, 3, "beta", "build123"))
.isEqualTo(Version(1, 2, 3, "beta", "build456"))
assertThat(Version(1, 2, 3, null, null)).isEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "SNAPSHOT", null)).isEqualTo(Version(1, 2, 3, "SNAPSHOT", null))
assertThat(Version(1, 2, 3, "alpha", null)).isEqualTo(Version(1, 2, 3, "alpha", null))
assertThat(Version(1, 2, 3, "beta", "build123")).isEqualTo(Version(1, 2, 3, "beta", "build456"))
assertThat(Version(1, 3, 3, null, null))
.isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 4, null, null))
.isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "SNAPSHOT", null))
.isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "beta", null))
.isNotEqualTo(Version(1, 2, 3, "alpha", null))
assertThat(Version(1, 3, 3, null, null)).isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 4, null, null)).isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "SNAPSHOT", null)).isNotEqualTo(Version(1, 2, 3, null, null))
assertThat(Version(1, 2, 3, "beta", null)).isNotEqualTo(Version(1, 2, 3, "alpha", null))
}
@Test

View File

@@ -1,12 +1,27 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core
import java.io.StringWriter
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.Test
import org.pkl.core.util.IoUtils
import org.snakeyaml.engine.v2.api.Load
import org.snakeyaml.engine.v2.api.LoadSettings
import org.pkl.core.util.IoUtils
class YamlRendererTest {
@Test
@@ -21,13 +36,15 @@ class YamlRendererTest {
val expected = IoUtils.readClassPathResourceAsString(javaClass, "rendererTest.yaml")
assertThat(output.trim()).isEqualTo(expected.trim())
assertThatCode { Load(LoadSettings.builder().build()).loadFromString(output) }.doesNotThrowAnyException()
assertThatCode { Load(LoadSettings.builder().build()).loadFromString(output) }
.doesNotThrowAnyException()
}
@Test
fun `render YAML stream`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
val module =
evaluator.evaluate(
ModuleSource.text(
"""
stream = new Listing {
@@ -48,7 +65,8 @@ class YamlRendererTest {
"Blue Rock Ltd."
12345
}
""".trimIndent()
"""
.trimIndent()
)
)
@@ -58,7 +76,8 @@ class YamlRendererTest {
renderer.renderDocument(module.getProperty("stream"))
val output = writer.toString()
assertThat(output.trim()).isEqualTo(
assertThat(output.trim())
.isEqualTo(
"""
name: Pigeon
age: 42
@@ -72,14 +91,14 @@ class YamlRendererTest {
three: 3
--- Blue Rock Ltd.
--- 12345
""".trimIndent()
"""
.trimIndent()
)
}
@Test
fun `rendered document ends in newline`() {
val module = Evaluator.preconfigured()
.evaluate(ModuleSource.text("foo { bar = 0 }"))
val module = Evaluator.preconfigured().evaluate(ModuleSource.text("foo { bar = 0 }"))
for (omitNullProperties in listOf(false, true)) {
for (isStream in listOf(false, true)) {
@@ -93,7 +112,8 @@ class YamlRendererTest {
@Test
fun `render truthy strings, octals and number-like strings`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
val module =
evaluator.evaluate(
ModuleSource.text(
"""
num1 = "50"
@@ -102,7 +122,8 @@ class YamlRendererTest {
yes = "yes"
truth = "true"
octalNumber = "0777"
""".trimIndent()
"""
.trimIndent()
)
)
@@ -112,7 +133,8 @@ class YamlRendererTest {
renderer.renderDocument(module)
val output = writer.toString()
assertThat(output.trim()).isEqualTo(
assertThat(output.trim())
.isEqualTo(
"""
num1: '50'
num2: '50.123'
@@ -120,7 +142,8 @@ class YamlRendererTest {
'yes': 'yes'
truth: 'true'
octalNumber: '0777'
""".trimIndent()
"""
.trimIndent()
)
}
}

View File

@@ -1,15 +1,31 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.ast.builder
import org.pkl.core.SecurityManagers
import org.pkl.core.module.ModuleKeys
import java.net.URI
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.net.URI
import org.pkl.core.SecurityManagers
import org.pkl.core.module.ModuleKeys
class ImportsAndReadsParserTest {
@Test
fun parse() {
val moduleText = """
val moduleText =
"""
amends "foo.pkl"
import "bar.pkl"
@@ -27,10 +43,14 @@ class ImportsAndReadsParserTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
val moduleKey = ModuleKeys.synthetic(URI("repl:text"), moduleText)
val imports = ImportsAndReadsParser.parse(moduleKey, moduleKey.resolve(SecurityManagers.defaultManager))
assertThat(imports?.map { it.first }).hasSameElementsAs(listOf(
val imports =
ImportsAndReadsParser.parse(moduleKey, moduleKey.resolve(SecurityManagers.defaultManager))
assertThat(imports?.map { it.first })
.hasSameElementsAs(
listOf(
"foo.pkl",
"bar.pkl",
"bazzy/buz.pkl",
@@ -39,6 +59,7 @@ class ImportsAndReadsParserTest {
"/some/dir/chown.txt",
"/some/dir/chowner.txt",
"/some/dir/*.txt"
))
)
)
}
}

View File

@@ -1,11 +1,26 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import java.net.URI
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
class DummyHttpClientTest {
@Test
@@ -13,13 +28,9 @@ class DummyHttpClientTest {
val client = HttpClient.dummyClient()
val request = HttpRequest.newBuilder(URI("https://example.com")).build()
assertThrows<AssertionError> {
client.send(request, HttpResponse.BodyHandlers.discarding())
}
assertThrows<AssertionError> { client.send(request, HttpResponse.BodyHandlers.discarding()) }
assertThrows<AssertionError> {
client.send(request, HttpResponse.BodyHandlers.discarding())
}
assertThrows<AssertionError> { client.send(request, HttpResponse.BodyHandlers.discarding()) }
}
@Test

View File

@@ -1,12 +1,20 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.test.FileTestUtils
import org.pkl.core.Release
import java.net.URI
import java.net.http.HttpRequest
import java.net.http.HttpResponse
@@ -14,19 +22,25 @@ import java.nio.file.Path
import java.time.Duration
import kotlin.io.path.createFile
import kotlin.io.path.readBytes
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.test.FileTestUtils
import org.pkl.core.Release
class HttpClientTest {
@Test
fun `can build default client`() {
val client = assertDoesNotThrow {
HttpClient.builder().build()
}
val client = assertDoesNotThrow { HttpClient.builder().build() }
assertThat(client).isInstanceOf(RequestRewritingClient::class.java)
client as RequestRewritingClient
val release = Release.current()
assertThat(client.userAgent).isEqualTo("Pkl/${release.version()} (${release.os()}; ${release.flavor()})")
assertThat(client.userAgent)
.isEqualTo("Pkl/${release.version()} (${release.os()}; ${release.flavor()})")
assertThat(client.requestTimeout).isEqualTo(Duration.ofSeconds(60))
assertThat(client.delegate).isInstanceOf(JdkHttpClient::class.java)
@@ -37,7 +51,8 @@ class HttpClientTest {
@Test
fun `can build custom client`() {
val client = HttpClient.builder()
val client =
HttpClient.builder()
.setUserAgent("Agent 1")
.setRequestTimeout(Duration.ofHours(86))
.setConnectTimeout(Duration.ofMinutes(42))
@@ -68,18 +83,15 @@ class HttpClientTest {
fun `certificate file cannot be empty`(@TempDir tempDir: Path) {
val file = tempDir.resolve("certs.pem").createFile()
val e = assertThrows<HttpClientInitException> {
HttpClient.builder().addCertificates(file).build()
}
val e =
assertThrows<HttpClientInitException> { HttpClient.builder().addCertificates(file).build() }
assertThat(e).hasMessageContaining("empty")
}
@Test
fun `can load built-in certificates`() {
assertDoesNotThrow {
HttpClient.builder().build()
}
assertDoesNotThrow { HttpClient.builder().build() }
}
@Test

View File

@@ -1,36 +1,45 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import java.net.URI
import java.net.http.HttpRequest
import java.net.http.HttpResponse.BodyHandlers
import java.nio.file.Path
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.createTempFile
import org.pkl.commons.writeString
import java.net.URI
import java.net.http.HttpRequest
import java.net.http.HttpResponse.BodyHandlers
import java.nio.file.Path
class LazyHttpClientTest {
@Test
fun `builds underlying client on first send`(@TempDir tempDir: Path) {
val certFile = tempDir.resolve("cert.pem").apply { writeString("broken") }
val client = HttpClient.builder()
.addCertificates(certFile)
.buildLazily()
val client = HttpClient.builder().addCertificates(certFile).buildLazily()
val request = HttpRequest.newBuilder(URI("https://example.com")).build()
assertThrows<HttpClientInitException> {
client.send(request, BodyHandlers.discarding())
}
assertThrows<HttpClientInitException> { client.send(request, BodyHandlers.discarding()) }
}
@Test
fun `does not build underlying client unnecessarily`(@TempDir tempDir: Path) {
val certFile = tempDir.createTempFile().apply { writeString("broken") }
val client = HttpClient.builder()
.addCertificates(certFile)
.buildLazily()
val client = HttpClient.builder().addCertificates(certFile).buildLazily()
assertDoesNotThrow {
client.close()

View File

@@ -1,9 +1,24 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import java.net.URI
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.net.URI
@Suppress("HttpUrlsUsage")
class NoProxyRuleTest {

View File

@@ -1,8 +1,23 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import org.pkl.commons.test.FakeHttpResponse
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import org.pkl.commons.test.FakeHttpResponse
class RequestCapturingClient : HttpClient {
lateinit var request: HttpRequest

View File

@@ -1,14 +1,29 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.http
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatList
import org.junit.jupiter.api.Test
import java.net.URI
import java.net.http.HttpClient as JdkHttpClient
import java.net.http.HttpRequest
import java.net.http.HttpRequest.BodyPublishers
import java.net.http.HttpResponse.BodyHandlers
import java.time.Duration
import java.net.http.HttpClient as JdkHttpClient
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatList
import org.junit.jupiter.api.Test
class RequestRewritingClientTest {
private val captured = RequestCapturingClient()
@@ -25,7 +40,8 @@ class RequestRewritingClientTest {
@Test
fun `overrides existing User-Agent headers`() {
val request = HttpRequest.newBuilder(exampleUri)
val request =
HttpRequest.newBuilder(exampleUri)
.header("User-Agent", "Agent 1")
.header("User-Agent", "Agent 2")
.build()
@@ -44,9 +60,7 @@ class RequestRewritingClientTest {
@Test
fun `leaves existing request timeout intact`() {
val request = HttpRequest.newBuilder(exampleUri)
.timeout(Duration.ofMinutes(33))
.build()
val request = HttpRequest.newBuilder(exampleUri).timeout(Duration.ofMinutes(33)).build()
client.send(request, BodyHandlers.discarding())
@@ -62,9 +76,7 @@ class RequestRewritingClientTest {
@Test
fun `leaves existing HTTP version intact`() {
val request = HttpRequest.newBuilder(exampleUri)
.version(JdkHttpClient.Version.HTTP_1_1)
.build()
val request = HttpRequest.newBuilder(exampleUri).version(JdkHttpClient.Version.HTTP_1_1).build()
client.send(request, BodyHandlers.discarding())
@@ -82,9 +94,7 @@ class RequestRewritingClientTest {
@Test
fun `leaves explicit method intact`() {
val request = HttpRequest.newBuilder(exampleUri)
.DELETE()
.build()
val request = HttpRequest.newBuilder(exampleUri).DELETE().build()
client.send(request, BodyHandlers.discarding())
@@ -94,9 +104,7 @@ class RequestRewritingClientTest {
@Test
fun `leaves body publisher intact`() {
val publisher = BodyPublishers.ofString("body")
val request = HttpRequest.newBuilder(exampleUri)
.PUT(publisher)
.build()
val request = HttpRequest.newBuilder(exampleUri).PUT(publisher).build()
client.send(request, BodyHandlers.discarding())
@@ -123,5 +131,3 @@ class RequestRewritingClientTest {
assertThat(captured.request.uri().port).isEqualTo(0)
}
}

View File

@@ -1,5 +1,24 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.outputStream
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
@@ -7,10 +26,6 @@ import org.pkl.commons.createParentDirectories
import org.pkl.commons.toPath
import org.pkl.commons.writeString
import org.pkl.core.SecurityManagers
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.outputStream
class ModuleKeyFactoriesTest {
@Test
@@ -78,9 +93,7 @@ class ModuleKeyFactoriesTest {
fun `module path - jar files`(@TempDir tempDir: Path) {
val jarFile = tempDir.resolve("test.jar")
jarFile.outputStream().use { outStream ->
javaClass.getResourceAsStream("test.jar")!!.use { inStream ->
inStream.copyTo(outStream)
}
javaClass.getResourceAsStream("test.jar")!!.use { inStream -> inStream.copyTo(outStream) }
}
val factory = ModuleKeyFactories.modulePath(ModulePathResolver(listOf(jarFile)))

View File

@@ -1,19 +1,34 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import org.pkl.commons.createParentDirectories
import org.pkl.commons.toPath
import org.pkl.commons.writeString
import org.pkl.core.SecurityManagers
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import java.io.FileNotFoundException
import java.net.MalformedURLException
import java.net.URI
import java.net.URISyntaxException
import java.nio.file.Path
import kotlin.io.path.createFile
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.createParentDirectories
import org.pkl.commons.toPath
import org.pkl.commons.writeString
import org.pkl.core.SecurityManagers
class ModuleKeysTest {
private val securityManager = SecurityManagers.defaultManager
@@ -46,9 +61,7 @@ class ModuleKeysTest {
@Test
fun `standard library - wrong scheme`() {
assertThrows<IllegalArgumentException> {
ModuleKeys.standardLibrary(URI("other:base"))
}
assertThrows<IllegalArgumentException> { ModuleKeys.standardLibrary(URI("other:base")) }
}
@Test
@@ -97,16 +110,16 @@ class ModuleKeysTest {
@Test
fun `class path - module not found`() {
val key = ModuleKeys.classPath(URI("modulepath:/non/existing"), ModuleKeysTest::class.java.classLoader)
val key =
ModuleKeys.classPath(URI("modulepath:/non/existing"), ModuleKeysTest::class.java.classLoader)
assertThrows<FileNotFoundException> {
key.resolve(SecurityManagers.defaultManager)
}
assertThrows<FileNotFoundException> { key.resolve(SecurityManagers.defaultManager) }
}
@Test
fun `class path - missing leading slash`() {
val e = assertThrows<IllegalArgumentException> {
val e =
assertThrows<IllegalArgumentException> {
ModuleKeys.classPath(URI("modulepath:foo/bar.pkl"), ModuleKeysTest::class.java.classLoader)
}
assertThat(e).hasMessageContaining("`/`")
@@ -127,10 +140,8 @@ class ModuleKeysTest {
val resolvedKey = key.resolve(securityManager)
assertThat(resolvedKey.uri.scheme)
.isEqualTo("file")
assertThat(resolvedKey.loadSource())
.isEqualTo("age = 40")
assertThat(resolvedKey.uri.scheme).isEqualTo("file")
assertThat(resolvedKey.loadSource()).isEqualTo("age = 40")
}
@Test
@@ -144,14 +155,13 @@ class ModuleKeysTest {
fun `module path - module not found`() {
val key = ModuleKeys.modulePath(URI("modulepath:/non/existing"), ModulePathResolver(listOf()))
assertThrows<FileNotFoundException> {
key.resolve(SecurityManagers.defaultManager)
}
assertThrows<FileNotFoundException> { key.resolve(SecurityManagers.defaultManager) }
}
@Test
fun `module path - missing leading slash`() {
val e = assertThrows<IllegalArgumentException> {
val e =
assertThrows<IllegalArgumentException> {
ModuleKeys.modulePath(URI("modulepath:foo/bar.pkl"), ModulePathResolver(listOf()))
}
assertThat(e).hasMessageContaining("`/`")
@@ -159,7 +169,8 @@ class ModuleKeysTest {
@Test
fun `package - no version`() {
val e = assertThrows<URISyntaxException> {
val e =
assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://localhost:0/birds#/Bird.pkl"))
}
assertThat(e).hasMessageContaining("A package URI must have its path suffixed by its version")
@@ -167,7 +178,8 @@ class ModuleKeysTest {
@Test
fun `package - invalid semver`() {
val e = assertThrows<URISyntaxException> {
val e =
assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://localhost:0/birds@notAVersion#/Bird.pkl"))
}
assertThat(e).hasMessageContaining("`notAVersion` could not be parsed")
@@ -175,30 +187,23 @@ class ModuleKeysTest {
@Test
fun `package - missing leading slash`() {
val e = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package:invalid"))
}
assertThat(e).hasMessageContaining("Module URI `package:invalid` is missing a `/` after `package:`")
val e = assertThrows<URISyntaxException> { ModuleKeys.pkg(URI("package:invalid")) }
assertThat(e)
.hasMessageContaining("Module URI `package:invalid` is missing a `/` after `package:`")
}
@Test
fun `package - missing authority`() {
val e = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package:/not/a/valid/path"))
}
val e = assertThrows<URISyntaxException> { ModuleKeys.pkg(URI("package:/not/a/valid/path")) }
assertThat(e).hasMessageContaining("Package URIs must have an authority component")
val e2 = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package:///not/a/valid/path"))
}
val e2 = assertThrows<URISyntaxException> { ModuleKeys.pkg(URI("package:///not/a/valid/path")) }
assertThat(e2).hasMessageContaining("Package URIs must have an authority component")
}
@Test
fun `package - missing path`() {
val e = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://example.com"))
}
val e = assertThrows<URISyntaxException> { ModuleKeys.pkg(URI("package://example.com")) }
assertThat(e).hasMessageContaining("Package URIs must have a path component")
}
@@ -234,11 +239,8 @@ class ModuleKeysTest {
val uri = URI("repl:foo")
val key = ModuleKeys.genericUrl(uri)
val e = assertThrows<MalformedURLException> {
key.resolve(securityManager)
}
val e = assertThrows<MalformedURLException> { key.resolve(securityManager) }
assertThat(e)
.hasMessage("unknown protocol: repl")
assertThat(e).hasMessage("unknown protocol: repl")
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import org.assertj.core.api.Assertions.assertThatCode

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import java.net.URI
@@ -26,9 +41,7 @@ class ResolvedModuleKeysTest {
fun `url()`(@TempDir tempDir: Path) {
val path = tempDir.createTempFile().writeString("x = 1")
val resolvedUri = URI("test:resolved.uri")
val resolved = ResolvedModuleKeys.url(
module, resolvedUri, path.toUri().toURL()
)
val resolved = ResolvedModuleKeys.url(module, resolvedUri, path.toUri().toURL())
assertThat(resolved.original).isSameAs(module)
assertThat(resolved.uri).isEqualTo(resolvedUri)

View File

@@ -1,22 +1,36 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import java.net.URI
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.pkl.core.Evaluator
import org.pkl.core.ModuleSource
import org.pkl.core.PClassInfo
import org.pkl.core.PModule
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import java.net.URI
class ServiceProviderTest {
@Test
fun `load module through service provider`() {
val module = Evaluator
.preconfigured()
.evaluate(ModuleSource.uri(URI("test:foo")))
val module = Evaluator.preconfigured().evaluate(ModuleSource.uri(URI("test:foo")))
val uri = URI("modulepath:/org/pkl/core/module/testFactoryTest.pkl")
Assertions.assertThat(module).isEqualTo(
Assertions.assertThat(module)
.isEqualTo(
PModule(
uri,
"testFactoryTest",

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.module
import java.net.URI

View File

@@ -1,21 +1,41 @@
package org.pkl.core.packages;
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.packages
import org.pkl.core.Version
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.io.ByteArrayOutputStream
import java.net.URI
import java.nio.charset.StandardCharsets
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.Version
class DependencyMetadataTest {
private val dependencyMetadata = DependencyMetadata(
private val dependencyMetadata =
DependencyMetadata(
"my-proj-name",
PackageUri("package://example.com/my-proj-name@0.10.0"),
Version.parse("0.10.0"),
URI("https://example.com/foo/bar@0.5.3.zip"),
Checksums("abc123"),
mapOf(
"foo" to Dependency.RemoteDependency(PackageUri("package://example.com/foo@0.5.3"), Checksums("abc123")),
"foo" to
Dependency.RemoteDependency(
PackageUri("package://example.com/foo@0.5.3"),
Checksums("abc123")
),
),
"https://example.com/my/source/0.5.3/blob%{path}#L%{line}-L%{endLine}",
URI("https://example.com/my/source"),
@@ -27,7 +47,8 @@ class DependencyMetadataTest {
"Some package description"
)
private val dependencyMetadataStr = """
private val dependencyMetadataStr =
"""
{
"name": "my-proj-name",
"packageUri": "package://example.com/my-proj-name@0.10.0",
@@ -55,7 +76,8 @@ class DependencyMetadataTest {
"issueTracker": "https://example.com/issues",
"description": "Some package description"
}
""".trimIndent()
"""
.trimIndent()
@Test
fun parse() {
@@ -65,7 +87,8 @@ class DependencyMetadataTest {
@Test
fun writeTo() {
val str = ByteArrayOutputStream()
val str =
ByteArrayOutputStream()
.apply { dependencyMetadata.writeTo(this) }
.toString(StandardCharsets.UTF_8)
assertThat(str).isEqualTo(dependencyMetadataStr)

View File

@@ -1,5 +1,25 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.packages
import java.io.FileNotFoundException
import java.io.IOException
import java.nio.charset.StandardCharsets
import kotlin.io.path.exists
import kotlin.io.path.readBytes
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.AfterAll
@@ -11,21 +31,17 @@ import org.pkl.commons.readString
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.listFilesRecursively
import org.pkl.core.http.HttpClient
import org.pkl.core.SecurityManagers
import org.pkl.core.http.HttpClient
import org.pkl.core.module.PathElement
import java.io.FileNotFoundException
import java.io.IOException
import java.nio.charset.StandardCharsets
import kotlin.io.path.exists
import kotlin.io.path.readBytes
class PackageResolversTest {
abstract class AbstractPackageResolverTest {
abstract val resolver: PackageResolver
private val packageRoot = FileTestUtils.rootProjectDir.resolve("pkl-commons-test/src/main/files/packages")
private val packageRoot =
FileTestUtils.rootProjectDir.resolve("pkl-commons-test/src/main/files/packages")
companion object {
private val packageServer = PackageServer()
@@ -46,21 +62,19 @@ class PackageResolversTest {
@Test
fun `get module bytes`() {
val expectedBirdModule = packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8)
val expectedBirdModule =
packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8)
val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl")
val birdModule = resolver
.getBytes(assetUri, false, null)
.toString(StandardCharsets.UTF_8)
val birdModule = resolver.getBytes(assetUri, false, null).toString(StandardCharsets.UTF_8)
assertThat(birdModule).isEqualTo(expectedBirdModule)
}
@Test
fun `get directory`() {
val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/")
val err = assertThrows<IOException> {
resolver
.getBytes(assetUri, false, null)
.toString(StandardCharsets.UTF_8)
val err =
assertThrows<IOException> {
resolver.getBytes(assetUri, false, null).toString(StandardCharsets.UTF_8)
}
assertThat(err).hasMessage("Is a directory")
}
@@ -68,36 +82,37 @@ class PackageResolversTest {
@Test
fun `get directory, allowing directory reads`() {
val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/")
val bytes = resolver
.getBytes(assetUri, true, null)
.toString(StandardCharsets.UTF_8)
assertThat(bytes).isEqualTo("""
val bytes = resolver.getBytes(assetUri, true, null).toString(StandardCharsets.UTF_8)
assertThat(bytes)
.isEqualTo(
"""
Bird.pkl
allFruit.pkl
catalog
catalog.pkl
some
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `get module bytes resolving path`() {
val expectedBirdModule = packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8)
val expectedBirdModule =
packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8)
val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/foo/../Bird.pkl")
val birdModule = resolver
.getBytes(assetUri, false, null)
.toString(StandardCharsets.UTF_8)
val birdModule = resolver.getBytes(assetUri, false, null).toString(StandardCharsets.UTF_8)
assertThat(birdModule).isEqualTo(expectedBirdModule)
}
@Test
fun `list path elements at root`() {
// cast to set to avoid sort issues
val elements = resolver
.listElements(PackageAssetUri("package://localhost:0/birds@0.5.0#/"), null)
.toSet()
assertThat(elements).isEqualTo(
val elements =
resolver.listElements(PackageAssetUri("package://localhost:0/birds@0.5.0#/"), null).toSet()
assertThat(elements)
.isEqualTo(
setOf(
PathElement("some", true),
PathElement("catalog", true),
@@ -110,25 +125,32 @@ class PackageResolversTest {
@Test
fun `get multiple assets`() {
val bird = resolver.getBytes(
val bird =
resolver.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl"),
false,
null
)
val swallow = resolver.getBytes(
val swallow =
resolver.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/catalog/Swallow.pkl"),
false,
null
)
assertThat(bird).isEqualTo(packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readBytes())
assertThat(swallow).isEqualTo(packageRoot.resolve("birds@0.5.0/package/catalog/Swallow.pkl").readBytes())
assertThat(swallow)
.isEqualTo(packageRoot.resolve("birds@0.5.0/package/catalog/Swallow.pkl").readBytes())
}
@Test
fun `list path elements in nested directory`() {
// cast to set to avoid sort issues
val elements = resolver.listElements(PackageAssetUri("package://localhost:0/birds@0.5.0#/catalog/"), null).toSet()
assertThat(elements).isEqualTo(
val elements =
resolver
.listElements(PackageAssetUri("package://localhost:0/birds@0.5.0#/catalog/"), null)
.toSet()
assertThat(elements)
.isEqualTo(
setOf(
PathElement("Ostritch.pkl", false),
PathElement("Swallow.pkl", false),
@@ -140,11 +162,7 @@ class PackageResolversTest {
fun `getBytes() throws FileNotFound if package exists but path does not`() {
assertThrows<FileNotFoundException> {
resolver
.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/Horse.pkl"),
false,
null
)
.getBytes(PackageAssetUri("package://localhost:0/birds@0.5.0#/Horse.pkl"), false, null)
.toString(StandardCharsets.UTF_8)
}
}
@@ -156,7 +174,8 @@ class PackageResolversTest {
.getBytes(
PackageAssetUri("package://localhost:0/not-a-package@0.5.0#/Horse.pkl"),
false,
null)
null
)
.toString(StandardCharsets.UTF_8)
}
}
@@ -167,23 +186,32 @@ class PackageResolversTest {
resolver.getBytes(
PackageAssetUri("package://localhost:0/badPackageZipUrl@1.0.0#/Bug.pkl"),
false,
null)
null
)
}
.hasMessage("Expected the zip asset for package `package://localhost:0/badPackageZipUrl@1.0.0` to be an HTTPS URI, but got `ftp://wait/a/minute`.")
.hasMessage(
"Expected the zip asset for package `package://localhost:0/badPackageZipUrl@1.0.0` to be an HTTPS URI, but got `ftp://wait/a/minute`."
)
}
@Test
fun `throws if package checksum is invalid`() {
val error = assertThrows<PackageLoadError> {
val error =
assertThrows<PackageLoadError> {
resolver.getBytes(
PackageAssetUri("package://localhost:0/badChecksum@1.0.0#/Bug.pkl"),
false,
null)
null
)
}
assertThat(error).hasMessageContaining("""
assertThat(error)
.hasMessageContaining(
"""
Computed checksum: "a6bf858cdd1c09da475c2abe50525902580910ee5cc1ff624999170591bf8f69"
Expected checksum: "intentionally bogus checksum"
""".trimIndent())
"""
.trimIndent()
)
}
}
@@ -205,12 +233,16 @@ class PackageResolversTest {
}
}
override val resolver: PackageResolver = PackageResolvers.DiskCachedPackageResolver(
SecurityManagers.defaultManager, httpClient, cacheDir)
override val resolver: PackageResolver =
PackageResolvers.DiskCachedPackageResolver(
SecurityManagers.defaultManager,
httpClient,
cacheDir
)
}
class InMemoryPackageResolverTest : AbstractPackageResolverTest() {
override val resolver: PackageResolver = PackageResolvers.InMemoryPackageResolver(
SecurityManagers.defaultManager, httpClient)
override val resolver: PackageResolver =
PackageResolvers.InMemoryPackageResolver(SecurityManagers.defaultManager, httpClient)
}
}

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.parser
import org.antlr.v4.runtime.CommonToken

View File

@@ -1,30 +1,42 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.parser
import org.pkl.core.Evaluator
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.Evaluator
import org.pkl.core.ModuleSource
// tests whitespace handling in multi-line string literals that cannot be reliably tested via snippets
// tests whitespace handling in multi-line string literals that cannot be reliably tested via
// snippets
// (e.g. due to editors not displaying and/or automatically removing whitespace)
class MultiLineStringLiteralTest {
private val evaluator = Evaluator.preconfigured()
@Test
fun `multi-line strings have unix newlines`() {
val module = evaluator.evaluate(
ModuleSource.text(
"x = \"\"\"\none\rtwo\nthree\r\nfour\n\"\"\""
)
)
val module =
evaluator.evaluate(ModuleSource.text("x = \"\"\"\none\rtwo\nthree\r\nfour\n\"\"\""))
assertThat(module.properties["x"]).isEqualTo("one\ntwo\nthree\nfour")
}
@Test
fun `raw multi-line strings have unix newlines`() {
val module = evaluator.evaluate(
ModuleSource.text("x = #\"\"\"\none\rtwo\nthree\r\nfour\n\"\"\"#")
)
val module =
evaluator.evaluate(ModuleSource.text("x = #\"\"\"\none\rtwo\nthree\r\nfour\n\"\"\"#"))
assertThat(module.properties["x"]).isEqualTo("one\ntwo\nthree\nfour")
}
}

View File

@@ -1,8 +1,23 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.parser
import org.pkl.core.Evaluator
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.Evaluator
import org.pkl.core.ModuleSource
class ShebangTest {
@@ -10,12 +25,14 @@ class ShebangTest {
@Test
fun `shebang is ignored`() {
val module = evaluator.evaluate(
val module =
evaluator.evaluate(
ModuleSource.text(
"""
#!/usr/local/bin/pkl
x = 1
""".trimIndent()
"""
.trimIndent()
)
)

View File

@@ -1,5 +1,22 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.project
import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
@@ -7,12 +24,10 @@ import org.junit.jupiter.api.assertThrows
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.toPath
import org.pkl.core.http.HttpClient
import org.pkl.core.PklException
import org.pkl.core.SecurityManagers
import org.pkl.core.http.HttpClient
import org.pkl.core.packages.PackageResolver
import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
class ProjectDependenciesResolverTest {
companion object {
@@ -36,13 +51,17 @@ class ProjectDependenciesResolverTest {
fun resolveDependencies() {
val project2Path = javaClass.getResource("project2/PklProject")!!.toURI().toPath()
val project = Project.loadFromPath(project2Path)
val packageResolver = PackageResolver.getInstance(SecurityManagers.defaultManager, httpClient, null)
val packageResolver =
PackageResolver.getInstance(SecurityManagers.defaultManager, httpClient, null)
val deps = ProjectDependenciesResolver(project, packageResolver, System.out.writer()).resolve()
val strDeps = ByteArrayOutputStream()
val strDeps =
ByteArrayOutputStream()
.apply { deps.writeTo(this) }
.toByteArray()
.toString(StandardCharsets.UTF_8)
assertThat(strDeps).isEqualTo("""
assertThat(strDeps)
.isEqualTo(
"""
{
"schemaVersion": 1,
"resolvedDependencies": {
@@ -67,22 +86,30 @@ class ProjectDependenciesResolverTest {
}
}
}
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `fails if project declares a package with an incorrect checksum`() {
val projectPath = javaClass.getResource("badProjectChecksum/PklProject")!!.toURI().toPath()
val project = Project.loadFromPath(projectPath)
val packageResolver = PackageResolver.getInstance(SecurityManagers.defaultManager, httpClient, null)
val e = assertThrows<PklException> {
val packageResolver =
PackageResolver.getInstance(SecurityManagers.defaultManager, httpClient, null)
val e =
assertThrows<PklException> {
ProjectDependenciesResolver(project, packageResolver, System.err.writer()).resolve()
}
assertThat(e).hasMessage("""
assertThat(e)
.hasMessage(
"""
Computed checksum did not match declared checksum for dependency `package://localhost:0/birds@0.5.0`.
Computed: "${PackageServer.BIRDS_SHA}"
Declared: "intentionally bogus value"
""".trimIndent())
"""
.trimIndent()
)
}
}

View File

@@ -1,16 +1,32 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.project
import java.io.ByteArrayOutputStream
import java.nio.file.Path
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.packages.Checksums
import org.pkl.core.packages.Dependency
import org.pkl.core.packages.PackageUri
import org.pkl.core.util.EconomicMaps
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.io.ByteArrayOutputStream
import java.nio.file.Path
class ProjectDepsTest {
private val projectDepsStr = """
private val projectDepsStr =
"""
{
"schemaVersion": 1,
"resolvedDependencies": {
@@ -28,15 +44,19 @@ class ProjectDepsTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
private val projectDeps = let {
val projectDepsMap = EconomicMaps.of<CanonicalPackageUri, Dependency>(
CanonicalPackageUri.of("package://localhost:0/birds@0"), Dependency.RemoteDependency(
val projectDepsMap =
EconomicMaps.of<CanonicalPackageUri, Dependency>(
CanonicalPackageUri.of("package://localhost:0/birds@0"),
Dependency.RemoteDependency(
PackageUri.create("package://localhost:0/birds@0.5.0"),
Checksums("abc123")
),
CanonicalPackageUri.of("package://localhost:0/fruit@1"), Dependency.LocalDependency(
CanonicalPackageUri.of("package://localhost:0/fruit@1"),
Dependency.LocalDependency(
PackageUri.create("package://localhost:0/fruit@1.1.0"),
Path.of("../fruit")
)
@@ -46,9 +66,7 @@ class ProjectDepsTest {
@Test
fun writeTo() {
val str = ByteArrayOutputStream()
.apply { projectDeps.writeTo(this) }
.toString(Charsets.UTF_8)
val str = ByteArrayOutputStream().apply { projectDeps.writeTo(this) }.toString(Charsets.UTF_8)
assertThat(str).isEqualTo(projectDepsStr)
}

View File

@@ -1,5 +1,23 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.project
import java.net.URI
import java.nio.file.Path
import java.util.regex.Pattern
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.Test
@@ -8,18 +26,16 @@ import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.writeString
import org.pkl.core.*
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
import org.pkl.core.http.HttpClient
import org.pkl.core.packages.PackageUri
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
import java.net.URI
import java.nio.file.Path
import java.util.regex.Pattern
class ProjectTest {
@Test
fun loadFromPath(@TempDir path: Path) {
val projectPath = path.resolve("PklProject")
val expectedPackage = Package(
val expectedPackage =
Package(
"hawk",
PackageUri("package://example.com/hawk@0.5.0"),
Version.parse("0.5.0"),
@@ -35,27 +51,27 @@ class ProjectTest {
# Some License text
This is my license text
""".trimIndent(),
"""
.trimIndent(),
URI("https://example.com/my/issues"),
listOf(Path.of("apiTest1.pkl"), Path.of("apiTest2.pkl")),
listOf("PklProject", "PklProject.deps.json", ".**", "*.exe")
)
val expectedSettings = PklEvaluatorSettings(
val expectedSettings =
PklEvaluatorSettings(
mapOf("two" to "2"),
mapOf("one" to "1"),
listOf("foo:", "bar:").map(Pattern::compile),
listOf("baz:", "biz:").map(Pattern::compile),
false,
path.resolve("cache/"),
listOf(
path.resolve("modulepath1/"),
path.resolve("modulepath2/")
),
listOf(path.resolve("modulepath1/"), path.resolve("modulepath2/")),
Duration.ofMinutes(5.0),
path,
null
)
projectPath.writeString("""
projectPath.writeString(
"""
amends "pkl:Project"
evaluatorSettings {
@@ -114,24 +130,28 @@ class ProjectTest {
"test1.pkl"
"test2.pkl"
}
""".trimIndent())
"""
.trimIndent()
)
val project = Project.loadFromPath(projectPath)
assertThat(project.`package`).isEqualTo(expectedPackage)
assertThat(project.evaluatorSettings).isEqualTo(expectedSettings)
assertThat(project.tests).isEqualTo(listOf(path.resolve("test1.pkl"), path.resolve("test2.pkl")))
assertThat(project.tests)
.isEqualTo(listOf(path.resolve("test1.pkl"), path.resolve("test2.pkl")))
}
@Test
fun `load wrong type`(@TempDir path: Path) {
val projectPath = path.resolve("PklProject")
projectPath.writeString("""
projectPath.writeString(
"""
module com.apple.Foo
foo = 1
""".trimIndent())
assertThatCode {
Project.loadFromPath(projectPath, SecurityManagers.defaultManager, null)
}
"""
.trimIndent()
)
assertThatCode { Project.loadFromPath(projectPath, SecurityManagers.defaultManager, null) }
.hasMessageContaining("be of type `pkl.Project`, but got type `com.apple.Foo`")
}
@@ -140,18 +160,20 @@ class ProjectTest {
PackageServer().use { server ->
val projectDir = Path.of(javaClass.getResource("badProjectChecksum2/")!!.toURI())
val project = Project.loadFromPath(projectDir.resolve("PklProject"))
val httpClient = HttpClient.builder()
val httpClient =
HttpClient.builder()
.addCertificates(FileTestUtils.selfSignedCertificate)
.setTestPort(server.port)
.build()
val evaluator = EvaluatorBuilder.preconfigured()
val evaluator =
EvaluatorBuilder.preconfigured()
.applyFromProject(project)
.setModuleCacheDir(null)
.setHttpClient(httpClient)
.build()
assertThatCode {
evaluator.evaluate(ModuleSource.path(projectDir.resolve("bug.pkl")))
}.hasMessageStartingWith("""
assertThatCode { evaluator.evaluate(ModuleSource.path(projectDir.resolve("bug.pkl"))) }
.hasMessageStartingWith(
"""
Pkl Error
Cannot download package `package://localhost:0/fruit@1.0.5` because the computed checksum for package metadata does not match the expected checksum.
@@ -161,7 +183,9 @@ class ProjectTest {
1 | import "@fruit/Fruit.pkl"
^^^^^^^^^^^^^^^^^^^^^^^^^
""".trimIndent())
"""
.trimIndent()
)
}
}
}

View File

@@ -1,21 +1,37 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.resource
import org.pkl.core.Evaluator
import java.nio.file.Path
import kotlin.io.path.outputStream
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import org.pkl.core.Evaluator
import org.pkl.core.EvaluatorBuilder
import org.pkl.core.ModuleSource
import org.pkl.core.module.ModulePathResolver
import kotlin.io.path.outputStream
class ResourceReadersEvaluatorTest {
@Test
fun `class path`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
val module =
evaluator.evaluate(
ModuleSource.text(
"""
res1 = read("modulepath:/org/pkl/core/resource/resource.txt").text
@@ -38,12 +54,10 @@ class ResourceReadersEvaluatorTest {
ModulePathResolver(listOf(jarFile)).use { resolver ->
val reader = ResourceReaders.modulePath(resolver)
val evaluator = EvaluatorBuilder
.preconfigured()
.addResourceReader(reader)
.build()
val evaluator = EvaluatorBuilder.preconfigured().addResourceReader(reader).build()
val module = evaluator.evaluate(
val module =
evaluator.evaluate(
ModuleSource.text(
"""
res1 = read("modulepath:/dir1/resource1.txt").text

View File

@@ -1,14 +1,29 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.resource
import java.net.URI
import java.net.URISyntaxException
import java.nio.file.Path
import kotlin.io.path.outputStream
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import org.pkl.core.module.ModulePathResolver
import java.net.URI
import java.net.URISyntaxException
import java.nio.file.Path
import kotlin.io.path.outputStream
class ResourceReadersTest {
@Test
@@ -82,9 +97,7 @@ class ResourceReadersTest {
fun `module path - missing leading slash`() {
val reader = ResourceReaders.modulePath(ModulePathResolver(listOf()))
assertThrows<URISyntaxException> {
reader.read(URI("modulepath:non/existing"))
}
assertThrows<URISyntaxException> { reader.read(URI("modulepath:non/existing")) }
}
@Test

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.resource
import java.net.URI

View File

@@ -1,4 +1,20 @@
package org.pkl.core.runtime;
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
//
// import java.io.IOException;
// import java.net.URI;
@@ -23,16 +39,20 @@ package org.pkl.core.runtime;
// public class DefaultModuleResolverTest {
// private final SourceSection sourceSection = VmUtils.unavailableSourceSection();
// private final ModuleResolver resolver =
// new ModuleResolver(ModuleKeyFactories.namedModuleOnClassPath, EvalOptions.namedModuleOnClassPath.getAllowedModules());
// new ModuleResolver(ModuleKeyFactories.namedModuleOnClassPath,
// EvalOptions.namedModuleOnClassPath.getAllowedModules());
// private final ModuleKey fileUrlModule;
// private final ModuleKey httpsUrlModule;
// private final ModuleKey literalUrlModule;
//
// {
// try {
// fileUrlModule = ModuleKeys.genericUrl(new URI("file:///path/script.pkl"), ModuleKeys.FULL_TRUST);
// httpsUrlModule = ModuleKeys.genericUrl(new URI("https://some.domain.com/path/script.pkl"), ModuleKeys.FULL_TRUST);
// literalUrlModule = ModuleKeys.synthetic("myLiteralModule", "my literal source code", ModuleKeys.FULL_TRUST);
// fileUrlModule = ModuleKeys.genericUrl(new URI("file:///path/script.pkl"),
// ModuleKeys.FULL_TRUST);
// httpsUrlModule = ModuleKeys.genericUrl(new URI("https://some.domain.com/path/script.pkl"),
// ModuleKeys.FULL_TRUST);
// literalUrlModule = ModuleKeys.synthetic("myLiteralModule", "my literal source code",
// ModuleKeys.FULL_TRUST);
// } catch (URISyntaxException e) {
// throw new RuntimeException(e);
// }
@@ -61,7 +81,8 @@ package org.pkl.core.runtime;
//
// @Test
// public void importHttpsUrlFromFileUrl() throws IOException {
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl", fileUrlModule, sourceSection);
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl",
// fileUrlModule, sourceSection);
// assertTrue(result instanceof ModuleKey.Url);
// assertEquals("https://other.domain.com/path2/script2.pkl", result.toString());
// }
@@ -94,7 +115,8 @@ package org.pkl.core.runtime;
//
// @Test
// public void importHttpsUrlFromHttpsUrl() throws IOException {
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl", httpsUrlModule, sourceSection);
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl",
// httpsUrlModule, sourceSection);
// assertTrue(result instanceof ModuleKey.Url);
// assertEquals("https://other.domain.com/path2/script2.pkl", result.toString());
// }
@@ -127,14 +149,16 @@ package org.pkl.core.runtime;
//
// @Test
// public void importFileUrlFromLiteral() throws IOException {
// ModuleKey result = resolver.resolve("file:///import/file.pkl", literalUrlModule, sourceSection);
// ModuleKey result = resolver.resolve("file:///import/file.pkl", literalUrlModule,
// sourceSection);
// assertTrue(result instanceof ModuleKey.Url);
// assertEquals("file:///import/file.pkl", result.toString());
// }
//
// @Test
// public void importHttpsUrlFromLiteral() throws IOException {
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl", literalUrlModule, sourceSection);
// ModuleKey result = resolver.resolve("https://other.domain.com/path2/script2.pkl",
// literalUrlModule, sourceSection);
// assertTrue(result instanceof ModuleKey.Url);
// assertEquals("https://other.domain.com/path2/script2.pkl", result.toString());
// }

View File

@@ -1,14 +1,28 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import java.net.URI
import java.nio.file.FileSystems
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.net.URI
import java.nio.file.FileSystems
class FileSystemManagerTest {
private val resource =
javaClass.getResource("/org/pkl/core/resource/resource1.jar")!!.toURI()
private val resource = javaClass.getResource("/org/pkl/core/resource/resource1.jar")!!.toURI()
private val resourceUri = URI("jar:$resource")
@Test

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,4 +1,20 @@
package org.pkl.core.runtime;
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
//
// import java.io.File;
// import java.io.IOException;

View File

@@ -1,10 +1,25 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.pkl.core.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.core.*
class StackTraceRendererTest {
companion object {
@@ -20,26 +35,34 @@ class StackTraceRendererTest {
@Test
fun `stringy self-reference`() {
val message = assertThrows<PklException> {
val message =
assertThrows<PklException> {
evaluator.evaluate(
ModuleSource.text(
"""
self: String = "Strings; if they were lazy, you could tie the knot on \(self.take(7))"
""".trimIndent())
"""
.trimIndent()
)
}.message!!
)
}
.message!!
assertThat(message)
.contains("A stack overflow occurred.")
.containsPattern("""
.containsPattern(
"""
┌─ \d* repetitions of:
│ 1 | self: String = "Strings; if they were lazy, you could tie the knot on \\\(self.take\(7\)\)"
│ ^^^^
""".trim())
"""
.trim()
)
}
@Test
fun `cyclic property references`() {
val message = assertThrows<PklException> {
val message =
assertThrows<PklException> {
evaluator.evaluate(
ModuleSource.text(
"""
@@ -47,12 +70,16 @@ class StackTraceRendererTest {
bar: String = "BAR:" + baz
baz: String = "BAZ:" + qux
qux: String = "QUX:" + foo
""".trimIndent())
"""
.trimIndent()
)
}.message!!
)
}
.message!!
assertThat(message)
.contains("A stack overflow occurred.")
.containsPattern("""
.containsPattern(
"""
┌─ \d+ repetitions of:
│ 4 | qux: String = "QUX:" + foo
│ ^^^
@@ -70,13 +97,16 @@ class StackTraceRendererTest {
│ ^^^
│ at text#foo (repl:text)
└─
""".trim())
"""
.trim()
)
}
@Test
@Suppress("RegExpRepeatedSpace")
fun `reduce stack overflow from actual Pkl code`() {
val pklCode = """
val pklCode =
"""
function suffix(n: UInt): UInt =
if (n == 0)
0
@@ -106,10 +136,10 @@ class StackTraceRendererTest {
prefix(n - 1)
result = prefix(13)
""".trimIndent()
val message = assertThrows<PklException> {
evaluator.evaluate(ModuleSource.text(pklCode))
}.message!!
"""
.trimIndent()
val message =
assertThrows<PklException> { evaluator.evaluate(ModuleSource.text(pklCode)) }.message!!
if (message.contains("5 | suffix")) {
assertThat(message).containsPattern("repetitions of:\n│ 5 | suffix(n - 1)")
@@ -159,15 +189,11 @@ class StackTraceRendererTest {
add(createFrame("foo", 3))
}
val loop = StackTraceRenderer.StackFrameLoop(loopFrames, 1)
val frames = listOf(
createFrame("bar", 1),
createFrame("baz", 2),
loop
)
val renderedFrames = buildString {
renderer.doRender(frames, null, this, "", true)
}
assertThat(renderedFrames).isEqualTo("""
val frames = listOf(createFrame("bar", 1), createFrame("baz", 2), loop)
val renderedFrames = buildString { renderer.doRender(frames, null, this, "", true) }
assertThat(renderedFrames)
.isEqualTo(
"""
1 | foo
^
at <unknown> (file:bar)
@@ -188,7 +214,9 @@ class StackTraceRendererTest {
^
at <unknown> (file:foo)
""".trimIndent())
"""
.trimIndent()
)
}
private fun createFrame(name: String, id: Int): StackFrame {

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat
@@ -10,15 +25,12 @@ class VmSafeMathTest {
assertThat(VmSafeMath.negate(0)).isEqualTo(0)
assertThat(VmSafeMath.negate(1)).isEqualTo(-1)
assertThat(VmSafeMath.negate(-1)).isEqualTo(1)
assertThat(VmSafeMath.negate(java.lang.Long.MAX_VALUE))
.isEqualTo(-java.lang.Long.MAX_VALUE)
assertThat(VmSafeMath.negate(java.lang.Long.MAX_VALUE)).isEqualTo(-java.lang.Long.MAX_VALUE)
}
@Test
fun `negate long - overflow`() {
assertThrows<VmEvalException> {
VmSafeMath.negate(java.lang.Long.MIN_VALUE)
}
assertThrows<VmEvalException> { VmSafeMath.negate(java.lang.Long.MIN_VALUE) }
}
@Test
@@ -27,10 +39,8 @@ class VmSafeMathTest {
assertThat(VmSafeMath.negate(-1.0)).isEqualTo(1.0)
assertThat(VmSafeMath.negate(1.0)).isEqualTo(-1.0)
assertThat(VmSafeMath.negate(123.456)).isEqualTo(-123.456)
assertThat(VmSafeMath.negate(-java.lang.Double.MAX_VALUE))
.isEqualTo(java.lang.Double.MAX_VALUE)
assertThat(VmSafeMath.negate(-java.lang.Double.MIN_VALUE))
.isEqualTo(java.lang.Double.MIN_VALUE)
assertThat(VmSafeMath.negate(-java.lang.Double.MAX_VALUE)).isEqualTo(java.lang.Double.MAX_VALUE)
assertThat(VmSafeMath.negate(-java.lang.Double.MIN_VALUE)).isEqualTo(java.lang.Double.MIN_VALUE)
}
@Test
@@ -38,31 +48,23 @@ class VmSafeMathTest {
assertThat(VmSafeMath.add(0, 0)).isEqualTo(0)
assertThat(VmSafeMath.add(1, 2)).isEqualTo(3)
assertThat(VmSafeMath.add(1, -2)).isEqualTo(-1)
assertThat(VmSafeMath.add(java.lang.Long.MAX_VALUE - 1, 1))
.isEqualTo(java.lang.Long.MAX_VALUE)
assertThat(VmSafeMath.add(java.lang.Long.MAX_VALUE - 1, 1)).isEqualTo(java.lang.Long.MAX_VALUE)
}
@Test
fun `add long - overflow #1`() {
assertThrows<VmEvalException> {
VmSafeMath.add(java.lang.Long.MAX_VALUE, 1)
}
assertThrows<VmEvalException> { VmSafeMath.add(java.lang.Long.MAX_VALUE, 1) }
}
@Test
fun `add long - overflow #2`() {
assertThrows<VmEvalException> {
VmSafeMath.add(java.lang.Long.MIN_VALUE, -1)
}
assertThrows<VmEvalException> { VmSafeMath.add(java.lang.Long.MIN_VALUE, -1) }
}
@Test
fun `add long - overflow #3`() {
assertThrows<VmEvalException> {
VmSafeMath.add(
java.lang.Long.MAX_VALUE / 2,
java.lang.Long.MAX_VALUE / 3 * 2
)
VmSafeMath.add(java.lang.Long.MAX_VALUE / 2, java.lang.Long.MAX_VALUE / 3 * 2)
}
}
}

View File

@@ -1,10 +1,22 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.pkl.core.SecurityManagers
import org.pkl.core.module.ModuleKeys
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.net.URI
class VmUtilsTest {
@Test

View File

@@ -1,3 +1,18 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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 org.pkl.core.runtime
import org.assertj.core.api.Assertions.assertThat

Some files were not shown because too many files have changed in this diff Show More