Skip to content

Commit

Permalink
adds dynamicPath sopport to enum, required, unevaluatedItem/Props sch…
Browse files Browse the repository at this point in the history
…emas
  • Loading branch information
erosb committed Dec 10, 2024
1 parent 16ba88d commit 1c2d420
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/main/kotlin/com/github/erosb/jsonsKema/Enum.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ internal val enumLoader: KeywordLoader = { ctx ->

class EnumValidationFailure(
override val schema: EnumSchema,
override val instance: IJsonValue
override val instance: IJsonValue,
val dynamicPath: JsonPointer
) : ValidationFailure("the instance is not equal to any enum values", schema, instance, Keyword.ENUM)
3 changes: 2 additions & 1 deletion src/main/kotlin/com/github/erosb/jsonsKema/Required.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ internal val requiredLoader: KeywordLoader = { ctx ->
data class RequiredValidationFailure(
val missingProperties: List<String>,
override val schema: RequiredSchema,
override val instance: IJsonObj
override val instance: IJsonObj,
val dynamicPath: JsonPointer
) : ValidationFailure(
"required properties are missing: " + missingProperties.joinToString(),
schema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ data class UnevaluatedItemsSchema(
data class UnevaluatedItemsValidationFailure(
val itemFailures: Map<Int, ValidationFailure>,
override val schema: UnevaluatedItemsSchema,
override val instance: IJsonArray<*>
override val instance: IJsonArray<*>,
val dynamicPath: JsonPointer
) : ValidationFailure(
"array items ${itemFailures.keys.joinToString(", ")} failed to validate against \"unevaluatedItems\" subschema",
schema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ data class UnevaluatedPropertiesSchema(
data class UnevaluatedPropertiesValidationFailure(
val propertyFailures: Map<String, ValidationFailure>,
override val schema: UnevaluatedPropertiesSchema,
override val instance: IJsonObj
override val instance: IJsonObj,
val dynamicPath: JsonPointer
) : ValidationFailure(
"object properties ${propertyFailures.keys.joinToString(", ")} failed to validate against \"unevaluatedProperties\" subschema",
schema,
Expand Down
23 changes: 10 additions & 13 deletions src/main/kotlin/com/github/erosb/jsonsKema/Validator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ private class DefaultValidator(
if (schema.potentialValues.any { it == instance }) {
null
} else {
EnumValidationFailure(schema, instance)
EnumValidationFailure(schema, instance, dynamicPath() + Keyword.ENUM)
}

override fun visitRequiredSchema(schema: RequiredSchema): ValidationFailure? =
Expand All @@ -463,7 +463,7 @@ private class DefaultValidator(
if (missingProps.isEmpty()) {
null
} else {
RequiredValidationFailure(missingProps, schema, it)
RequiredValidationFailure(missingProps, schema, it, dynamicPath() + Keyword.REQUIRED)
}
}

Expand Down Expand Up @@ -675,7 +675,7 @@ private class DefaultValidator(
null
}

override fun visitUnevaluatedItemsSchema(schema: UnevaluatedItemsSchema): ValidationFailure? {
override fun visitUnevaluatedItemsSchema(schema: UnevaluatedItemsSchema): ValidationFailure? = inPathSegment(Keyword.UNEVALUATED_ITEMS) {
val instance = this.instance
if (instance is MarkableJsonArray<*>) {
val failures = mutableMapOf<Int, ValidationFailure>()
Expand All @@ -687,12 +687,10 @@ private class DefaultValidator(
}
instance.markEvaluated(index)
}
return if (failures.isNotEmpty()) {
UnevaluatedItemsValidationFailure(failures, schema, instance)
if (failures.isNotEmpty()) {
UnevaluatedItemsValidationFailure(failures, schema, instance, dynamicPath())
} else null
} else {
return null
}
} else null
}

private val formatValidators: Map<String, FormatValidator> = mapOf(
Expand All @@ -714,7 +712,7 @@ private class DefaultValidator(
null
}

override fun visitUnevaluatedPropertiesSchema(schema: UnevaluatedPropertiesSchema): ValidationFailure? {
override fun visitUnevaluatedPropertiesSchema(schema: UnevaluatedPropertiesSchema): ValidationFailure? = inPathSegment(Keyword.UNEVALUATED_PROPERTIES) {
val instance = this.instance
if (instance is MarkableJsonObject<*, *>) {
val failures = mutableMapOf<String, ValidationFailure>()
Expand All @@ -724,11 +722,10 @@ private class DefaultValidator(
}
instance.markEvaluated(propName)
}
return if (failures.isNotEmpty()) {
UnevaluatedPropertiesValidationFailure(failures, schema, instance)
if (failures.isNotEmpty()) {
UnevaluatedPropertiesValidationFailure(failures, schema, instance, dynamicPath())
} else null
}
return null
} else null
}

override fun visitReadOnlySchema(readOnlySchema: ReadOnlySchema): ValidationFailure? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.github.erosb.jsonsKema

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class UnevaluatedPropsItemsTest {

@Test
fun `dynamic path for unevaluatedProps`() {
val schema = SchemaLoader("""
{
"unevaluatedProperties": {
"type": "object",
"required": ["reason"]
},
"properties": {
"a": {"type": "string"}
}
}
""".trimIndent())()

val actual = Validator.forSchema(schema).validate("""
{
"x": {}
}
""".trimIndent()) as UnevaluatedPropertiesValidationFailure

assertEquals("#/unevaluatedProperties", actual.dynamicPath.toString())

val cause = actual.causes.single() as RequiredValidationFailure
assertEquals("#/unevaluatedProperties/required", cause.dynamicPath.toString())
}

@Test
fun `dynamic path for unevaluatedItems`() {
val schema = SchemaLoader("""
{
"unevaluatedItems": {
"enum": [null]
},
"prefixItems": [
{"type": "string"}
]
}
""".trimIndent())()

val actual = Validator.forSchema(schema).validate("""
["a", "b"]
""".trimIndent()) as UnevaluatedItemsValidationFailure

assertEquals("#/unevaluatedItems", actual.dynamicPath.toString())

val cause = actual.causes.single() as EnumValidationFailure
assertEquals("#/unevaluatedItems/enum", cause.dynamicPath.toString())
}
}

0 comments on commit 1c2d420

Please sign in to comment.