Initial commit

This commit is contained in:
Peter Niederwieser
2016-01-19 14:51:19 +01:00
committed by Dan Chao
commit ecad035dca
2972 changed files with 211653 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin;
import java.util.List;
import org.pkl.config.java.mapper.Named;
public class JavaPerson {
private final String name;
private final int age;
private final List<String> hobbies;
public JavaPerson(@Named("name") String name) {
this.name = name;
age = 0;
hobbies = List.of();
}
public JavaPerson(
@Named("name") String name, @Named("age") int age, @Named("hobbies") List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
public JavaPerson(@Named("age") int age) {
this.age = age;
name = "Default";
hobbies = List.of();
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public List<String> getHobbies() {
return hobbies;
}
}

View File

@@ -0,0 +1,257 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.config.java.ConfigEvaluator
import org.pkl.config.java.ConfigEvaluatorBuilder
import org.pkl.config.java.mapper.ConversionException
import org.pkl.config.kotlin.ConfigExtensionsTest.Hobby.READING
import org.pkl.config.kotlin.ConfigExtensionsTest.Hobby.SWIMMING
import org.pkl.core.ModuleSource.text
class ConfigExtensionsTest {
private val evaluator = ConfigEvaluator.preconfigured().forKotlin()
@Test
fun `convert to kotlin classes`() {
val config =
evaluator.evaluate(
text(
"""
pigeon {
name = "pigeon"
age = 30
hobbies = List("swimming", "reading")
address {
street = "Fuzzy St."
}
}
"""
)
)
val address = config["pigeon"]["address"].to<Address<String>>()
assertThat(address.street).isEqualTo("Fuzzy St.")
val pigeon = config["pigeon"].to<Person<String>>()
assertThat(pigeon).isNotNull
assertThat(pigeon.name).isEqualTo("pigeon")
assertThat(pigeon.age).isEqualTo(30)
assertThat(pigeon.hobbies).isEqualTo(setOf(READING, SWIMMING))
assertThat(pigeon.address.street).isEqualTo("Fuzzy St.")
}
@Test
fun `convert to kotlin class with nullable property`() {
// cover ConfigEvaluatorBuilder.preconfigured()
val evaluator = ConfigEvaluatorBuilder.preconfigured().forKotlin().build()
val config = evaluator.evaluate(text("pigeon { address = null }"))
val pigeon = config["pigeon"].to<Person2>()
assertThat(pigeon.address).isNull()
}
@Test
fun `convert to kotlin class with covariant collection property type`() {
val config =
evaluator.evaluate(
text(
"""pigeon { addresses = List(new Dynamic { street = "Fuzzy St." }, new Dynamic { street = "Other St." }) }"""
)
)
config["pigeon"].to<Person3>()
}
@Test
fun `convert to nullable type`() {
val config =
evaluator.evaluate(text("""pigeon { address1 { street = "Fuzzy St." }; address2 = null }"""))
val address1 = config["pigeon"]["address1"].to<Address<String>?>()
assertThat(address1).isEqualTo(Address(street = "Fuzzy St."))
val address2 = config["pigeon"]["address2"].to<Address<String>?>()
assertThat(address2).isNull()
val e = assertThrows<ConversionException> { config["pigeon"]["address2"].to<Address<String>>() }
assertThat(e)
.hasMessage(
"Expected a non-null value but got `null`. " +
"To allow null values, convert to a nullable Kotlin type, for example `String?`."
)
}
@Test
fun `convert to kotlin class that has defaults for constructor args`() {
val config =
evaluator.evaluate(
text(
"""
pigeon {
name = "Pigeon"
age = 42
hobbies = List()
}
"""
)
)
val pigeon = config["pigeon"].to<PersonWithDefaults>()
assertThat(pigeon.name).isEqualTo("Pigeon")
assertThat(pigeon.age).isEqualTo(42)
assertThat(pigeon.hobbies).isEqualTo(listOf<String>())
}
// check that java converter factory still kicks in
@Test
fun `convert to java class with multiple constructors`() {
val config =
evaluator.evaluate(
text(
"""
pigeon {
name = "Pigeon"
age = 42
hobbies = List()
}
"""
)
)
val pigeon = config["pigeon"].to<JavaPerson>()
assertThat(pigeon.name).isEqualTo("Pigeon")
assertThat(pigeon.age).isEqualTo(42)
assertThat(pigeon.hobbies).isEqualTo(listOf<String>())
}
@Test
fun `convert list to parameterized list`() {
val config =
evaluator.evaluate(
text(
"""friends = List(new Dynamic { name = "lilly"}, new Dynamic {name = "bob"}, new Dynamic {name = "susan"})"""
)
)
val friends = config["friends"].to<List<SimplePerson>>()
assertThat(friends)
.isEqualTo(listOf(SimplePerson("lilly"), SimplePerson("bob"), SimplePerson("susan")))
}
@Test
fun `convert map to parameterized map`() {
val config =
evaluator.evaluate(
text(
"""friends = Map("l", new Dynamic { name = "lilly"}, "b", new Dynamic { name = "bob"}, "s", new Dynamic { name = "susan"})"""
)
)
val friends = config["friends"].to<Map<String, SimplePerson>>()
assertThat(friends)
.isEqualTo(
mapOf(
"l" to SimplePerson("lilly"),
"b" to SimplePerson("bob"),
"s" to SimplePerson("susan")
)
)
}
@Test
fun `convert container to parameterized map`() {
val config =
evaluator.evaluate(
text("""friends {l { name = "lilly"}; b { name = "bob"}; s { name = "susan"}}""")
)
val friends = config["friends"].to<Map<String, SimplePerson>>()
assertThat(friends)
.isEqualTo(
mapOf(
"l" to SimplePerson("lilly"),
"b" to SimplePerson("bob"),
"s" to SimplePerson("susan")
)
)
}
@Test
fun `convert enum with mangled names`() {
val values = MangledNameEnum.values().map { "\"$it\"" }
val config =
evaluator.evaluate(
text(
"""
typealias MangledNameEnum = ${values.joinToString(" | ")}
allEnumValues: Set<MangledNameEnum> = Set(${values.joinToString(", ")})
"""
.trimIndent()
)
)
val allEnumValues = config["allEnumValues"].to<Set<MangledNameEnum>>()
assertThat(allEnumValues).isEqualTo(MangledNameEnum.values().toSet())
}
data class SimplePerson(val name: String)
class Person<T>(val name: String, val age: Int, val hobbies: Set<Hobby>, val address: Address<T>)
enum class Hobby {
SWIMMING,
@Suppress("unused") SURFING,
READING
}
data class Address<out T>(val street: T)
class Person2(val address: Address<String>?)
class Person3(@Suppress("unused") val addresses: List<OpenAddress>)
open class OpenAddress(val street: String) {
override fun equals(other: Any?): Boolean {
return other is OpenAddress && street == other.street
}
override fun hashCode(): Int {
return street.hashCode()
}
}
class PersonWithDefaults(
val name: String = "Pigeon",
val age: Int = 42,
val hobbies: List<String>
)
@Suppress("NonAsciiCharacters", "EnumEntryName")
enum class MangledNameEnum(val value: String) {
FROM_CAMEL_CASE("fromCamelCase"),
HYPHENATED_NAME("hyphenated-name"),
EN_QUAD_EM_SPACE_IDEOGRAPHIC_SPACE_("EnQuad\\u2000EmSpace\\u2003IdeographicSpace\\u3000"),
_ᾨ("\u0ABF"),
_42_FROM_INVALID_START("42-from-invalid-start"),
__EMOJI__("❎Emoji✅✅"),
ÀŒÜ("àœü"),
日本_つくば("日本-つくば")
}
}

View File

@@ -0,0 +1,122 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.pkl.config.java.ConfigEvaluator
import org.pkl.core.ModuleSource.text
class KotlinObjectMappingTest {
data class TypedKey(val value: Int)
data class KotlinGenericTypesTest(
// Sets
val stringSet: Set<String>,
val intSet: Set<Int>,
val booleanSetSet: Set<Set<Boolean>>,
// Lists
val stringList: List<String>,
val intList: List<Int>,
val booleanListList: List<List<Boolean>>,
// Maps
val intStringMap: Map<Int, String>,
val booleanIntStringMapMap: Map<Boolean, Map<Int, String>>,
val booleanIntMapStringMap: Map<Map<Boolean, Int>, String>,
val intSetListStringMap: Map<List<Set<Int>>, String>,
val typedStringMap: Map<TypedKey, String>,
val dynamicStringMap: Map<Map<String, Any>, String>,
// Listings
val stringSetListing: List<Set<String>>,
val intListingListing: List<List<Int>>,
// Mapping
val intStringMapping: Map<Int, String>,
val stringStringSetMapping: Map<String, Set<String>>,
// Map & Mapping with structured keys
val intListingStringMapping: Map<List<Int>, String>,
val intSetListStringMapping: Map<List<Set<Int>>, String>,
val thisOneGoesToEleven: Map<List<Set<Int>>, Map<List<Int>, Map<Int, String>>>
)
@Test
fun `generic types correspond`() {
val code =
"""
module KotlinGenericTypesTest
class Foo {
value: Int
}
// Sets
stringSet: Set<String> = Set("in set")
intSet: Set<Int> = Set(1,2,4,8,16,32)
booleanSetSet: Set<Set<Boolean>> = Set(Set(false), Set(true), Set(true, false))
// Lists
stringList: List<String> = List("in list")
intList: List<Int> = List(1,2,3,5,7,11)
booleanListList: List<List<Boolean>> = List(List(false), List(true), List(true, false))
// Maps
intStringMap: Map<Int, String> = Map(0, "in map")
booleanIntStringMapMap: Map<Boolean, Map<Int, String>> = Map(false, Map(0, "in map in map"))
booleanIntMapStringMap: Map<Map<Boolean, Int>, String> = Map(Map(true, 42), "in map with map keys")
// Listings
stringSetListing: Listing<Set<String>> = new { Set("in set in listing") }
intListingListing: Listing<Listing<Int>> = new { new { 1337 } new { 100 } }
// Mappings
intStringMapping: Mapping<Int, String> = new { [42] = "in map" }
stringStringSetMapping: Mapping<String, Set<String>> = new { ["key"] = Set("in set in map") }
// Map & Mappings with structured keys
intSetListStringMap: Map<List<Set<Int>>, String> = Map(List(Set(27)), "in map with structured key")
typedStringMap: Map<Foo, String> = Map(
new Foo { value = 1 }, "using typed objects",
new Foo { value = 2 }, "also works")
dynamicStringMap: Map<Dynamic, String> = Map(
new Dynamic { value = 42 }, "using Dynamics",
new Dynamic { hello = "world" }, "also works")
intListingStringMapping: Mapping<Listing<Int>, String> = new {
[new Listing { 42 1337 }] = "structured key works"
}
intSetListStringMapping: Mapping<List<Set<Int>>, String> = new {
[List(Set(27))] = "in mapping with structured key"
}
local intListing: Listing<Int> = new { 0 0 7 }
thisOneGoesToEleven: Mapping<List<Set<Int>>, Map<Listing<Int>, Mapping<Int, String>>> = new {
[List(Set(0), Set(0), Set(7))] = Map(intListing, intStringMapping)
}
"""
.trimIndent()
val result = ConfigEvaluator.preconfigured().forKotlin().evaluate(text(code))
assertDoesNotThrow { result.to<KotlinGenericTypesTest>() }
.apply {
assertThat(typedStringMap.keys).isEqualTo(setOf(TypedKey(1), TypedKey(2)))
assertThat(dynamicStringMap.keys)
.isEqualTo(setOf(hashMapOf("hello" to "world"), hashMapOf("value" to 42.toLong())))
}
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin.mapper
import java.util.regex.Pattern
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.config.java.mapper.ConversionException
import org.pkl.config.java.mapper.ValueMapperBuilder
class KotlinConversionsTest {
private val mapper = ValueMapperBuilder.unconfigured().build()
@Test
fun pStringToKotlinRegex() {
val result = KotlinConversions.pStringToKotlinRegex.converter.convert("(?i)\\w*", mapper)
assertThat(result.pattern).isEqualTo("(?i)\\w*")
assertThat(result.options).isEqualTo(setOf(RegexOption.IGNORE_CASE))
}
@Test
fun pRegexToKotlinRegex() {
val result =
KotlinConversions.pRegexToKotlinRegex.converter.convert(Pattern.compile("(?i)\\w*"), mapper)
assertThat(result.pattern).isEqualTo("(?i)\\w*")
assertThat(result.options).isEqualTo(setOf(RegexOption.IGNORE_CASE))
}
@Test
fun pIntToULong() {
assertThat(KotlinConversions.pIntToULong.converter.convert(0, mapper)).isEqualTo(0UL)
assertThat(KotlinConversions.pIntToULong.converter.convert(Long.MAX_VALUE, mapper))
.isEqualTo(Long.MAX_VALUE.toULong())
assertThrows<ConversionException> {
KotlinConversions.pIntToULong.converter.convert(-1, mapper)
}
}
@Test
fun pIntToUInt() {
assertThat(KotlinConversions.pIntToUInt.converter.convert(0, mapper)).isEqualTo(0u)
assertThat(KotlinConversions.pIntToUInt.converter.convert(UInt.MAX_VALUE.toLong(), mapper))
.isEqualTo(UInt.MAX_VALUE)
assertThrows<ConversionException> {
KotlinConversions.pIntToUInt.converter.convert(UInt.MAX_VALUE.toLong() + 1, mapper)
}
assertThrows<ConversionException> { KotlinConversions.pIntToUInt.converter.convert(-1, mapper) }
}
@Test
fun pIntToUShort() {
assertThat(KotlinConversions.pIntToUShort.converter.convert(0, mapper)).isEqualTo(0.toUShort())
assertThat(KotlinConversions.pIntToUShort.converter.convert(UShort.MAX_VALUE.toLong(), mapper))
.isEqualTo(UShort.MAX_VALUE)
assertThrows<ConversionException> {
KotlinConversions.pIntToUShort.converter.convert(UShort.MAX_VALUE.toLong() + 1, mapper)
}
assertThrows<ConversionException> {
KotlinConversions.pIntToUShort.converter.convert(-1, mapper)
}
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin.mapper
import com.example.OverriddenProperty
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.config.java.ConfigEvaluatorBuilder
import org.pkl.config.kotlin.forKotlin
import org.pkl.config.kotlin.to
import org.pkl.core.ModuleSource
class OverriddenPropertyTest {
@Test
fun `overridden property`() {
ConfigEvaluatorBuilder.preconfigured().forKotlin().build().use { evaluator ->
val config = evaluator.evaluate(ModuleSource.modulePath("/codegenPkl/OverriddenProperty.pkl"))
val module = config.to<OverriddenProperty>()
assertThat(module.theClass.bar[0].prop1).isEqualTo("hello")
assertThat(module.theClass.bar[0].prop2).isEqualTo("hello again")
}
}
}

View File

@@ -0,0 +1,70 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin.mapper
import kotlin.Pair
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.entry
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.pkl.config.java.mapper.Types
import org.pkl.config.java.mapper.ValueMapperBuilder
import org.pkl.config.kotlin.forKotlin
import org.pkl.core.*
import org.pkl.core.ModuleSource.modulePath
class PPairToKotlinPairTest {
companion object {
private val evaluator = Evaluator.preconfigured()
private val module =
evaluator.evaluate(modulePath("org/pkl/config/kotlin/mapper/PPairToKotlinPairTest.pkl"))
private val mapper = ValueMapperBuilder.preconfigured().forKotlin().build()
@AfterAll
@Suppress("unused")
@JvmStatic
fun afterAll() {
evaluator.close()
}
}
@Test
fun ex1() {
val ex1 = module.getProperty("ex1")
val mapped: Pair<Int, Duration> =
mapper.map(
ex1,
Types.parameterizedType(Pair::class.java, Integer::class.java, Duration::class.java)
)
assertThat(mapped).isEqualTo(Pair(1, Duration(3.0, DurationUnit.SECONDS)))
}
@Test
fun ex2() {
val ex2 = module.getProperty("ex2")
val mapped: Pair<PObject, PObject> =
mapper.map(
ex2,
Types.parameterizedType(Pair::class.java, PObject::class.java, PObject::class.java)
)
assertThat(mapped.first.properties).containsOnly(entry("name", "pigeon"), entry("age", 40L))
assertThat(mapped.second.properties).containsOnly(entry("name", "parrot"), entry("age", 30L))
}
}

View File

@@ -0,0 +1,38 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.config.kotlin.mapper
import com.example.PolymorphicLib
import com.example.PolymorphicModuleTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.config.java.ConfigEvaluatorBuilder
import org.pkl.config.kotlin.forKotlin
import org.pkl.config.kotlin.to
import org.pkl.core.ModuleSource.modulePath
class PolymorphicTest {
@Test
fun `deserializing polymorphic objects`() {
val evaluator = ConfigEvaluatorBuilder.preconfigured().forKotlin().build()
val config = evaluator.evaluate(modulePath("/codegenPkl/PolymorphicModuleTest.pkl"))
val module = config.to<PolymorphicModuleTest>()
assertThat(module.desserts[0]).isInstanceOf(PolymorphicModuleTest.Strudel::class.java)
assertThat(module.desserts[1]).isInstanceOf(PolymorphicModuleTest.TurkishDelight::class.java)
assertThat(module.planes[0]).isInstanceOf(PolymorphicLib.Jet::class.java)
assertThat(module.planes[1]).isInstanceOf(PolymorphicLib.Propeller::class.java)
}
}

View File

@@ -0,0 +1,28 @@
module com.example.OverriddenProperty
abstract class BaseClass {
fixed bar: Listing<BaseBar> = new {
new {
prop1 = "hello"
}
}
}
theClass: TheClass
class TheClass extends BaseClass {
fixed bar: Listing<Bar> = new {
new {
prop1 = "hello"
prop2 = "hello again"
}
}
}
open class BaseBar {
prop1: String
}
class Bar extends BaseBar {
prop2: String
}

View File

@@ -0,0 +1,14 @@
module com.example.PolymorphicLib
open class Airplane {
name: String
numSeats: Int
}
class Jet extends Airplane {
isSuperSonic: Boolean
}
class Propeller extends Airplane {
isTurboprop: Boolean
}

View File

@@ -0,0 +1,24 @@
/// Gets generated into a Kotlin via Gradle task `generateTestConfigClasses`.
module com.example.PolymorphicModuleTest
import "PolymorphicLib.pkl"
abstract class Dessert
class Strudel extends Dessert {
numberOfRolls: Int
}
class TurkishDelight extends Dessert {
isOfferedToEdmund: Boolean
}
desserts: Listing<Dessert> = new {
new Strudel { numberOfRolls = 3 }
new TurkishDelight { isOfferedToEdmund = true }
}
planes: Listing<PolymorphicLib.Airplane> = new {
new PolymorphicLib.Jet { name = "Concorde"; numSeats = 128; isSuperSonic = true }
new PolymorphicLib.Propeller { name = "Cessna 172"; numSeats = 4; isTurboprop = true }
}

View File

@@ -0,0 +1,7 @@
class Person {
name: String
age: Int
}
ex1 = Pair(1, 3.s)
ex2 = Pair(new Person {name = "pigeon"; age = 40}, new Dynamic {name = "parrot"; age = 30})