-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds writers for range-based constraints (#290)
- Loading branch information
Showing
8 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
...schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ExponentWriter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.writer.internal.writeRange | ||
|
||
@ExperimentalIonSchemaModel | ||
internal object ExponentWriter : ConstraintWriter { | ||
override val supportedClasses = setOf(Constraint.Exponent::class) | ||
override fun IonWriter.write(c: Constraint) { | ||
check(c is Constraint.Exponent) | ||
setFieldName("exponent") | ||
writeRange(c.range) | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
...c/main/kotlin/com/amazon/ionschema/writer/internal/constraints/LengthConstraintsWriter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.writer.internal.writeRange | ||
import kotlin.reflect.KClass | ||
|
||
@ExperimentalIonSchemaModel | ||
internal object LengthConstraintsWriter : ConstraintWriter { | ||
|
||
override val supportedClasses: Set<KClass<out Constraint>> = setOf( | ||
Constraint.ByteLength::class, | ||
Constraint.CodepointLength::class, | ||
Constraint.ContainerLength::class, | ||
Constraint.Utf8ByteLength::class, | ||
) | ||
|
||
override fun IonWriter.write(c: Constraint) { | ||
when (c) { | ||
is Constraint.ByteLength -> { | ||
setFieldName("byte_length") | ||
writeRange(c.range) | ||
} | ||
is Constraint.CodepointLength -> { | ||
setFieldName("codepoint_length") | ||
writeRange(c.range) | ||
} | ||
is Constraint.ContainerLength -> { | ||
setFieldName("container_length") | ||
writeRange(c.range) | ||
} | ||
is Constraint.Utf8ByteLength -> { | ||
setFieldName("utf8_byte_length") | ||
writeRange(c.range) | ||
} | ||
else -> throw IllegalStateException("Unsupported constraint. Should be unreachable.") | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...chema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/PrecisionWriter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.writer.internal.writeRange | ||
|
||
@ExperimentalIonSchemaModel | ||
internal object PrecisionWriter : ConstraintWriter { | ||
override val supportedClasses = setOf(Constraint.Precision::class) | ||
|
||
override fun IonWriter.write(c: Constraint) { | ||
check(c is Constraint.Precision) | ||
setFieldName("precision") | ||
writeRange(c.range) | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/ranges.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.model.DiscreteIntRange | ||
|
||
internal fun IonWriter.writeRange(range: DiscreteIntRange) { | ||
val (start, endInclusive) = range | ||
if (start == endInclusive) { | ||
writeInt(start!!.toLong()) | ||
} else { | ||
setTypeAnnotations("range") | ||
writeList { | ||
start?.let { writeInt(it.toLong()) } | ||
?: writeSymbol("min") | ||
endInclusive?.let { writeInt(it.toLong()) } | ||
?: writeSymbol("max") | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
...ma/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ConstraintTestBase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
@file:OptIn(ExperimentalIonSchemaModel::class) | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.assertEqualIon | ||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.writer.internal.writeStruct | ||
import io.mockk.mockk | ||
import org.junit.jupiter.api.Assertions.assertEquals | ||
import org.junit.jupiter.api.Test | ||
import org.junit.jupiter.api.TestInstance | ||
import org.junit.jupiter.api.assertThrows | ||
import org.junit.jupiter.params.ParameterizedTest | ||
import org.junit.jupiter.params.provider.MethodSource | ||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* Base class for eliminating boilerplate code in the constraint writer test classes. | ||
* | ||
* Given a [ConstraintWriter] instance, this will check: | ||
* 1. That [ConstraintWriter.supportedClasses] returns the correct values | ||
* 2. That [ConstraintWriter.writeTo] throws if called for the wrong constraint type | ||
* 3. That [ConstraintWriter.writeTo] writes the expected field name and value to a struct | ||
*/ | ||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) | ||
abstract class ConstraintTestBase internal constructor( | ||
internal val writer: ConstraintWriter, | ||
protected val expectedConstraints: Set<KClass<out Constraint>>, | ||
/** | ||
* Pairs of [Constraint] instances to the field name and value that is expected for writing that constraint. E.g.: | ||
* ``` | ||
* listOf( | ||
* Constraint.Exponent(DiscreteIntRange(null, 23)) to "exponent: range::[min, 23]", | ||
* Constraint.Exponent(DiscreteIntRange(7, null)) to "exponent: range::[7, max]", | ||
* ) | ||
* ``` | ||
*/ | ||
protected val writeTestCases: List<Pair<Constraint, String>> | ||
) { | ||
/** Runs the test cases given in [writeTestCases]. */ | ||
@ParameterizedTest | ||
@MethodSource("getWriteTestCases") | ||
private fun `writer should be able to write constraint`(testCase: Pair<Constraint, String>) = runWriteCase(writer, testCase) | ||
|
||
/** Helper function that can be used by subclasses to run additional "write" test cases */ | ||
internal fun runWriteCase(writer: ConstraintWriter, testCase: Pair<Constraint, String>) { | ||
val (constraint, expectedField) = testCase | ||
assertEqualIon("{ $expectedField }") { | ||
it.writeStruct { | ||
writer.writeTo(it, constraint) | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
private fun `supportedClasses should return the correct classes`() { | ||
assertEquals(expectedConstraints, writer.supportedClasses) | ||
} | ||
|
||
@Test | ||
private fun `attempting to write an unsupported constraint should throw an exception`() { | ||
val ionWriter = mockk<IonWriter>() | ||
val constraint = mockk<Constraint>() | ||
assertThrows<IllegalStateException> { | ||
writer.writeTo(ionWriter, constraint) | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...ma/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ExponentWriterTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.DiscreteIntRange | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
|
||
@OptIn(ExperimentalIonSchemaModel::class) | ||
class ExponentWriterTest : ConstraintTestBase( | ||
writer = ExponentWriter, | ||
expectedConstraints = setOf(Constraint.Exponent::class), | ||
writeTestCases = listOf( | ||
Constraint.Exponent(DiscreteIntRange(2, 5)) to "exponent: range::[2, 5]", | ||
Constraint.Exponent(DiscreteIntRange(null, 23)) to "exponent: range::[min, 23]", | ||
Constraint.Exponent(DiscreteIntRange(7, null)) to "exponent: range::[7, max]", | ||
Constraint.Exponent(DiscreteIntRange(3, 3)) to "exponent: 3", | ||
), | ||
) |
37 changes: 37 additions & 0 deletions
37
...st/kotlin/com/amazon/ionschema/writer/internal/constraints/LengthConstraintsWriterTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.DiscreteIntRange | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
|
||
@OptIn(ExperimentalIonSchemaModel::class) | ||
class LengthConstraintsWriterTest : ConstraintTestBase( | ||
writer = LengthConstraintsWriter, | ||
expectedConstraints = setOf( | ||
Constraint.ByteLength::class, | ||
Constraint.CodepointLength::class, | ||
Constraint.ContainerLength::class, | ||
Constraint.Utf8ByteLength::class, | ||
), | ||
writeTestCases = listOf( | ||
Constraint.ByteLength(DiscreteIntRange(2, 5)) to "byte_length: range::[2, 5]", | ||
Constraint.ByteLength(DiscreteIntRange(null, 23)) to "byte_length: range::[min, 23]", | ||
Constraint.ByteLength(DiscreteIntRange(7, null)) to "byte_length: range::[7, max]", | ||
Constraint.ByteLength(DiscreteIntRange(3, 3)) to "byte_length: 3", | ||
Constraint.CodepointLength(DiscreteIntRange(2, 5)) to "codepoint_length: range::[2, 5]", | ||
Constraint.CodepointLength(DiscreteIntRange(null, 23)) to "codepoint_length: range::[min, 23]", | ||
Constraint.CodepointLength(DiscreteIntRange(7, null)) to "codepoint_length: range::[7, max]", | ||
Constraint.CodepointLength(DiscreteIntRange(3, 3)) to "codepoint_length: 3", | ||
Constraint.CodepointLength(DiscreteIntRange(2, 5)) to "codepoint_length: range::[2, 5]", | ||
Constraint.ContainerLength(DiscreteIntRange(null, 23)) to "container_length: range::[min, 23]", | ||
Constraint.ContainerLength(DiscreteIntRange(7, null)) to "container_length: range::[7, max]", | ||
Constraint.ContainerLength(DiscreteIntRange(3, 3)) to "container_length: 3", | ||
Constraint.Utf8ByteLength(DiscreteIntRange(2, 5)) to "utf8_byte_length: range::[2, 5]", | ||
Constraint.Utf8ByteLength(DiscreteIntRange(null, 23)) to "utf8_byte_length: range::[min, 23]", | ||
Constraint.Utf8ByteLength(DiscreteIntRange(7, null)) to "utf8_byte_length: range::[7, max]", | ||
Constraint.Utf8ByteLength(DiscreteIntRange(3, 3)) to "utf8_byte_length: 3", | ||
) | ||
) |
20 changes: 20 additions & 0 deletions
20
...a/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/PrecisionWriterTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal.constraints | ||
|
||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.DiscreteIntRange | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
|
||
@OptIn(ExperimentalIonSchemaModel::class) | ||
class PrecisionWriterTest : ConstraintTestBase( | ||
writer = PrecisionWriter, | ||
expectedConstraints = setOf(Constraint.Precision::class), | ||
writeTestCases = listOf( | ||
Constraint.Precision(DiscreteIntRange(2, 5)) to "precision: range::[2, 5]", | ||
Constraint.Precision(DiscreteIntRange(null, 23)) to "precision: range::[min, 23]", | ||
Constraint.Precision(DiscreteIntRange(7, null)) to "precision: range::[7, max]", | ||
Constraint.Precision(DiscreteIntRange(3, 3)) to "precision: 3", | ||
) | ||
) |