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,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
.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() },
{ it.simpleName.toString() }
))
.groupBy { processingEnv.elementUtils.getPackageOf(it) }
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()
},
{ 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,32 +96,38 @@ 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)
.addJavadoc("Generated by {@link ${this::class.qualifiedName}}.")
.addModifiers(Modifier.FINAL)
.superclass(externalMemberRegistryClassName)
val registryClass =
TypeSpec.classBuilder(registryClassName)
.addJavadoc("Generated by {@link ${this::class.qualifiedName}}.")
.addModifiers(Modifier.FINAL)
.superclass(externalMemberRegistryClassName)
val registryClassConstructor = MethodSpec.constructorBuilder()
for (nodeClass in nodeClasses) {
val enclosingClass = nodeClass.enclosingElement
val pklClassName = getAnnotatedPklName(enclosingClass)
?: enclosingClass.simpleName.toString().removeSuffix(truffleNodeFactorySuffix)
val pklMemberName = getAnnotatedPklName(nodeClass)
?: nodeClass.simpleName.toString().removeSuffix(truffleNodeClassSuffix)
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"
}
val pklClassName =
getAnnotatedPklName(enclosingClass)
?: enclosingClass.simpleName.toString().removeSuffix(truffleNodeFactorySuffix)
val pklMemberName =
getAnnotatedPklName(nodeClass)
?: nodeClass.simpleName.toString().removeSuffix(truffleNodeClassSuffix)
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"
}
registryClass.addOriginatingElement(nodeClass)
registryClassConstructor
.addStatement("register(\$S, \$T::create)", pklMemberNameQualified, nodeClass)
registryClassConstructor.addStatement(
"register(\$S, \$T::create)",
pklMemberNameQualified,
nodeClass
)
}
registryClass.addMethod(registryClassConstructor.build())
@@ -109,25 +136,27 @@ class MemberRegistryGenerator : AbstractProcessor() {
}
private fun generateRegistryFactoryClass(packages: Collection<PackageElement>) {
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 registryFactoryClass =
TypeSpec.classBuilder(memberRegistryFactoryClassName)
.addJavadoc("Generated by {@link ${this::class.qualifiedName}}.")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
val registryFactoryConstructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE)
registryFactoryClass.addMethod(registryFactoryConstructor.build())
val registryFactoryGetMethod = MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(moduleKeyClassName, "moduleKey")
.returns(externalMemberRegistryClassName)
.beginControlFlow("if (!\$T.isStdLibModule(moduleKey))", moduleKeysClassName)
.addStatement("return \$T.INSTANCE", emptyMemberRegistryClassName)
.endControlFlow()
.beginControlFlow("switch (moduleKey.getUri().getSchemeSpecificPart())")
val registryFactoryGetMethod =
MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(moduleKeyClassName, "moduleKey")
.returns(externalMemberRegistryClassName)
.beginControlFlow("if (!\$T.isStdLibModule(moduleKey))", moduleKeysClassName)
.addStatement("return \$T.INSTANCE", emptyMemberRegistryClassName)
.endControlFlow()
.beginControlFlow("switch (moduleKey.getUri().getSchemeSpecificPart())")
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,9 +23,10 @@ class ClassInheritanceTest {
@Test
fun `property override without type annotation is considered an object property definition`() {
val module = evaluator.evaluateSchema(
ModuleSource.text(
"""
val module =
evaluator.evaluateSchema(
ModuleSource.text(
"""
class Thing
open class Base {
hidden thing: Thing
@@ -18,9 +34,10 @@ class ClassInheritanceTest {
class Derived extends Base {
thing {}
}
""".trimIndent()
"""
.trimIndent()
)
)
)
val derivedClass = module.classes["Derived"]!!
assertThat(derivedClass.properties["thing"]).isNull()
@@ -33,9 +50,10 @@ class ClassInheritanceTest {
@Test
fun `property override with type annotation is considered a class property definition`() {
val module = evaluator.evaluateSchema(
ModuleSource.text(
"""
val module =
evaluator.evaluateSchema(
ModuleSource.text(
"""
class Thing
open class Base {
hidden thing: Thing
@@ -43,9 +61,10 @@ class ClassInheritanceTest {
class Derived extends Base {
thing: Thing = new {}
}
""".trimIndent()
"""
.trimIndent()
)
)
)
val derivedClass = module.classes["Derived"]!!
val thingProperty = derivedClass.properties["thing"]

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,10 +83,9 @@ 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
fun toIsoString() {
assertThat(duration1.toIsoString()).isEqualTo("PT0.3S")
@@ -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,19 +20,21 @@ 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`() {
// Does not involve Dynamic, but is a baseline for the other cases.
val evaluator = Evaluator.preconfigured()
assertThrows<PklException> {
assertThrows<PklException> {
evaluator.evaluateOutputText(ModuleSource.text(brokenInput("person.name")))
}
}

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
@@ -18,33 +33,41 @@ class ErrorColoringTest {
private fun evaluate(program: String, expression: String): Any {
return evaluator.evaluateExpression(ModuleSource.text(program), expression)
}
@BeforeEach
fun setup() {
// Enable colouring before each test
Ansi.setEnabled(true)
}
@AfterEach
fun teardown() {
// Disable colouring after each test
Ansi.setEnabled(false)
}
@Test
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^")
}
@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(
text(
"""
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,9 +91,8 @@ 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)
assertThat(propertyb3.sourceLocation.endLine).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)
@@ -119,7 +128,7 @@ class EvaluateSchemaTest {
returnBaseType as PType.Class
assertThat(returnBaseType.pClass).isEqualTo(BaseModule.getIntClass().export())
assertThat(returnType.constraints).isEqualTo(listOf("isPositive"))
val methodb3 = methods.getValue("methodb3")
assertThat(methodb3.sourceLocation.startLine).isEqualTo(26)
assertThat(methodb3.sourceLocation.endLine).isEqualTo(26)
@@ -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,9 +60,10 @@ class EvaluateTestsTest {
@Test
fun `test module failure`() {
val results = evaluator.evaluateTest(
text(
"""
val results =
evaluator.evaluateTest(
text(
"""
amends "pkl:test"
facts {
@@ -49,19 +72,20 @@ class EvaluateTestsTest {
"foo" == "bar"
}
}
""".trimIndent()
),
true
)
"""
.trimIndent()
),
true
)
assertThat(results.totalTests()).isEqualTo(1)
assertThat(results.totalFailures()).isEqualTo(2)
assertThat(results.failed()).isTrue
val res = results.results[0]
assertThat(res.name).isEqualTo("should fail")
assertThat(res.errors).isEmpty()
val fail1 = res.failures[0]
assertThat(fail1.rendered).isEqualTo("1 == 2 ❌ (repl:text)")
@@ -71,9 +95,10 @@ class EvaluateTestsTest {
@Test
fun `test module error`() {
val results = evaluator.evaluateTest(
text(
"""
val results =
evaluator.evaluateTest(
text(
"""
amends "pkl:test"
facts {
@@ -82,10 +107,11 @@ class EvaluateTestsTest {
throw("got an error")
}
}
""".trimIndent()
),
true
)
"""
.trimIndent()
),
true
)
assertThat(results.totalTests()).isEqualTo(1)
assertThat(results.totalFailures()).isEqualTo(0)
@@ -95,10 +121,12 @@ class EvaluateTestsTest {
assertThat(res.name).isEqualTo("text")
assertThat(res.failures).isEmpty()
assertThat(res.errors.size).isEqualTo(1)
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())
Files.writeString(createExpected(file), """
"""
.trimIndent()
)
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,40 +49,32 @@ class EvaluatorBuilderTest {
@Test
fun `enforces that security manager is set`() {
val e1 = assertThrows<IllegalStateException> {
EvaluatorBuilder.unconfigured()
.setStackFrameTransformer(StackFrameTransformers.empty)
.build()
}
val e1 =
assertThrows<IllegalStateException> {
EvaluatorBuilder.unconfigured()
.setStackFrameTransformer(StackFrameTransformers.empty)
.build()
}
assertThat(e1).hasMessage("No security manager set.")
}
@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.")
}
@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,112 +186,117 @@ 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> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
val e2 = assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
val e1 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
val e2 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule1.pkl"))
}
assertThat(e2.message).isEqualTo(e1.message)
val e3 = assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
val e4 = assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
val e3 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
val e4 =
assertThrows<PklException> {
evaluator.evaluate(modulePath("org/pkl/core/brokenModule2.pkl"))
}
assertThat(e4.message).isEqualTo(e3.message)
}
@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")
}
@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()
.setSecurityManager(
SecurityManagers.standard(
SecurityManagers.defaultAllowedModules,
SecurityManagers.defaultAllowedResources,
SecurityManagers.defaultTrustLevels,
tempDir
val evaluator =
EvaluatorBuilder.preconfigured()
.setSecurityManager(
SecurityManagers.standard(
SecurityManagers.defaultAllowedModules,
SecurityManagers.defaultAllowedResources,
SecurityManagers.defaultTrustLevels,
tempDir
)
)
)
.build()
.build()
val module = tempDir.resolve("test.pkl")
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 ->
evaluator.evaluateOutputText(modulePath("/org/pkl/core/project/project5/main.pkl"))
}
assertThat(result).isEqualTo("""
val result =
evaluatorBuilder.setProjectDependencies(project.dependencies).build().use { evaluator ->
evaluator.evaluateOutputText(modulePath("/org/pkl/core/project/project5/main.pkl"))
}
assertThat(result)
.isEqualTo(
"""
prop1 {
name = "Apple"
}
@@ -339,30 +342,37 @@ class EvaluatorTest {
res = 1
}
""".trimIndent())
"""
.trimIndent()
)
}
@Test
fun `project set from custom ModuleKeyFactory`(@TempDir cacheDir: Path) {
PackageServer.populateCacheDir(cacheDir)
val evaluatorBuilder = with(EvaluatorBuilder.preconfigured()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("custom:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("custom:"))
setModuleCacheDir(cacheDir)
setModuleKeyFactories(
listOf(
CustomModuleKeyFactory,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.pkg,
ModuleKeyFactories.projectpackage,
ModuleKeyFactories.file
val evaluatorBuilder =
with(EvaluatorBuilder.preconfigured()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("custom:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("custom:"))
setModuleCacheDir(cacheDir)
setModuleKeyFactories(
listOf(
CustomModuleKeyFactory,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.pkg,
ModuleKeyFactories.projectpackage,
ModuleKeyFactories.file
)
)
)
}
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,45 +392,55 @@ 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()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("foobar:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("foobar:"))
setModuleKeyFactories(
listOf(
fooBayModuleKeyFactory,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.pkg,
ModuleKeyFactories.projectpackage,
ModuleKeyFactories.file
val evaluatorBuilder =
with(EvaluatorBuilder.preconfigured()) {
setAllowedModules(SecurityManagers.defaultAllowedModules + Pattern.compile("foobar:"))
setAllowedResources(SecurityManagers.defaultAllowedResources + Pattern.compile("foobar:"))
setModuleKeyFactories(
listOf(
fooBayModuleKeyFactory,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.pkg,
ModuleKeyFactories.projectpackage,
ModuleKeyFactories.file
)
)
)
}
}
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,17 +46,17 @@ 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
// language=regexp
internal val selection: String = ""
protected val packageServer: PackageServer = PackageServer()
override val includedTests: List<Regex> = listOf(Regex(".*$selection\\.pkl"))
override val excludedTests: List<Regex> = buildList {
override val excludedTests: List<Regex> = buildList {
add(Regex(".*/native/.*"))
if (IoUtils.isWindows()) {
addAll(windowsExcludedTests)
@@ -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()
@@ -75,17 +89,19 @@ abstract class AbstractLanguageSnippetTestsEngine : InputOutputTestEngine() {
private val replacement by lazy {
if (snippetsDir.root.toString() != "/") "\$snippetsDir" else "/\$snippetsDir"
}
}
protected fun String.stripFilePaths(): String =
replace(IoUtils.toNormalizedPathString(snippetsDir), replacement)
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.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()
.setTestPort(packageServer.port)
.addCertificates(FileTestUtils.selfSignedCertificate)
.buildLazily())
.setHttpClient(
HttpClient.builder()
.setTestPort(packageServer.port)
.addCertificates(FileTestUtils.selfSignedCertificate)
.buildLazily()
)
}
override val testClass: KClass<*> = LanguageSnippetTests::class
@@ -140,60 +155,65 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
override fun generateOutputFor(inputFile: Path): kotlin.Pair<Boolean, String> {
val logWriter = StringWriter()
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(
projectDir.resolve("PklProject"),
SecurityManagers.defaultManager,
null,
StackFrameTransformers.empty,
mapOf()
)
securityManager = null
applyFromProject(project)
}
}
.build()
evaluator.use { true to it.evaluateOutputText(ModuleSource.path(inputFile)) }
} catch (e: PklBugException) {
false to e.stackTraceToString()
} catch (e: PklException) {
false to e.message!!
.stripLineNumbers()
.stripVersionCheckErrorMessage()
}
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(
projectDir.resolve("PklProject"),
SecurityManagers.defaultManager,
null,
StackFrameTransformers.empty,
mapOf()
)
securityManager = null
applyFromProject(project)
}
}
.build()
evaluator.use { true to it.evaluateOutputText(ModuleSource.path(inputFile)) }
} catch (e: PklBugException) {
false to e.stackTraceToString()
} catch (e: PklException) {
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)
// on the other hand, don't exclude /native/
Regex(".*/import1b\\.pkl"),
)
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)
}
return super.discover(discoveryRequest, uniqueId)
}
override fun generateOutputFor(inputFile: Path): kotlin.Pair<Boolean, String> {
val args = buildList {
add(pklExecutablePath.toString())
@@ -234,20 +254,22 @@ 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)
.stripFilePaths()
.stripLineNumbers()
.stripWebsite()
.stripVersionCheckErrorMessage()
.stripStdlibLocationSha()
success to
(out + err)
.stripFilePaths()
.stripLineNumbers()
.stripWebsite()
.stripVersionCheckErrorMessage()
.stripStdlibLocationSha()
} finally {
process.destroy()
}
@@ -280,11 +302,12 @@ 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
override val testClass: KClass<*> = WindowsLanguageSnippetTests::class
override val excludedTests: List<Regex>
override val excludedTests: List<Regex>
get() = super.excludedTests + windowsExcludedTests
}

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,28 +51,29 @@ 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 {
setEntityResolver { _, _ ->
InputSource(PListRendererTest::class.java.getResourceAsStream("PropertyList-1.0.dtd"))
val builder =
builderFactory.newDocumentBuilder().apply {
setEntityResolver { _, _ ->
InputSource(PListRendererTest::class.java.getResourceAsStream("PropertyList-1.0.dtd"))
}
setErrorHandler(
object : ErrorHandler {
override fun warning(exception: SAXParseException) {
throw exception
}
override fun error(exception: SAXParseException) {
throw exception
}
override fun fatalError(exception: SAXParseException) {
throw exception
}
}
)
}
setErrorHandler(object : ErrorHandler {
override fun warning(exception: SAXParseException) {
throw exception
}
override fun error(exception: SAXParseException) {
throw exception
}
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,14 +40,12 @@ class PModuleTest {
@Test
fun `get unknown property`() {
val e = assertThrows<NoSuchPropertyException> {
pigeon.getProperty("other")
}
val e = assertThrows<NoSuchPropertyException> { pigeon.getProperty("other") }
assertThat(e)
.hasMessage(
"Module `test.module` does not have a property " +
"named `other`. Available properties: [name, age]"
"named `other`. Available properties: [name, age]"
)
}
@@ -48,15 +61,16 @@ class PModuleTest {
var objectVisited = false
var moduleVisited = false
val visitor = object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
val visitor =
object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
override fun visitModule(value: PModule) {
moduleVisited = true
override fun visitModule(value: PModule) {
moduleVisited = true
}
}
}
pigeon.accept(visitor)
@@ -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,12 +123,13 @@ class PModuleTest {
@Test
fun `non-equal - extra property`() {
val pigeon2 = PModule(
moduleUri,
moduleName,
classInfo,
mapOf("name" to "Pigeon", "age" to 42, "other" to true)
)
val pigeon2 =
PModule(
moduleUri,
moduleName,
classInfo,
mapOf("name" to "Pigeon", "age" to 42, "other" to true)
)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -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,14 +44,12 @@ class PObjectTest {
@Test
fun `get unknown property`() {
val e = assertThrows<NoSuchPropertyException> {
pigeon.getProperty("other")
}
val e = assertThrows<NoSuchPropertyException> { pigeon.getProperty("other") }
assertThat(e)
.hasMessage(
"Object of type `test#Person` does not have a property " +
"named `other`. Available properties: [name, age]"
"named `other`. Available properties: [name, age]"
)
}
@@ -52,15 +65,16 @@ class PObjectTest {
var objectVisited = false
var moduleVisited = false
val visitor = object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
val visitor =
object : ValueVisitor {
override fun visitObject(value: PObject) {
objectVisited = true
}
override fun visitModule(value: PModule) {
moduleVisited = true
override fun visitModule(value: PModule) {
moduleVisited = true
}
}
}
pigeon.accept(visitor)
@@ -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,10 +103,11 @@ class PObjectTest {
@Test
fun `non-equal - different property value`() {
val pigeon2 = PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 21)
)
val pigeon2 =
PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 21)
)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -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,10 +124,11 @@ class PObjectTest {
@Test
fun `non-equal - extra property`() {
val pigeon2 = PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 42, "other" to true)
)
val pigeon2 =
PObject(
PClassInfo.get("test", "Person", URI("repl:test")),
mapOf("name" to "Pigeon", "age" to 42, "other" to true)
)
assertThat(pigeon2).isNotEqualTo(pigeon)
assertThat(pigeon2.hashCode()).isNotEqualTo(pigeon.hashCode())
@@ -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
@@ -21,14 +36,13 @@ class PcfRendererTest {
assertThat(output.trim()).isEqualTo(expected.trim())
// TODO: make pcf a pkl subset again
//assertThatCode { evaluator.evaluateText(output) }.doesNotThrowAnyException()
// assertThatCode { evaluator.evaluateText(output) }.doesNotThrowAnyException()
}
@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,12 +72,15 @@ class PcfRendererTest {
corge = List(null, 1337, null, "Hello World")
grault = Map("garply", null, "waldo", 42, "pigeon", null)
}
""".trimIndent()
)
val module = Evaluator.preconfigured().evaluate(
ModuleSource.text(
"""
.trimIndent()
)
val module =
Evaluator.preconfigured()
.evaluate(
ModuleSource.text(
"""
foo = null
bar = null
baz {
@@ -78,9 +98,10 @@ class PcfRendererTest {
["pigeon"] = null
}
}
""".trimIndent()
)
)
"""
.trimIndent()
)
)
for ((omitNullProperties, expected) in cases) {
val writer = StringWriter()
ValueRenderers.pcf(writer, " ", omitNullProperties, false).renderDocument(module)
@@ -90,7 +111,7 @@ class PcfRendererTest {
// TODO: ada
// can happen in REPL or when rendering manually constructed container
/* @Test
/* @Test
fun `render container with unevaluated element`() {
renderer.renderValue(PObject(PClassInfo.Mapping, mapOf("one" to 1L, "two" to null)))

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,23 +25,31 @@ 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 {
val evaluator = Evaluator.preconfigured()
@@ -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,36 +26,30 @@ import org.pkl.core.repl.ReplServer
import org.pkl.core.resource.ResourceReaders
class ReplServerTest {
private val server = ReplServer(
SecurityManagers.defaultManager,
HttpClient.dummyClient(),
Loggers.stdErr(),
listOf(
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.classPath(this::class.java.classLoader),
ModuleKeyFactories.file
),
listOf(
ResourceReaders.environmentVariable(),
ResourceReaders.externalProperty()
),
mapOf("NAME1" to "value1", "NAME2" to "value2"),
mapOf("name1" to "value1", "name2" to "value2"),
null,
null,
null,
"/".toPath(),
StackFrameTransformers.defaultTransformer
)
private val server =
ReplServer(
SecurityManagers.defaultManager,
HttpClient.dummyClient(),
Loggers.stdErr(),
listOf(
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.classPath(this::class.java.classLoader),
ModuleKeyFactories.file
),
listOf(ResourceReaders.environmentVariable(), ResourceReaders.externalProperty()),
mapOf("NAME1" to "value1", "NAME2" to "value2"),
mapOf("name1" to "value1", "name2" to "value2"),
null,
null,
null,
"/".toPath(),
StackFrameTransformers.defaultTransformer
)
@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,18 +37,24 @@ 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 path = input.relativize(it).toString()
inputRegex.replace(path, "$1$2")
}.collect(Collectors.toSet())
val inputs =
input
.walk()
.filter { it.extension == "pkl" }
.map {
val path = input.relativize(it).toString()
inputRegex.replace(path, "$1$2")
}
.collect(Collectors.toSet())
val output = snippetsFolder.resolve("output")
output.walk().filter { it.isRegularFile() }.forEach {
val out = output.relativize(it).toString()
checkOutputHasInput(inputs, out)
}
output
.walk()
.filter { it.isRegularFile() }
.forEach {
val out = output.relativize(it).toString()
checkOutputHasInput(inputs, out)
}
}
private fun checkOutputHasInput(inputs: Set<String>, output: String) {

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,116 +27,84 @@ import org.junit.jupiter.api.io.TempDir
import org.pkl.commons.toPath
class SecurityManagersTest {
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 },
null
)
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 },
null
)
@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,12 +137,13 @@ class SecurityManagersTest {
val rootDir = tempDir.resolve("root")
Files.createDirectory(rootDir)
val manager = SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
val path = rootDir.resolve("baz.pkl")
Files.createFile(path)
@@ -174,12 +158,13 @@ class SecurityManagersTest {
fun `can resolve modules and resources under root dir - files don't exist`() {
val rootDir = "/foo/bar".toPath()
val manager = SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
manager.checkResolveModule(Path.of("/foo/bar/baz.pkl").toUri())
manager.checkReadResource(Path.of("/foo/bar/baz.pkl").toUri())
@@ -189,48 +174,44 @@ 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(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
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(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
val manager =
SecurityManagers.standard(
listOf(Pattern.compile("file")),
listOf(Pattern.compile("file")),
SecurityManagers.defaultTrustLevels,
rootDir
)
assertThrows<SecurityManagerException> {
manager.checkResolveModule(Path.of("/foo/baz.pkl").toUri())

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,21 +28,13 @@ 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,137 +74,80 @@ class VersionTest {
@Test
fun withMethods() {
val version = Version.parse("0.0.0")
.withMajor(1)
.withMinor(2)
.withPatch(3)
.withPreRelease("rc.1")
.withBuild("456.789")
val version =
Version.parse("0.0.0")
.withMajor(1)
.withMinor(2)
.withPatch(3)
.withPreRelease("rc.1")
.withBuild("456.789")
assertThat(version).isEqualTo(Version.parse("1.2.3-rc.1+456.789"))
val version2 = Version.parse("0.0.0")
.withBuild("456.789")
.withPreRelease("rc.1")
.withPatch(3)
.withMinor(2)
.withMajor(1)
val version2 =
Version.parse("0.0.0")
.withBuild("456.789")
.withPreRelease("rc.1")
.withPatch(3)
.withMinor(2)
.withMajor(1)
assertThat(version2).isEqualTo(version)
}
@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,15 +36,17 @@ 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(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
stream = new Listing {
new Dynamic {
name = "Pigeon"
@@ -48,9 +65,10 @@ class YamlRendererTest {
"Blue Rock Ltd."
12345
}
""".trimIndent()
"""
.trimIndent()
)
)
)
val writer = StringWriter()
val renderer = ValueRenderers.yaml(writer, 2, true, true)
@@ -58,8 +76,9 @@ 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,18 +112,20 @@ class YamlRendererTest {
@Test
fun `render truthy strings, octals and number-like strings`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
num1 = "50"
num2 = "50.123"
`60.123` = "60.123"
yes = "yes"
truth = "true"
octalNumber = "0777"
""".trimIndent()
"""
.trimIndent()
)
)
)
val writer = StringWriter()
val renderer = ValueRenderers.yaml(writer, 2, true, false)
@@ -112,15 +133,17 @@ class YamlRendererTest {
renderer.renderDocument(module)
val output = writer.toString()
assertThat(output.trim()).isEqualTo(
"""
assertThat(output.trim())
.isEqualTo(
"""
num1: '50'
num2: '50.123'
'60.123': '60.123'
'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,18 +43,23 @@ 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(
"foo.pkl",
"bar.pkl",
"bazzy/buz.pkl",
"qux.pkl",
"qux/*.pkl",
"/some/dir/chown.txt",
"/some/dir/chowner.txt",
"/some/dir/*.txt"
))
val imports =
ImportsAndReadsParser.parse(moduleKey, moduleKey.resolve(SecurityManagers.defaultManager))
assertThat(imports?.map { it.first })
.hasSameElementsAs(
listOf(
"foo.pkl",
"bar.pkl",
"bazzy/buz.pkl",
"qux.pkl",
"qux/*.pkl",
"/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,11 +51,12 @@ class HttpClientTest {
@Test
fun `can build custom client`() {
val client = HttpClient.builder()
.setUserAgent("Agent 1")
.setRequestTimeout(Duration.ofHours(86))
.setConnectTimeout(Duration.ofMinutes(42))
.build() as RequestRewritingClient
val client =
HttpClient.builder()
.setUserAgent("Agent 1")
.setRequestTimeout(Duration.ofHours(86))
.setConnectTimeout(Duration.ofMinutes(42))
.build() as RequestRewritingClient
assertThat(client.userAgent).isEqualTo("Agent 1")
assertThat(client.requestTimeout).isEqualTo(Duration.ofHours(86))
@@ -68,27 +83,24 @@ 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
fun `can be closed multiple times`() {
val client = HttpClient.builder().build()
assertDoesNotThrow {
client.close()
client.close()
assertDoesNotThrow {
client.close()
client.close()
}
}

View File

@@ -1,37 +1,46 @@
/**
* 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()
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 {
@@ -44,7 +59,7 @@ class NoProxyRuleTest {
assertFalse(noProxyRule.matches(URI("https://ooofoo.com")))
assertFalse(noProxyRule.matches(URI("pkl:foo.com")))
}
@Test
fun `hostname matching, with port`() {
val noProxyRule = NoProxyRule("foo.com:5000")
@@ -52,7 +67,7 @@ class NoProxyRuleTest {
assertFalse(noProxyRule.matches(URI("https://foo.com")))
assertFalse(noProxyRule.matches(URI("https://foo.com:3000")))
}
@Test
fun `ipv4 address literal matching`() {
val noProxyRule = NoProxyRule("192.168.1.1")
@@ -95,7 +110,7 @@ class NoProxyRuleTest {
assertFalse(noProxyRule.matches(URI("https://[::2]")))
assertFalse(noProxyRule.matches(URI("https://[::2]:5000")))
}
@Test
fun `ipv4 port from protocol`() {
val noProxyRuleHttp = NoProxyRule("192.168.1.1:80")
@@ -104,7 +119,7 @@ class NoProxyRuleTest {
assertTrue(noProxyRuleHttp.matches(URI("https://192.168.1.1:80")))
assertFalse(noProxyRuleHttp.matches(URI("https://192.168.1.1")))
assertFalse(noProxyRuleHttp.matches(URI("https://192.168.1.1:5000")))
val noProxyRuleHttps = NoProxyRule("192.168.1.1:443")
assertTrue(noProxyRuleHttps.matches(URI("https://192.168.1.1")))
assertTrue(noProxyRuleHttps.matches(URI("http://192.168.1.1:443")))

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.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
override fun <T : Any> send(
request: HttpRequest,
responseBodyHandler: HttpResponse.BodyHandler<T>

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()
@@ -19,17 +34,18 @@ class RequestRewritingClientTest {
@Test
fun `fills in missing User-Agent header`() {
client.send(exampleRequest, BodyHandlers.discarding())
assertThatList(captured.request.headers().allValues("User-Agent")).containsOnly("Pkl")
}
@Test
fun `overrides existing User-Agent headers`() {
val request = HttpRequest.newBuilder(exampleUri)
.header("User-Agent", "Agent 1")
.header("User-Agent", "Agent 2")
.build()
val request =
HttpRequest.newBuilder(exampleUri)
.header("User-Agent", "Agent 1")
.header("User-Agent", "Agent 2")
.build()
client.send(request, BodyHandlers.discarding())
assertThatList(captured.request.headers().allValues("User-Agent")).containsOnly("Pkl")
@@ -38,16 +54,14 @@ class RequestRewritingClientTest {
@Test
fun `fills in missing request timeout`() {
client.send(exampleRequest, BodyHandlers.discarding())
assertThat(captured.request.timeout()).hasValue(Duration.ofSeconds(42))
}
@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())
assertThat(captured.request.timeout()).hasValue(Duration.ofMinutes(33))
@@ -62,12 +76,10 @@ 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())
assertThat(captured.request.version()).hasValue(JdkHttpClient.Version.HTTP_1_1)
}
@@ -79,30 +91,26 @@ class RequestRewritingClientTest {
assertThat(captured.request.method()).isEqualTo("GET")
}
@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())
assertThat(captured.request.method()).isEqualTo("DELETE")
}
@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())
assertThat(captured.request.bodyPublisher().get()).isSameAs(publisher)
}
@Test
fun `rewrites port 0 if test port is set`() {
val captured = RequestCapturingClient()
@@ -113,15 +121,13 @@ class RequestRewritingClientTest {
assertThat(captured.request.uri().port).isEqualTo(5000)
}
@Test
fun `leaves port 0 intact if no test port is set`() {
val request = HttpRequest.newBuilder(URI("https://example.com:0")).build()
client.send(request, BodyHandlers.discarding())
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,18 +110,18 @@ 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> {
ModuleKeys.classPath(URI("modulepath:foo/bar.pkl"), ModuleKeysTest::class.java.classLoader)
}
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,61 +155,55 @@ 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> {
ModuleKeys.modulePath(URI("modulepath:foo/bar.pkl"), ModulePathResolver(listOf()))
}
val e =
assertThrows<IllegalArgumentException> {
ModuleKeys.modulePath(URI("modulepath:foo/bar.pkl"), ModulePathResolver(listOf()))
}
assertThat(e).hasMessageContaining("`/`")
}
@Test
fun `package - no version`() {
val e = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://localhost:0/birds#/Bird.pkl"))
}
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")
}
@Test
fun `package - invalid semver`() {
val e = assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://localhost:0/birds@notAVersion#/Bird.pkl"))
}
val e =
assertThrows<URISyntaxException> {
ModuleKeys.pkg(URI("package://localhost:0/birds@notAVersion#/Bird.pkl"))
}
assertThat(e).hasMessageContaining("`notAVersion` could not be parsed")
}
@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,28 +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.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(
PModule(
uri,
"testFactoryTest",
PClassInfo.forModuleClass("testFactoryTest", uri),
mapOf("name" to "Pigeon", "age" to 40L)
Assertions.assertThat(module)
.isEqualTo(
PModule(
uri,
"testFactoryTest",
PClassInfo.forModuleClass("testFactoryTest", uri),
mapOf("name" to "Pigeon", "age" to 40L)
)
)
)
}
}

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,33 +1,54 @@
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(
"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")),
),
"https://example.com/my/source/0.5.3/blob%{path}#L%{line}-L%{endLine}",
URI("https://example.com/my/source"),
URI("https://example.com/my/docs"),
"MIT",
"The MIT License, you know it",
listOf("birdy@bird.com"),
URI("https://example.com/issues"),
"Some package description"
)
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")
),
),
"https://example.com/my/source/0.5.3/blob%{path}#L%{line}-L%{endLine}",
URI("https://example.com/my/source"),
URI("https://example.com/my/docs"),
"MIT",
"The MIT License, you know it",
listOf("birdy@bird.com"),
URI("https://example.com/issues"),
"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() {
@@ -64,10 +86,11 @@ class DependencyMetadataTest {
}
@Test
fun writeTo(){
val str = ByteArrayOutputStream()
.apply { dependencyMetadata.writeTo(this) }
.toString(StandardCharsets.UTF_8)
fun writeTo() {
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,31 +31,27 @@ 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()
@JvmStatic
@AfterAll
fun afterAll() {
packageServer.close()
}
val httpClient: HttpClient by lazy {
HttpClient.builder()
.addCertificates(FileTestUtils.selfSignedCertificate)
@@ -46,105 +62,107 @@ 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")
}
@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(
setOf(
PathElement("some", true),
PathElement("catalog", true),
PathElement("Bird.pkl", false),
PathElement("allFruit.pkl", false),
PathElement("catalog.pkl", false)
val elements =
resolver.listElements(PackageAssetUri("package://localhost:0/birds@0.5.0#/"), null).toSet()
assertThat(elements)
.isEqualTo(
setOf(
PathElement("some", true),
PathElement("catalog", true),
PathElement("Bird.pkl", false),
PathElement("allFruit.pkl", false),
PathElement("catalog.pkl", false)
)
)
)
}
@Test
fun `get multiple assets`() {
val bird = resolver.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl"),
false,
null
)
val swallow = resolver.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/catalog/Swallow.pkl"),
false,
null
)
val bird =
resolver.getBytes(
PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl"),
false,
null
)
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(
setOf(
PathElement("Ostritch.pkl", false),
PathElement("Swallow.pkl", false),
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),
)
)
)
}
@Test
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)
}
}
@@ -164,26 +183,35 @@ class PackageResolversTest {
@Test
fun `requires package zip to be an HTTPS URI`() {
assertThatCode {
resolver.getBytes(
PackageAssetUri("package://localhost:0/badPackageZipUrl@1.0.0#/Bug.pkl"),
false,
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`.")
resolver.getBytes(
PackageAssetUri("package://localhost:0/badPackageZipUrl@1.0.0#/Bug.pkl"),
false,
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`."
)
}
@Test
fun `throws if package checksum is invalid`() {
val error = assertThrows<PackageLoadError> {
resolver.getBytes(
PackageAssetUri("package://localhost:0/badChecksum@1.0.0#/Bug.pkl"),
false,
null)
}
assertThat(error).hasMessageContaining("""
val error =
assertThrows<PackageLoadError> {
resolver.getBytes(
PackageAssetUri("package://localhost:0/badChecksum@1.0.0#/Bug.pkl"),
false,
null
)
}
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,15 +25,17 @@ class ShebangTest {
@Test
fun `shebang is ignored`() {
val module = evaluator.evaluate(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
#!/usr/local/bin/pkl
x = 1
""".trimIndent()
"""
.trimIndent()
)
)
)
assertThat (module.properties["x"]).isEqualTo(1L)
assertThat(module.properties["x"]).isEqualTo(1L)
}
}

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,23 +24,21 @@ 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 {
private val packageServer = PackageServer()
@JvmStatic
@AfterAll
fun afterAll() {
packageServer.close()
}
val httpClient: HttpClient by lazy {
HttpClient.builder()
.addCertificates(FileTestUtils.selfSignedCertificate)
@@ -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()
.apply { deps.writeTo(this) }
.toByteArray()
.toString(StandardCharsets.UTF_8)
assertThat(strDeps).isEqualTo("""
val strDeps =
ByteArrayOutputStream()
.apply { deps.writeTo(this) }
.toByteArray()
.toString(StandardCharsets.UTF_8)
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> {
ProjectDependenciesResolver(project, packageResolver, System.err.writer()).resolve()
}
assertThat(e).hasMessage("""
val packageResolver =
PackageResolver.getInstance(SecurityManagers.defaultManager, httpClient, null)
val e =
assertThrows<PklException> {
ProjectDependenciesResolver(project, packageResolver, System.err.writer()).resolve()
}
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,27 +44,29 @@ class ProjectDepsTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
private val projectDeps = let {
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(
PackageUri.create("package://localhost:0/fruit@1.1.0"),
Path.of("../fruit")
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(
PackageUri.create("package://localhost:0/fruit@1.1.0"),
Path.of("../fruit")
)
)
)
ProjectDeps(projectDepsMap)
}
@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,54 +26,52 @@ 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(
"hawk",
PackageUri("package://example.com/hawk@0.5.0"),
Version.parse("0.5.0"),
URI("https://example.com/hawk/0.5.0/hawk-0.5.0.zip"),
"Some project about hawks",
listOf("Birdy Bird <birdy@bird.com>"),
URI("https://example.com/my/website"),
URI("https://example.com/my/docs"),
URI("https://example.com/my/repo"),
"https://example.com/my/repo/0.5.0%{path}",
"MIT",
"""
val expectedPackage =
Package(
"hawk",
PackageUri("package://example.com/hawk@0.5.0"),
Version.parse("0.5.0"),
URI("https://example.com/hawk/0.5.0/hawk-0.5.0.zip"),
"Some project about hawks",
listOf("Birdy Bird <birdy@bird.com>"),
URI("https://example.com/my/website"),
URI("https://example.com/my/docs"),
URI("https://example.com/my/repo"),
"https://example.com/my/repo/0.5.0%{path}",
"MIT",
"""
# Some License text
This is my license text
""".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(
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/")
),
Duration.ofMinutes(5.0),
path,
null
)
projectPath.writeString("""
"""
.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(
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/")),
Duration.ofMinutes(5.0),
path,
null
)
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()
.addCertificates(FileTestUtils.selfSignedCertificate)
.setTestPort(server.port)
.build()
val evaluator = EvaluatorBuilder.preconfigured()
.applyFromProject(project)
.setModuleCacheDir(null)
.setHttpClient(httpClient)
.build()
assertThatCode {
evaluator.evaluate(ModuleSource.path(projectDir.resolve("bug.pkl")))
}.hasMessageStartingWith("""
val httpClient =
HttpClient.builder()
.addCertificates(FileTestUtils.selfSignedCertificate)
.setTestPort(server.port)
.build()
val evaluator =
EvaluatorBuilder.preconfigured()
.applyFromProject(project)
.setModuleCacheDir(null)
.setHttpClient(httpClient)
.build()
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,27 +1,43 @@
/**
* 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(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
res1 = read("modulepath:/org/pkl/core/resource/resource.txt").text
"""
)
)
)
assertThat(module.getProperty("res1")).isEqualTo("content")
}
@@ -38,18 +54,16 @@ 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(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
res1 = read("modulepath:/dir1/resource1.txt").text
"""
)
)
)
assertThat(module.getProperty("res1")).isEqualTo("content\n")
}

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,38 +1,58 @@
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;
//import java.net.URISyntaxException;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.util.Arrays;
//import java.util.Collections;
// import java.io.IOException;
// import java.net.URI;
// import java.net.URISyntaxException;
// import java.nio.file.Files;
// import java.nio.file.Path;
// import java.util.Arrays;
// import java.util.Collections;
//
//import org.pkl.core.EvalOptions;
//import org.pkl.core.EvalException;
//import org.pkl.core.resolve.ModuleKey;
//import org.pkl.core.resolve.ModuleKeyFactories;
//import org.pkl.core.resolve.ModuleKeys;
//import com.oracle.truffle.api.source.SourceSection;
//import org.junit.Ignore;
//import org.junit.Test;
// import org.pkl.core.EvalOptions;
// import org.pkl.core.EvalException;
// import org.pkl.core.resolve.ModuleKey;
// import org.pkl.core.resolve.ModuleKeyFactories;
// import org.pkl.core.resolve.ModuleKeys;
// import com.oracle.truffle.api.source.SourceSection;
// import org.junit.Ignore;
// import org.junit.Test;
//
//import static org.junit.Assert.assertEquals;
//import static org.junit.Assert.assertTrue;
// import static org.junit.Assert.assertEquals;
// import static org.junit.Assert.assertTrue;
//
//public class DefaultModuleResolverTest {
// 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());
// }
@@ -183,4 +207,4 @@ package org.pkl.core.runtime;
//
// resolver.resolve("pkl:base", fileUrlModule, sourceSection);
// }
//}
// }

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,22 +1,38 @@
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;
//import java.net.URI;
//import java.net.URISyntaxException;
// import java.io.File;
// import java.io.IOException;
// import java.net.URI;
// import java.net.URISyntaxException;
//
//import org.pkl.core.resolve.ModuleKey;
//import org.pkl.core.resolve.ModuleKeys;
//import org.junit.Rule;
//import org.junit.Test;
//import org.junit.rules.TemporaryFolder;
// import org.pkl.core.resolve.ModuleKey;
// import org.pkl.core.resolve.ModuleKeys;
// import org.junit.Rule;
// import org.junit.Test;
// import org.junit.rules.TemporaryFolder;
//
//import static org.junit.Assert.assertEquals;
//import static org.junit.Assert.assertFalse;
//import static org.junit.Assert.assertTrue;
// import static org.junit.Assert.assertEquals;
// import static org.junit.Assert.assertFalse;
// import static org.junit.Assert.assertTrue;
//
//// some parts of ModuleKey are tested as part of DefaultModuleResolverTest
//public class ModuleKeyTest {
// public class ModuleKeyTest {
// @Rule
// public TemporaryFolder folder = new TemporaryFolder();
//
@@ -73,4 +89,4 @@ package org.pkl.core.runtime;
// assertEquals("literal:name", module.getUri());
// assertFalse(module.isBaseModule());
// }
//}
// }

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,39 +35,51 @@ class StackTraceRendererTest {
@Test
fun `stringy self-reference`() {
val message = assertThrows<PklException> {
evaluator.evaluate(
ModuleSource.text(
"""
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())
)
}.message!!
"""
.trimIndent()
)
)
}
.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> {
evaluator.evaluate(
ModuleSource.text(
"""
val message =
assertThrows<PklException> {
evaluator.evaluate(
ModuleSource.text(
"""
foo: String = "FOO:" + bar
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,15 +136,15 @@ 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)")
}
assertThat(message)
.contains("A stack overflow occurred.")
.containsPattern("┌─ \\d+ repetitions of:\n\n│ 9 | loop\\(\\)")
@@ -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

View File

@@ -1,21 +1,33 @@
/**
* 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.settings
import java.net.URI
import java.nio.file.Path
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
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.writeString
import org.pkl.core.Evaluator
import org.pkl.core.ModuleSource
import org.pkl.core.PObject
import org.pkl.core.StackFrameTransformers
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
import org.pkl.core.runtime.VmException
import org.pkl.core.settings.PklSettings.Editor
import java.net.URI
class PklSettingsTest {
@Test
@@ -26,13 +38,14 @@ class PklSettingsTest {
"""
amends "pkl:settings"
editor = Sublime
""".trimIndent()
"""
.trimIndent()
)
val settings = PklSettings.loadFromPklHomeDir(tempDir)
assertThat(settings).isEqualTo(PklSettings(Editor.SUBLIME, null))
}
@Test
fun `load user settings with http`(@TempDir tempDir: Path) {
val settingsPath = tempDir.resolve("settings.pkl")
@@ -49,16 +62,18 @@ class PklSettingsTest {
}
}
}
""".trimIndent()
"""
.trimIndent()
)
val settings = PklSettings.loadFromPklHomeDir(tempDir)
val expectedHttp = PklEvaluatorSettings.Http(
PklEvaluatorSettings.Proxy(
URI("http://localhost:8080"),
listOf("example.com", "pkg.pkl-lang.org")
val expectedHttp =
PklEvaluatorSettings.Http(
PklEvaluatorSettings.Proxy(
URI("http://localhost:8080"),
listOf("example.com", "pkg.pkl-lang.org")
)
)
)
assertThat(settings).isEqualTo(PklSettings(Editor.SYSTEM, expectedHttp))
}
@@ -74,16 +89,18 @@ class PklSettingsTest {
address = "http://localhost:8080"
}
}
""".trimIndent()
"""
.trimIndent()
)
val settings = PklSettings.loadFromPklHomeDir(tempDir)
val expectedHttp = PklEvaluatorSettings.Http(
PklEvaluatorSettings.Proxy(
URI("http://localhost:8080"),
listOf(),
val expectedHttp =
PklEvaluatorSettings.Http(
PklEvaluatorSettings.Proxy(
URI("http://localhost:8080"),
listOf(),
)
)
)
assertThat(settings).isEqualTo(PklSettings(Editor.SYSTEM, expectedHttp))
}
@@ -94,7 +111,8 @@ class PklSettingsTest {
"""
amends "pkl:settings"
editor = Idea
""".trimIndent()
"""
.trimIndent()
)
val settings = PklSettings.load(ModuleSource.path(settingsPath))
@@ -104,9 +122,10 @@ class PklSettingsTest {
@Test
fun `predefined editors`() {
val evaluator = Evaluator.preconfigured()
val module = evaluator.evaluate(
ModuleSource.text(
"""
val module =
evaluator.evaluate(
ModuleSource.text(
"""
import "pkl:settings"
system = settings.System
@@ -115,9 +134,10 @@ class PklSettingsTest {
sublime = settings.Sublime
atom = settings.Atom
vsCode = settings.VsCode
""".trimIndent()
"""
.trimIndent()
)
)
)
checkEquals(Editor.SYSTEM, module.getProperty("system") as PObject)
checkEquals(Editor.IDEA, module.getProperty("idea") as PObject)
@@ -131,7 +151,9 @@ class PklSettingsTest {
fun `invalid settings file`(@TempDir tempDir: Path) {
val settingsFile = tempDir.resolve("settings.pkl").apply { writeString("foo = 1") }
assertThatCode { PklSettings.loadFromPklHomeDir(tempDir) }
.hasMessageContaining("Expected `output.value` of module `${settingsFile.toUri()}` to be of type `pkl.settings`, but got type `settings`.")
.hasMessageContaining(
"Expected `output.value` of module `${settingsFile.toUri()}` to be of type `pkl.settings`, but got type `settings`."
)
}
private fun checkEquals(expected: Editor, actual: PObject) {

View File

@@ -1,9 +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.stdlib
import org.pkl.core.runtime.Identifier
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.pkl.core.runtime.Identifier
class PathConverterSupportTest {
@Test
@@ -15,14 +29,16 @@ class PathConverterSupportTest {
@Test
fun `wildcard properties`() {
val pathSpec = listOf(Identifier.get("foo"), PklConverter.WILDCARD_PROPERTY, Identifier.get("baz"))
val pathSpec =
listOf(Identifier.get("foo"), PklConverter.WILDCARD_PROPERTY, Identifier.get("baz"))
val pathPartSpec = listOf(Identifier.get("foo"), Identifier.get("bar"), Identifier.get("baz"))
assertTrue(PathConverterSupport.pathMatches(pathSpec, pathPartSpec))
}
@Test
fun `wildcard elements`() {
val pathSpec = listOf(Identifier.get("foo"), PklConverter.WILDCARD_ELEMENT, Identifier.get("baz"))
val pathSpec =
listOf(Identifier.get("foo"), PklConverter.WILDCARD_ELEMENT, Identifier.get("baz"))
val pathPartSpec = listOf(Identifier.get("foo"), 0, Identifier.get("baz"))
assertTrue(PathConverterSupport.pathMatches(pathSpec, pathPartSpec))
}

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.stdlib
import org.assertj.core.api.Assertions.assertThat
@@ -12,14 +27,11 @@ class PathSpecParserTest {
@Test
fun `parse valid path specs`() {
assertThat(parser.parse(""))
.isEqualTo(arrayOf(TOP_LEVEL_VALUE))
assertThat(parser.parse("")).isEqualTo(arrayOf(TOP_LEVEL_VALUE))
assertThat(parser.parse("^"))
.isEqualTo(arrayOf(TOP_LEVEL_VALUE))
assertThat(parser.parse("^")).isEqualTo(arrayOf(TOP_LEVEL_VALUE))
assertThat(parser.parse("property"))
.isEqualTo(arrayOf(Identifier.get("property")))
assertThat(parser.parse("property")).isEqualTo(arrayOf(Identifier.get("property")))
assertThat(parser.parse("^property"))
.isEqualTo(arrayOf(Identifier.get("property"), TOP_LEVEL_VALUE))
@@ -28,107 +40,55 @@ class PathSpecParserTest {
.isEqualTo(arrayOf(Identifier.get("prop3"), Identifier.get("prop2"), Identifier.get("prop1")))
assertThat(parser.parse("^prop1.prop2.prop3"))
.isEqualTo(arrayOf(Identifier.get("prop3"), Identifier.get("prop2"), Identifier.get("prop1"), TOP_LEVEL_VALUE))
.isEqualTo(
arrayOf(
Identifier.get("prop3"),
Identifier.get("prop2"),
Identifier.get("prop1"),
TOP_LEVEL_VALUE
)
)
assertThat(parser.parse("[key]"))
.isEqualTo(arrayOf("key"))
assertThat(parser.parse("[key]")).isEqualTo(arrayOf("key"))
assertThat(parser.parse("^[key]"))
.isEqualTo(arrayOf("key", TOP_LEVEL_VALUE))
assertThat(parser.parse("^[key]")).isEqualTo(arrayOf("key", TOP_LEVEL_VALUE))
assertThat(parser.parse("[key1][key2][key3]"))
.isEqualTo(arrayOf("key3", "key2", "key1"))
assertThat(parser.parse("[key1][key2][key3]")).isEqualTo(arrayOf("key3", "key2", "key1"))
assertThat(parser.parse("^[key1][key2][key3]"))
.isEqualTo(arrayOf("key3", "key2", "key1", TOP_LEVEL_VALUE))
assertThat(parser.parse("*"))
.isEqualTo(arrayOf(WILDCARD_PROPERTY))
assertThat(parser.parse("*")).isEqualTo(arrayOf(WILDCARD_PROPERTY))
assertThat(parser.parse("^*"))
.isEqualTo(arrayOf(WILDCARD_PROPERTY, TOP_LEVEL_VALUE))
assertThat(parser.parse("^*")).isEqualTo(arrayOf(WILDCARD_PROPERTY, TOP_LEVEL_VALUE))
assertThat(parser.parse("[*]"))
.isEqualTo(arrayOf(WILDCARD_ELEMENT))
assertThat(parser.parse("[*]")).isEqualTo(arrayOf(WILDCARD_ELEMENT))
assertThat(parser.parse("^[*]"))
.isEqualTo(arrayOf(WILDCARD_ELEMENT, TOP_LEVEL_VALUE))
assertThat(parser.parse("^[*]")).isEqualTo(arrayOf(WILDCARD_ELEMENT, TOP_LEVEL_VALUE))
assertThat(parser.parse("*.*.*"))
.isEqualTo(
arrayOf(
WILDCARD_PROPERTY,
WILDCARD_PROPERTY,
WILDCARD_PROPERTY
)
)
.isEqualTo(arrayOf(WILDCARD_PROPERTY, WILDCARD_PROPERTY, WILDCARD_PROPERTY))
assertThat(parser.parse("^*.*.*"))
.isEqualTo(
arrayOf(
WILDCARD_PROPERTY,
WILDCARD_PROPERTY,
WILDCARD_PROPERTY,
TOP_LEVEL_VALUE
)
)
.isEqualTo(arrayOf(WILDCARD_PROPERTY, WILDCARD_PROPERTY, WILDCARD_PROPERTY, TOP_LEVEL_VALUE))
assertThat(parser.parse("[*][*][*]"))
.isEqualTo(
arrayOf(
WILDCARD_ELEMENT,
WILDCARD_ELEMENT,
WILDCARD_ELEMENT
)
)
.isEqualTo(arrayOf(WILDCARD_ELEMENT, WILDCARD_ELEMENT, WILDCARD_ELEMENT))
assertThat(parser.parse("^[*][*][*]"))
.isEqualTo(
arrayOf(
WILDCARD_ELEMENT,
WILDCARD_ELEMENT,
WILDCARD_ELEMENT,
TOP_LEVEL_VALUE
)
)
.isEqualTo(arrayOf(WILDCARD_ELEMENT, WILDCARD_ELEMENT, WILDCARD_ELEMENT, TOP_LEVEL_VALUE))
assertThat(parser.parse("[*].*[*]"))
.isEqualTo(
arrayOf(
WILDCARD_ELEMENT,
WILDCARD_PROPERTY,
WILDCARD_ELEMENT
)
)
.isEqualTo(arrayOf(WILDCARD_ELEMENT, WILDCARD_PROPERTY, WILDCARD_ELEMENT))
assertThat(parser.parse("^[*].*[*]"))
.isEqualTo(
arrayOf(
WILDCARD_ELEMENT,
WILDCARD_PROPERTY,
WILDCARD_ELEMENT,
TOP_LEVEL_VALUE
)
)
.isEqualTo(arrayOf(WILDCARD_ELEMENT, WILDCARD_PROPERTY, WILDCARD_ELEMENT, TOP_LEVEL_VALUE))
assertThat(parser.parse("*[*].*"))
.isEqualTo(
arrayOf(
WILDCARD_PROPERTY,
WILDCARD_ELEMENT,
WILDCARD_PROPERTY
)
)
.isEqualTo(arrayOf(WILDCARD_PROPERTY, WILDCARD_ELEMENT, WILDCARD_PROPERTY))
assertThat(parser.parse("^*[*].*"))
.isEqualTo(
arrayOf(
WILDCARD_PROPERTY,
WILDCARD_ELEMENT,
WILDCARD_PROPERTY,
TOP_LEVEL_VALUE
)
)
.isEqualTo(arrayOf(WILDCARD_PROPERTY, WILDCARD_ELEMENT, WILDCARD_PROPERTY, TOP_LEVEL_VALUE))
assertThat(parser.parse("prop1[key1].*[key2].prop2[*]"))
.isEqualTo(
@@ -160,60 +120,32 @@ class PathSpecParserTest {
// TODO: support quoted identifiers?
@Test
fun `parse invalid path specs`() {
assertThrows<VmException> {
parser.parse("^^")
}
assertThrows<VmException> { parser.parse("^^") }
assertThrows<VmException> {
parser.parse("property.")
}
assertThrows<VmException> { parser.parse("property.") }
assertThrows<VmException> {
parser.parse("property^")
}
assertThrows<VmException> { parser.parse("property^") }
assertThrows<VmException> {
parser.parse(".property")
}
assertThrows<VmException> { parser.parse(".property") }
assertThrows<VmException> {
parser.parse("prop1..prop2")
}
assertThrows<VmException> { parser.parse("prop1..prop2") }
assertThrows<VmException> {
parser.parse("[key")
}
assertThrows<VmException> { parser.parse("[key") }
assertThrows<VmException> {
parser.parse("key]")
}
assertThrows<VmException> { parser.parse("key]") }
assertThrows<VmException> {
parser.parse("[[key]]")
}
assertThrows<VmException> { parser.parse("[[key]]") }
assertThrows<VmException> {
parser.parse("property.[key]")
}
assertThrows<VmException> { parser.parse("property.[key]") }
assertThrows<VmException> {
parser.parse("[key1].[key2]")
}
assertThrows<VmException> { parser.parse("[key1].[key2]") }
assertThrows<VmException> {
parser.parse("[key1] [key2]")
}
assertThrows<VmException> { parser.parse("[key1] [key2]") }
assertThrows<VmException> {
parser.parse("**")
}
assertThrows<VmException> { parser.parse("**") }
assertThrows<VmException> {
parser.parse("[**]")
}
assertThrows<VmException> { parser.parse("[**]") }
assertThrows<VmException> {
parser.parse("[*")
}
assertThrows<VmException> { parser.parse("[*") }
}
}

View File

@@ -1,22 +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.stdlib
import org.pkl.core.Evaluator
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import org.pkl.core.Evaluator
import org.pkl.core.ModuleSource
class ReflectModuleTest {
private val evaluator = Evaluator.preconfigured()
@ValueSource(
strings = [
"pkl:base", "pkl:json", "pkl:jsonnet", "pkl:math", "pkl:protobuf", "pkl:reflect",
"pkl:settings", "pkl:shell", "pkl:test", "pkl:xml", "pkl:yaml"
]
strings =
[
"pkl:base",
"pkl:json",
"pkl:jsonnet",
"pkl:math",
"pkl:protobuf",
"pkl:reflect",
"pkl:settings",
"pkl:shell",
"pkl:test",
"pkl:xml",
"pkl:yaml"
]
)
@ParameterizedTest(name = "can reflect on {0} module")
fun `can reflect on stdlib module`(moduleName: String) {
//language=Pkl
// language=Pkl
evaluator.evaluate(
ModuleSource.text(
"""
@@ -26,7 +51,8 @@ class ReflectModuleTest {
output {
text = reflect.Module(import("$moduleName")).toString()
}
""".trimIndent()
"""
.trimIndent()
)
)
}

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.truffle
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
// Verifies that (long, long) specialization is chosen for (long, long) inputs
@@ -18,84 +33,84 @@ class LongVsDoubleSpecializationTest {
@Test
fun addition() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text("""
x1 = Pair(1.0 + 2.0, 1 + 2).second
"""
""")
)
)
assertThat(result.properties["x1"]).isEqualTo(3L)
}
@Test
fun subtraction() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text("""
x1 = Pair(1.0 - 2.0, 1 - 2).second
"""
""")
)
)
assertThat(result.properties["x1"]).isEqualTo(-1L)
}
@Test
fun multiplication() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text("""
x1 = Pair(1.0 * 2.0, 1 * 2).second
"""
""")
)
)
assertThat(result.properties["x1"]).isEqualTo(2L)
}
@Test
fun exponentiation() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text(
"""
import "pkl:math"
x1 = Pair(2.0 ** 2.0, 2 ** 2).second
"""
)
)
)
assertThat(result.properties["x1"]).isEqualTo(4L)
}
@Test
fun math_min() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text(
"""
import "pkl:math"
x1 = Pair(math.min(1.0, 2.0), math.min(1, 2)).second
"""
)
)
)
assertThat(result.properties["x1"]).isEqualTo(1L)
}
@Test
fun math_max() {
val result = evaluator.evaluate(
ModuleSource.text(
"""
val result =
evaluator.evaluate(
ModuleSource.text(
"""
import "pkl:math"
x1 = Pair(math.max(1.0, 2.0), math.max(1, 2)).second
"""
)
)
)
assertThat(result.properties["x1"]).isEqualTo(2L)
}

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.util
import org.assertj.core.api.Assertions.assertThat
@@ -7,11 +22,12 @@ import org.junit.jupiter.api.assertThrows
class ArrayCharEscaperTest {
@Test
fun `basic usage`() {
val escaper = ArrayCharEscaper.builder()
.withEscape('ä', "ae")
.withEscape('ö', "oe")
.withEscape('ü', "ue")
.build()
val escaper =
ArrayCharEscaper.builder()
.withEscape('ä', "ae")
.withEscape('ö', "oe")
.withEscape('ü', "ue")
.build()
assertThat(escaper.escape("")).isEqualTo("")
assertThat(escaper.escape("äää")).isEqualTo("aeaeae")
@@ -26,10 +42,7 @@ class ArrayCharEscaperTest {
@Test
fun `enforces size limit`() {
assertThrows<IllegalStateException> {
ArrayCharEscaper.builder()
.withEscape('a', "aa")
.withEscape('Ɇ', "ee")
.build()
ArrayCharEscaper.builder().withEscape('a', "aa").withEscape('Ɇ', "ee").build()
}
}
@@ -44,9 +57,7 @@ class ArrayCharEscaperTest {
@Test
fun `returns original string if no escaping required`() {
val escaper = ArrayCharEscaper.builder()
.withEscape('ä', "ae")
.build()
val escaper = ArrayCharEscaper.builder().withEscape('ä', "ae").build()
val fox = "The quick brown fox jumps over the lazy dog."
assertThat(escaper.escape(fox)).isSameAs(fox)

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.util
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.io.IOException
import java.lang.Error
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
class ExceptionsTest {
@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.util
import org.junit.jupiter.api.Assertions.assertFalse
@@ -26,77 +41,74 @@ class GlobResolverTest {
}
@ParameterizedTest
@ValueSource(strings = [
"foo.pkl",
"bar.pkl",
"baz.pkl",
"buzzy...baz.pkl",
"ted_lasso.min.pkl",
"ted_lasso.pkl.min.pkl"
])
@ValueSource(
strings =
[
"foo.pkl",
"bar.pkl",
"baz.pkl",
"buzzy...baz.pkl",
"ted_lasso.min.pkl",
"ted_lasso.pkl.min.pkl"
]
)
fun `glob match`(input: String) {
val pattern = GlobResolver.toRegexPattern("*.pkl")
assertTrue(pattern.matcher(input).matches())
}
@ParameterizedTest
@ValueSource(strings = [
"bar.pcf",
"bar.yml",
"bar.pkl.bcl",
"bar.pklpkl",
"pkl",
// crosses directory boundaries
"/bar/baz.pkl",
"/baz.pkl"
])
@ValueSource(
strings =
[
"bar.pcf",
"bar.yml",
"bar.pkl.bcl",
"bar.pklpkl",
"pkl",
// crosses directory boundaries
"/bar/baz.pkl",
"/baz.pkl"
]
)
fun `glob non-match`(input: String) {
val pattern = GlobResolver.toRegexPattern("*.pkl")
assertFalse(pattern.matcher(input).matches())
}
@ParameterizedTest
@ValueSource(strings = [
"/foo.pkl/bar/baz.pkl",
"//fo///ba.pkl",
".pkl",
"buz.pkl",
"pkl.pkl.pkl.pkl"
])
@ValueSource(
strings = ["/foo.pkl/bar/baz.pkl", "//fo///ba.pkl", ".pkl", "buz.pkl", "pkl.pkl.pkl.pkl"]
)
fun `globstar match`(input: String) {
val pattern = GlobResolver.toRegexPattern("**.pkl")
assertTrue(pattern.matcher(input).matches())
}
@ParameterizedTest
@ValueSource(strings = [
"/foo.pkl/bar/baz.pkl",
"//fo///ba.pkl",
".pkl",
"buz.pkl",
"pkl.pkl.pkl.pkl"
])
@ValueSource(
strings = ["/foo.pkl/bar/baz.pkl", "//fo///ba.pkl", ".pkl", "buz.pkl", "pkl.pkl.pkl.pkl"]
)
fun `globstar non-match`(input: String) {
val pattern = GlobResolver.toRegexPattern("**.pkl")
assertTrue(pattern.matcher(input).matches())
}
@ParameterizedTest
@ValueSource(strings = [
"/foo.pkl/bar/baz.pkl",
"//fo///ba.pkl",
])
@ValueSource(
strings =
[
"/foo.pkl/bar/baz.pkl",
"//fo///ba.pkl",
]
)
fun `globstar match 2`(input: String) {
val pattern = GlobResolver.toRegexPattern("/**/*.pkl")
assertTrue(pattern.matcher(input).matches())
}
@ParameterizedTest
@ValueSource(strings = [
"bar.pkl",
".pkl",
"/foo.pkl"
])
@ValueSource(strings = ["bar.pkl", ".pkl", "/foo.pkl"])
fun `globstar non-match 2`(input: String) {
val pattern = GlobResolver.toRegexPattern("/**/*.pkl")
assertFalse(pattern.matcher(input).matches())
@@ -135,7 +147,9 @@ class GlobResolverTest {
@Test
fun `invalid sub-patterns`() {
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("{foo{bar}}") }
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("{foo{bar}}")
}
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("{foo") }
// no leading open curly means closing curly is treated verbatim
assertDoesNotThrow { GlobResolver.toRegexPattern("foo}") }
@@ -164,21 +178,39 @@ class GlobResolverTest {
@Test
fun `invalid character classes`() {
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("thing[") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("thing[foo/bar]") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("[[=a=]]") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("[[:alnum:]]") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("[[.a-acute.]]") }
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("thing[foo/bar]")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("[[=a=]]")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("[[:alnum:]]")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("[[.a-acute.]]")
}
// no leading open square bracket means closing square bracket is verbatim
assertDoesNotThrow { GlobResolver.toRegexPattern("]") }
}
@Test
fun `invalid extglob`() {
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("!(foo|bar)") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("+(foo|bar)") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("?(foo|bar)") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("@(foo|bar)") }
assertThrows<GlobResolver.InvalidGlobPatternException> { GlobResolver.toRegexPattern("*(foo|bar)") }
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("!(foo|bar)")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("+(foo|bar)")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("?(foo|bar)")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("@(foo|bar)")
}
assertThrows<GlobResolver.InvalidGlobPatternException> {
GlobResolver.toRegexPattern("*(foo|bar)")
}
}
@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.util
import java.io.IOException
import java.net.URI
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.pkl.commons.test.FakeHttpResponse
import java.io.IOException
import java.net.URI
class HttpUtilsTest {
@Test
@@ -21,32 +36,20 @@ class HttpUtilsTest {
assertThat(HttpUtils.isHttpUrl(URI("HtTpS://example.com").toURL())).isTrue
assertThat(HttpUtils.isHttpUrl(URI("file://example.com").toURL())).isFalse
}
@Test
fun checkHasStatusCode200() {
val response = FakeHttpResponse.withoutBody {
statusCode = 200
}
assertDoesNotThrow {
HttpUtils.checkHasStatusCode200(response)
}
val response = FakeHttpResponse.withoutBody { statusCode = 200 }
assertDoesNotThrow { HttpUtils.checkHasStatusCode200(response) }
val response2 = FakeHttpResponse.withoutBody {
statusCode = 404
}
assertThrows<IOException> {
HttpUtils.checkHasStatusCode200(response2)
}
val response2 = FakeHttpResponse.withoutBody { statusCode = 404 }
assertThrows<IOException> { HttpUtils.checkHasStatusCode200(response2) }
}
@Test
fun setPort() {
assertThrows<IllegalArgumentException> {
HttpUtils.setPort(URI("https://example.com"), -1)
}
assertThrows<IllegalArgumentException> {
HttpUtils.setPort(URI("https://example.com"), 65536)
}
assertThrows<IllegalArgumentException> { HttpUtils.setPort(URI("https://example.com"), -1) }
assertThrows<IllegalArgumentException> { HttpUtils.setPort(URI("https://example.com"), 65536) }
assertThat(HttpUtils.setPort(URI("http://example.com"), 123))
.isEqualTo(URI("http://example.com:123"))
assertThat(HttpUtils.setPort(URI("http://example.com:456"), 123))

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.util
import java.io.FileNotFoundException
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.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.jupiter.api.Test
@@ -11,12 +31,6 @@ import org.pkl.core.SecurityManager
import org.pkl.core.module.ModuleKeyFactories
import org.pkl.core.module.ModuleKeys
import org.pkl.core.runtime.ModuleResolver
import java.io.FileNotFoundException
import java.net.URI
import java.net.URISyntaxException
import java.net.URL
import java.nio.file.Path
import kotlin.io.path.createFile
class IoUtilsTest {
object FakeSecurityManager : SecurityManager {
@@ -29,35 +43,32 @@ class IoUtilsTest {
override fun checkResolveResource(resource: URI) {}
}
private val moduleResolver = ModuleResolver(
listOf(
ModuleKeyFactories.pkg,
ModuleKeyFactories.file,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.genericUrl
private val moduleResolver =
ModuleResolver(
listOf(
ModuleKeyFactories.pkg,
ModuleKeyFactories.file,
ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.genericUrl
)
)
)
@Test
fun `ensurePathEndsWithSlash() - relative URI`() {
val uri = URI("/some/path")
assertThat(IoUtils.ensurePathEndsWithSlash(uri))
.isEqualTo(URI("/some/path/"))
assertThat(IoUtils.ensurePathEndsWithSlash(uri)).isEqualTo(URI("/some/path/"))
val uri2 = URI("/some/path/")
assertThat(IoUtils.ensurePathEndsWithSlash(uri2))
.isEqualTo(URI("/some/path/"))
assertThat(IoUtils.ensurePathEndsWithSlash(uri2)).isEqualTo(URI("/some/path/"))
}
@Test
fun `ensurePathEndsWithSlash() - absolute URI`() {
val uri = URI("https://apple.com/path")
assertThat(IoUtils.ensurePathEndsWithSlash(uri))
.isEqualTo(URI("https://apple.com/path/"))
assertThat(IoUtils.ensurePathEndsWithSlash(uri)).isEqualTo(URI("https://apple.com/path/"))
val uri2 = URI("https://apple.com/path/")
assertThat(IoUtils.ensurePathEndsWithSlash(uri2))
.isEqualTo(URI("https://apple.com/path/"))
assertThat(IoUtils.ensurePathEndsWithSlash(uri2)).isEqualTo(URI("https://apple.com/path/"))
val uri3 = URI("https://user:pwd@apple.com:8080/path?foo=bar#frag")
assertThat(IoUtils.ensurePathEndsWithSlash(uri3))
@@ -71,8 +82,7 @@ class IoUtilsTest {
@Test
fun `ensurePathEndsWithSlash() - opaque URI`() {
val uri = URI("foo:some.thing")
assertThat(IoUtils.ensurePathEndsWithSlash(uri))
.isEqualTo(URI("foo:some.thing"))
assertThat(IoUtils.ensurePathEndsWithSlash(uri)).isEqualTo(URI("foo:some.thing"))
}
@Test
@@ -86,7 +96,7 @@ class IoUtilsTest {
val resolved = IoUtils.resolve(URI("file:/foo/bar"), URI("baz"))
assertThat(resolved).isEqualTo(URI("file:/foo/baz"))
}
@Test
fun `resolving relative URI against triple-slash jar-file URI results in triple-slash jar-file URI`() {
val resolved = IoUtils.resolve(URI("jar:file:///some/archive.zip!/foo/bar"), URI("baz"))
@@ -98,12 +108,11 @@ class IoUtilsTest {
val resolved = IoUtils.resolve(URI("jar:file:/some/archive.zip!/foo/bar"), URI("baz"))
assertThat(resolved).isEqualTo(URI("jar:file:/some/archive.zip!/foo/baz"))
}
@Test
fun `resolve absolute URI against jar-file URI`() {
val uri = URI("jar:file:///some/archive.zip!/foo/bar.pkl")
assertThat(IoUtils.resolve(uri, URI("https://apple.com")))
.isEqualTo(URI("https://apple.com"))
assertThat(IoUtils.resolve(uri, URI("https://apple.com"))).isEqualTo(URI("https://apple.com"))
}
@Test
@@ -117,150 +126,106 @@ class IoUtilsTest {
@Test
fun `relativize file URLs`() {
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/bar/baz.pkl")
)
).isEqualTo(URI("baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/bar/baz.pkl")))
.isEqualTo(URI("baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/bar/qux.pkl")
)
).isEqualTo(URI("baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/bar/qux.pkl")))
.isEqualTo(URI("baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/bar/")
)
).isEqualTo(URI("baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/bar/")))
.isEqualTo(URI("baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/bar")
)
).isEqualTo(URI("bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/bar")))
.isEqualTo(URI("bar/baz.pkl"))
// URI.relativize() returns an absolute URI here
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/qux/")
)
).isEqualTo(URI("../bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/qux/")))
.isEqualTo(URI("../bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/qux/qux2/")
)
).isEqualTo(URI("../../bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/qux/qux2/")))
.isEqualTo(URI("../../bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///foo/qux/qux2")
)
).isEqualTo(URI("../bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///foo/qux/qux2")))
.isEqualTo(URI("../bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("file:///qux/qux2/")
)
).isEqualTo(URI("../../foo/bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("file:///qux/qux2/")))
.isEqualTo(URI("../../foo/bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("file:///foo/bar/baz.pkl"),
URI("https:///foo/bar/baz.pkl")
)
).isEqualTo(URI("file:///foo/bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("file:///foo/bar/baz.pkl"), URI("https:///foo/bar/baz.pkl")))
.isEqualTo(URI("file:///foo/bar/baz.pkl"))
}
@Test
fun `relativize HTTP URLs`() {
// perhaps URI("") would be a more precise result
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl"),
URI("https://foo.com/bar/baz.pkl")
IoUtils.relativize(URI("https://foo.com/bar/baz.pkl"), URI("https://foo.com/bar/baz.pkl"))
)
).isEqualTo(URI("baz.pkl"))
.isEqualTo(URI("baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl"),
URI("https://foo.com/bar/qux.pkl")
IoUtils.relativize(URI("https://foo.com/bar/baz.pkl"), URI("https://foo.com/bar/qux.pkl"))
)
).isEqualTo(URI("baz.pkl"))
.isEqualTo(URI("baz.pkl"))
assertThat(IoUtils.relativize(URI("https://foo.com/bar/baz.pkl"), URI("https://foo.com/qux/")))
.isEqualTo(URI("../bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl"),
URI("https://foo.com/qux/")
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query"),
URI("https://foo.com/bar/qux.pkl")
)
)
).isEqualTo(URI("../bar/baz.pkl"))
.isEqualTo(URI("baz.pkl?query"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query"),
URI("https://foo.com/bar/qux.pkl")
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl#fragment"),
URI("https://foo.com/bar/qux.pkl")
)
)
).isEqualTo(URI("baz.pkl?query"))
.isEqualTo(URI("baz.pkl#fragment"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl#fragment"),
URI("https://foo.com/bar/qux.pkl")
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query#fragment"),
URI("https://foo.com/bar/qux.pkl")
)
)
).isEqualTo(URI("baz.pkl#fragment"))
.isEqualTo(URI("baz.pkl?query#fragment"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query#fragment"),
URI("https://foo.com/bar/qux.pkl")
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query#fragment"),
URI("https://foo.com/bar/qux.pkl?query2#fragment2")
)
)
).isEqualTo(URI("baz.pkl?query#fragment"))
.isEqualTo(URI("baz.pkl?query#fragment"))
assertThat(
IoUtils.relativize(
URI("https://foo.com/bar/baz.pkl?query#fragment"),
URI("https://foo.com/bar/qux.pkl?query2#fragment2")
IoUtils.relativize(URI("https://foo.com:80/bar/baz.pkl"), URI("https://foo.com:443/bar/"))
)
).isEqualTo(URI("baz.pkl?query#fragment"))
.isEqualTo(URI("https://foo.com:80/bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo.com:80/bar/baz.pkl"),
URI("https://foo.com:443/bar/")
IoUtils.relativize(
URI("https://foo.com:80/bar/baz.pkl"),
URI("https://bar.com:80/bar/baz.pkl")
)
)
).isEqualTo(URI("https://foo.com:80/bar/baz.pkl"))
.isEqualTo(URI("https://foo.com:80/bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo.com:80/bar/baz.pkl"),
URI("https://bar.com:80/bar/baz.pkl")
IoUtils.relativize(
URI("https://foo:bar@foo.com:80/bar/baz.pkl"),
URI("https://foo:baz@bar.com:80/bar/baz.pkl")
)
)
).isEqualTo(URI("https://foo.com:80/bar/baz.pkl"))
.isEqualTo(URI("https://foo:bar@foo.com:80/bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo:bar@foo.com:80/bar/baz.pkl"),
URI("https://foo:baz@bar.com:80/bar/baz.pkl")
)
).isEqualTo(URI("https://foo:bar@foo.com:80/bar/baz.pkl"))
assertThat(
IoUtils.relativize(
URI("https://foo/bar/baz.pkl"),
URI("file://foo/bar/baz.pkl")
)
).isEqualTo(URI("https://foo/bar/baz.pkl"))
assertThat(IoUtils.relativize(URI("https://foo/bar/baz.pkl"), URI("file://foo/bar/baz.pkl")))
.isEqualTo(URI("https://foo/bar/baz.pkl"))
}
@Test
@@ -304,20 +269,21 @@ class IoUtilsTest {
@Test
fun inferModuleName() {
val assertions = mapOf(
"file:///foo.pkl" to "foo",
"file:///foo/bar/baz.pkl" to "baz",
"jar:file:///some/archive.zip!/foo.pkl" to "foo",
"jar:file:///some/archive.zip!/foo/bar/baz.pkl" to "baz",
"https://apple.com/foo.pkl" to "foo",
"https://apple.com/foo/bar/baz.pkl" to "baz",
"pkl:foo" to "foo",
"pkl:foo.bar.baz" to "baz",
"modulepath:/foo.pkl" to "foo",
"modulepath:/foo/bar/baz.pkl" to "baz",
"package://example.com/foo/bar@1.0.0#/baz.pkl" to "baz",
"package://example.com/foo/bar@1.0.0#/baz/biz/qux.pkl" to "qux"
)
val assertions =
mapOf(
"file:///foo.pkl" to "foo",
"file:///foo/bar/baz.pkl" to "baz",
"jar:file:///some/archive.zip!/foo.pkl" to "foo",
"jar:file:///some/archive.zip!/foo/bar/baz.pkl" to "baz",
"https://apple.com/foo.pkl" to "foo",
"https://apple.com/foo/bar/baz.pkl" to "baz",
"pkl:foo" to "foo",
"pkl:foo.bar.baz" to "baz",
"modulepath:/foo.pkl" to "foo",
"modulepath:/foo/bar/baz.pkl" to "baz",
"package://example.com/foo/bar@1.0.0#/baz.pkl" to "baz",
"package://example.com/foo/bar@1.0.0#/baz/biz/qux.pkl" to "qux"
)
for ((uriStr, name) in assertions) {
val uri = URI(uriStr)
val moduleKey = moduleResolver.resolve(uri)
@@ -330,33 +296,32 @@ class IoUtilsTest {
assertThat(IoUtils.toUri("file://foo.pkl")).isEqualTo(URI("file://foo.pkl"))
assertThat(IoUtils.toUri("foo.pkl")).isEqualTo(URI("foo.pkl"))
assertThat(IoUtils.toUri("foo bar.pkl").rawPath).isEqualTo("foo%20bar.pkl")
assertThrows<URISyntaxException> {
IoUtils.toUri("file:foo bar.pkl")
}
assertThrows<URISyntaxException> { IoUtils.toUri("file:foo bar.pkl") }
}
@Test
fun `resolveUri - file hierarchy`(@TempDir tempDir: Path) {
val file1 = tempDir.resolve("base1/base2/foo.pkl").createParentDirectories().createFile()
val file2 = tempDir.resolve("base1/base2/dir1/dir2/foo.pkl").createParentDirectories().createFile()
val file2 =
tempDir.resolve("base1/base2/dir1/dir2/foo.pkl").createParentDirectories().createFile()
val file3 = tempDir.resolve("base1/dir2/foo.pkl").createParentDirectories().createFile()
val uri = file2.toUri()
val key = ModuleKeys.file(uri)
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI("..."))).isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../foo.pkl"))).isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../base2/foo.pkl"))).isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../base1/base2/foo.pkl"))).isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../dir2/foo.pkl"))).isEqualTo(file3.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../foo.pkl")))
.isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../base2/foo.pkl")))
.isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../base1/base2/foo.pkl")))
.isEqualTo(file1.toUri())
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../dir2/foo.pkl")))
.isEqualTo(file3.toUri())
assertThrows<URISyntaxException> {
IoUtils.resolve(FakeSecurityManager, key, URI(".../"))
}
assertThrows<URISyntaxException> { IoUtils.resolve(FakeSecurityManager, key, URI(".../")) }
assertThrows<URISyntaxException> {
IoUtils.resolve(FakeSecurityManager, key, URI("...abc"))
}
assertThrows<URISyntaxException> { IoUtils.resolve(FakeSecurityManager, key, URI("...abc")) }
assertThrows<FileNotFoundException> {
IoUtils.resolve(FakeSecurityManager, key, URI(".../bar.pkl"))
@@ -382,20 +347,32 @@ class IoUtilsTest {
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../NamedModuleResolversTest.pkl")))
.isEqualTo(URI("modulepath:/org/pkl/core/module/NamedModuleResolversTest.pkl"))
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../module/NamedModuleResolversTest.pkl")))
assertThat(
IoUtils.resolve(FakeSecurityManager, key, URI(".../module/NamedModuleResolversTest.pkl"))
)
.isEqualTo(URI("modulepath:/org/pkl/core/module/NamedModuleResolversTest.pkl"))
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../core/module/NamedModuleResolversTest.pkl")))
assertThat(
IoUtils.resolve(
FakeSecurityManager,
key,
URI(".../core/module/NamedModuleResolversTest.pkl")
)
)
.isEqualTo(URI("modulepath:/org/pkl/core/module/NamedModuleResolversTest.pkl"))
assertThat(IoUtils.resolve(FakeSecurityManager, key, URI(".../org/pkl/core/module/NamedModuleResolversTest.pkl")))
assertThat(
IoUtils.resolve(
FakeSecurityManager,
key,
URI(".../org/pkl/core/module/NamedModuleResolversTest.pkl")
)
)
.isEqualTo(URI("modulepath:/org/pkl/core/module/NamedModuleResolversTest.pkl"))
val uri2 = URI("modulepath:/foo/bar/baz.pkl")
val key2 = ModuleKeys.classPath(uri2, classLoader)
assertThrows<FileNotFoundException> {
IoUtils.resolve(FakeSecurityManager, key2, URI("..."))
}
assertThrows<FileNotFoundException> { IoUtils.resolve(FakeSecurityManager, key2, URI("...")) }
assertThrows<FileNotFoundException> {
IoUtils.resolve(FakeSecurityManager, key2, URI(".../other.pkl"))
}
@@ -403,22 +380,16 @@ class IoUtilsTest {
IoUtils.resolve(FakeSecurityManager, key2, URI(".../dir1/dir2/NamedModuleResolversTest.pkl"))
}
assertThrows<URISyntaxException> {
IoUtils.resolve(FakeSecurityManager, key2, URI(".../"))
}
assertThrows<URISyntaxException> { IoUtils.resolve(FakeSecurityManager, key2, URI(".../")) }
assertThrows<URISyntaxException> {
IoUtils.resolve(FakeSecurityManager, key2, URI("...NamedModuleResolversTest.pkl"))
}
}
@Test
fun `readBytes(URL) does not support HTTP URLs`() {
assertThrows<IllegalArgumentException> {
IoUtils.readBytes(URI("https://example.com"))
}
assertThrows<IllegalArgumentException> {
IoUtils.readBytes(URI("http://example.com"))
}
assertThrows<IllegalArgumentException> { IoUtils.readBytes(URI("https://example.com")) }
assertThrows<IllegalArgumentException> { IoUtils.readBytes(URI("http://example.com")) }
}
@Test
@@ -426,9 +397,7 @@ class IoUtilsTest {
assertThrows<IllegalArgumentException> {
IoUtils.readString(URI("https://example.com").toURL())
}
assertThrows<IllegalArgumentException> {
IoUtils.readString(URI("http://example.com").toURL())
}
assertThrows<IllegalArgumentException> { IoUtils.readString(URI("http://example.com").toURL()) }
}
@Test