diff --git a/.github/workflows/test-pr.yaml b/.github/workflows/test-pr.yaml index e1e30b95a5..0e53ae7b11 100644 --- a/.github/workflows/test-pr.yaml +++ b/.github/workflows/test-pr.yaml @@ -81,6 +81,8 @@ jobs: # Kotlin is also slow - fixture: kotlin,schema-kotlin,kotlin-jackson,schema-kotlin-jackson runs-on: ubuntu-latest-16-cores + - fixture: kotlinx,schema-kotlinx + runs-on: ubuntu-latest-16-cores # - fixture: objective-c # segfault on compiled test cmd # runs-on: macos-latest diff --git a/test/fixtures.ts b/test/fixtures.ts index d9f78eaea2..d8bc01ed3f 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1562,6 +1562,7 @@ export const allFixtures: Fixture[] = [ new JSONFixture(languages.KotlinLanguage), new JSONFixture(languages.Scala3Language), new JSONFixture(languages.KotlinJacksonLanguage, "kotlin-jackson"), + new JSONFixture(languages.KotlinXLanguage, "kotlinx"), new JSONFixture(languages.DartLanguage), new JSONFixture(languages.PikeLanguage), new JSONFixture(languages.HaskellLanguage), @@ -1601,6 +1602,7 @@ export const allFixtures: Fixture[] = [ languages.KotlinJacksonLanguage, "schema-kotlin-jackson", ), + new JSONSchemaFixture(languages.KotlinXLanguage, "schema-kotlinx"), new JSONSchemaFixture(languages.Scala3Language), new JSONSchemaFixture(languages.DartLanguage), new JSONSchemaFixture(languages.PikeLanguage), diff --git a/test/fixtures/kotlinx/build.sh b/test/fixtures/kotlinx/build.sh new file mode 100755 index 0000000000..fc1ba9881c --- /dev/null +++ b/test/fixtures/kotlinx/build.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# The kotlinx-serialization compiler plugin ships with the Kotlin compiler +# distribution, in lib/ next to bin/kotlinc. +KOTLINC_PATH="$(readlink -f "$(command -v kotlinc)")" +KOTLIN_LIB="$(cd "$(dirname "$KOTLINC_PATH")/../lib" && pwd)" + +kotlinc main.kt TopLevel.kt -include-runtime -Xplugin="$KOTLIN_LIB/kotlinx-serialization-compiler-plugin.jar" -cp kotlinx-serialization-core-jvm-1.7.3.jar:kotlinx-serialization-json-jvm-1.7.3.jar -d main.jar diff --git a/test/fixtures/kotlinx/kotlinx-serialization-core-jvm-1.7.3.jar b/test/fixtures/kotlinx/kotlinx-serialization-core-jvm-1.7.3.jar new file mode 100644 index 0000000000..96a1308d30 Binary files /dev/null and b/test/fixtures/kotlinx/kotlinx-serialization-core-jvm-1.7.3.jar differ diff --git a/test/fixtures/kotlinx/kotlinx-serialization-json-jvm-1.7.3.jar b/test/fixtures/kotlinx/kotlinx-serialization-json-jvm-1.7.3.jar new file mode 100644 index 0000000000..683271d047 Binary files /dev/null and b/test/fixtures/kotlinx/kotlinx-serialization-json-jvm-1.7.3.jar differ diff --git a/test/fixtures/kotlinx/main.kt b/test/fixtures/kotlinx/main.kt new file mode 100644 index 0000000000..fa1228a30e --- /dev/null +++ b/test/fixtures/kotlinx/main.kt @@ -0,0 +1,21 @@ +package quicktype + +import java.io.File +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json + +// explicitNulls = false makes kotlinx omit nulls when serializing, like the +// other Kotlin frameworks we test; the test harness runs this fixture with +// allowMissingNull. +val json = Json { allowStructuredMapKeys = true; explicitNulls = false } + +fun output(text: String) { + val bytes = text.toByteArray() + System.out.write(bytes, 0, bytes.size) +} + +fun main(args: Array) { + val text = File(args[0]).readText() + val top = json.decodeFromString(text) + output(json.encodeToString(top)) +} diff --git a/test/fixtures/kotlinx/run.sh b/test/fixtures/kotlinx/run.sh new file mode 100755 index 0000000000..a9238634de --- /dev/null +++ b/test/fixtures/kotlinx/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +kotlin -cp kotlinx-serialization-core-jvm-1.7.3.jar:kotlinx-serialization-json-jvm-1.7.3.jar:main.jar quicktype.MainKt "$1" diff --git a/test/languages.ts b/test/languages.ts index 9ed081dc8b..d1a7107354 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -1282,6 +1282,137 @@ export const KotlinJacksonLanguage: Language = { sourceFiles: ["src/language/Kotlin/index.ts"], }; +export const KotlinXLanguage: Language = { + name: "kotlin", + base: "test/fixtures/kotlinx", + compileCommand: "./build.sh", + runCommand(sample: string) { + return `./run.sh "${sample}"`; + }, + diffViaSchema: true, + skipDiffViaSchema: [ + "bug427.json", + "keywords.json", + // TODO Investigate these + "34702.json", + "76ae1.json", + ], + allowMissingNull: true, + // No "union": the kotlinx renderer emits unions as sealed classes + // without any serializer wiring, so they don't (de)serialize + // (documented TODO in KotlinXRenderer.ts). + features: ["enum", "no-defaults"], + output: "TopLevel.kt", + topLevel: "TopLevel", + skipJSON: [ + // Top-level arrays render as `typealias TopLevel = JsonArray`, + // which doesn't compile — kotlinx's JsonArray takes no type + // arguments (documented TODO in KotlinXRenderer.ts). + "bug863.json", + "github-events.json", + "optional-union.json", + "00c36.json", + "010b1.json", + "050b0.json", + "06bee.json", + "07c75.json", + "0a91a.json", + "10be4.json", + "13d8d.json", + "1a7f5.json", + "2df80.json", + "32d5c.json", + "3536b.json", + "43970.json", + "570ec.json", + "5eae5.json", + "66121.json", + "6eb00.json", + "77392.json", + "7f568.json", + "7fbfb.json", + "9847b.json", + "996bd.json", + "9a503.json", + "9eed5.json", + "a45b0.json", + "ab0d1.json", + "ad8be.json", + "b4865.json", + "c8c7e.json", + "cda6c.json", + "e2a58.json", + "e53b5.json", + "e8a0b.json", + "e8b04.json", + "f3139.json", + "f3edf.json", + "f466a.json", + // Unions render as sealed classes without serializer wiring, so + // deserialization fails at runtime (documented TODO in + // KotlinXRenderer.ts). + "combinations1.json", + "combinations2.json", + "combinations3.json", + "combinations4.json", + "kitchen-sink.json", + "nbl-stats.json", + "nst-test-suite.json", + "php-mixed-union.json", + "union-constructor-clash.json", + "unions.json", + "26c9c.json", + "29f47.json", + "33d2e.json", + "421d4.json", + "5f7fe.json", + "617e8.json", + "a0496.json", + "a3d8c.json", + "f74d5.json", + "fcca3.json", + // stringEscape renders astral-plane characters as `\u{5 hex digits}`, + // which Kotlin misparses (it only supports 4-digit `\u` escapes), so + // the @SerialName annotations don't match the JSON keys. + "blns-object.json", + "identifiers.json", + ], + skipSchema: [ + // Unions render as sealed classes without serializer wiring, so + // deserialization fails at runtime (documented TODO in + // KotlinXRenderer.ts). + "accessors.schema", + "bool-string.schema", + "class-map-union.schema", + "class-with-additional.schema", + "date-time.schema", + "description.schema", + "direct-union.schema", + "enum.schema", // enum.3.json contains an int|string union + "implicit-class-array-union.schema", + "integer-float-union.schema", + "integer-string.schema", + "minmaxlength.schema", + "multi-type-enum.schema", + "mutually-recursive.schema", + "prefix-items.schema", + "recursive-union-flattening.schema", + "tuple.schema", + "union-int-double.schema", + "union-list.schema", + // Additionally exceeds the JVM's 255-parameter limit when the + // serialization plugin generates the synthesized constructors. + "keyword-unions.schema", + // Top-level array: `typealias TopLevel = JsonArray` doesn't + // compile (documented TODO in KotlinXRenderer.ts). + "union.schema", + ], + skipMiscJSON: false, + rendererOptions: { framework: "kotlinx" }, + quickTestRendererOptions: [], + sourceFiles: ["src/language/Kotlin/index.ts"], +}; + export const DartLanguage: Language = { name: "dart", base: "test/fixtures/dart",