diff --git a/.github/workflows/build-everything.yml b/.github/workflows/build-everything.yml index 8243e14..5424c06 100644 --- a/.github/workflows/build-everything.yml +++ b/.github/workflows/build-everything.yml @@ -16,7 +16,7 @@ on: jobs: build-everything: - uses: a-sit-plus/internal-workflows/.github/workflows/build-everything.yml@xcode-26 + uses: a-sit-plus/internal-workflows/.github/workflows/build-everything.yml@v3 with: matrix-file-name: ".github/config/build-strategy-matrix.json" kotlin-version: ${{ inputs.kotlin-version }} diff --git a/.github/workflows/publish-dry-run.yml b/.github/workflows/publish-dry-run.yml index 3bcec3e..0e7802d 100644 --- a/.github/workflows/publish-dry-run.yml +++ b/.github/workflows/publish-dry-run.yml @@ -25,7 +25,7 @@ jobs: TESTBALLOON_VERSION_OVERRIDE: ${{ inputs.testballoon-version }} steps: - name: Common Setup - uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v2 + uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v3 with: override-cache: 'false' setup-xcode: 'true' diff --git a/.github/workflows/publish-pages-only.yml b/.github/workflows/publish-pages-only.yml index bbedd18..bb9fdb4 100644 --- a/.github/workflows/publish-pages-only.yml +++ b/.github/workflows/publish-pages-only.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Common Setup - uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v2 + uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v3 with: override-cache: 'false' - name: Build Dokka HTML diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 105e040..f8670ad 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 300 steps: - name: Common Setup - uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v2 + uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v3 with: override-cache: 'true' setup-xcode: 'true' @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Common Setup - uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v2 + uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v3 with: override-cache: 'false' - name: Build Dokka HTML diff --git a/.github/workflows/spotless.yml b/.github/workflows/spotless.yml index f05d7b9..f427c76 100644 --- a/.github/workflows/spotless.yml +++ b/.github/workflows/spotless.yml @@ -25,8 +25,8 @@ jobs: timeout-minutes: 300 steps: - name: Common Setup - uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v2 + uses: a-sit-plus/internal-workflows/.github/actions/common-setup@v3 with: - override-cache: ${{ github.ref_name == 'main' }} + override-cache: ${{ github.ref_name == 'main' || github.ref_name == 'development'}} - name: check run: ./gradlew spotlessCheck \ No newline at end of file diff --git a/.github/workflows/test-everything.yml b/.github/workflows/test-everything.yml index 662d4f0..1b77cde 100644 --- a/.github/workflows/test-everything.yml +++ b/.github/workflows/test-everything.yml @@ -21,9 +21,9 @@ on: jobs: test-everything: - uses: a-sit-plus/internal-workflows/.github/workflows/test-everything.yml@xcode-26 + uses: a-sit-plus/internal-workflows/.github/workflows/test-everything.yml@v3 with: - override-cache: ${{ github.ref_name == 'main' }} + override-cache: ${{ github.ref_name == 'main'|| github.ref_name == 'development' }} matrix-file-name: ".github/config/test-strategy-matrix.json" kotlin-version: ${{ inputs.kotlin-version }} testballoon-version: ${{ inputs.testballoon-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index eb1fb59..45a8488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog +### Unreleased +- Updated backed property nullability so nullable fields are declared with nullable Kotlin types; this keeps the same optional-field functionality without a separate nullable delegate. + ### Version 0.0.1 - Initial version - Supports json and yaml - Supports custom serializers -- Supports backedProperties and slices \ No newline at end of file +- Supports backedProperties and slices diff --git a/README.md b/README.md index 975e1c8..3de2ebc 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,8 @@ dependencies { ## JSON Quick Start -Define a nominal wrapper class around `JsonObjectBacked`. Add required properties with `jsonProperty()` and nullable properties with `nullableJsonProperty()`. +Define a nominal wrapper class around `JsonObjectBacked`. Add typed properties with `jsonProperty()`. +The declared Kotlin type controls whether the backing field is required or nullable. ```kotlin @Serializable(with = PersonJsonObject.Serializer::class) @@ -94,7 +95,7 @@ class PersonJsonObject( var id: String by jsonProperty() var name: String by jsonProperty() var active: Boolean by jsonProperty("is_active") - var nickname: String? by nullableJsonProperty("nick", NullWriteMode.REMOVE_KEY) + var nickname: String? by jsonProperty("nick", nullWriteMode = NullWriteMode.REMOVE_KEY) override fun validate() { id @@ -142,7 +143,7 @@ class ServiceYamlObject( ) : YamlObjectBacked(raw, YamlBackingCodec(yaml)), ObjectBackedValidated { var id: String by yamlProperty() var endpoint: String by yamlProperty() - var description: String? by nullableYamlProperty() + var description: String? by yamlProperty() override fun validate() { id @@ -174,34 +175,31 @@ val encoded = yaml.encodeToString(ServiceYamlObject.serializer(), service) ## Delegated Properties -Required properties use `jsonProperty()` or `yamlProperty()`. +Required and nullable properties both use `jsonProperty()` or `yamlProperty()`. +The property type, together with the supplied serializer, defines the nullability contract. ```kotlin var id: String by jsonProperty() var displayName: String by jsonProperty("display_name") +var nickname: String? by jsonProperty("nick") ``` If no key is supplied, the Kotlin property name is used as the object key. If a key is supplied, that key is used instead. -Reading a missing required property throws `SerializationException`: +Reading a missing or explicit-null required property throws `SerializationException`: ```kotlin -val id = person.id // throws if "id" is absent +val id = person.id // throws if "id" is absent or null ``` -Nullable properties use `nullableJsonProperty()` or `nullableYamlProperty()`. - -```kotlin -var nickname: String? by nullableJsonProperty("nick") -``` - -Missing keys and explicit format-native null values both read as `null`. +For nullable properties, missing keys and explicit format-native null values both read as `null`. +The serializer must also be nullable; declaring the Kotlin property as `String?` gives the delegate a nullable serializer. Read-only views are also useful: ```kotlin val PersonJsonObject.publicName: String by jsonProperty("name") -val PersonJsonObject.optionalNick: String? by nullableJsonProperty("nick") +val PersonJsonObject.optionalNick: String? by jsonProperty("nick") ``` ## Whole-Object Slices @@ -226,7 +224,7 @@ class ClaimsJsonObject( json: Json = Json.Default, ) : JsonObjectBacked(raw, JsonBackingCodec(json)), ObjectBackedValidated { val claims: PublicClaims by jsonSlice() - var nonce: String? by nullableJsonProperty() + var nonce: String? by jsonProperty() override fun validate() { claims @@ -252,7 +250,7 @@ Propigator supports per-property null write behavior. The default is `NullWriteMode.STORE_NULL`: assigning `null` stores a format-native null value. ```kotlin -var middleName: String? by nullableJsonProperty("middle_name") +var middleName: String? by jsonProperty("middle_name") person.middleName = null // JSON: "middle_name": null @@ -261,13 +259,14 @@ person.middleName = null Use `NullWriteMode.REMOVE_KEY` when `null` should mean absence: ```kotlin -var nickname: String? by nullableJsonProperty("nick", NullWriteMode.REMOVE_KEY) +var nickname: String? by jsonProperty("nick", nullWriteMode = NullWriteMode.REMOVE_KEY) person.nickname = null // JSON: "nick" is removed ``` This is intentionally per property. Some formats or schemas distinguish explicit null from an absent key; others do not. Propigator lets the wrapper encode that decision where the semantic meaning is known. +`NullWriteMode` only applies to nullable delegated properties. A non-null property remains required and cannot be assigned `null`. ## Parse, Not Validate @@ -305,9 +304,9 @@ class JwsSigned( object Serializer : KSerializer by JsonObjectBackedSerializer(::JwsSigned) } -var JwsSigned.kid: String? by nullableJsonProperty("kid") -var JwsSigned.trustDomain: String? by nullableJsonProperty("trust_domain") -var JwsSigned.policyVersion: Int? by nullableJsonProperty("policy_version") +var JwsSigned.kid: String? by jsonProperty("kid") +var JwsSigned.trustDomain: String? by jsonProperty("trust_domain") +var JwsSigned.policyVersion: Int? by jsonProperty("policy_version") ``` An integrator can read the fields it needs: @@ -347,7 +346,7 @@ Use this sparingly: You can add semantic fields outside the nominal wrapper class. ```kotlin -var PersonJsonObject.locale: String? by nullableJsonProperty("locale") +var PersonJsonObject.locale: String? by jsonProperty("locale") val PersonJsonObject.displayLabel: String get() = locale?.let { "$name ($it)" } ?: name diff --git a/build.gradle.kts b/build.gradle.kts index d4e0e72..8775da4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,7 @@ plugins { //work around nexus publish bug val propigatorVersion: String by extra +group = "at.asitplus.propigator" version = propigatorVersion //end work around nexus publish bug diff --git a/common/src/commonMain/kotlin/at/asitplus/propigator/common/ObjectBackedProperty.kt b/common/src/commonMain/kotlin/at/asitplus/propigator/common/ObjectBackedProperty.kt index 7f06954..d9dc10f 100644 --- a/common/src/commonMain/kotlin/at/asitplus/propigator/common/ObjectBackedProperty.kt +++ b/common/src/commonMain/kotlin/at/asitplus/propigator/common/ObjectBackedProperty.kt @@ -9,7 +9,6 @@ import kotlinx.serialization.serializer import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty -//TODO: this can go, as the underlyign format will do null handling, right!? enum class NullWriteMode { /** Store an explicit format-native null value. */ STORE_NULL, @@ -18,61 +17,53 @@ enum class NullWriteMode { REMOVE_KEY, } -class RequiredBackedProperty( +class BackedProperty( private val key: K?, private val serializer: KSerializer, + private val nullWriteMode: NullWriteMode, ) : ReadWriteProperty where O : ObjectBacked { override fun getValue(thisRef: O, property: KProperty<*>): T { - val actualKey = (key ?: (property.name as? K)) - ?: throw SerializationException("property ${property.name} is not identifiable by String") + val actualKey = actualKey(property) val element = thisRef.getElement(actualKey) - ?: throw SerializationException("Missing required backing property: $actualKey") + ?: return readNull(actualKey) + if (thisRef.codec.isNull(element)) return readNull(actualKey) return thisRef.codec.decode(serializer, element) } override fun setValue(thisRef: O, property: KProperty<*>, value: T) { - val actualKey = (key ?: (property.name as? K)) - ?: throw SerializationException("property ${property.name} is not identifiable by String") + val actualKey = actualKey(property) + if (value == null) { + if (!serializer.descriptor.isNullable) { + throw SerializationException("Required backing property cannot be set to null: $actualKey") + } + when (nullWriteMode) { + NullWriteMode.STORE_NULL -> + thisRef.putElement(actualKey, thisRef.codec.nullElement()) + + NullWriteMode.REMOVE_KEY -> + thisRef.removeElement(actualKey) + } + return + } + thisRef.putElement(actualKey, thisRef.codec.encode(serializer, value)) } -} -class NullableBackedProperty( - private val key: K?, - private val serializer: KSerializer, - private val nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL, -) : ReadWriteProperty where O : ObjectBacked { - override fun getValue(thisRef: O, property: KProperty<*>): T? { - val actualKey = (key ?: (property.name as? K)) - ?: throw SerializationException("property ${property.name} is not identifiable by String") - val element = thisRef.getElement(actualKey) ?: return null - if (thisRef.codec.isNull(element)) return null - return thisRef.codec.decode(serializer, element) - } + @Suppress("UNCHECKED_CAST") + private fun actualKey(property: KProperty<*>): K = + key ?: (property.name as? K) + ?: throw SerializationException("property ${property.name} is not identifiable by backing key type") - override fun setValue(thisRef: O, property: KProperty<*>, value: T?) { - val actualKey = (key ?: (property.name as? K)) - ?: throw SerializationException("property ${property.name} is not identifiable by String") - if (value == null && nullWriteMode == NullWriteMode.REMOVE_KEY) { - thisRef.removeElement(actualKey) - } else { - thisRef.putElement( - actualKey, - if (value == null) thisRef.codec.nullElement() else thisRef.codec.encode(serializer, value), - ) - } + @Suppress("UNCHECKED_CAST") + private fun readNull(actualKey: K): T { + if (serializer.descriptor.isNullable) return null as T + throw SerializationException("Missing required backing property: $actualKey") } } inline fun backedProperty( key: K? = null, serializer: KSerializer = serializer(), + nullWriteMode: NullWriteMode, ): ReadWriteProperty where O : ObjectBacked = - RequiredBackedProperty(key, serializer) - -inline fun nullableBackedProperty( - key: K? = null, - nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL, - serializer: KSerializer = serializer(), -): ReadWriteProperty where O : ObjectBacked = - NullableBackedProperty(key, serializer, nullWriteMode) + BackedProperty(key, serializer, nullWriteMode) diff --git a/common/src/commonTest/kotlin/at/asitplus/propigator/common/ObjectBackedCommonTest.kt b/common/src/commonTest/kotlin/at/asitplus/propigator/common/ObjectBackedCommonTest.kt new file mode 100644 index 0000000..611f9cc --- /dev/null +++ b/common/src/commonTest/kotlin/at/asitplus/propigator/common/ObjectBackedCommonTest.kt @@ -0,0 +1,20 @@ +package at.asitplus.propigator.common + +import at.asitplus.testballoon.matrix.matrixSuite +import io.kotest.matchers.shouldBe + +internal val ObjectBackedCommonTest by matrixSuite { + "Object-backed common test data" - { + "exposes a valid reusable person fixture" { + ObjectBackedTestData.validate() + + ObjectBackedTestData.id shouldBe "p-1" + ObjectBackedTestData.name shouldBe "Ada" + ObjectBackedTestData.renamed shouldBe true + ObjectBackedTestData.foo shouldBe ObjectBackedTestPerson.Foo( + bar = 2, + baz = "eyz", + ) + } + } +} diff --git a/gradle.properties b/gradle.properties index 7897ef7..279b1b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ kotlin.native.ignoreDisabledTargets=true publishVersionCatalog=true -propigatorVersion = 0.0.1-SNAPSHOT +propigatorVersion = 0.0.2-SNAPSHOT # This is not a well-defined property, the ASP convention plugin respects it, though jdk.version=17 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cad2425..bd5771f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] kotlin="2.3.20" -testballoon = "0.8.4-K2.3.20" +testballoon = "1.0.0-K2.3.20" yamlkt = "0.13.0" -asp="20260428" +asp="20260610" agp = "8.12.3" sbombastic = "0.0.3" spotless = "8.2.1" diff --git a/json/src/commonMain/kotlin/at/asitplus/propigator/json/JsonBackedObject.kt b/json/src/commonMain/kotlin/at/asitplus/propigator/json/JsonBackedObject.kt index 099a613..9600025 100644 --- a/json/src/commonMain/kotlin/at/asitplus/propigator/json/JsonBackedObject.kt +++ b/json/src/commonMain/kotlin/at/asitplus/propigator/json/JsonBackedObject.kt @@ -3,7 +3,10 @@ package at.asitplus.propigator.json -import at.asitplus.propigator.common.* +import at.asitplus.propigator.common.BackingCodec +import at.asitplus.propigator.common.NullWriteMode +import at.asitplus.propigator.common.ObjectBacked +import at.asitplus.propigator.common.backedProperty import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement @@ -45,17 +48,20 @@ open class JsonObjectBacked( } } +/** + * Optional fields are backed as nullable type. + * Example + * ```val foo: String? by jsonProperty("foo")``` + * + * Required fields are backed as strict types + * ```val bar: Bar by jsonProperty("bar_obj", CustomBarSerializer)``` + */ inline fun jsonProperty( key: String? = null, serializer: KSerializer = serializer(), + nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL ): ReadWriteProperty = - backedProperty(key, serializer) + backedProperty(key, serializer, nullWriteMode) inline fun jsonSlice(serializer: KSerializer = serializer()): ReadOnlyProperty = ReadOnlyProperty { thisRef, _ -> thisRef.codec.decode(serializer, thisRef.rawObject) } - -inline fun nullableJsonProperty( - key: String? = null, - nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL, -): ReadWriteProperty = - nullableBackedProperty(key, nullWriteMode) diff --git a/json/src/commonTest/kotlin/at/asitplus/propigator/json/JsonObjectBackedTest.kt b/json/src/commonTest/kotlin/at/asitplus/propigator/json/JsonObjectBackedTest.kt index b8e909e..0e238d7 100644 --- a/json/src/commonTest/kotlin/at/asitplus/propigator/json/JsonObjectBackedTest.kt +++ b/json/src/commonTest/kotlin/at/asitplus/propigator/json/JsonObjectBackedTest.kt @@ -3,9 +3,7 @@ package at.asitplus.propigator.json import at.asitplus.propigator.common.NullWriteMode import at.asitplus.propigator.common.ObjectBackedTestData import at.asitplus.propigator.common.ObjectBackedTestPerson -import at.asitplus.testballoon.invoke -import at.asitplus.testballoon.minus -import de.infix.testBalloon.framework.core.testSuite +import at.asitplus.testballoon.matrix.matrixSuite import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe import kotlinx.serialization.KSerializer @@ -27,11 +25,14 @@ private class PersonJsonObject( object Serializer : KSerializer by JsonObjectBackedSerializer(::PersonJsonObject) } -private var PersonJsonObject.nickname: String? by nullableJsonProperty("nick", NullWriteMode.REMOVE_KEY) -private var PersonJsonObject.middleName: String? by nullableJsonProperty("middle", NullWriteMode.STORE_NULL) -private val PersonJsonObject.readOnlyNickname: String? by nullableJsonProperty("nick") +private var PersonJsonObject.nickname: String? by jsonProperty("nick", nullWriteMode = NullWriteMode.REMOVE_KEY) +private var PersonJsonObject.middleName: String? by jsonProperty( + "middle", + nullWriteMode = NullWriteMode.STORE_NULL +) +private val PersonJsonObject.readOnlyNickname: String? by jsonProperty("nick") -internal val JsonObjectBackedTest by testSuite { +internal val JsonObjectBackedTest by matrixSuite { "JSON-backed objects" - { "round-trip known properties while preserving unknown fields" { val json = Json { prettyPrint = false } diff --git a/json/src/commonTest/kotlin/at/asitplus/propigator/json/SignumInteropTest.kt b/json/src/commonTest/kotlin/at/asitplus/propigator/json/SignumInteropTest.kt index 85c8710..11b8b1e 100644 --- a/json/src/commonTest/kotlin/at/asitplus/propigator/json/SignumInteropTest.kt +++ b/json/src/commonTest/kotlin/at/asitplus/propigator/json/SignumInteropTest.kt @@ -2,9 +2,7 @@ package at.asitplus.propigator.json import at.asitplus.signum.indispensable.josef.KeyAttestationJwt import at.asitplus.signum.indispensable.josef.io.joseCompliantSerializer -import at.asitplus.testballoon.invoke -import at.asitplus.testballoon.minus -import de.infix.testBalloon.framework.core.testSuite +import at.asitplus.testballoon.matrix.matrixSuite import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe import kotlinx.serialization.SerializationException @@ -13,7 +11,7 @@ import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject -internal val SignumInteropTest by testSuite { +internal val SignumInteropTest by matrixSuite { "Signum-backed key attestation" - { "matches KeyAttestationJwt while preserving unmodelled claims" { val keyAttestation = joseCompliantSerializer.decodeFromString(keyAttestationJwtClaims) diff --git a/json/src/jvmTest/kotlin/at/asitplus/propigator/json/NimbusSignumInteropTest.kt b/json/src/jvmTest/kotlin/at/asitplus/propigator/json/NimbusSignumInteropTest.kt index ef2429b..6823f02 100644 --- a/json/src/jvmTest/kotlin/at/asitplus/propigator/json/NimbusSignumInteropTest.kt +++ b/json/src/jvmTest/kotlin/at/asitplus/propigator/json/NimbusSignumInteropTest.kt @@ -2,15 +2,13 @@ package at.asitplus.propigator.json import at.asitplus.signum.indispensable.josef.JsonWebToken import at.asitplus.signum.indispensable.josef.io.joseCompliantSerializer -import at.asitplus.testballoon.invoke -import at.asitplus.testballoon.minus +import at.asitplus.testballoon.matrix.matrixSuite import com.nimbusds.jose.JOSEObjectType import com.nimbusds.jose.JWSAlgorithm import com.nimbusds.jose.JWSHeader import com.nimbusds.jose.crypto.MACSigner import com.nimbusds.jwt.JWTClaimsSet import com.nimbusds.jwt.SignedJWT -import de.infix.testBalloon.framework.core.testSuite import io.kotest.matchers.shouldBe import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable @@ -31,7 +29,7 @@ private class NimbusJwtClaims( object Serializer : KSerializer by JsonObjectBackedSerializer(::NimbusJwtClaims) } -internal val NimbusSignumInteropTest by testSuite { +internal val NimbusSignumInteropTest by matrixSuite { "Nimbus-generated JWT claims" - { "deserialize through Signum JsonWebToken while preserving custom claims" { val issuer = "https://issuer.example/${UUID.randomUUID()}" diff --git a/yaml/src/commonMain/kotlin/at/asitplus/propigator/yaml/YamlBackedObject.kt b/yaml/src/commonMain/kotlin/at/asitplus/propigator/yaml/YamlBackedObject.kt index bfe9862..ce8d58f 100644 --- a/yaml/src/commonMain/kotlin/at/asitplus/propigator/yaml/YamlBackedObject.kt +++ b/yaml/src/commonMain/kotlin/at/asitplus/propigator/yaml/YamlBackedObject.kt @@ -49,14 +49,9 @@ open class YamlObjectBacked( inline fun yamlProperty( key: String? = null, serializer: KSerializer = serializer(), + nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL ): ReadWriteProperty = - backedProperty(key, serializer) + backedProperty(key, serializer, nullWriteMode) inline fun yamlSlice(serializer: KSerializer = serializer()): ReadOnlyProperty = - ReadOnlyProperty { thisRef, _ -> thisRef.codec.decode(serializer, thisRef.rawObject) } - -inline fun nullableYamlProperty( - key: String? = null, - nullWriteMode: NullWriteMode = NullWriteMode.STORE_NULL, -): ReadWriteProperty = - nullableBackedProperty(key, nullWriteMode) + ReadOnlyProperty { thisRef, _ -> thisRef.codec.decode(serializer, thisRef.rawObject) } \ No newline at end of file diff --git a/yaml/src/commonTest/kotlin/at/asitplus/propigator/yaml/YamlObjectBackedTest.kt b/yaml/src/commonTest/kotlin/at/asitplus/propigator/yaml/YamlObjectBackedTest.kt index 6eb565c..a4d126b 100644 --- a/yaml/src/commonTest/kotlin/at/asitplus/propigator/yaml/YamlObjectBackedTest.kt +++ b/yaml/src/commonTest/kotlin/at/asitplus/propigator/yaml/YamlObjectBackedTest.kt @@ -3,9 +3,7 @@ package at.asitplus.propigator.yaml import at.asitplus.propigator.common.NullWriteMode import at.asitplus.propigator.common.ObjectBackedTestData import at.asitplus.propigator.common.ObjectBackedTestPerson -import at.asitplus.testballoon.invoke -import at.asitplus.testballoon.minus -import de.infix.testBalloon.framework.core.testSuite +import at.asitplus.testballoon.matrix.matrixSuite import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe import kotlinx.serialization.KSerializer @@ -30,11 +28,11 @@ private class PersonYamlObject( object Serializer : KSerializer by YamlObjectBackedSerializer(create = ::PersonYamlObject) } -private var PersonYamlObject.nickname: String? by nullableYamlProperty("nick", NullWriteMode.REMOVE_KEY) -private var PersonYamlObject.middleName: String? by nullableYamlProperty("middle", NullWriteMode.STORE_NULL) -private val PersonYamlObject.readOnlyNickname: String? by nullableYamlProperty("nick") +private var PersonYamlObject.nickname: String? by yamlProperty("nick", nullWriteMode = NullWriteMode.REMOVE_KEY) +private var PersonYamlObject.middleName: String? by yamlProperty("middle", nullWriteMode = NullWriteMode.STORE_NULL) +private val PersonYamlObject.readOnlyNickname: String? by yamlProperty("nick") -internal val YamlObjectBackedTest by testSuite { +internal val YamlObjectBackedTest by matrixSuite { "YAML-backed objects" - { "round-trip known properties while preserving unknown fields" { val decoded = Yaml.decodeFromString(