diff --git a/buildSrc/src/main/kotlin/org/kson/jsonsuite/JsonTestSuiteGenerator.kt b/buildSrc/src/main/kotlin/org/kson/jsonsuite/JsonTestSuiteGenerator.kt index 2176c83c..974aec41 100644 --- a/buildSrc/src/main/kotlin/org/kson/jsonsuite/JsonTestSuiteGenerator.kt +++ b/buildSrc/src/main/kotlin/org/kson/jsonsuite/JsonTestSuiteGenerator.kt @@ -1,5 +1,6 @@ package org.kson.jsonsuite +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement @@ -273,10 +274,10 @@ ${ tests.joinToString("\n") { | $schemaComment | assertKsonEnforcesSchema( | ${"\"\"\""} - | ${formatForTest(test.data)} + | ${formatForTest(test.data, " ")} | ${"\"\"\""}, | ${"\"\"\""} - | ${formatForTest(schema.schema)} + | ${formatForTest(schema.schema, " ")} | ${"\"\"\""}, | ${test.valid}, | ${"\"\"\""}${formatForTest(schema.description)} -> ${formatForTest(test.description)}${"\"\"\""}) @@ -362,10 +363,16 @@ private class SchemaTestDataLoader(private val testDefinitionFilesDir: Path, pri } } -private val prettyPrintingJson = Json { prettyPrint = true } - -private fun formatForTest(jsonElement: JsonElement): String { - return formatForTest(jsonElement.toString()) +@OptIn(ExperimentalSerializationApi::class) +private val prettyPrintingJson = Json { + prettyPrint = true + // 4 spaces for indentation + prettyPrintIndent = " " +} +private fun formatForTest(jsonElement: JsonElement, indent: String): String { + return formatForTest(prettyPrintingJson.encodeToString(JsonElement.serializer(), jsonElement)) + .split("\n") + .joinToString(separator = "\n$indent") } private fun formatForTest(string: String): String { diff --git a/buildSrc/src/main/kotlin/org/kson/jsonsuite/SchemaTestSuiteExclusionsList.kt b/buildSrc/src/main/kotlin/org/kson/jsonsuite/SchemaTestSuiteExclusionsList.kt index 80743feb..238bc316 100644 --- a/buildSrc/src/main/kotlin/org/kson/jsonsuite/SchemaTestSuiteExclusionsList.kt +++ b/buildSrc/src/main/kotlin/org/kson/jsonsuite/SchemaTestSuiteExclusionsList.kt @@ -2,122 +2,40 @@ package org.kson.jsonsuite /** * This is the list of [JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite) - * tests which test as-yet unimplemented aspects of our Json Schema support. - * - * TODO: once Json Schema support is fully implemented, this list should be empty and hence deleted. - * This will likely be done in an iterative fashion, eliminating the exclusions here for few tests at a time - * as support is filled out + * tests which should not be run as part of test suite. See comments on specific exclusions for more details. */ fun schemaTestSuiteExclusions() = setOf( - "infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_passingCase", - "infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_failingCase", - "definitions_validateDefinitionAgainstMetaschema_validDefinitionSchema", - "definitions_validateDefinitionAgainstMetaschema_invalidDefinitionSchema", - "items_itemsAndSubitems_fewerItemsIsValid", - "items_itemsAndSubitems_tooManyItems", - "items_itemsAndSubitems_tooManySub_items", - "items_itemsAndSubitems_validItems", - "items_itemsAndSubitems_wrongItem", - "items_itemsAndSubitems_wrongSub_item", - "refRemote_______refTo______refFindsLocation_independent______id_non_numberIsInvalid", - "refRemote_______refTo______refFindsLocation_independent______id_numberIsValid", - "refRemote_baseURIChange_ChangeFolderInSubschema_numberIsValid", - "refRemote_baseURIChange_ChangeFolderInSubschema_stringIsInvalid", - "refRemote_baseURIChange_ChangeFolder_numberIsValid", - "refRemote_baseURIChange_ChangeFolder_stringIsInvalid", + + /** + * These excludes are all tests which require fetching remote schemas. We do not want to support fetching + * right now and so require that schemas be [bundled](https://json-schema.org/blog/posts/bundling-json-schema-compound-documents) + * before they are passed to Kson. + * + * We test bundled versions of these test in [org.kson.schema.JsonSchemaTestBundledRemotes]. + */ "refRemote_baseURIChange_baseURIChangeRefInvalid", "refRemote_baseURIChange_baseURIChangeRefValid", + "refRemote_baseURIChange_ChangeFolder_numberIsValid", + "refRemote_baseURIChange_ChangeFolder_stringIsInvalid", + "refRemote_baseURIChange_ChangeFolderInSubschema_numberIsValid", + "refRemote_baseURIChange_ChangeFolderInSubschema_stringIsInvalid", "refRemote_fragmentWithinRemoteRef_remoteFragmentInvalid", "refRemote_fragmentWithinRemoteRef_remoteFragmentValid", "refRemote_location_independentIdentifierInRemoteRef_integerIsValid", "refRemote_location_independentIdentifierInRemoteRef_stringIsInvalid", "refRemote_refWithinRemoteRef_refWithinRefInvalid", "refRemote_refWithinRemoteRef_refWithinRefValid", - "refRemote_remoteRefWithRefToDefinitions_invalid", - "refRemote_remoteRefWithRefToDefinitions_valid", "refRemote_remoteRef_remoteRefInvalid", "refRemote_remoteRef_remoteRefValid", + "refRemote_remoteRefWithRefToDefinitions_invalid", + "refRemote_remoteRefWithRefToDefinitions_valid", "refRemote_retrievedNestedRefsResolveRelativeToTheirURINot______id_numberIsInvalid", "refRemote_retrievedNestedRefsResolveRelativeToTheirURINot______id_stringIsValid", "refRemote_rootRefInRemoteRef_nullIsValid", "refRemote_rootRefInRemoteRef_objectIsInvalid", "refRemote_rootRefInRemoteRef_stringIsValid", - "ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_non_numberIsInvalid", - "ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_numberIsValid", - "ref_______idWithFileURIStillResolvesPointers_Windows_non_numberIsInvalid", - "ref_______idWithFileURIStillResolvesPointers_Windows_numberIsValid", - "ref_______idWithFileURIStillResolvesPointers__nix_non_numberIsInvalid", - "ref_______idWithFileURIStillResolvesPointers__nix_numberIsValid", - "ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataDoesNotValidate", - "ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataValidates", - "ref_______refToBooleanSchemaFalse_anyValueIsInvalid", - "ref_______refToBooleanSchemaTrue_anyValueIsValid", - "ref_emptyTokensIn______refJson_pointer_non_numberIsInvalid", - "ref_emptyTokensIn______refJson_pointer_numberIsValid", - "ref_escapedPointerRef_percentInvalid", - "ref_escapedPointerRef_percentValid", - "ref_escapedPointerRef_slashInvalid", - "ref_escapedPointerRef_slashValid", - "ref_escapedPointerRef_tildeInvalid", - "ref_escapedPointerRef_tildeValid", - "ref_location_independentIdentifierWithBaseURIChangeInSubschema_match", - "ref_location_independentIdentifierWithBaseURIChangeInSubschema_mismatch", - "ref_location_independentIdentifier_match", - "ref_location_independentIdentifier_mismatch", - "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_DefinitionExactMatch", - "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_MatchingAnyString", - "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_matchTheEnumExactly", - "ref_nestedRefs_nestedRefInvalid", - "ref_nestedRefs_nestedRefValid", - "ref_propertyNamed______refThatIsNotAReference_propertyNamed______refInvalid", - "ref_propertyNamed______refThatIsNotAReference_propertyNamed______refValid", - "ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refInvalid", - "ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refValid", - "ref_recursiveReferencesBetweenSchemas_invalidTree", - "ref_recursiveReferencesBetweenSchemas_validTree", - "ref_refOverridesAnySiblingKeywords_refInvalid", - "ref_refOverridesAnySiblingKeywords_refValid", - "ref_refOverridesAnySiblingKeywords_refValid_MaxItemsIgnored", - "ref_refToElse_aNon_integerIsInvalidDueToThe______ref", - "ref_refToElse_anIntegerIsValid", - "ref_refToIf_aNon_integerIsInvalidDueToThe______ref", - "ref_refToIf_anIntegerIsValid", - "ref_refToThen_aNon_integerIsInvalidDueToThe______ref", - "ref_refToThen_anIntegerIsValid", - "ref_refWithAbsolute_path_reference_aStringIsValid", - "ref_refWithAbsolute_path_reference_anIntegerIsInvalid", - "ref_referenceAnAnchorWithANon_relativeURI_match", - "ref_referenceAnAnchorWithANon_relativeURI_mismatch", - "ref_refsWithQuote_objectWithNumbersIsValid", - "ref_refsWithQuote_objectWithStringsIsInvalid", - "ref_refsWithRelativeUrisAndDefs_invalidOnInnerField", - "ref_refsWithRelativeUrisAndDefs_invalidOnOuterField", - "ref_refsWithRelativeUrisAndDefs_validOnBothFields", - "ref_relativePointerRefToArray_matchArray", - "ref_relativePointerRefToArray_mismatchArray", - "ref_relativePointerRefToObject_match", - "ref_relativePointerRefToObject_mismatch", - "ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnInnerField", - "ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnOuterField", - "ref_relativeRefsWithAbsoluteUrisAndDefs_validOnBothFields", "ref_remoteRef_ContainingRefsItself_remoteRefInvalid", "ref_remoteRef_ContainingRefsItself_remoteRefValid", - "ref_rootPointerRef_match", - "ref_rootPointerRef_mismatch", - "ref_rootPointerRef_recursiveMatch", - "ref_rootPointerRef_recursiveMismatch", - "ref_simpleURNBaseURIWithJSONPointer_aNon_stringIsInvalid", - "ref_simpleURNBaseURIWithJSONPointer_aStringIsValid", - "ref_simpleURNBaseURIWith______refViaTheURN_invalidUnderTheURNIDedSchema", - "ref_simpleURNBaseURIWith______refViaTheURN_validUnderTheURNIDedSchema", - "ref_uRNBaseURIWithNSS_aNon_stringIsInvalid", - "ref_uRNBaseURIWithNSS_aStringIsValid", - "ref_uRNBaseURIWithQ_component_aNon_stringIsInvalid", - "ref_uRNBaseURIWithQ_component_aStringIsValid", - "ref_uRNBaseURIWithR_component_aNon_stringIsInvalid", - "ref_uRNBaseURIWithR_component_aStringIsValid", - "ref_uRNBaseURIWithURNAndAnchorRef_aNon_stringIsInvalid", - "ref_uRNBaseURIWithURNAndAnchorRef_aStringIsValid", - "ref_uRNBaseURIWithURNAndJSONPointerRef_aNon_stringIsInvalid", - "ref_uRNBaseURIWithURNAndJSONPointerRef_aStringIsValid", + "refRemote_______refTo______refFindsLocation_independent______id_non_numberIsInvalid", + "refRemote_______refTo______refFindsLocation_independent______id_numberIsValid", ) diff --git a/lib-kotlin/src/commonMain/kotlin/org/kson/Kson.kt b/lib-kotlin/src/commonMain/kotlin/org/kson/Kson.kt index ff827523..3c072a0d 100644 --- a/lib-kotlin/src/commonMain/kotlin/org/kson/Kson.kt +++ b/lib-kotlin/src/commonMain/kotlin/org/kson/Kson.kt @@ -79,8 +79,13 @@ object Kson { */ fun parseSchema(schemaKson: String): SchemaResult { val schemaParseResult = KsonCore.parseSchema(schemaKson) + val messages = publishMessages(schemaParseResult.messages) val jsonSchema = schemaParseResult.jsonSchema - ?: return SchemaResult.Failure(publishMessages(schemaParseResult.messages)) + ?: return SchemaResult.Failure(messages) + + if (messages.isNotEmpty()) { + return SchemaResult.Failure(messages) + } return SchemaResult.Success(SchemaValidator(jsonSchema)) } diff --git a/src/commonMain/kotlin/org/kson/KsonCore.kt b/src/commonMain/kotlin/org/kson/KsonCore.kt index 271c6858..70ca84f0 100644 --- a/src/commonMain/kotlin/org/kson/KsonCore.kt +++ b/src/commonMain/kotlin/org/kson/KsonCore.kt @@ -99,7 +99,7 @@ object KsonCore { } val messageSink = MessageSink() - val jsonSchema = SchemaParser.parseSchemaElement(ksonValue, messageSink) + val jsonSchema = SchemaParser.parseSchemaRoot(ksonValue, messageSink) return SchemaParseResult(jsonSchema, messageSink.loggedMessages()) } diff --git a/src/commonMain/kotlin/org/kson/parser/messages/Message.kt b/src/commonMain/kotlin/org/kson/parser/messages/Message.kt index 55611876..ab222666 100644 --- a/src/commonMain/kotlin/org/kson/parser/messages/Message.kt +++ b/src/commonMain/kotlin/org/kson/parser/messages/Message.kt @@ -12,7 +12,7 @@ enum class MessageSeverity { * Instances of [Message] are created with [MessageType.create]. [Message]s can be created during Parsing or * post-processing. Post-processing messages are created by any of the validators, for example * [org.kson.validation.IndentValidator] or [org.kson.schema.JsonSchemaValidator]. - * + * * Core parse messages (created during lexing/parsing) are wrapped in [CoreParseMessage] when they pass through * [org.kson.parser.KsonMarker.error]. All other messages from validators and post-processors remain unwrapped. */ @@ -729,6 +729,56 @@ enum class MessageType( val keyName = parsedArgs.getArg("Key name") return "Duplicate key \"$keyName\" in object" } + }, + JSON_POINTER_BAD_START { + override fun expectedArgs(): List { + return listOf("Bad Start Character") + } + + override fun doFormat(parsedArgs: ParsedErrorArgs): String { + val badStartChar = parsedArgs.getArg("Bad Start Character") + return "JSON Pointer must start with '/' but found '$badStartChar' at position 0" + } + }, + JSON_POINTER_INVALID_CHARACTER { + override fun expectedArgs(): List { + return listOf("Invalid Character") + } + + override fun doFormat(parsedArgs: ParsedErrorArgs): String { + val invalidChar = parsedArgs.getArg("Invalid Character") + return "Invalid character in reference token: '$invalidChar'" + } + }, + JSON_POINTER_INVALID_ESCAPE { + override fun expectedArgs(): List { + return listOf("Invalid Escape Character") + } + + override fun doFormat(parsedArgs: ParsedErrorArgs): String { + val invalidEscapeChar = parsedArgs.getArg("Invalid Escape Character") + return "Invalid escape sequence: '~$invalidEscapeChar'. " + + "Valid escape sequences are '~0' for '~' and '~1' for '/'" + } + }, + JSON_POINTER_INCOMPLETE_ESCAPE { + override fun expectedArgs(): List { + return emptyList() + } + + override fun doFormat(parsedArgs: ParsedErrorArgs): String { + return "Incomplete escape sequence '~' at end of token. Must be '~0' or '~1'. " + } + }, + SCHEMA_REF_RESOLUTION_FAILED { + override fun expectedArgs(): List { + return listOf("Reference") + } + + override fun doFormat(parsedArgs: ParsedErrorArgs): String { + val reference = parsedArgs.getArg("Reference") + return "Failed to resolve schema reference: $reference" + } }; /** diff --git a/src/commonMain/kotlin/org/kson/schema/JsonPointerParser.kt b/src/commonMain/kotlin/org/kson/schema/JsonPointerParser.kt new file mode 100644 index 00000000..726f3cad --- /dev/null +++ b/src/commonMain/kotlin/org/kson/schema/JsonPointerParser.kt @@ -0,0 +1,236 @@ +package org.kson.schema + +import org.kson.parser.messages.Message +import org.kson.parser.messages.MessageType.* +import org.kson.stdlibx.exceptions.ShouldNotHappenException + +/** + * Parser for JSON Pointers according to RFC 6901. + * + * JSON Pointers provide a string syntax for identifying specific values within a JSON document. + * A JSON Pointer is a Unicode string containing zero or more reference tokens, each prefixed by '/'. + * + * The grammar from RFC 6901 Section 3: + * ``` + * json-pointer -> *( "/" reference-token ) + * reference-token -> *( unescaped | escaped ) + * unescaped -> %x00-2E | %x30-7D | %x7F-10FFFF + * ; %x2F ('/') and %x7E ('~') are excluded from 'unescaped' + * escaped -> "~" ( "0" | "1" ) + * ; representing '~' and '/', respectively + * ``` + * + * Examples: + * - "" - references the entire document + * - "/foo" - references the "foo" member of the root object + * - "/foo/0" - references the first element of the array at "foo" + * - "/a~1b" - references a member with name "a/b" (escaped slash) + * - "/m~0n" - references a member with name "m~n" (escaped tilde) + * + * @param pointerString The JSON Pointer string to parse + */ +class JsonPointerParser(private val pointerString: String) { + private val scanner: Scanner = Scanner(pointerString) + private var error: Message? = null + private val tokens = mutableListOf() + + companion object { + // Character constants from RFC 6901 + private const val PATH_SEPARATOR = '/' + private const val ESCAPE_CHAR = '~' + private const val TILDE_ESCAPE = '0' // ~0 represents '~' + private const val SLASH_ESCAPE = '1' // ~1 represents '/' + } + + /** + * Result of parsing a JSON Pointer + */ + sealed class ParseResult { + /** + * Successfully parsed JSON Pointer + * @property tokens List of reference tokens after unescaping + */ + data class Success(val tokens: List) : ParseResult() + + /** + * Failed to parse JSON Pointer + * @property message Description of the parsing error + */ + data class Error(val message: Message) : ParseResult() + } + + /** + * Parse the JSON Pointer string + * @return ParseResult.Success with tokens if valid, ParseResult.Error with message if invalid + */ + fun parse(): ParseResult { + // Parse according to grammar: json-pointer = *( "/" reference-token ) + if (!jsonPointer()) { + return ParseResult.Error( + error + ?: throw RuntimeException("must always set `errorMessage` for a failed parse") + ) + } + + // Check for unexpected trailing content + if (!scanner.eof()) { + val char = scanner.peek() + // If we haven't consumed anything and found a non-slash character, it's an invalid start + if (tokens.isEmpty() && char != PATH_SEPARATOR) { + return ParseResult.Error(JSON_POINTER_BAD_START.create(char.toString())) + } + + throw ShouldNotHappenException( + "All unicode characters after the initial slash are allowed an consumed by the parser" + ) + } + + return ParseResult.Success(tokens.toList()) + } + + /** + * json-pointer = *( "/" reference-token ) + */ + private fun jsonPointer(): Boolean { + // Zero or more occurrences of "/" followed by reference-token + while (scanner.peek() == PATH_SEPARATOR) { + scanner.advance() // consume '/' + + if (!referenceToken()) { + return false + } + } + + return true + } + + /** + * reference-token = *( unescaped / escaped ) + * + * Collects characters for a single reference token and adds the unescaped version to tokens list. + * A reference token consists of any combination of unescaped characters and escape sequences. + * Empty tokens are valid (e.g., "//" contains two empty tokens). + * + * @return true if token was successfully parsed, false if an error occurred + */ + private fun referenceToken(): Boolean { + val tokenBuilder = StringBuilder() + + // Collect all characters until next '/' or EOF + while (!scanner.eof() && scanner.peek() != PATH_SEPARATOR) { + val char = scanner.peek()!! + + if (char == ESCAPE_CHAR) { + // Handle escaped sequence + val escapedChar = escaped() ?: return false + tokenBuilder.append(escapedChar) + } else if (isUnescaped(char)) { + tokenBuilder.append(char) + scanner.advance() + } else { + error = JSON_POINTER_INVALID_CHARACTER.create(char.toString()) + return false + } + } + + tokens.add(tokenBuilder.toString()) + return true + } + + /** + * unescaped = %x00-2E / %x30-7D / %x7F-10FFFF + * ; %x2F ('/') and %x7E ('~') are excluded from 'unescaped' + * + * Checks if a character is allowed as an unescaped character in a reference token. + * The two special characters that must be escaped are: + * - '/' (PATH_SEPARATOR) because it delimits tokens + * - '~' (ESCAPE_CHAR) because it starts escape sequences + * See [escaped] + * + * @param char The character to check + * @return true if the character can appear unescaped, false otherwise + */ + private fun isUnescaped(char: Char): Boolean { + // All characters are valid except '/' (0x2F) and '~' (0x7E) + val code = char.code + return code != 0x2F && code != 0x7E + } + + /** + * escaped = "~" ( "0" / "1" ) + * ; representing '~' and '/', respectively + * + * Processes an escape sequence starting with '~'. + * Valid escape sequences are: + * - "~0" which represents a literal '~' + * - "~1" which represents a literal '/' + * + * Any other character following '~' is an error according to RFC 6901. + * + * @return The unescaped character if valid, null if invalid escape sequence + */ + private fun escaped(): Char? { + if (scanner.peek() != ESCAPE_CHAR) { + return null + } + + // consume '~' + scanner.advance() + + if (scanner.eof()) { + error = JSON_POINTER_INCOMPLETE_ESCAPE.create() + return null + } + + return when (val nextChar = scanner.peek()) { + TILDE_ESCAPE -> { + scanner.advance() + ESCAPE_CHAR // ~0 represents '~' + } + + SLASH_ESCAPE -> { + scanner.advance() + PATH_SEPARATOR // ~1 represents '/' + } + + else -> { + error = JSON_POINTER_INVALID_ESCAPE.create(nextChar.toString()) + null + } + } + } + + /** + * Scanner for character-by-character processing of the pointer string + */ + private class Scanner(private val source: String) { + var currentIndex = 0 + private set + + /** + * Get the current character without advancing + * @return Current character or null if at end + */ + fun peek(): Char? { + return if (eof()) null else source[currentIndex] + } + + /** + * Advance to the next character + */ + fun advance() { + if (!eof()) { + currentIndex++ + } + } + + /** + * Check if at end of string. + * + * @return true if no more characters to read, false otherwise + */ + fun eof(): Boolean { + return currentIndex >= source.length + } + } +} diff --git a/src/commonMain/kotlin/org/kson/schema/SchemaIdLookup.kt b/src/commonMain/kotlin/org/kson/schema/SchemaIdLookup.kt new file mode 100644 index 00000000..34406d47 --- /dev/null +++ b/src/commonMain/kotlin/org/kson/schema/SchemaIdLookup.kt @@ -0,0 +1,542 @@ +package org.kson.schema + +import org.kson.* + +/** + * Manages the mapping of `$id` values to their corresponding schema nodes for `$ref` resolution. + * + * @param schemaRootValue the [KsonValue] root of the schema to build this [SchemaIdLookup] from + */ +class SchemaIdLookup(schemaRootValue: KsonValue) { + + private val idMap: Map + + init { + /** + * Collect all `$id` entries from the given schema tree. + * This pre-processes the entire schema to build a map of fully-qualified IDs. + */ + idMap = mutableMapOf() + + // preload know meta-schemas + idMap[Draft7MetaSchema.ID] = Draft7MetaSchema.schemaValue + + if (schemaRootValue is KsonObject) { + val rootBaseUri = schemaRootValue.propertyLookup["\$id"]?.let { idValue -> + if (idValue is KsonString) { + idValue.value + } else { + // this $id is completely invalid + null + } + } ?: "" + + // Store the root schema at is baseUri + idMap[rootBaseUri] = schemaRootValue + + // Walk the schema tree to collect all IDs with fully-qualified URIs + walkSchemaForIds(schemaRootValue, idMap, rootBaseUri) + } + } + + /** + * Resolves a `$ref` reference string to the corresponding schema value. + * + * @param ref The reference string (e.g., "#foo", "#/definitions/address", "bar") + * @param currentBaseUri The current base URI context for resolving relative references + * @return The resolved [KsonValue] representing the referenced schema, or null if not found + */ + fun resolveRef(ref: String, currentBaseUri: String): ResolvedRef? { + val resolvedRefUri = resolveUri(ref, currentBaseUri) + + // try a direct lookup of our resolved ref URI + idMap[resolvedRefUri.toString()]?.let { + return ResolvedRef(it, currentBaseUri) + } + + // otherwise, see if we can interpret the fragment + return if (resolvedRefUri.fragment.startsWith("#/")) { + val decodedPointer = decodeUriEncoding(resolvedRefUri.fragment.substring(1)) + if (resolvedRefUri.origin.isNotBlank()) { + idMap[resolvedRefUri.toString().substringBefore("#")]?.let { resolveJsonPointer(decodedPointer, it, resolvedRefUri.toString()) } + } else { + idMap[currentBaseUri]?.let { resolveJsonPointer(decodedPointer, it, currentBaseUri) } + } + } else { + idMap[resolvedRefUri.toString().substringBefore("#") + resolvedRefUri.fragment.removePrefix("#")] + ?.let { ResolvedRef(it, currentBaseUri) } + } + } + + companion object { + /** + * Recursively walks a schema value to collect all `$id` entries with fully-qualified URIs. + * + * @param schemaValue The current schema node to examine + * @param idMap The map to collect fully-qualified $id entries into + * @param currentBaseUri The current base URI context for resolving relative URIs + */ + private fun walkSchemaForIds( + schemaValue: KsonValue, + idMap: MutableMap, + currentBaseUri: String + ) { + when (schemaValue) { + is KsonObject -> { + var contextBaseUri = currentBaseUri + + // Check for $id in this object + schemaValue.propertyLookup["\$id"]?.let { idValue -> + if (idValue is KsonString) { + val idString = idValue.value + + // Resolve the ID to its fully-qualified form + val fullyQualifiedId = resolveUri(idString, currentBaseUri) + contextBaseUri = fullyQualifiedId.toString() + idMap[contextBaseUri] = schemaValue + } + } + + // Recursively walk all property values with the updated context + schemaValue.propertyMap.values.forEach { propertyValue -> + walkSchemaForIds(propertyValue, idMap, contextBaseUri) + } + } + + is KsonList -> { + // Recursively walk all list elements + schemaValue.elements.forEach { element -> + walkSchemaForIds(element, idMap, currentBaseUri) + } + } + + else -> { + /** no-op, only [KsonObject] and [KsonValue] have children */ + } + } + } + + data class RefUriParts ( + val origin: String, + val path: String, + val fragment: String) { + override fun toString(): String { + return "$origin$path$fragment" + } + } + + /** + * Parse the given string into [RefUriParts]. This is a simplified version of that parsing specified in + * [RFC 3986 Section 3](https://datatracker.ietf.org/doc/html/rfc3986#section-3) targeted towards our + * $ref parsing use case. + * TODO we likely want to consider implementing a more formal parser implementation based on that specification + */ + private fun parseUri(uri: String): RefUriParts { + val origin = if (uri.contains("://")) { + val scheme = uri.substringBefore("://") + val authority = uri.substringAfter("://") + .substringBefore('/') + .substringBefore('#') + "$scheme://$authority" + } else if (uri.substringBefore("/").contains(":")){ + uri.substringBefore("#") + } else { + "" + } + + val afterOrigin = uri.substringAfter(origin) + val path = if (origin.isBlank()) { + afterOrigin.substringBeforeLast('#') + } else if (afterOrigin.isNotBlank() && !afterOrigin.startsWith("#")) { + "/" + afterOrigin.removePrefix("/").substringBefore('#') + } else { + "" + } + + val fragment = if (uri.contains('#')) { + "#" + uri.substringAfter('#') + } else { + "" + } + + return RefUriParts(origin, path, fragment) + } + + /** + * Resolve [uri] in the context of [baseUri]. + * + * This works analogously to how url updates in a web browsers: if you are "on" [baseUri] and "click" on + * and link with href="[uri]", you will be sent to the uri defined by the returned [RefUriParts] + * + * NOTE: this attempts to implement the rules specified in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-5) + * but is a little ad-hoc compared to what is there. If/when bugs creep up with their root cause in this + * method, let's more carefully port the behavior specified there + */ + fun resolveUri(uri: String, baseUri: String): RefUriParts { + val uriParts = parseUri(uri) + val baseUriParts = parseUri(baseUri) + val origin = uriParts.origin.ifBlank { baseUriParts.origin } + val path = if (uriParts.path.startsWith('/')) { + uriParts.path + } else if (uriParts.path.isNotBlank()) { + baseUriParts.path.substringBeforeLast("/") + "/" + uriParts.path.removePrefix("/") + } + else { + baseUriParts.path + } + return RefUriParts(origin, path, uriParts.fragment) + } + } +} + +/** + * Decodes percent-encoded characters in a URI. According to RFC 6901, percent-encoding must be decoded + * before JSON Pointer processing. + * + * @param encoded The percent-encoded string + * @return The decoded string + */ +private fun decodeUriEncoding(encoded: String): String { + if (!encoded.contains('%')) { + return encoded + } + + val result = StringBuilder() + var i = 0 + while (i < encoded.length) { + val char = encoded[i] + if (char == '%' && i + 2 < encoded.length) { + // Try to decode the next two characters as hex + val hex = encoded.substring(i + 1, i + 3) + val decoded = try { + hex.toInt(16).toChar() + } catch (e: NumberFormatException) { + // Invalid hex sequence, keep the % and continue + result.append(char) + i++ + continue + } + result.append(decoded) + i += 3 + } else { + result.append(char) + i++ + } + } + return result.toString() +} + +/** + * Resolves a JSON Pointer path within a [KsonValue] structure. + * + * @param pointer The JSON Pointer string (e.g., "/definitions/address") + * @param ksonValue The [KsonValue] to traverse + * @return The [KsonValue] at the pointer location, or null if not found + */ +private fun resolveJsonPointer(pointer: String, ksonValue: KsonValue, currentBaseUri: String): ResolvedRef? { + return when (val parseResult = JsonPointerParser(pointer).parse()) { + is JsonPointerParser.ParseResult.Success -> { + navigatePointer(ksonValue, parseResult.tokens, currentBaseUri) + } + + is JsonPointerParser.ParseResult.Error -> { + // Invalid JSON Pointer + null + } + } +} + +data class ResolvedRef(val resolvedValue: KsonValue, val resolvedValueBaseUri: String) + +/** + * Navigates through a [KsonValue] structure using JSON Pointer tokens. + * + * @param current The current [KsonValue] node + * @param tokens The list of reference tokens to follow + * @return The [KsonValue] at the final location, or null if path not found + */ +private fun navigatePointer(current: KsonValue, tokens: List, currentBaseUri: String): ResolvedRef? { + if (tokens.isEmpty()) { + return ResolvedRef(current, currentBaseUri) + } + + var node: KsonValue? = current + var updatedBaseUri = currentBaseUri + + for (token in tokens) { + node = when (node) { + is KsonObject -> { + node.propertyLookup["\$id"]?.let { idValue -> + if (idValue is KsonString) { + val idString = idValue.value + // Resolve the ID relative to the current base URI and update it + val fullyQualifiedId = SchemaIdLookup.resolveUri(idString, updatedBaseUri) + updatedBaseUri = fullyQualifiedId.toString() + } + } + + // Navigate into object property + node.propertyLookup[token] + } + + is KsonList -> { + // Navigate into array element + val index = token.toIntOrNull() + if (index != null && index >= 0 && index < node.elements.size) { + node.elements[index] + } else { + null + } + } + + else -> { + // Cannot navigate further + null + } + } + + if (node == null) { + break + } + } + + return node?.let { ResolvedRef(it, updatedBaseUri) } +} + +/** + * Built-in Draft-07 meta-schema + */ +data object Draft7MetaSchema { + const val ID = "http://json-schema.org/draft-07/schema" + val schemaValue = KsonCore.parseToAst(""" + '${'$'}schema': 'http://json-schema.org/draft-07/schema#' + '${'$'}id': 'http://json-schema.org/draft-07/schema#' + title: 'Core schema meta-schema' + definitions: + schemaArray: + type: array + minItems: 1 + items: + '${'$'}ref': '#' + . + . + nonNegativeInteger: + type: integer + minimum: 0 + . + nonNegativeIntegerDefault0: + allOf: + - '${'$'}ref': '#/definitions/nonNegativeInteger' + - default: 0 + . + . + simpleTypes: + enum: + - array + - boolean + - integer + - 'null' + - number + - object + - string + . + stringArray: + type: array + items: + type: string + . + uniqueItems: true + default: + <> + . + . + type: + - object + - boolean + properties: + '${'$'}id': + type: string + format: 'uri-reference' + . + '${'$'}schema': + type: string + format: uri + . + '${'$'}ref': + type: string + format: 'uri-reference' + . + '${'$'}comment': + type: string + . + title: + type: string + . + description: + type: string + . + default: true + readOnly: + type: boolean + default: false + . + writeOnly: + type: boolean + default: false + . + examples: + type: array + items: true + . + multipleOf: + type: number + exclusiveMinimum: 0 + . + maximum: + type: number + . + exclusiveMaximum: + type: number + . + minimum: + type: number + . + exclusiveMinimum: + type: number + . + maxLength: + '${'$'}ref': '#/definitions/nonNegativeInteger' + . + minLength: + '${'$'}ref': '#/definitions/nonNegativeIntegerDefault0' + . + pattern: + type: string + format: regex + . + additionalItems: + '${'$'}ref': '#' + . + items: + anyOf: + - '${'$'}ref': '#' + - '${'$'}ref': '#/definitions/schemaArray' + . + default: true + . + maxItems: + '${'$'}ref': '#/definitions/nonNegativeInteger' + . + minItems: + '${'$'}ref': '#/definitions/nonNegativeIntegerDefault0' + . + uniqueItems: + type: boolean + default: false + . + contains: + '${'$'}ref': '#' + . + maxProperties: + '${'$'}ref': '#/definitions/nonNegativeInteger' + . + minProperties: + '${'$'}ref': '#/definitions/nonNegativeIntegerDefault0' + . + required: + '${'$'}ref': '#/definitions/stringArray' + . + additionalProperties: + '${'$'}ref': '#' + . + definitions: + type: object + additionalProperties: + '${'$'}ref': '#' + . + default: + {} + . + properties: + type: object + additionalProperties: + '${'$'}ref': '#' + . + default: + {} + . + patternProperties: + type: object + additionalProperties: + '${'$'}ref': '#' + . + propertyNames: + format: regex + . + default: + {} + . + dependencies: + type: object + additionalProperties: + anyOf: + - '${'$'}ref': '#' + - '${'$'}ref': '#/definitions/stringArray' + . + . + . + propertyNames: + '${'$'}ref': '#' + . + const: true + enum: + type: array + items: true + minItems: 1 + uniqueItems: true + . + type: + anyOf: + - '${'$'}ref': '#/definitions/simpleTypes' + - type: array + items: + '${'$'}ref': '#/definitions/simpleTypes' + . + minItems: 1 + uniqueItems: true + . + . + format: + type: string + . + contentMediaType: + type: string + . + contentEncoding: + type: string + . + if: + '${'$'}ref': '#' + . + then: + '${'$'}ref': '#' + . + else: + '${'$'}ref': '#' + . + allOf: + '${'$'}ref': '#/definitions/schemaArray' + . + anyOf: + '${'$'}ref': '#/definitions/schemaArray' + . + oneOf: + '${'$'}ref': '#/definitions/schemaArray' + . + not: + '${'$'}ref': '#' + . + . + default: true + """).ksonValue!! +} diff --git a/src/commonMain/kotlin/org/kson/schema/SchemaParser.kt b/src/commonMain/kotlin/org/kson/schema/SchemaParser.kt index 6a514756..03d076f8 100644 --- a/src/commonMain/kotlin/org/kson/schema/SchemaParser.kt +++ b/src/commonMain/kotlin/org/kson/schema/SchemaParser.kt @@ -4,360 +4,476 @@ import org.kson.* import org.kson.parser.* import org.kson.parser.messages.MessageType.* import org.kson.schema.validators.* +import org.kson.schema.SchemaIdLookup.Companion.resolveUri /** * Parses a JSON Schema string into our JsonSchema model. */ object SchemaParser { - fun parseSchemaElement(schemaValue: KsonValue, messageSink: MessageSink): JsonSchema? { - return when (schemaValue) { - is KsonBoolean -> JsonBooleanSchema(schemaValue.value) - is KsonObject -> parseObjectSchema(schemaValue, messageSink) - else -> { - messageSink.error(schemaValue.location, SCHEMA_OBJECT_OR_BOOLEAN.create()) - null - } - } - } - - private fun parseObjectSchema(schemaObject: KsonObject, messageSink: MessageSink): JsonSchema { - val schemaProperties = schemaObject.propertyLookup - - val title = schemaProperties["title"] ?.let { title -> - if (title is KsonString) { - title.value - } else { - messageSink.error(title.location, SCHEMA_STRING_REQUIRED.create("title")) - null - } - } - val description = schemaProperties["description"] ?.let { description -> - if (description is KsonString) { - description.value - } else { - messageSink.error(description.location, SCHEMA_STRING_REQUIRED.create("description")) - null - } - } - val default = schemaProperties["default"] - val definitions = schemaProperties["definitions"] ?.let { definitions -> - if (definitions is KsonObject) { - definitions.propertyMap.mapValues { (_, value) -> - parseSchemaElement(value, messageSink) - } - } else { - messageSink.error(definitions.location, SCHEMA_OBJECT_REQUIRED.create("definitions")) - null - } + /** + * Parse [schemaRootValue] as a JSON Schema root, i.e. a complete JSON Schema, not a sub-schema. + * See [parseSchemaElement] for sub-schema parsing. + */ + fun parseSchemaRoot(schemaRootValue: KsonValue, messageSink: MessageSink): JsonSchema? { + // Determine the initial base URI from the root schema's $id if present + val initialBaseUri = if (schemaRootValue is KsonObject) { + extractId(schemaRootValue, messageSink) ?: "" + } else { + "" + } + + val idLookup = SchemaIdLookup(schemaRootValue) + return parseSchemaElement(schemaRootValue, messageSink, initialBaseUri, idLookup) + } + + /** + * Parse [schemaValue] as a JSON sub-schema. See [parseSchemaRoot] for full schema parsing. + * + * @param schemaValue The schema value to parse + * @param messageSink The message sink for errors + * @param currentBaseUri The current base URI context for resolving references + * @param idLookup The lookup for resolving $id and $ref references + */ + fun parseSchemaElement( + schemaValue: KsonValue, + messageSink: MessageSink, + currentBaseUri: String, + idLookup: SchemaIdLookup + ): JsonSchema? { + return when (schemaValue) { + is KsonBoolean -> JsonBooleanSchema(schemaValue.value) + is KsonObject -> parseObjectSchema(schemaValue, messageSink, currentBaseUri, idLookup) + else -> { + messageSink.error(schemaValue.location, SCHEMA_OBJECT_OR_BOOLEAN.create()) + null + } + } } - val typeValidator = schemaProperties["type"] ?.let { typeValue -> - when (typeValue) { - is KsonString -> TypeValidator(typeValue.value) - is KsonList -> { - val typeArrayEntries = ArrayList() - for (element in typeValue.elements) { - if (element is KsonString) { - typeArrayEntries.add(element.value) + private fun parseObjectSchema( + schemaObject: KsonObject, + messageSink: MessageSink, + currentBaseUri: String, + idLookup: SchemaIdLookup + ): JsonSchema? { + val schemaProperties = schemaObject.propertyLookup + + schemaProperties["\$ref"]?.let { refString -> + if (refString is KsonString) { + val resolvedValue = idLookup.resolveRef(refString.value, currentBaseUri) + + if (resolvedValue == null) { + // Reference path could not be found + messageSink.error(refString.location, SCHEMA_REF_RESOLUTION_FAILED.create(refString.value)) + return null + } + + val refValidator = RefValidator(resolvedValue, idLookup) + + return JsonObjectSchema(null, null, null, null, null, listOf(refValidator)) } else { - messageSink.error(element.location, SCHEMA_TYPE_ARRAY_ENTRY_ERROR.create()) + messageSink.error(refString.location, SCHEMA_STRING_REQUIRED.create("\$ref")) } - } - TypeValidator(typeArrayEntries) } - else -> { - messageSink.error(typeValue.location, SCHEMA_TYPE_TYPE_ERROR.create()) - null + + // Check if this schema defines a new $id and update base URI accordingly + val idString = extractId(schemaObject, messageSink) + val updatedBaseUri = if (idString != null) { + resolveUri(idString, currentBaseUri).toString() + } else { + currentBaseUri } - } - } - // Collect all declared validators in this schema - val validators = mutableListOf() - schemaProperties["minimum"] ?.let { minimum -> - if (minimum is KsonNumber) { - validators.add(MinimumValidator(minimum.value.asDouble)) - } else { - messageSink.error(minimum.location, SCHEMA_NUMBER_REQUIRED.create("minimum")) - } - } - schemaProperties["maximum"] ?.let { maximum -> - if (maximum is KsonNumber) { - validators.add(MaximumValidator(maximum.value.asDouble)) - } else { - messageSink.error(maximum.location, SCHEMA_NUMBER_REQUIRED.create("maximum")) - } - } + val title = schemaProperties["title"]?.let { title -> + if (title is KsonString) { + title.value + } else { + messageSink.error(title.location, SCHEMA_STRING_REQUIRED.create("title")) + null + } + } + val description = schemaProperties["description"]?.let { description -> + if (description is KsonString) { + description.value + } else { + messageSink.error(description.location, SCHEMA_STRING_REQUIRED.create("description")) + null + } + } - schemaProperties["multipleOf"] ?.let { multipleOf -> - if (multipleOf is KsonNumber) { - validators.add(MultipleOfValidator(multipleOf.value.asDouble)) - } else { - messageSink.error(multipleOf.location, SCHEMA_NUMBER_REQUIRED.create("multipleOf")) - } - } + val default = schemaProperties["default"] + val definitions = schemaProperties["definitions"]?.let { definitions -> + if (definitions is KsonObject) { + definitions.propertyMap.mapValues { (_, value) -> + parseSchemaElement(value, messageSink, updatedBaseUri, idLookup) + } + } else { + messageSink.error(definitions.location, SCHEMA_OBJECT_REQUIRED.create("definitions")) + null + } + } - schemaProperties["exclusiveMinimum"] ?.let { exclusiveMinimum -> - if (exclusiveMinimum is KsonNumber) { - validators.add(ExclusiveMinimumValidator(exclusiveMinimum.value.asDouble)) - } else { - messageSink.error(exclusiveMinimum.location, SCHEMA_NUMBER_REQUIRED.create("exclusiveMinimum")) - } - } + val typeValidator = schemaProperties["type"]?.let { typeValue -> + when (typeValue) { + is KsonString -> TypeValidator(typeValue.value) + is KsonList -> { + val typeArrayEntries = ArrayList() + for (element in typeValue.elements) { + if (element is KsonString) { + typeArrayEntries.add(element.value) + } else { + messageSink.error(element.location, SCHEMA_TYPE_ARRAY_ENTRY_ERROR.create()) + } + } + TypeValidator(typeArrayEntries) + } + + else -> { + messageSink.error(typeValue.location, SCHEMA_TYPE_TYPE_ERROR.create()) + null + } + } + } - schemaProperties["exclusiveMaximum"] ?.let { exclusiveMaximum -> - if (exclusiveMaximum is KsonNumber) { - validators.add(ExclusiveMaximumValidator(exclusiveMaximum.value.asDouble)) - } else { - messageSink.error(exclusiveMaximum.location, SCHEMA_NUMBER_REQUIRED.create("exclusiveMaximum")) - } - } + // Collect all declared validators in this schema + val validators = mutableListOf() + schemaProperties["minimum"]?.let { minimum -> + if (minimum is KsonNumber) { + validators.add(MinimumValidator(minimum.value.asDouble)) + } else { + messageSink.error(minimum.location, SCHEMA_NUMBER_REQUIRED.create("minimum")) + } + } + schemaProperties["maximum"]?.let { maximum -> + if (maximum is KsonNumber) { + validators.add(MaximumValidator(maximum.value.asDouble)) + } else { + messageSink.error(maximum.location, SCHEMA_NUMBER_REQUIRED.create("maximum")) + } + } - schemaProperties["minLength"] ?.let { minLength -> - if (minLength is KsonNumber) { - asSchemaInteger(minLength) ?.let { minLengthLong -> - validators.add(MinLengthValidator(minLengthLong)) + schemaProperties["multipleOf"]?.let { multipleOf -> + if (multipleOf is KsonNumber) { + validators.add(MultipleOfValidator(multipleOf.value.asDouble)) + } else { + messageSink.error(multipleOf.location, SCHEMA_NUMBER_REQUIRED.create("multipleOf")) + } } - } else { - messageSink.error(minLength.location, SCHEMA_INTEGER_REQUIRED.create("minLength")) - } - } - schemaProperties["maxLength"] ?.let { maxLength -> - if (maxLength is KsonNumber) { - asSchemaInteger(maxLength) ?.let { maxLengthLong -> - validators.add(MaxLengthValidator(maxLengthLong)) + schemaProperties["exclusiveMinimum"]?.let { exclusiveMinimum -> + if (exclusiveMinimum is KsonNumber) { + validators.add(ExclusiveMinimumValidator(exclusiveMinimum.value.asDouble)) + } else { + messageSink.error(exclusiveMinimum.location, SCHEMA_NUMBER_REQUIRED.create("exclusiveMinimum")) + } } - } else { - messageSink.error(maxLength.location, SCHEMA_INTEGER_REQUIRED.create("maxLength")) - } - } - schemaProperties["pattern"] ?.let { pattern -> - if (pattern is KsonString) { - validators.add(PatternValidator(pattern.value)) - } else { - messageSink.error(pattern.location, SCHEMA_STRING_REQUIRED.create("pattern")) - } - } + schemaProperties["exclusiveMaximum"]?.let { exclusiveMaximum -> + if (exclusiveMaximum is KsonNumber) { + validators.add(ExclusiveMaximumValidator(exclusiveMaximum.value.asDouble)) + } else { + messageSink.error(exclusiveMaximum.location, SCHEMA_NUMBER_REQUIRED.create("exclusiveMaximum")) + } + } - schemaProperties["enum"] ?.let { enum -> - if (enum is KsonList) { - validators.add(EnumValidator(enum)) - } else { - messageSink.error(enum.location, SCHEMA_ARRAY_REQUIRED.create("enum")) - } - } + schemaProperties["minLength"]?.let { minLength -> + if (minLength is KsonNumber) { + asSchemaInteger(minLength)?.let { minLengthLong -> + validators.add(MinLengthValidator(minLengthLong)) + } + } else { + messageSink.error(minLength.location, SCHEMA_INTEGER_REQUIRED.create("minLength")) + } + } - schemaProperties["items"]?.let { itemsValue -> - val additionalItemsValidator = schemaProperties["additionalItems"]?.let { additionalItems -> - when (additionalItems) { - is KsonBoolean -> AdditionalItemsBooleanValidator(additionalItems.value) - else -> AdditionalItemsSchemaValidator(parseSchemaElement(additionalItems, messageSink)) - } - } - - when (itemsValue) { - is KsonList -> { - val leadingItemsValidator = LeadingItemsTupleValidator(itemsValue.elements.mapNotNull { - parseSchemaElement(it, messageSink) - }) - validators.add(ItemsValidator(leadingItemsValidator, additionalItemsValidator)) - } - else -> { - val itemsSchema = parseSchemaElement(itemsValue, messageSink) - if (itemsSchema != null) { - val leadingItemsValidator = LeadingItemsSchemaValidator(itemsSchema) - validators.add(ItemsValidator(leadingItemsValidator, additionalItemsValidator)) - } else { - // no-op todo this shouldn't be necessary - bug in Intellij inspections? - } - } - } - } + schemaProperties["maxLength"]?.let { maxLength -> + if (maxLength is KsonNumber) { + asSchemaInteger(maxLength)?.let { maxLengthLong -> + validators.add(MaxLengthValidator(maxLengthLong)) + } + } else { + messageSink.error(maxLength.location, SCHEMA_INTEGER_REQUIRED.create("maxLength")) + } + } - schemaProperties["contains"]?.let { contains -> - parseSchemaElement(contains, messageSink) ?.let { - validators.add(ContainsValidator(it)) - } - } + schemaProperties["pattern"]?.let { pattern -> + if (pattern is KsonString) { + validators.add(PatternValidator(pattern.value)) + } else { + messageSink.error(pattern.location, SCHEMA_STRING_REQUIRED.create("pattern")) + } + } - schemaProperties["minItems"] ?.let { minItems -> - if (minItems is KsonNumber) { - asSchemaInteger(minItems) ?.let { minItemsLong -> - validators.add(MinItemsValidator(minItemsLong)) + schemaProperties["enum"]?.let { enum -> + if (enum is KsonList) { + validators.add(EnumValidator(enum)) + } else { + messageSink.error(enum.location, SCHEMA_ARRAY_REQUIRED.create("enum")) + } } - } else { - messageSink.error(minItems.location, SCHEMA_INTEGER_REQUIRED.create("minItems")) - } - } - schemaProperties["maxItems"] ?.let { maxItems -> - if (maxItems is KsonNumber) { - asSchemaInteger(maxItems) ?.let { maxItemsLong -> - validators.add(MaxItemsValidator(maxItemsLong)) + schemaProperties["items"]?.let { itemsValue -> + val additionalItemsValidator = schemaProperties["additionalItems"]?.let { additionalItems -> + when (additionalItems) { + is KsonBoolean -> AdditionalItemsBooleanValidator(additionalItems.value) + else -> AdditionalItemsSchemaValidator( + parseSchemaElement( + additionalItems, + messageSink, + updatedBaseUri, + idLookup + ) + ) + } + } + + when (itemsValue) { + is KsonList -> { + val leadingItemsValidator = LeadingItemsTupleValidator(itemsValue.elements.mapNotNull { + parseSchemaElement(it, messageSink, updatedBaseUri, idLookup) + }) + validators.add(ItemsValidator(leadingItemsValidator, additionalItemsValidator)) + } + + else -> { + val itemsSchema = parseSchemaElement(itemsValue, messageSink, updatedBaseUri, idLookup) + if (itemsSchema != null) { + val leadingItemsValidator = LeadingItemsSchemaValidator(itemsSchema) + validators.add(ItemsValidator(leadingItemsValidator, additionalItemsValidator)) + } else { + // no-op todo this shouldn't be necessary - bug in Intellij inspections? + } + } + } } - } else { - messageSink.error(maxItems.location, SCHEMA_INTEGER_REQUIRED.create("maxItems")) - } - } - schemaProperties["uniqueItems"] ?.let { uniqueItems -> - if (uniqueItems is KsonBoolean) { - validators.add(UniqueItemsValidator(uniqueItems.value)) - } else { - messageSink.error(uniqueItems.location, SCHEMA_BOOLEAN_REQUIRED.create("uniqueItems")) - } - } + schemaProperties["contains"]?.let { contains -> + parseSchemaElement(contains, messageSink, updatedBaseUri, idLookup)?.let { + validators.add(ContainsValidator(it)) + } + } - val propertySchemas = schemaProperties["properties"] ?.let { properties -> - if (properties is KsonObject) { - properties.propertyMap.mapValues { - parseSchemaElement(it.value, messageSink) + schemaProperties["minItems"]?.let { minItems -> + if (minItems is KsonNumber) { + asSchemaInteger(minItems)?.let { minItemsLong -> + validators.add(MinItemsValidator(minItemsLong)) + } + } else { + messageSink.error(minItems.location, SCHEMA_INTEGER_REQUIRED.create("minItems")) + } } - } else { - messageSink.error(properties.location, SCHEMA_OBJECT_REQUIRED.create("properties")) - null - } - } - val patternPropertySchemas = schemaProperties["patternProperties"] ?.let { patternProperties -> - if (patternProperties is KsonObject) { - patternProperties.propertyMap.mapValues { - parseSchemaElement(it.value, messageSink) ?: return@mapValues null + schemaProperties["maxItems"]?.let { maxItems -> + if (maxItems is KsonNumber) { + asSchemaInteger(maxItems)?.let { maxItemsLong -> + validators.add(MaxItemsValidator(maxItemsLong)) + } + } else { + messageSink.error(maxItems.location, SCHEMA_INTEGER_REQUIRED.create("maxItems")) + } } - } else { - messageSink.error(patternProperties.location, SCHEMA_OBJECT_REQUIRED.create("patternProperties")) - null - } - } - val additionalPropertiesValidator = schemaProperties["additionalProperties"]?.let { additionalProperties -> - when (additionalProperties) { - is KsonBoolean -> AdditionalPropertiesBooleanValidator(additionalProperties.value) - else -> AdditionalPropertiesSchemaValidator(parseSchemaElement(additionalProperties, messageSink)) - } - } + schemaProperties["uniqueItems"]?.let { uniqueItems -> + if (uniqueItems is KsonBoolean) { + validators.add(UniqueItemsValidator(uniqueItems.value)) + } else { + messageSink.error(uniqueItems.location, SCHEMA_BOOLEAN_REQUIRED.create("uniqueItems")) + } + } - if (propertySchemas != null || patternPropertySchemas != null || additionalPropertiesValidator != null) { - validators.add(PropertiesValidator(propertySchemas, patternPropertySchemas, additionalPropertiesValidator)) - } + val propertySchemas = schemaProperties["properties"]?.let { properties -> + if (properties is KsonObject) { + properties.propertyMap.mapValues { + parseSchemaElement(it.value, messageSink, updatedBaseUri, idLookup) + } + } else { + messageSink.error(properties.location, SCHEMA_OBJECT_REQUIRED.create("properties")) + null + } + } - schemaProperties["required"] ?.let { required -> - if (required is KsonList) { - val requiredArrayEntries = ArrayList() - for (element in required.elements) { - if (element is KsonString) { - requiredArrayEntries.add(element) - } else { - messageSink.error(element.location, SCHEMA_STRING_ARRAY_ENTRY_ERROR.create("required")) - } - } - validators.add(RequiredValidator(requiredArrayEntries)) - } else { - messageSink.error(required.location, SCHEMA_ARRAY_REQUIRED.create("required")) - } - } + val patternPropertySchemas = schemaProperties["patternProperties"]?.let { patternProperties -> + if (patternProperties is KsonObject) { + patternProperties.propertyMap.mapValues { + parseSchemaElement(it.value, messageSink, updatedBaseUri, idLookup) ?: return@mapValues null + } + } else { + messageSink.error(patternProperties.location, SCHEMA_OBJECT_REQUIRED.create("patternProperties")) + null + } + } - schemaProperties["minProperties"] ?.let { minProperties -> - if (minProperties is KsonNumber) { - asSchemaInteger(minProperties) ?.let { minPropertiesLong -> - validators.add(MinPropertiesValidator(minPropertiesLong)) + val additionalPropertiesValidator = schemaProperties["additionalProperties"]?.let { additionalProperties -> + when (additionalProperties) { + is KsonBoolean -> AdditionalPropertiesBooleanValidator(additionalProperties.value) + else -> AdditionalPropertiesSchemaValidator( + parseSchemaElement( + additionalProperties, + messageSink, + updatedBaseUri, + idLookup + ) + ) + } } - } else { - messageSink.error(minProperties.location, SCHEMA_INTEGER_REQUIRED.create("minProperties")) - } - } - schemaProperties["maxProperties"] ?.let { maxProperties -> - if (maxProperties is KsonNumber) { - asSchemaInteger(maxProperties) ?.let { maxPropertiesLong -> - validators.add(MaxPropertiesValidator(maxPropertiesLong)) + if (propertySchemas != null || patternPropertySchemas != null || additionalPropertiesValidator != null) { + validators.add(PropertiesValidator(propertySchemas, patternPropertySchemas, additionalPropertiesValidator)) } - } else { - messageSink.error(maxProperties.location, SCHEMA_INTEGER_REQUIRED.create("maxProperties")) - } - } - schemaProperties["const"] ?.let { const -> - validators.add(ConstValidator(const)) - } + schemaProperties["required"]?.let { required -> + if (required is KsonList) { + val requiredArrayEntries = ArrayList() + for (element in required.elements) { + if (element is KsonString) { + requiredArrayEntries.add(element) + } else { + messageSink.error(element.location, SCHEMA_STRING_ARRAY_ENTRY_ERROR.create("required")) + } + } + validators.add(RequiredValidator(requiredArrayEntries)) + } else { + messageSink.error(required.location, SCHEMA_ARRAY_REQUIRED.create("required")) + } + } - schemaProperties["allOf"] ?.let { allOf -> - if (allOf is KsonList) { - val allOfArrayEntries = ArrayList() - for (element in allOf.elements) { - allOfArrayEntries.add(parseSchemaElement(element, messageSink) ?: continue) + schemaProperties["minProperties"]?.let { minProperties -> + if (minProperties is KsonNumber) { + asSchemaInteger(minProperties)?.let { minPropertiesLong -> + validators.add(MinPropertiesValidator(minPropertiesLong)) + } + } else { + messageSink.error(minProperties.location, SCHEMA_INTEGER_REQUIRED.create("minProperties")) + } } - validators.add(AllOfValidator(allOfArrayEntries)) - } else { - messageSink.error(allOf.location, SCHEMA_ARRAY_REQUIRED.create("allOf")) - } - } - schemaProperties["anyOf"] ?.let { anyOf -> - if (anyOf is KsonList) { - val anyOfArrayEntries = ArrayList() - for (element in anyOf.elements) { - anyOfArrayEntries.add(parseSchemaElement(element, messageSink) ?: continue) + schemaProperties["maxProperties"]?.let { maxProperties -> + if (maxProperties is KsonNumber) { + asSchemaInteger(maxProperties)?.let { maxPropertiesLong -> + validators.add(MaxPropertiesValidator(maxPropertiesLong)) + } + } else { + messageSink.error(maxProperties.location, SCHEMA_INTEGER_REQUIRED.create("maxProperties")) + } } - validators.add(AnyOfValidator(anyOfArrayEntries)) - } else { - messageSink.error(anyOf.location, SCHEMA_ARRAY_REQUIRED.create("anyOf")) - } - } - schemaProperties["oneOf"] ?.let { oneOf -> - if (oneOf is KsonList) { - val oneOfArrayEntries = ArrayList() - for (element in oneOf.elements) { - oneOfArrayEntries.add(parseSchemaElement(element, messageSink) ?: continue) + schemaProperties["const"]?.let { const -> + validators.add(ConstValidator(const)) } - validators.add(OneOfValidator(oneOfArrayEntries)) - } else { - messageSink.error(oneOf.location, SCHEMA_ARRAY_REQUIRED.create("oneOf")) - } - } - schemaProperties["not"]?.let { not -> - validators.add(NotValidator(parseSchemaElement(not, messageSink))) - } + schemaProperties["allOf"]?.let { allOf -> + if (allOf is KsonList) { + val allOfArrayEntries = ArrayList() + for (element in allOf.elements) { + allOfArrayEntries.add( + parseSchemaElement(element, messageSink, updatedBaseUri, idLookup) ?: continue + ) + } + validators.add(AllOfValidator(allOfArrayEntries)) + } else { + messageSink.error(allOf.location, SCHEMA_ARRAY_REQUIRED.create("allOf")) + } + } - schemaProperties["if"]?.let { ifElement -> - val ifSchema = parseSchemaElement(ifElement, messageSink) - val thenSchema = schemaProperties["then"]?.let { parseSchemaElement(it, messageSink) } - val elseSchema = schemaProperties["else"]?.let { parseSchemaElement(it, messageSink) } - validators.add(IfValidator(ifSchema, thenSchema, elseSchema)) - } + schemaProperties["anyOf"]?.let { anyOf -> + if (anyOf is KsonList) { + val anyOfArrayEntries = ArrayList() + for (element in anyOf.elements) { + anyOfArrayEntries.add( + parseSchemaElement(element, messageSink, updatedBaseUri, idLookup) ?: continue + ) + } + validators.add(AnyOfValidator(anyOfArrayEntries)) + } else { + messageSink.error(anyOf.location, SCHEMA_ARRAY_REQUIRED.create("anyOf")) + } + } - schemaProperties["dependencies"] ?.let { dependencies -> - if (dependencies !is KsonObject) { - messageSink.error(dependencies.location, SCHEMA_OBJECT_REQUIRED.create("dependencies")) - return@let - } - - val dependencyMap = dependencies.propertyMap.mapValues { (_, value) -> - if (value is KsonList) { - val dependencyArrayEntries = mutableSetOf() - for (element in value.elements) { - if (element is KsonString) { - dependencyArrayEntries.add(element) + schemaProperties["oneOf"]?.let { oneOf -> + if (oneOf is KsonList) { + val oneOfArrayEntries = ArrayList() + for (element in oneOf.elements) { + oneOfArrayEntries.add( + parseSchemaElement(element, messageSink, updatedBaseUri, idLookup) ?: continue + ) + } + validators.add(OneOfValidator(oneOfArrayEntries)) } else { - messageSink.error(element.location, SCHEMA_DEPENDENCIES_ARRAY_STRING_REQUIRED.create()) + messageSink.error(oneOf.location, SCHEMA_ARRAY_REQUIRED.create("oneOf")) } - } - return@mapValues DependencyValidatorArray(dependencyArrayEntries) - } else { - return@mapValues DependencyValidatorSchema(parseSchemaElement(value, messageSink)) } - } - validators.add(DependenciesValidator(dependencyMap)) - } - schemaProperties["propertyNames"] ?.let { propertyNames -> - validators.add(PropertyNamesValidator(parseSchemaElement(propertyNames, messageSink))) + schemaProperties["not"]?.let { not -> + validators.add(NotValidator(parseSchemaElement(not, messageSink, updatedBaseUri, idLookup))) + } + + schemaProperties["if"]?.let { ifElement -> + val ifSchema = parseSchemaElement(ifElement, messageSink, updatedBaseUri, idLookup) + val thenSchema = + schemaProperties["then"]?.let { parseSchemaElement(it, messageSink, updatedBaseUri, idLookup) } + val elseSchema = + schemaProperties["else"]?.let { parseSchemaElement(it, messageSink, updatedBaseUri, idLookup) } + validators.add(IfValidator(ifSchema, thenSchema, elseSchema)) + } + + schemaProperties["dependencies"]?.let { dependencies -> + if (dependencies !is KsonObject) { + messageSink.error(dependencies.location, SCHEMA_OBJECT_REQUIRED.create("dependencies")) + return@let + } + + val dependencyMap = dependencies.propertyMap.mapValues { (_, value) -> + if (value is KsonList) { + val dependencyArrayEntries = mutableSetOf() + for (element in value.elements) { + if (element is KsonString) { + dependencyArrayEntries.add(element) + } else { + messageSink.error(element.location, SCHEMA_DEPENDENCIES_ARRAY_STRING_REQUIRED.create()) + } + } + return@mapValues DependencyValidatorArray(dependencyArrayEntries) + } else { + return@mapValues DependencyValidatorSchema( + parseSchemaElement( + value, + messageSink, + updatedBaseUri, + idLookup + ) + ) + } + } + validators.add(DependenciesValidator(dependencyMap)) + } + + schemaProperties["propertyNames"]?.let { propertyNames -> + validators.add( + PropertyNamesValidator( + parseSchemaElement( + propertyNames, + messageSink, + updatedBaseUri, + idLookup + ) + ) + ) + } + + return JsonObjectSchema(title, description, default, definitions, typeValidator, validators) } +} - return JsonObjectSchema(title, description, default, definitions, typeValidator, validators) - } +/** + * Extract the `$id` property from the given [KsonObject] if it has one, ensuring it is of type string + */ +private fun extractId(schemaObject: KsonObject, messageSink: MessageSink): String? { + return schemaObject.propertyLookup["\$id"]?.let { idValue -> + if (idValue is KsonString) { + idValue.value + } else { + messageSink.error(idValue.location, SCHEMA_STRING_REQUIRED.create("\$id")) + null + } + } } diff --git a/src/commonMain/kotlin/org/kson/schema/validators/RefValidator.kt b/src/commonMain/kotlin/org/kson/schema/validators/RefValidator.kt new file mode 100644 index 00000000..6d09c81b --- /dev/null +++ b/src/commonMain/kotlin/org/kson/schema/validators/RefValidator.kt @@ -0,0 +1,36 @@ +package org.kson.schema.validators + +import org.kson.KsonValue +import org.kson.parser.MessageSink +import org.kson.schema.* + +/** + * Validator for JSON Schema `$ref` references + * + * @param [resolvedRef] the [ResolvedRef] object for this $ref + * @param [idLookup] the IdSchemaLookup for resolving nested $ref references within the referenced schema + */ +class RefValidator( + private val resolvedRef: ResolvedRef, + private val idLookup: SchemaIdLookup +) : JsonSchemaValidator { + private val refSchema: JsonSchema? by lazy { + // Parse the resolved value as a schema with the appropriate base URI context + val messageSink = MessageSink() + // TODO these parsed $ref schemas should be cached for efficiency + SchemaParser.parseSchemaElement( + resolvedRef.resolvedValue, + messageSink, + resolvedRef.resolvedValueBaseUri, + idLookup) + } + + override fun validate(ksonValue: KsonValue, messageSink: MessageSink) { + val schema = refSchema + ?: // Schema parsing failed, so can't perform validation against it + return + + // Validate the value against our referenced schema + schema.validate(ksonValue, messageSink) + } +} diff --git a/src/commonTest/kotlin/org/kson/parser/json/generated/SchemaSuiteTest.kt b/src/commonTest/kotlin/org/kson/parser/json/generated/SchemaSuiteTest.kt index d54237af..d1016cf3 100644 --- a/src/commonTest/kotlin/org/kson/parser/json/generated/SchemaSuiteTest.kt +++ b/src/commonTest/kotlin/org/kson/parser/json/generated/SchemaSuiteTest.kt @@ -22,10 +22,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null,2,3,4] + [ + null, + 2, + 3, + 4 + ] """, """ - {"items":[{}],"additionalItems":{"type":"integer"}} + { + "items": [ + { + } + ], + "additionalItems": { + "type": "integer" + } + } """, true, """additionalItems as schema -> additional items match schema""") @@ -40,10 +53,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null,2,3,"foo"] + [ + null, + 2, + 3, + "foo" + ] """, """ - {"items":[{}],"additionalItems":{"type":"integer"}} + { + "items": [ + { + } + ], + "additionalItems": { + "type": "integer" + } + } """, false, """additionalItems as schema -> additional items do not match schema""") @@ -58,10 +84,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"items":{"type":"integer"},"additionalItems":{"type":"string"}} + { + "items": { + "type": "integer" + }, + "additionalItems": { + "type": "string" + } + } """, true, """when items is schema, additionalItems does nothing -> valid with a array of type integers""") @@ -76,10 +113,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"2","3"] + [ + 1, + "2", + "3" + ] """, """ - {"items":{"type":"integer"},"additionalItems":{"type":"string"}} + { + "items": { + "type": "integer" + }, + "additionalItems": { + "type": "string" + } + } """, false, """when items is schema, additionalItems does nothing -> invalid with a array of mixed types""") @@ -94,10 +142,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3,4,5] + [ + 1, + 2, + 3, + 4, + 5 + ] """, """ - {"items":{},"additionalItems":false} + { + "items": { + }, + "additionalItems": false + } """, true, """when items is schema, boolean additionalItems does nothing -> all items match schema""") @@ -112,10 +170,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"items":[{},{},{}],"additionalItems":false} + { + "items": [ + { + }, + { + }, + { + } + ], + "additionalItems": false + } """, true, """array of items with no additionalItems permitted -> empty array""") @@ -130,10 +199,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"items":[{},{},{}],"additionalItems":false} + { + "items": [ + { + }, + { + }, + { + } + ], + "additionalItems": false + } """, true, """array of items with no additionalItems permitted -> fewer number of items present (1)""") @@ -148,10 +229,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"items":[{},{},{}],"additionalItems":false} + { + "items": [ + { + }, + { + }, + { + } + ], + "additionalItems": false + } """, true, """array of items with no additionalItems permitted -> fewer number of items present (2)""") @@ -166,10 +260,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"items":[{},{},{}],"additionalItems":false} + { + "items": [ + { + }, + { + }, + { + } + ], + "additionalItems": false + } """, true, """array of items with no additionalItems permitted -> equal number of items present""") @@ -184,10 +292,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3,4] + [ + 1, + 2, + 3, + 4 + ] """, """ - {"items":[{},{},{}],"additionalItems":false} + { + "items": [ + { + }, + { + }, + { + } + ], + "additionalItems": false + } """, false, """array of items with no additionalItems permitted -> additional items are not permitted""") @@ -202,10 +325,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3,4,5] + [ + 1, + 2, + 3, + 4, + 5 + ] """, """ - {"additionalItems":false} + { + "additionalItems": false + } """, true, """additionalItems as false without items -> items defaults to empty schema so everything is valid""") @@ -220,10 +351,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"additionalItems":false} + { + "additionalItems": false + } """, true, """additionalItems as false without items -> ignores non-arrays""") @@ -238,10 +373,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo",false] + [ + 1, + "foo", + false + ] """, """ - {"items":[{"type":"integer"}]} + { + "items": [ + { + "type": "integer" + } + ] + } """, true, """additionalItems are allowed by default -> only the first item is validated""") @@ -256,10 +401,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,null] + [ + 1, + null + ] """, """ - {"allOf":[{"items":[{"type":"integer"}]}],"additionalItems":{"type":"boolean"}} + { + "allOf": [ + { + "items": [ + { + "type": "integer" + } + ] + } + ], + "additionalItems": { + "type": "boolean" + } + } """, true, """additionalItems does not look in applicators, valid case -> items defined in allOf are not examined""") @@ -274,10 +435,34 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"hello"] - """, - """ - {"allOf":[{"items":[{"type":"integer"},{"type":"string"}]}],"items":[{"type":"integer"}],"additionalItems":{"type":"boolean"}} + [ + 1, + "hello" + ] + """, + """ + { + "allOf": [ + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + ], + "items": [ + { + "type": "integer" + } + ], + "additionalItems": { + "type": "boolean" + } + } """, false, """additionalItems does not look in applicators, invalid case -> items defined in allOf are not examined""") @@ -292,10 +477,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["x",2,3] + [ + "x", + 2, + 3 + ] """, """ - {"items":[{"type":"string"}],"additionalItems":{"type":"integer"}} + { + "items": [ + { + "type": "string" + } + ], + "additionalItems": { + "type": "integer" + } + } """, true, """items validation adjusts the starting index for additionalItems -> valid items""") @@ -310,10 +508,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["x","y"] + [ + "x", + "y" + ] """, """ - {"items":[{"type":"string"}],"additionalItems":{"type":"integer"}} + { + "items": [ + { + "type": "string" + } + ], + "additionalItems": { + "type": "integer" + } + } """, false, """items validation adjusts the starting index for additionalItems -> wrong type of second item""") @@ -328,10 +538,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo","bar",37] + [ + "foo", + "bar", + 37 + ] """, """ - {"items":[{}],"additionalItems":false} + { + "items": [ + { + } + ], + "additionalItems": false + } """, false, """additionalItems with heterogeneous array -> heterogeneous invalid instance""") @@ -346,10 +566,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null] + [ + null + ] """, """ - {"items":[{}],"additionalItems":false} + { + "items": [ + { + } + ], + "additionalItems": false + } """, true, """additionalItems with heterogeneous array -> valid instance""") @@ -364,10 +592,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null] + [ + null + ] """, """ - {"additionalItems":{"type":"null"}} + { + "additionalItems": { + "type": "null" + } + } """, true, """additionalItems with null instance elements -> allows null elements""") @@ -381,10 +615,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, true, """additionalProperties being false does not allow other properties -> no additional properties is valid""") @@ -399,10 +647,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"quux":"boom"} + { + "foo": 1, + "bar": 2, + "quux": "boom" + } """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, false, """additionalProperties being false does not allow other properties -> an additional property is invalid""") @@ -417,10 +681,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, true, """additionalProperties being false does not allow other properties -> ignores arrays""") @@ -438,7 +718,19 @@ class SchemaSuiteTest : JsonSchemaTest { "foobarbaz" """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, true, """additionalProperties being false does not allow other properties -> ignores strings""") @@ -456,7 +748,19 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, true, """additionalProperties being false does not allow other properties -> ignores other non-objects""") @@ -471,10 +775,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"vroom":2} + { + "foo": 1, + "vroom": 2 + } """, """ - {"properties":{"foo":{},"bar":{}},"patternProperties":{"^v":{}},"additionalProperties":false} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "patternProperties": { + "^v": { + } + }, + "additionalProperties": false + } """, true, """additionalProperties being false does not allow other properties -> patternProperties are not additional properties""") @@ -489,10 +808,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"ármányos":2} + { + "ármányos": 2 + } """, """ - {"patternProperties":{"^á":{}},"additionalProperties":false} + { + "patternProperties": { + "^á": { + } + }, + "additionalProperties": false + } """, true, """non-ASCII pattern with additionalProperties -> matching the pattern is valid""") @@ -507,10 +834,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"élmény":2} + { + "élmény": 2 + } """, """ - {"patternProperties":{"^á":{}},"additionalProperties":false} + { + "patternProperties": { + "^á": { + } + }, + "additionalProperties": false + } """, false, """non-ASCII pattern with additionalProperties -> not matching the pattern is invalid""") @@ -525,10 +860,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"properties":{"foo":{},"bar":{}},"additionalProperties":{"type":"boolean"}} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "additionalProperties": { + "type": "boolean" + } + } """, true, """additionalProperties with schema -> no additional properties is valid""") @@ -543,10 +890,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"quux":true} + { + "foo": 1, + "bar": 2, + "quux": true + } """, """ - {"properties":{"foo":{},"bar":{}},"additionalProperties":{"type":"boolean"}} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "additionalProperties": { + "type": "boolean" + } + } """, true, """additionalProperties with schema -> an additional valid property is valid""") @@ -561,10 +922,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"quux":12} + { + "foo": 1, + "bar": 2, + "quux": 12 + } """, """ - {"properties":{"foo":{},"bar":{}},"additionalProperties":{"type":"boolean"}} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "additionalProperties": { + "type": "boolean" + } + } """, false, """additionalProperties with schema -> an additional invalid property is invalid""") @@ -579,10 +954,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":true} + { + "foo": true + } """, """ - {"additionalProperties":{"type":"boolean"}} + { + "additionalProperties": { + "type": "boolean" + } + } """, true, """additionalProperties can exist by itself -> an additional valid property is valid""") @@ -597,10 +978,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"additionalProperties":{"type":"boolean"}} + { + "additionalProperties": { + "type": "boolean" + } + } """, false, """additionalProperties can exist by itself -> an additional invalid property is invalid""") @@ -615,10 +1002,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"quux":true} + { + "foo": 1, + "bar": 2, + "quux": true + } """, """ - {"properties":{"foo":{},"bar":{}}} + { + "properties": { + "foo": { + }, + "bar": { + } + } + } """, true, """additionalProperties are allowed by default -> additional properties are allowed""") @@ -633,10 +1031,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":true} + { + "foo": 1, + "bar": true + } """, """ - {"allOf":[{"properties":{"foo":{}}}],"additionalProperties":{"type":"boolean"}} + { + "allOf": [ + { + "properties": { + "foo": { + } + } + } + ], + "additionalProperties": { + "type": "boolean" + } + } """, false, """additionalProperties does not look in applicators -> properties defined in allOf are not examined""") @@ -651,10 +1064,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":null} + { + "foo": null + } """, """ - {"additionalProperties":{"type":"null"}} + { + "additionalProperties": { + "type": "null" + } + } """, true, """additionalProperties with null valued instance properties -> allows null values""") @@ -668,10 +1087,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz","bar":2} - """, - """ - {"allOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz", + "bar": 2 + } + """, + """ + { + "allOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """allOf -> allOf""") @@ -686,10 +1131,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz"} - """, - """ - {"allOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz" + } + """, + """ + { + "allOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """allOf -> mismatch second""") @@ -704,10 +1174,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} - """, - """ - {"allOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "bar": 2 + } + """, + """ + { + "allOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """allOf -> mismatch first""") @@ -722,10 +1217,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz","bar":"quux"} - """, - """ - {"allOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz", + "bar": "quux" + } + """, + """ + { + "allOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """allOf -> wrong type""") @@ -740,10 +1261,45 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux","bar":2,"baz":null} - """, - """ - {"properties":{"bar":{"type":"integer"}},"required":["bar"],"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}]} + { + "foo": "quux", + "bar": 2, + "baz": null + } + """, + """ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ], + "allOf": [ + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + }, + { + "properties": { + "baz": { + "type": "null" + } + }, + "required": [ + "baz" + ] + } + ] + } """, true, """allOf with base schema -> valid""") @@ -758,10 +1314,44 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux","baz":null} - """, - """ - {"properties":{"bar":{"type":"integer"}},"required":["bar"],"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}]} + { + "foo": "quux", + "baz": null + } + """, + """ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ], + "allOf": [ + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + }, + { + "properties": { + "baz": { + "type": "null" + } + }, + "required": [ + "baz" + ] + } + ] + } """, false, """allOf with base schema -> mismatch base schema""") @@ -776,10 +1366,44 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2,"baz":null} - """, - """ - {"properties":{"bar":{"type":"integer"}},"required":["bar"],"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}]} + { + "bar": 2, + "baz": null + } + """, + """ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ], + "allOf": [ + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + }, + { + "properties": { + "baz": { + "type": "null" + } + }, + "required": [ + "baz" + ] + } + ] + } """, false, """allOf with base schema -> mismatch first allOf""") @@ -794,10 +1418,44 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux","bar":2} - """, - """ - {"properties":{"bar":{"type":"integer"}},"required":["bar"],"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}]} + { + "foo": "quux", + "bar": 2 + } + """, + """ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ], + "allOf": [ + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + }, + { + "properties": { + "baz": { + "type": "null" + } + }, + "required": [ + "baz" + ] + } + ] + } """, false, """allOf with base schema -> mismatch second allOf""") @@ -812,10 +1470,43 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} - """, - """ - {"properties":{"bar":{"type":"integer"}},"required":["bar"],"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}]} + { + "bar": 2 + } + """, + """ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ], + "allOf": [ + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + }, + { + "properties": { + "baz": { + "type": "null" + } + }, + "required": [ + "baz" + ] + } + ] + } """, false, """allOf with base schema -> mismatch both""") @@ -833,7 +1524,16 @@ class SchemaSuiteTest : JsonSchemaTest { 25 """, """ - {"allOf":[{"maximum":30},{"minimum":20}]} + { + "allOf": [ + { + "maximum": 30 + }, + { + "minimum": 20 + } + ] + } """, true, """allOf simple types -> valid""") @@ -851,7 +1551,16 @@ class SchemaSuiteTest : JsonSchemaTest { 35 """, """ - {"allOf":[{"maximum":30},{"minimum":20}]} + { + "allOf": [ + { + "maximum": 30 + }, + { + "minimum": 20 + } + ] + } """, false, """allOf simple types -> mismatch one""") @@ -869,7 +1578,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"allOf":[true,true]} + { + "allOf": [ + true, + true + ] + } """, true, """allOf with boolean schemas, all true -> any value is valid""") @@ -887,7 +1601,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"allOf":[true,false]} + { + "allOf": [ + true, + false + ] + } """, false, """allOf with boolean schemas, some false -> any value is invalid""") @@ -905,7 +1624,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"allOf":[false,false]} + { + "allOf": [ + false, + false + ] + } """, false, """allOf with boolean schemas, all false -> any value is invalid""") @@ -923,7 +1647,12 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"allOf":[{}]} + { + "allOf": [ + { + } + ] + } """, true, """allOf with one empty schema -> any data is valid""") @@ -941,7 +1670,14 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"allOf":[{},{}]} + { + "allOf": [ + { + }, + { + } + ] + } """, true, """allOf with two empty schemas -> any data is valid""") @@ -959,7 +1695,15 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"allOf":[{},{"type":"number"}]} + { + "allOf": [ + { + }, + { + "type": "number" + } + ] + } """, true, """allOf with the first empty schema -> number is valid""") @@ -977,7 +1721,15 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"allOf":[{},{"type":"number"}]} + { + "allOf": [ + { + }, + { + "type": "number" + } + ] + } """, false, """allOf with the first empty schema -> string is invalid""") @@ -995,7 +1747,15 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"allOf":[{"type":"number"},{}]} + { + "allOf": [ + { + "type": "number" + }, + { + } + ] + } """, true, """allOf with the last empty schema -> number is valid""") @@ -1013,7 +1773,15 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"allOf":[{"type":"number"},{}]} + { + "allOf": [ + { + "type": "number" + }, + { + } + ] + } """, false, """allOf with the last empty schema -> string is invalid""") @@ -1031,7 +1799,17 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"allOf":[{"allOf":[{"type":"null"}]}]} + { + "allOf": [ + { + "allOf": [ + { + "type": "null" + } + ] + } + ] + } """, true, """nested allOf, to check validation semantics -> null is valid""") @@ -1049,7 +1827,17 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"allOf":[{"allOf":[{"type":"null"}]}]} + { + "allOf": [ + { + "allOf": [ + { + "type": "null" + } + ] + } + ] + } """, false, """nested allOf, to check validation semantics -> anything non-null is invalid""") @@ -1067,7 +1855,23 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: false, anyOf: false, oneOf: false""") @@ -1085,7 +1889,23 @@ class SchemaSuiteTest : JsonSchemaTest { 5 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: false, anyOf: false, oneOf: true""") @@ -1103,7 +1923,23 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: false, anyOf: true, oneOf: false""") @@ -1121,7 +1957,23 @@ class SchemaSuiteTest : JsonSchemaTest { 15 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: false, anyOf: true, oneOf: true""") @@ -1139,7 +1991,23 @@ class SchemaSuiteTest : JsonSchemaTest { 2 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: true, anyOf: false, oneOf: false""") @@ -1157,7 +2025,23 @@ class SchemaSuiteTest : JsonSchemaTest { 10 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: true, anyOf: false, oneOf: true""") @@ -1175,7 +2059,23 @@ class SchemaSuiteTest : JsonSchemaTest { 6 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, false, """allOf combined with anyOf, oneOf -> allOf: true, anyOf: true, oneOf: false""") @@ -1193,7 +2093,23 @@ class SchemaSuiteTest : JsonSchemaTest { 30 """, """ - {"allOf":[{"multipleOf":2}],"anyOf":[{"multipleOf":3}],"oneOf":[{"multipleOf":5}]} + { + "allOf": [ + { + "multipleOf": 2 + } + ], + "anyOf": [ + { + "multipleOf": 3 + } + ], + "oneOf": [ + { + "multipleOf": 5 + } + ] + } """, true, """allOf combined with anyOf, oneOf -> allOf: true, anyOf: true, oneOf: true""") @@ -1210,7 +2126,16 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"anyOf":[{"type":"integer"},{"minimum":2}]} + { + "anyOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, true, """anyOf -> first anyOf valid""") @@ -1228,7 +2153,16 @@ class SchemaSuiteTest : JsonSchemaTest { 2.5 """, """ - {"anyOf":[{"type":"integer"},{"minimum":2}]} + { + "anyOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, true, """anyOf -> second anyOf valid""") @@ -1246,7 +2180,16 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"anyOf":[{"type":"integer"},{"minimum":2}]} + { + "anyOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, true, """anyOf -> both anyOf valid""") @@ -1264,7 +2207,16 @@ class SchemaSuiteTest : JsonSchemaTest { 1.5 """, """ - {"anyOf":[{"type":"integer"},{"minimum":2}]} + { + "anyOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, false, """anyOf -> neither anyOf valid""") @@ -1282,7 +2234,17 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"type":"string","anyOf":[{"maxLength":2},{"minLength":4}]} + { + "type": "string", + "anyOf": [ + { + "maxLength": 2 + }, + { + "minLength": 4 + } + ] + } """, false, """anyOf with base schema -> mismatch base schema""") @@ -1300,7 +2262,17 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"type":"string","anyOf":[{"maxLength":2},{"minLength":4}]} + { + "type": "string", + "anyOf": [ + { + "maxLength": 2 + }, + { + "minLength": 4 + } + ] + } """, true, """anyOf with base schema -> one anyOf valid""") @@ -1318,7 +2290,17 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"string","anyOf":[{"maxLength":2},{"minLength":4}]} + { + "type": "string", + "anyOf": [ + { + "maxLength": 2 + }, + { + "minLength": 4 + } + ] + } """, false, """anyOf with base schema -> both anyOf invalid""") @@ -1336,7 +2318,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"anyOf":[true,true]} + { + "anyOf": [ + true, + true + ] + } """, true, """anyOf with boolean schemas, all true -> any value is valid""") @@ -1354,7 +2341,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"anyOf":[true,false]} + { + "anyOf": [ + true, + false + ] + } """, true, """anyOf with boolean schemas, some true -> any value is valid""") @@ -1372,7 +2364,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"anyOf":[false,false]} + { + "anyOf": [ + false, + false + ] + } """, false, """anyOf with boolean schemas, all false -> any value is invalid""") @@ -1387,10 +2384,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} - """, - """ - {"anyOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "bar": 2 + } + """, + """ + { + "anyOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """anyOf complex types -> first anyOf valid (complex)""") @@ -1405,10 +2427,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz"} - """, - """ - {"anyOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz" + } + """, + """ + { + "anyOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """anyOf complex types -> second anyOf valid (complex)""") @@ -1423,10 +2470,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz","bar":2} - """, - """ - {"anyOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz", + "bar": 2 + } + """, + """ + { + "anyOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """anyOf complex types -> both anyOf valid (complex)""") @@ -1441,10 +2514,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":2,"bar":"quux"} - """, - """ - {"anyOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": 2, + "bar": "quux" + } + """, + """ + { + "anyOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """anyOf complex types -> neither anyOf valid (complex)""") @@ -1462,7 +2561,15 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"anyOf":[{"type":"number"},{}]} + { + "anyOf": [ + { + "type": "number" + }, + { + } + ] + } """, true, """anyOf with one empty schema -> string is valid""") @@ -1480,7 +2587,15 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"anyOf":[{"type":"number"},{}]} + { + "anyOf": [ + { + "type": "number" + }, + { + } + ] + } """, true, """anyOf with one empty schema -> number is valid""") @@ -1498,7 +2613,17 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"anyOf":[{"anyOf":[{"type":"null"}]}]} + { + "anyOf": [ + { + "anyOf": [ + { + "type": "null" + } + ] + } + ] + } """, true, """nested anyOf, to check validation semantics -> null is valid""") @@ -1516,7 +2641,17 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"anyOf":[{"anyOf":[{"type":"null"}]}]} + { + "anyOf": [ + { + "anyOf": [ + { + "type": "null" + } + ] + } + ] + } """, false, """nested anyOf, to check validation semantics -> anything non-null is invalid""") @@ -1620,7 +2755,9 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ true @@ -1638,7 +2775,8 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ true @@ -1656,7 +2794,9 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ true @@ -1674,7 +2814,8 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ true @@ -1782,7 +2923,9 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ false @@ -1800,7 +2943,8 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ false @@ -1818,7 +2962,9 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ false @@ -1836,7 +2982,8 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ false @@ -1856,7 +3003,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2 """, """ - {"const":2} + { + "const": 2 + } """, true, """const validation -> same value is valid""") @@ -1874,7 +3023,9 @@ class SchemaSuiteTest : JsonSchemaTest { 5 """, """ - {"const":2} + { + "const": 2 + } """, false, """const validation -> another value is invalid""") @@ -1892,7 +3043,9 @@ class SchemaSuiteTest : JsonSchemaTest { "a" """, """ - {"const":2} + { + "const": 2 + } """, false, """const validation -> another type is invalid""") @@ -1907,10 +3060,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar","baz":"bax"} + { + "foo": "bar", + "baz": "bax" + } """, """ - {"const":{"foo":"bar","baz":"bax"}} + { + "const": { + "foo": "bar", + "baz": "bax" + } + } """, true, """const with object -> same object is valid""") @@ -1925,10 +3086,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"baz":"bax","foo":"bar"} + { + "baz": "bax", + "foo": "bar" + } """, """ - {"const":{"foo":"bar","baz":"bax"}} + { + "const": { + "foo": "bar", + "baz": "bax" + } + } """, true, """const with object -> same object with different property order is valid""") @@ -1943,10 +3112,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"const":{"foo":"bar","baz":"bax"}} + { + "const": { + "foo": "bar", + "baz": "bax" + } + } """, false, """const with object -> another object is invalid""") @@ -1961,10 +3137,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"const":{"foo":"bar","baz":"bax"}} + { + "const": { + "foo": "bar", + "baz": "bax" + } + } """, false, """const with object -> another type is invalid""") @@ -1979,10 +3163,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar"}] + [ + { + "foo": "bar" + } + ] """, """ - {"const":[{"foo":"bar"}]} + { + "const": [ + { + "foo": "bar" + } + ] + } """, true, """const with array -> same array is valid""") @@ -1997,10 +3191,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [2] + [ + 2 + ] """, """ - {"const":[{"foo":"bar"}]} + { + "const": [ + { + "foo": "bar" + } + ] + } """, false, """const with array -> another array item is invalid""") @@ -2015,10 +3217,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"const":[{"foo":"bar"}]} + { + "const": [ + { + "foo": "bar" + } + ] + } """, false, """const with array -> array with additional items is invalid""") @@ -2036,7 +3248,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"const":null} + { + "const": null + } """, true, """const with null -> null is valid""") @@ -2054,7 +3268,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"const":null} + { + "const": null + } """, false, """const with null -> not null is invalid""") @@ -2072,7 +3288,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"const":false} + { + "const": false + } """, true, """const with false does not match 0 -> false is valid""") @@ -2090,7 +3308,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"const":false} + { + "const": false + } """, false, """const with false does not match 0 -> integer zero is invalid""") @@ -2108,7 +3328,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.0 """, """ - {"const":false} + { + "const": false + } """, false, """const with false does not match 0 -> float zero is invalid""") @@ -2126,7 +3348,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"const":true} + { + "const": true + } """, true, """const with true does not match 1 -> true is valid""") @@ -2144,7 +3368,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"const":true} + { + "const": true + } """, false, """const with true does not match 1 -> integer one is invalid""") @@ -2162,7 +3388,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"const":true} + { + "const": true + } """, false, """const with true does not match 1 -> float one is invalid""") @@ -2177,10 +3405,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false] + [ + false + ] """, """ - {"const":[false]} + { + "const": [ + false + ] + } """, true, """const with [false] does not match [0] -> [false] is valid""") @@ -2195,10 +3429,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0] + [ + 0 + ] """, """ - {"const":[false]} + { + "const": [ + false + ] + } """, false, """const with [false] does not match [0] -> [0] is invalid""") @@ -2213,10 +3453,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0.0] + [ + 0.0 + ] """, """ - {"const":[false]} + { + "const": [ + false + ] + } """, false, """const with [false] does not match [0] -> [0.0] is invalid""") @@ -2231,10 +3477,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true] + [ + true + ] """, """ - {"const":[true]} + { + "const": [ + true + ] + } """, true, """const with [true] does not match [1] -> [true] is valid""") @@ -2249,10 +3501,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"const":[true]} + { + "const": [ + true + ] + } """, false, """const with [true] does not match [1] -> [1] is invalid""") @@ -2267,10 +3525,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1.0] + [ + 1.0 + ] """, """ - {"const":[true]} + { + "const": [ + true + ] + } """, false, """const with [true] does not match [1] -> [1.0] is invalid""") @@ -2285,10 +3549,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":false} + { + "a": false + } """, """ - {"const":{"a":false}} + { + "const": { + "a": false + } + } """, true, """const with {"a": false} does not match {"a": 0} -> {"a": false} is valid""") @@ -2303,10 +3573,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":0} + { + "a": 0 + } """, """ - {"const":{"a":false}} + { + "const": { + "a": false + } + } """, false, """const with {"a": false} does not match {"a": 0} -> {"a": 0} is invalid""") @@ -2321,10 +3597,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":0.0} + { + "a": 0.0 + } """, """ - {"const":{"a":false}} + { + "const": { + "a": false + } + } """, false, """const with {"a": false} does not match {"a": 0} -> {"a": 0.0} is invalid""") @@ -2339,10 +3621,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":true} + { + "a": true + } """, """ - {"const":{"a":true}} + { + "const": { + "a": true + } + } """, true, """const with {"a": true} does not match {"a": 1} -> {"a": true} is valid""") @@ -2357,10 +3645,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":1} + { + "a": 1 + } """, """ - {"const":{"a":true}} + { + "const": { + "a": true + } + } """, false, """const with {"a": true} does not match {"a": 1} -> {"a": 1} is invalid""") @@ -2375,10 +3669,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":1.0} + { + "a": 1.0 + } """, """ - {"const":{"a":true}} + { + "const": { + "a": true + } + } """, false, """const with {"a": true} does not match {"a": 1} -> {"a": 1.0} is invalid""") @@ -2396,7 +3696,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"const":0} + { + "const": 0 + } """, false, """const with 0 does not match other zero-like types -> false is invalid""") @@ -2414,7 +3716,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"const":0} + { + "const": 0 + } """, true, """const with 0 does not match other zero-like types -> integer zero is valid""") @@ -2432,7 +3736,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.0 """, """ - {"const":0} + { + "const": 0 + } """, true, """const with 0 does not match other zero-like types -> float zero is valid""") @@ -2447,10 +3753,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"const":0} + { + "const": 0 + } """, false, """const with 0 does not match other zero-like types -> empty object is invalid""") @@ -2465,10 +3774,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"const":0} + { + "const": 0 + } """, false, """const with 0 does not match other zero-like types -> empty array is invalid""") @@ -2486,7 +3798,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"const":0} + { + "const": 0 + } """, false, """const with 0 does not match other zero-like types -> empty string is invalid""") @@ -2504,7 +3818,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"const":1} + { + "const": 1 + } """, false, """const with 1 does not match true -> true is invalid""") @@ -2522,7 +3838,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"const":1} + { + "const": 1 + } """, true, """const with 1 does not match true -> integer one is valid""") @@ -2540,7 +3858,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"const":1} + { + "const": 1 + } """, true, """const with 1 does not match true -> float one is valid""") @@ -2558,7 +3878,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2 """, """ - {"const":-2.0} + { + "const": -2.0 + } """, true, """const with -2.0 matches integer and float types -> integer -2 is valid""") @@ -2576,7 +3898,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2 """, """ - {"const":-2.0} + { + "const": -2.0 + } """, false, """const with -2.0 matches integer and float types -> integer 2 is invalid""") @@ -2594,7 +3918,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2.0 """, """ - {"const":-2.0} + { + "const": -2.0 + } """, true, """const with -2.0 matches integer and float types -> float -2.0 is valid""") @@ -2612,7 +3938,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2.0 """, """ - {"const":-2.0} + { + "const": -2.0 + } """, false, """const with -2.0 matches integer and float types -> float 2.0 is invalid""") @@ -2630,7 +3958,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2.00001 """, """ - {"const":-2.0} + { + "const": -2.0 + } """, false, """const with -2.0 matches integer and float types -> float -2.00001 is invalid""") @@ -2648,7 +3978,9 @@ class SchemaSuiteTest : JsonSchemaTest { 9007199254740992 """, """ - {"const":9007199254740992} + { + "const": 9007199254740992 + } """, true, """float and integers are equal up to 64-bit representation limits -> integer is valid""") @@ -2666,7 +3998,9 @@ class SchemaSuiteTest : JsonSchemaTest { 9007199254740991 """, """ - {"const":9007199254740992} + { + "const": 9007199254740992 + } """, false, """float and integers are equal up to 64-bit representation limits -> integer minus one is invalid""") @@ -2681,10 +4015,12 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - 9007199254740992.0 + 9.007199254740992E15 """, """ - {"const":9007199254740992} + { + "const": 9007199254740992 + } """, true, """float and integers are equal up to 64-bit representation limits -> float is valid""") @@ -2699,10 +4035,12 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - 9007199254740991.0 + 9.007199254740991E15 """, """ - {"const":9007199254740992} + { + "const": 9007199254740992 + } """, false, """float and integers are equal up to 64-bit representation limits -> float minus one is invalid""") @@ -2720,7 +4058,9 @@ class SchemaSuiteTest : JsonSchemaTest { "hello\u0000there" """, """ - {"const":"hello\u0000there"} + { + "const": "hello\u0000there" + } """, true, """nul characters in strings -> match string with nul""") @@ -2738,7 +4078,9 @@ class SchemaSuiteTest : JsonSchemaTest { "hellothere" """, """ - {"const":"hello\u0000there"} + { + "const": "hello\u0000there" + } """, false, """nul characters in strings -> do not match string lacking nul""") @@ -2752,10 +4094,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,4,5] + [ + 3, + 4, + 5 + ] """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, true, """contains keyword validation -> array with item matching schema (5) is valid""") @@ -2770,10 +4120,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,4,6] + [ + 3, + 4, + 6 + ] """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, true, """contains keyword validation -> array with item matching schema (6) is valid""") @@ -2788,10 +4146,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,4,5,6] + [ + 3, + 4, + 5, + 6 + ] """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, true, """contains keyword validation -> array with two items matching schema (5, 6) is valid""") @@ -2806,10 +4173,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [2,3,4] + [ + 2, + 3, + 4 + ] """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, false, """contains keyword validation -> array without items matching schema is invalid""") @@ -2824,10 +4199,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, false, """contains keyword validation -> empty array is invalid""") @@ -2842,10 +4222,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"contains":{"minimum":5}} + { + "contains": { + "minimum": 5 + } + } """, true, """contains keyword validation -> not array is valid""") @@ -2860,10 +4245,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,4,5] + [ + 3, + 4, + 5 + ] """, """ - {"contains":{"const":5}} + { + "contains": { + "const": 5 + } + } """, true, """contains keyword with const keyword -> array with item 5 is valid""") @@ -2878,10 +4271,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,4,5,5] + [ + 3, + 4, + 5, + 5 + ] """, """ - {"contains":{"const":5}} + { + "contains": { + "const": 5 + } + } """, true, """contains keyword with const keyword -> array with two items 5 is valid""") @@ -2896,10 +4298,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3,4] + [ + 1, + 2, + 3, + 4 + ] """, """ - {"contains":{"const":5}} + { + "contains": { + "const": 5 + } + } """, false, """contains keyword with const keyword -> array without item 5 is invalid""") @@ -2914,10 +4325,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"contains":true} + { + "contains": true + } """, true, """contains keyword with boolean schema true -> any non-empty array is valid""") @@ -2932,10 +4347,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"contains":true} + { + "contains": true + } """, false, """contains keyword with boolean schema true -> empty array is invalid""") @@ -2950,10 +4368,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"contains":false} + { + "contains": false + } """, false, """contains keyword with boolean schema false -> any non-empty array is invalid""") @@ -2968,10 +4390,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"contains":false} + { + "contains": false + } """, false, """contains keyword with boolean schema false -> empty array is invalid""") @@ -2989,7 +4414,9 @@ class SchemaSuiteTest : JsonSchemaTest { "contains does not apply to strings" """, """ - {"contains":false} + { + "contains": false + } """, true, """contains keyword with boolean schema false -> non-arrays are valid""") @@ -3004,10 +4431,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [2,4,8] + [ + 2, + 4, + 8 + ] """, """ - {"items":{"multipleOf":2},"contains":{"multipleOf":3}} + { + "items": { + "multipleOf": 2 + }, + "contains": { + "multipleOf": 3 + } + } """, false, """items + contains -> matches items, does not match contains""") @@ -3022,10 +4460,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [3,6,9] + [ + 3, + 6, + 9 + ] """, """ - {"items":{"multipleOf":2},"contains":{"multipleOf":3}} + { + "items": { + "multipleOf": 2 + }, + "contains": { + "multipleOf": 3 + } + } """, false, """items + contains -> does not match items, matches contains""") @@ -3040,10 +4489,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [6,12] + [ + 6, + 12 + ] """, """ - {"items":{"multipleOf":2},"contains":{"multipleOf":3}} + { + "items": { + "multipleOf": 2 + }, + "contains": { + "multipleOf": 3 + } + } """, true, """items + contains -> matches both items and contains""") @@ -3058,10 +4517,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,5] + [ + 1, + 5 + ] """, """ - {"items":{"multipleOf":2},"contains":{"multipleOf":3}} + { + "items": { + "multipleOf": 2 + }, + "contains": { + "multipleOf": 3 + } + } """, false, """items + contains -> matches neither items nor contains""") @@ -3076,10 +4545,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"contains":{"if":false,"else":true}} + { + "contains": { + "if": false, + "else": true + } + } """, true, """contains with false if subschema -> any non-empty array is valid""") @@ -3094,10 +4570,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"contains":{"if":false,"else":true}} + { + "contains": { + "if": false, + "else": true + } + } """, false, """contains with false if subschema -> empty array is invalid""") @@ -3112,10 +4594,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null] + [ + null + ] """, """ - {"contains":{"type":"null"}} + { + "contains": { + "type": "null" + } + } """, true, """contains with null instance elements -> allows null items""") @@ -3129,10 +4617,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":13} + { + "foo": 13 + } """, """ - {"properties":{"foo":{"type":"integer","default":[]}}} + { + "properties": { + "foo": { + "type": "integer", + "default": [ + ] + } + } + } """, true, """invalid type for default -> valid when property is specified""") @@ -3147,10 +4645,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"foo":{"type":"integer","default":[]}}} + { + "properties": { + "foo": { + "type": "integer", + "default": [ + ] + } + } + } """, true, """invalid type for default -> still valid when the invalid default is used""") @@ -3165,10 +4672,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":"good"} + { + "bar": "good" + } """, """ - {"properties":{"bar":{"type":"string","minLength":4,"default":"bad"}}} + { + "properties": { + "bar": { + "type": "string", + "minLength": 4, + "default": "bad" + } + } + } """, true, """invalid string value for default -> valid when property is specified""") @@ -3183,10 +4700,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"bar":{"type":"string","minLength":4,"default":"bad"}}} + { + "properties": { + "bar": { + "type": "string", + "minLength": 4, + "default": "bad" + } + } + } """, true, """invalid string value for default -> still valid when the invalid default is used""") @@ -3201,10 +4727,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"alpha":1} + { + "alpha": 1 + } """, """ - {"type":"object","properties":{"alpha":{"type":"number","maximum":3,"default":5}}} + { + "type": "object", + "properties": { + "alpha": { + "type": "number", + "maximum": 3, + "default": 5 + } + } + } """, true, """the default keyword does not do anything if the property is missing -> an explicit property value is checked against maximum (passing)""") @@ -3219,10 +4756,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"alpha":5} + { + "alpha": 5 + } """, """ - {"type":"object","properties":{"alpha":{"type":"number","maximum":3,"default":5}}} + { + "type": "object", + "properties": { + "alpha": { + "type": "number", + "maximum": 3, + "default": 5 + } + } + } """, false, """the default keyword does not do anything if the property is missing -> an explicit property value is checked against maximum (failing)""") @@ -3237,10 +4785,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"object","properties":{"alpha":{"type":"number","maximum":3,"default":5}}} + { + "type": "object", + "properties": { + "alpha": { + "type": "number", + "maximum": 3, + "default": 5 + } + } + } """, true, """the default keyword does not do anything if the property is missing -> missing properties are not filled in with the default""") @@ -3251,19 +4809,21 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun definitions_validateDefinitionAgainstMetaschema_validDefinitionSchema() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "definitions_validateDefinitionAgainstMetaschema_validDefinitionSchema" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"definitions":{"foo":{"type":"integer"}}} + { + "definitions": { + "foo": { + "type": "integer" + } + } + } """, """ - {"${'$'}ref":"http://json-schema.org/draft-07/schema#"} + { + "${'$'}ref": "http://json-schema.org/draft-07/schema#" + } """, true, """validate definition against metaschema -> valid definition schema""") @@ -3275,19 +4835,21 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun definitions_validateDefinitionAgainstMetaschema_invalidDefinitionSchema() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "definitions_validateDefinitionAgainstMetaschema_invalidDefinitionSchema" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"definitions":{"foo":{"type":1}}} + { + "definitions": { + "foo": { + "type": 1 + } + } + } """, """ - {"${'$'}ref":"http://json-schema.org/draft-07/schema#"} + { + "${'$'}ref": "http://json-schema.org/draft-07/schema#" + } """, false, """validate definition against metaschema -> invalid definition schema""") @@ -3301,10 +4863,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> neither""") @@ -3319,10 +4888,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> nondependant""") @@ -3337,10 +4914,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> with dependency""") @@ -3355,10 +4941,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, false, """dependencies -> missing dependency""") @@ -3373,10 +4967,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["bar"] + [ + "bar" + ] """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> ignores arrays""") @@ -3394,7 +4996,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> ignores strings""") @@ -3412,7 +5020,13 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"dependencies":{"bar":["foo"]}} + { + "dependencies": { + "bar": [ + "foo" + ] + } + } """, true, """dependencies -> ignores other non-objects""") @@ -3427,10 +5041,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"dependencies":{"bar":[]}} + { + "dependencies": { + "bar": [ + ] + } + } """, true, """dependencies with empty array -> empty object""") @@ -3445,10 +5065,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"dependencies":{"bar":[]}} + { + "dependencies": { + "bar": [ + ] + } + } """, true, """dependencies with empty array -> object with one property""") @@ -3466,7 +5093,12 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"dependencies":{"bar":[]}} + { + "dependencies": { + "bar": [ + ] + } + } """, true, """dependencies with empty array -> non-object is valid""") @@ -3481,10 +5113,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, true, """multiple dependencies -> neither""") @@ -3499,10 +5139,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, true, """multiple dependencies -> nondependants""") @@ -3517,10 +5167,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"quux":3} + { + "foo": 1, + "bar": 2, + "quux": 3 + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, true, """multiple dependencies -> with dependencies""") @@ -3535,10 +5196,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"quux":2} + { + "foo": 1, + "quux": 2 + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, false, """multiple dependencies -> missing dependency""") @@ -3553,10 +5224,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":1,"quux":2} + { + "bar": 1, + "quux": 2 + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, false, """multiple dependencies -> missing other dependency""") @@ -3571,10 +5252,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"quux":1} + { + "quux": 1 + } """, """ - {"dependencies":{"quux":["foo","bar"]}} + { + "dependencies": { + "quux": [ + "foo", + "bar" + ] + } + } """, false, """multiple dependencies -> missing both dependencies""") @@ -3589,10 +5279,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"dependencies":{"bar":{"properties":{"foo":{"type":"integer"},"bar":{"type":"integer"}}}}} + { + "dependencies": { + "bar": { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "integer" + } + } + } + } + } """, true, """multiple dependencies subschema -> valid""") @@ -3607,10 +5313,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux"} + { + "foo": "quux" + } """, """ - {"dependencies":{"bar":{"properties":{"foo":{"type":"integer"},"bar":{"type":"integer"}}}}} + { + "dependencies": { + "bar": { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "integer" + } + } + } + } + } """, true, """multiple dependencies subschema -> no dependency""") @@ -3625,10 +5346,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux","bar":2} + { + "foo": "quux", + "bar": 2 + } """, """ - {"dependencies":{"bar":{"properties":{"foo":{"type":"integer"},"bar":{"type":"integer"}}}}} + { + "dependencies": { + "bar": { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "integer" + } + } + } + } + } """, false, """multiple dependencies subschema -> wrong type""") @@ -3643,10 +5380,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":2,"bar":"quux"} + { + "foo": 2, + "bar": "quux" + } """, """ - {"dependencies":{"bar":{"properties":{"foo":{"type":"integer"},"bar":{"type":"integer"}}}}} + { + "dependencies": { + "bar": { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "integer" + } + } + } + } + } """, false, """multiple dependencies subschema -> wrong type other""") @@ -3661,10 +5414,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"quux","bar":"quux"} + { + "foo": "quux", + "bar": "quux" + } """, """ - {"dependencies":{"bar":{"properties":{"foo":{"type":"integer"},"bar":{"type":"integer"}}}}} + { + "dependencies": { + "bar": { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "integer" + } + } + } + } + } """, false, """multiple dependencies subschema -> wrong type both""") @@ -3679,10 +5448,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"dependencies":{"foo":true,"bar":false}} + { + "dependencies": { + "foo": true, + "bar": false + } + } """, true, """dependencies with boolean subschemas -> object with property having schema true is valid""") @@ -3697,10 +5473,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"dependencies":{"foo":true,"bar":false}} + { + "dependencies": { + "foo": true, + "bar": false + } + } """, false, """dependencies with boolean subschemas -> object with property having schema false is invalid""") @@ -3715,10 +5498,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"dependencies":{"foo":true,"bar":false}} + { + "dependencies": { + "foo": true, + "bar": false + } + } """, false, """dependencies with boolean subschemas -> object with both properties is invalid""") @@ -3733,10 +5524,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"dependencies":{"foo":true,"bar":false}} + { + "dependencies": { + "foo": true, + "bar": false + } + } """, true, """dependencies with boolean subschemas -> empty object is valid""") @@ -3751,10 +5548,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":1,"foo\rbar":2} + { + "foo\nbar": 1, + "foo\rbar": 2 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, true, """dependencies with escaped characters -> valid object 1""") @@ -3769,10 +5586,32 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\tbar":1,"a":2,"b":3,"c":4} + { + "foo\tbar": 1, + "a": 2, + "b": 3, + "c": 4 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, true, """dependencies with escaped characters -> valid object 2""") @@ -3787,10 +5626,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo'bar":1,"foo\"bar":2} + { + "foo'bar": 1, + "foo\"bar": 2 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, true, """dependencies with escaped characters -> valid object 3""") @@ -3805,10 +5664,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":1,"foo":2} + { + "foo\nbar": 1, + "foo": 2 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, false, """dependencies with escaped characters -> invalid object 1""") @@ -3823,10 +5702,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\tbar":1,"a":2} + { + "foo\tbar": 1, + "a": 2 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, false, """dependencies with escaped characters -> invalid object 2""") @@ -3841,10 +5740,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo'bar":1} + { + "foo'bar": 1 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, false, """dependencies with escaped characters -> invalid object 3""") @@ -3859,10 +5777,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\"bar":2} + { + "foo\"bar": 2 + } """, """ - {"dependencies":{"foo\nbar":["foo\rbar"],"foo\tbar":{"minProperties":4},"foo'bar":{"required":["foo\"bar"]},"foo\"bar":["foo'bar"]}} + { + "dependencies": { + "foo\nbar": [ + "foo\rbar" + ], + "foo\tbar": { + "minProperties": 4 + }, + "foo'bar": { + "required": [ + "foo\"bar" + ] + }, + "foo\"bar": [ + "foo'bar" + ] + } + } """, false, """dependencies with escaped characters -> invalid object 4""") @@ -3877,10 +5814,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"properties":{"foo":{}},"dependencies":{"foo":{"properties":{"bar":{}},"additionalProperties":false}}} + { + "properties": { + "foo": { + } + }, + "dependencies": { + "foo": { + "properties": { + "bar": { + } + }, + "additionalProperties": false + } + } + } """, false, """dependent subschema incompatible with root -> matches root""") @@ -3895,10 +5848,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":1} + { + "bar": 1 + } """, """ - {"properties":{"foo":{}},"dependencies":{"foo":{"properties":{"bar":{}},"additionalProperties":false}}} + { + "properties": { + "foo": { + } + }, + "dependencies": { + "foo": { + "properties": { + "bar": { + } + }, + "additionalProperties": false + } + } + } """, true, """dependent subschema incompatible with root -> matches dependency""") @@ -3913,10 +5882,27 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"properties":{"foo":{}},"dependencies":{"foo":{"properties":{"bar":{}},"additionalProperties":false}}} + { + "properties": { + "foo": { + } + }, + "dependencies": { + "foo": { + "properties": { + "bar": { + } + }, + "additionalProperties": false + } + } + } """, false, """dependent subschema incompatible with root -> matches both""") @@ -3931,10 +5917,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"baz":1} + { + "baz": 1 + } """, """ - {"properties":{"foo":{}},"dependencies":{"foo":{"properties":{"bar":{}},"additionalProperties":false}}} + { + "properties": { + "foo": { + } + }, + "dependencies": { + "foo": { + "properties": { + "bar": { + } + }, + "additionalProperties": false + } + } + } """, true, """dependent subschema incompatible with root -> no dependency""") @@ -3951,7 +5953,13 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"enum":[1,2,3]} + { + "enum": [ + 1, + 2, + 3 + ] + } """, true, """simple enum validation -> one of the enum is valid""") @@ -3969,7 +5977,13 @@ class SchemaSuiteTest : JsonSchemaTest { 4 """, """ - {"enum":[1,2,3]} + { + "enum": [ + 1, + 2, + 3 + ] + } """, false, """simple enum validation -> something else is invalid""") @@ -3984,10 +5998,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"enum":[6,"foo",[],true,{"foo":12}]} + { + "enum": [ + 6, + "foo", + [ + ], + true, + { + "foo": 12 + } + ] + } """, true, """heterogeneous enum validation -> one of the enum is valid""") @@ -4005,7 +6031,18 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"enum":[6,"foo",[],true,{"foo":12}]} + { + "enum": [ + 6, + "foo", + [ + ], + true, + { + "foo": 12 + } + ] + } """, false, """heterogeneous enum validation -> something else is invalid""") @@ -4020,10 +6057,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":false} + { + "foo": false + } """, """ - {"enum":[6,"foo",[],true,{"foo":12}]} + { + "enum": [ + 6, + "foo", + [ + ], + true, + { + "foo": 12 + } + ] + } """, false, """heterogeneous enum validation -> objects are deep compared""") @@ -4038,10 +6088,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"enum":[6,"foo",[],true,{"foo":12}]} + { + "enum": [ + 6, + "foo", + [ + ], + true, + { + "foo": 12 + } + ] + } """, true, """heterogeneous enum validation -> valid object matches""") @@ -4056,10 +6119,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":12,"boo":42} + { + "foo": 12, + "boo": 42 + } """, """ - {"enum":[6,"foo",[],true,{"foo":12}]} + { + "enum": [ + 6, + "foo", + [ + ], + true, + { + "foo": 12 + } + ] + } """, false, """heterogeneous enum validation -> extra properties in object is invalid""") @@ -4077,7 +6154,12 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"enum":[6,null]} + { + "enum": [ + 6, + null + ] + } """, true, """heterogeneous enum-with-null validation -> null is valid""") @@ -4095,7 +6177,12 @@ class SchemaSuiteTest : JsonSchemaTest { 6 """, """ - {"enum":[6,null]} + { + "enum": [ + 6, + null + ] + } """, true, """heterogeneous enum-with-null validation -> number is valid""") @@ -4113,7 +6200,12 @@ class SchemaSuiteTest : JsonSchemaTest { "test" """, """ - {"enum":[6,null]} + { + "enum": [ + 6, + null + ] + } """, false, """heterogeneous enum-with-null validation -> something else is invalid""") @@ -4128,10 +6220,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foo","bar":"bar"} + { + "foo": "foo", + "bar": "bar" + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, true, """enums in properties -> both properties are valid""") @@ -4146,10 +6258,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foot","bar":"bar"} + { + "foo": "foot", + "bar": "bar" + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, false, """enums in properties -> wrong foo value""") @@ -4164,10 +6296,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foo","bar":"bart"} + { + "foo": "foo", + "bar": "bart" + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, false, """enums in properties -> wrong bar value""") @@ -4182,10 +6334,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":"bar"} + { + "bar": "bar" + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, true, """enums in properties -> missing optional property is valid""") @@ -4200,10 +6371,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foo"} + { + "foo": "foo" + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, false, """enums in properties -> missing required property is invalid""") @@ -4218,10 +6408,28 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"object","properties":{"foo":{"enum":["foo"]},"bar":{"enum":["bar"]}},"required":["bar"]} + { + "type": "object", + "properties": { + "foo": { + "enum": [ + "foo" + ] + }, + "bar": { + "enum": [ + "bar" + ] + } + }, + "required": [ + "bar" + ] + } """, false, """enums in properties -> missing all properties is invalid""") @@ -4239,7 +6447,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo\nbar" """, """ - {"enum":["foo\nbar","foo\rbar"]} + { + "enum": [ + "foo\nbar", + "foo\rbar" + ] + } """, true, """enum with escaped characters -> member 1 is valid""") @@ -4257,7 +6470,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo\rbar" """, """ - {"enum":["foo\nbar","foo\rbar"]} + { + "enum": [ + "foo\nbar", + "foo\rbar" + ] + } """, true, """enum with escaped characters -> member 2 is valid""") @@ -4275,7 +6493,12 @@ class SchemaSuiteTest : JsonSchemaTest { "abc" """, """ - {"enum":["foo\nbar","foo\rbar"]} + { + "enum": [ + "foo\nbar", + "foo\rbar" + ] + } """, false, """enum with escaped characters -> another string is invalid""") @@ -4293,7 +6516,11 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"enum":[false]} + { + "enum": [ + false + ] + } """, true, """enum with false does not match 0 -> false is valid""") @@ -4311,7 +6538,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"enum":[false]} + { + "enum": [ + false + ] + } """, false, """enum with false does not match 0 -> integer zero is invalid""") @@ -4329,7 +6560,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0.0 """, """ - {"enum":[false]} + { + "enum": [ + false + ] + } """, false, """enum with false does not match 0 -> float zero is invalid""") @@ -4344,10 +6579,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false] + [ + false + ] """, """ - {"enum":[[false]]} + { + "enum": [ + [ + false + ] + ] + } """, true, """enum with [false] does not match [0] -> [false] is valid""") @@ -4362,10 +6605,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0] + [ + 0 + ] """, """ - {"enum":[[false]]} + { + "enum": [ + [ + false + ] + ] + } """, false, """enum with [false] does not match [0] -> [0] is invalid""") @@ -4380,10 +6631,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0.0] + [ + 0.0 + ] """, """ - {"enum":[[false]]} + { + "enum": [ + [ + false + ] + ] + } """, false, """enum with [false] does not match [0] -> [0.0] is invalid""") @@ -4401,7 +6660,11 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"enum":[true]} + { + "enum": [ + true + ] + } """, true, """enum with true does not match 1 -> true is valid""") @@ -4419,7 +6682,11 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"enum":[true]} + { + "enum": [ + true + ] + } """, false, """enum with true does not match 1 -> integer one is invalid""") @@ -4437,7 +6704,11 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"enum":[true]} + { + "enum": [ + true + ] + } """, false, """enum with true does not match 1 -> float one is invalid""") @@ -4452,10 +6723,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true] + [ + true + ] """, """ - {"enum":[[true]]} + { + "enum": [ + [ + true + ] + ] + } """, true, """enum with [true] does not match [1] -> [true] is valid""") @@ -4470,10 +6749,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"enum":[[true]]} + { + "enum": [ + [ + true + ] + ] + } """, false, """enum with [true] does not match [1] -> [1] is invalid""") @@ -4488,10 +6775,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1.0] + [ + 1.0 + ] """, """ - {"enum":[[true]]} + { + "enum": [ + [ + true + ] + ] + } """, false, """enum with [true] does not match [1] -> [1.0] is invalid""") @@ -4509,7 +6804,11 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"enum":[0]} + { + "enum": [ + 0 + ] + } """, false, """enum with 0 does not match false -> false is invalid""") @@ -4527,7 +6826,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"enum":[0]} + { + "enum": [ + 0 + ] + } """, true, """enum with 0 does not match false -> integer zero is valid""") @@ -4545,7 +6848,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0.0 """, """ - {"enum":[0]} + { + "enum": [ + 0 + ] + } """, true, """enum with 0 does not match false -> float zero is valid""") @@ -4560,10 +6867,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false] + [ + false + ] """, """ - {"enum":[[0]]} + { + "enum": [ + [ + 0 + ] + ] + } """, false, """enum with [0] does not match [false] -> [false] is invalid""") @@ -4578,10 +6893,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0] + [ + 0 + ] """, """ - {"enum":[[0]]} + { + "enum": [ + [ + 0 + ] + ] + } """, true, """enum with [0] does not match [false] -> [0] is valid""") @@ -4596,10 +6919,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0.0] + [ + 0.0 + ] """, """ - {"enum":[[0]]} + { + "enum": [ + [ + 0 + ] + ] + } """, true, """enum with [0] does not match [false] -> [0.0] is valid""") @@ -4617,7 +6948,11 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"enum":[1]} + { + "enum": [ + 1 + ] + } """, false, """enum with 1 does not match true -> true is invalid""") @@ -4635,7 +6970,11 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"enum":[1]} + { + "enum": [ + 1 + ] + } """, true, """enum with 1 does not match true -> integer one is valid""") @@ -4653,7 +6992,11 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"enum":[1]} + { + "enum": [ + 1 + ] + } """, true, """enum with 1 does not match true -> float one is valid""") @@ -4668,10 +7011,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true] + [ + true + ] """, """ - {"enum":[[1]]} + { + "enum": [ + [ + 1 + ] + ] + } """, false, """enum with [1] does not match [true] -> [true] is invalid""") @@ -4686,10 +7037,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"enum":[[1]]} + { + "enum": [ + [ + 1 + ] + ] + } """, true, """enum with [1] does not match [true] -> [1] is valid""") @@ -4704,10 +7063,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1.0] + [ + 1.0 + ] """, """ - {"enum":[[1]]} + { + "enum": [ + [ + 1 + ] + ] + } """, true, """enum with [1] does not match [true] -> [1.0] is valid""") @@ -4725,7 +7092,11 @@ class SchemaSuiteTest : JsonSchemaTest { "hello\u0000there" """, """ - {"enum":["hello\u0000there"]} + { + "enum": [ + "hello\u0000there" + ] + } """, true, """nul characters in strings -> match string with nul""") @@ -4743,7 +7114,11 @@ class SchemaSuiteTest : JsonSchemaTest { "hellothere" """, """ - {"enum":["hello\u0000there"]} + { + "enum": [ + "hello\u0000there" + ] + } """, false, """nul characters in strings -> do not match string lacking nul""") @@ -4760,7 +7135,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2.2 """, """ - {"exclusiveMaximum":3.0} + { + "exclusiveMaximum": 3.0 + } """, true, """exclusiveMaximum validation -> below the exclusiveMaximum is valid""") @@ -4778,7 +7155,9 @@ class SchemaSuiteTest : JsonSchemaTest { 3.0 """, """ - {"exclusiveMaximum":3.0} + { + "exclusiveMaximum": 3.0 + } """, false, """exclusiveMaximum validation -> boundary point is invalid""") @@ -4796,7 +7175,9 @@ class SchemaSuiteTest : JsonSchemaTest { 3.5 """, """ - {"exclusiveMaximum":3.0} + { + "exclusiveMaximum": 3.0 + } """, false, """exclusiveMaximum validation -> above the exclusiveMaximum is invalid""") @@ -4814,7 +7195,9 @@ class SchemaSuiteTest : JsonSchemaTest { "x" """, """ - {"exclusiveMaximum":3.0} + { + "exclusiveMaximum": 3.0 + } """, true, """exclusiveMaximum validation -> ignores non-numbers""") @@ -4831,7 +7214,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.2 """, """ - {"exclusiveMinimum":1.1} + { + "exclusiveMinimum": 1.1 + } """, true, """exclusiveMinimum validation -> above the exclusiveMinimum is valid""") @@ -4849,7 +7234,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"exclusiveMinimum":1.1} + { + "exclusiveMinimum": 1.1 + } """, false, """exclusiveMinimum validation -> boundary point is invalid""") @@ -4867,7 +7254,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.6 """, """ - {"exclusiveMinimum":1.1} + { + "exclusiveMinimum": 1.1 + } """, false, """exclusiveMinimum validation -> below the exclusiveMinimum is invalid""") @@ -4885,7 +7274,9 @@ class SchemaSuiteTest : JsonSchemaTest { "x" """, """ - {"exclusiveMinimum":1.1} + { + "exclusiveMinimum": 1.1 + } """, true, """exclusiveMinimum validation -> ignores non-numbers""") @@ -4902,7 +7293,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore integers""") @@ -4920,7 +7313,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore floats""") @@ -4935,10 +7330,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore objects""") @@ -4953,10 +7351,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore arrays""") @@ -4974,7 +7375,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore booleans""") @@ -4992,7 +7395,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"email"} + { + "format": "email" + } """, true, """email format -> all string formats ignore nulls""") @@ -5010,7 +7415,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore integers""") @@ -5028,7 +7435,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore floats""") @@ -5043,10 +7452,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore objects""") @@ -5061,10 +7473,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore arrays""") @@ -5082,7 +7497,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore booleans""") @@ -5100,7 +7517,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"idn-email"} + { + "format": "idn-email" + } """, true, """idn-email format -> all string formats ignore nulls""") @@ -5118,7 +7537,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore integers""") @@ -5136,7 +7557,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore floats""") @@ -5151,10 +7574,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore objects""") @@ -5169,10 +7595,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore arrays""") @@ -5190,7 +7619,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore booleans""") @@ -5208,7 +7639,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"regex"} + { + "format": "regex" + } """, true, """regex format -> all string formats ignore nulls""") @@ -5226,7 +7659,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore integers""") @@ -5244,7 +7679,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore floats""") @@ -5259,10 +7696,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore objects""") @@ -5277,10 +7717,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore arrays""") @@ -5298,7 +7741,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore booleans""") @@ -5316,7 +7761,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"ipv4"} + { + "format": "ipv4" + } """, true, """ipv4 format -> all string formats ignore nulls""") @@ -5334,7 +7781,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore integers""") @@ -5352,7 +7801,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore floats""") @@ -5367,10 +7818,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore objects""") @@ -5385,10 +7839,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore arrays""") @@ -5406,7 +7863,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore booleans""") @@ -5424,7 +7883,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"ipv6"} + { + "format": "ipv6" + } """, true, """ipv6 format -> all string formats ignore nulls""") @@ -5442,7 +7903,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore integers""") @@ -5460,7 +7923,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore floats""") @@ -5475,10 +7940,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore objects""") @@ -5493,10 +7961,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore arrays""") @@ -5514,7 +7985,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore booleans""") @@ -5532,7 +8005,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"idn-hostname"} + { + "format": "idn-hostname" + } """, true, """idn-hostname format -> all string formats ignore nulls""") @@ -5550,7 +8025,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore integers""") @@ -5568,7 +8045,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore floats""") @@ -5583,10 +8062,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore objects""") @@ -5601,10 +8083,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore arrays""") @@ -5622,7 +8107,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore booleans""") @@ -5640,7 +8127,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"hostname"} + { + "format": "hostname" + } """, true, """hostname format -> all string formats ignore nulls""") @@ -5658,7 +8147,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore integers""") @@ -5676,7 +8167,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore floats""") @@ -5691,10 +8184,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore objects""") @@ -5709,10 +8205,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore arrays""") @@ -5730,7 +8229,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore booleans""") @@ -5748,7 +8249,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"date"} + { + "format": "date" + } """, true, """date format -> all string formats ignore nulls""") @@ -5766,7 +8269,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore integers""") @@ -5784,7 +8289,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore floats""") @@ -5799,10 +8306,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore objects""") @@ -5817,10 +8327,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore arrays""") @@ -5838,7 +8351,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore booleans""") @@ -5856,7 +8371,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"date-time"} + { + "format": "date-time" + } """, true, """date-time format -> all string formats ignore nulls""") @@ -5874,7 +8391,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore integers""") @@ -5892,7 +8411,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore floats""") @@ -5907,10 +8428,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore objects""") @@ -5925,10 +8449,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore arrays""") @@ -5946,7 +8473,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore booleans""") @@ -5964,7 +8493,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"time"} + { + "format": "time" + } """, true, """time format -> all string formats ignore nulls""") @@ -5982,7 +8513,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore integers""") @@ -6000,7 +8533,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore floats""") @@ -6015,10 +8550,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore objects""") @@ -6033,10 +8571,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore arrays""") @@ -6054,7 +8595,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore booleans""") @@ -6072,7 +8615,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"json-pointer"} + { + "format": "json-pointer" + } """, true, """json-pointer format -> all string formats ignore nulls""") @@ -6090,7 +8635,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore integers""") @@ -6108,7 +8655,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore floats""") @@ -6123,10 +8672,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore objects""") @@ -6141,10 +8693,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore arrays""") @@ -6162,7 +8717,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore booleans""") @@ -6180,7 +8737,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"relative-json-pointer"} + { + "format": "relative-json-pointer" + } """, true, """relative-json-pointer format -> all string formats ignore nulls""") @@ -6198,7 +8757,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore integers""") @@ -6216,7 +8777,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore floats""") @@ -6231,10 +8794,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore objects""") @@ -6249,10 +8815,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore arrays""") @@ -6270,7 +8839,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore booleans""") @@ -6288,7 +8859,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"iri"} + { + "format": "iri" + } """, true, """iri format -> all string formats ignore nulls""") @@ -6306,7 +8879,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore integers""") @@ -6324,7 +8899,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore floats""") @@ -6339,10 +8916,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore objects""") @@ -6357,10 +8937,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore arrays""") @@ -6378,7 +8961,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore booleans""") @@ -6396,7 +8981,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"iri-reference"} + { + "format": "iri-reference" + } """, true, """iri-reference format -> all string formats ignore nulls""") @@ -6414,7 +9001,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore integers""") @@ -6432,7 +9021,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore floats""") @@ -6447,10 +9038,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore objects""") @@ -6465,10 +9059,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore arrays""") @@ -6486,7 +9083,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore booleans""") @@ -6504,7 +9103,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"uri"} + { + "format": "uri" + } """, true, """uri format -> all string formats ignore nulls""") @@ -6522,7 +9123,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore integers""") @@ -6540,7 +9143,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore floats""") @@ -6555,10 +9160,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore objects""") @@ -6573,10 +9181,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore arrays""") @@ -6594,7 +9205,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore booleans""") @@ -6612,7 +9225,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"uri-reference"} + { + "format": "uri-reference" + } """, true, """uri-reference format -> all string formats ignore nulls""") @@ -6630,7 +9245,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore integers""") @@ -6648,7 +9265,9 @@ class SchemaSuiteTest : JsonSchemaTest { 13.7 """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore floats""") @@ -6663,10 +9282,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore objects""") @@ -6681,10 +9303,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore arrays""") @@ -6702,7 +9327,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore booleans""") @@ -6720,7 +9347,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"format":"uri-template"} + { + "format": "uri-template" + } """, true, """uri-template format -> all string formats ignore nulls""") @@ -6737,7 +9366,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"if":{"const":0}} + { + "if": { + "const": 0 + } + } """, true, """ignore if without then or else -> valid when valid against lone if""") @@ -6755,7 +9388,11 @@ class SchemaSuiteTest : JsonSchemaTest { "hello" """, """ - {"if":{"const":0}} + { + "if": { + "const": 0 + } + } """, true, """ignore if without then or else -> valid when invalid against lone if""") @@ -6773,7 +9410,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"then":{"const":0}} + { + "then": { + "const": 0 + } + } """, true, """ignore then without if -> valid when valid against lone then""") @@ -6791,7 +9432,11 @@ class SchemaSuiteTest : JsonSchemaTest { "hello" """, """ - {"then":{"const":0}} + { + "then": { + "const": 0 + } + } """, true, """ignore then without if -> valid when invalid against lone then""") @@ -6809,7 +9454,11 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"else":{"const":0}} + { + "else": { + "const": 0 + } + } """, true, """ignore else without if -> valid when valid against lone else""") @@ -6827,7 +9476,11 @@ class SchemaSuiteTest : JsonSchemaTest { "hello" """, """ - {"else":{"const":0}} + { + "else": { + "const": 0 + } + } """, true, """ignore else without if -> valid when invalid against lone else""") @@ -6845,7 +9498,14 @@ class SchemaSuiteTest : JsonSchemaTest { -1 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + } + } """, true, """if and then without else -> valid through then""") @@ -6863,7 +9523,14 @@ class SchemaSuiteTest : JsonSchemaTest { -100 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + } + } """, false, """if and then without else -> invalid through then""") @@ -6881,7 +9548,14 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + } + } """, true, """if and then without else -> valid when if test fails""") @@ -6899,7 +9573,14 @@ class SchemaSuiteTest : JsonSchemaTest { -1 """, """ - {"if":{"exclusiveMaximum":0},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "else": { + "multipleOf": 2 + } + } """, true, """if and else without then -> valid when if test passes""") @@ -6917,7 +9598,14 @@ class SchemaSuiteTest : JsonSchemaTest { 4 """, """ - {"if":{"exclusiveMaximum":0},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "else": { + "multipleOf": 2 + } + } """, true, """if and else without then -> valid through else""") @@ -6935,7 +9623,14 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"if":{"exclusiveMaximum":0},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "else": { + "multipleOf": 2 + } + } """, false, """if and else without then -> invalid through else""") @@ -6953,7 +9648,17 @@ class SchemaSuiteTest : JsonSchemaTest { -1 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + }, + "else": { + "multipleOf": 2 + } + } """, true, """validate against correct branch, then vs else -> valid through then""") @@ -6971,7 +9676,17 @@ class SchemaSuiteTest : JsonSchemaTest { -100 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + }, + "else": { + "multipleOf": 2 + } + } """, false, """validate against correct branch, then vs else -> invalid through then""") @@ -6989,7 +9704,17 @@ class SchemaSuiteTest : JsonSchemaTest { 4 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + }, + "else": { + "multipleOf": 2 + } + } """, true, """validate against correct branch, then vs else -> valid through else""") @@ -7007,7 +9732,17 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"if":{"exclusiveMaximum":0},"then":{"minimum":-10},"else":{"multipleOf":2}} + { + "if": { + "exclusiveMaximum": 0 + }, + "then": { + "minimum": -10 + }, + "else": { + "multipleOf": 2 + } + } """, false, """validate against correct branch, then vs else -> invalid through else""") @@ -7025,7 +9760,25 @@ class SchemaSuiteTest : JsonSchemaTest { -100 """, """ - {"allOf":[{"if":{"exclusiveMaximum":0}},{"then":{"minimum":-10}},{"else":{"multipleOf":2}}]} + { + "allOf": [ + { + "if": { + "exclusiveMaximum": 0 + } + }, + { + "then": { + "minimum": -10 + } + }, + { + "else": { + "multipleOf": 2 + } + } + ] + } """, true, """non-interference across combined schemas -> valid, but would have been invalid through then""") @@ -7043,7 +9796,25 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"allOf":[{"if":{"exclusiveMaximum":0}},{"then":{"minimum":-10}},{"else":{"multipleOf":2}}]} + { + "allOf": [ + { + "if": { + "exclusiveMaximum": 0 + } + }, + { + "then": { + "minimum": -10 + } + }, + { + "else": { + "multipleOf": 2 + } + } + ] + } """, true, """non-interference across combined schemas -> valid, but would have been invalid through else""") @@ -7061,7 +9832,15 @@ class SchemaSuiteTest : JsonSchemaTest { "then" """, """ - {"if":true,"then":{"const":"then"},"else":{"const":"else"}} + { + "if": true, + "then": { + "const": "then" + }, + "else": { + "const": "else" + } + } """, true, """if with boolean schema true -> boolean schema true in if always chooses the then path (valid)""") @@ -7079,7 +9858,15 @@ class SchemaSuiteTest : JsonSchemaTest { "else" """, """ - {"if":true,"then":{"const":"then"},"else":{"const":"else"}} + { + "if": true, + "then": { + "const": "then" + }, + "else": { + "const": "else" + } + } """, false, """if with boolean schema true -> boolean schema true in if always chooses the then path (invalid)""") @@ -7097,7 +9884,15 @@ class SchemaSuiteTest : JsonSchemaTest { "then" """, """ - {"if":false,"then":{"const":"then"},"else":{"const":"else"}} + { + "if": false, + "then": { + "const": "then" + }, + "else": { + "const": "else" + } + } """, false, """if with boolean schema false -> boolean schema false in if always chooses the else path (invalid)""") @@ -7115,7 +9910,15 @@ class SchemaSuiteTest : JsonSchemaTest { "else" """, """ - {"if":false,"then":{"const":"then"},"else":{"const":"else"}} + { + "if": false, + "then": { + "const": "then" + }, + "else": { + "const": "else" + } + } """, true, """if with boolean schema false -> boolean schema false in if always chooses the else path (valid)""") @@ -7133,7 +9936,17 @@ class SchemaSuiteTest : JsonSchemaTest { "yes" """, """ - {"then":{"const":"yes"},"else":{"const":"other"},"if":{"maxLength":4}} + { + "then": { + "const": "yes" + }, + "else": { + "const": "other" + }, + "if": { + "maxLength": 4 + } + } """, true, """if appears at the end when serialized (keyword processing sequence) -> yes redirects to then and passes""") @@ -7151,7 +9964,17 @@ class SchemaSuiteTest : JsonSchemaTest { "other" """, """ - {"then":{"const":"yes"},"else":{"const":"other"},"if":{"maxLength":4}} + { + "then": { + "const": "yes" + }, + "else": { + "const": "other" + }, + "if": { + "maxLength": 4 + } + } """, true, """if appears at the end when serialized (keyword processing sequence) -> other redirects to else and passes""") @@ -7169,7 +9992,17 @@ class SchemaSuiteTest : JsonSchemaTest { "no" """, """ - {"then":{"const":"yes"},"else":{"const":"other"},"if":{"maxLength":4}} + { + "then": { + "const": "yes" + }, + "else": { + "const": "other" + }, + "if": { + "maxLength": 4 + } + } """, false, """if appears at the end when serialized (keyword processing sequence) -> no redirects to then and fails""") @@ -7187,7 +10020,17 @@ class SchemaSuiteTest : JsonSchemaTest { "invalid" """, """ - {"then":{"const":"yes"},"else":{"const":"other"},"if":{"maxLength":4}} + { + "then": { + "const": "yes" + }, + "else": { + "const": "other" + }, + "if": { + "maxLength": 4 + } + } """, false, """if appears at the end when serialized (keyword processing sequence) -> invalid redirects to else and fails""") @@ -7198,19 +10041,35 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_passingCase() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_passingCase" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"definitions":{"int":{"type":"integer"}},"allOf":[{"properties":{"foo":{"${'$'}ref":"#/definitions/int"}}},{"additionalProperties":{"${'$'}ref":"#/definitions/int"}}]} + { + "definitions": { + "int": { + "type": "integer" + } + }, + "allOf": [ + { + "properties": { + "foo": { + "${'$'}ref": "#/definitions/int" + } + } + }, + { + "additionalProperties": { + "${'$'}ref": "#/definitions/int" + } + } + ] + } """, true, """evaluating the same schema location against the same data location twice is not a sign of an infinite loop -> passing case""") @@ -7222,19 +10081,35 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_failingCase() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "infinite_loop_detection_evaluatingTheSameSchemaLocationAgainstTheSameDataLocationTwiceIsNotASignOfAnInfiniteLoop_failingCase" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"a string"} + { + "foo": "a string" + } """, """ - {"definitions":{"int":{"type":"integer"}},"allOf":[{"properties":{"foo":{"${'$'}ref":"#/definitions/int"}}},{"additionalProperties":{"${'$'}ref":"#/definitions/int"}}]} + { + "definitions": { + "int": { + "type": "integer" + } + }, + "allOf": [ + { + "properties": { + "foo": { + "${'$'}ref": "#/definitions/int" + } + } + }, + { + "additionalProperties": { + "${'$'}ref": "#/definitions/int" + } + } + ] + } """, false, """evaluating the same schema location against the same data location twice is not a sign of an infinite loop -> failing case""") @@ -7248,10 +10123,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"items":{"type":"integer"}} + { + "items": { + "type": "integer" + } + } """, true, """a schema given for items -> valid items""") @@ -7266,10 +10149,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"x"] + [ + 1, + "x" + ] """, """ - {"items":{"type":"integer"}} + { + "items": { + "type": "integer" + } + } """, false, """a schema given for items -> wrong type of items""") @@ -7284,10 +10174,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"items":{"type":"integer"}} + { + "items": { + "type": "integer" + } + } """, true, """a schema given for items -> ignores non-arrays""") @@ -7302,10 +10198,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"0":"invalid","length":1} + { + "0": "invalid", + "length": 1 + } """, """ - {"items":{"type":"integer"}} + { + "items": { + "type": "integer" + } + } """, true, """a schema given for items -> JavaScript pseudo-array is valid""") @@ -7320,10 +10223,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo"] + [ + 1, + "foo" + ] """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, true, """an array of schemas for items -> correct types""") @@ -7338,10 +10253,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo",1] + [ + "foo", + 1 + ] """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, false, """an array of schemas for items -> wrong types""") @@ -7356,10 +10283,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, true, """an array of schemas for items -> incomplete array of items""") @@ -7374,10 +10312,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo",true] + [ + 1, + "foo", + true + ] """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, true, """an array of schemas for items -> array with additional items""") @@ -7392,10 +10343,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, true, """an array of schemas for items -> empty array""") @@ -7410,10 +10371,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"0":"invalid","1":"valid","length":2} + { + "0": "invalid", + "1": "valid", + "length": 2 + } """, """ - {"items":[{"type":"integer"},{"type":"string"}]} + { + "items": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } """, true, """an array of schemas for items -> JavaScript pseudo-array is valid""") @@ -7428,10 +10402,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo",true] + [ + 1, + "foo", + true + ] """, """ - {"items":true} + { + "items": true + } """, true, """items with boolean schema (true) -> any array is valid""") @@ -7446,10 +10426,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"items":true} + { + "items": true + } """, true, """items with boolean schema (true) -> empty array is valid""") @@ -7464,10 +10447,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo",true] + [ + 1, + "foo", + true + ] """, """ - {"items":false} + { + "items": false + } """, false, """items with boolean schema (false) -> any non-empty array is invalid""") @@ -7482,10 +10471,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"items":false} + { + "items": false + } """, true, """items with boolean schema (false) -> empty array is valid""") @@ -7500,10 +10492,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"items":[true,false]} + { + "items": [ + true, + false + ] + } """, true, """items with boolean schemas -> array with one item is valid""") @@ -7518,10 +10517,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,"foo"] + [ + 1, + "foo" + ] """, """ - {"items":[true,false]} + { + "items": [ + true, + false + ] + } """, false, """items with boolean schemas -> array with two items is invalid""") @@ -7536,10 +10543,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"items":[true,false]} + { + "items": [ + true, + false + ] + } """, true, """items with boolean schemas -> empty array is valid""") @@ -7551,19 +10564,72 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_validItems() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_validItems" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, true, """items and subitems -> valid items""") @@ -7575,19 +10641,80 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_tooManyItems() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_tooManyItems" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, false, """items and subitems -> too many items""") @@ -7599,19 +10726,75 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_tooManySub_items() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_tooManySub_items" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [[{"foo":null},{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + [ + { + "foo": null + }, + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, false, """items and subitems -> too many sub-items""") @@ -7623,19 +10806,67 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_wrongItem() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_wrongItem" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [{"foo":null},[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + { + "foo": null + }, + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, false, """items and subitems -> wrong item""") @@ -7647,19 +10878,71 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_wrongSub_item() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_wrongSub_item" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [[{},{"foo":null}],[{"foo":null},{"foo":null}],[{"foo":null},{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + [ + { + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ], + [ + { + "foo": null + }, + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, false, """items and subitems -> wrong sub-item""") @@ -7671,19 +10954,58 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun items_itemsAndSubitems_fewerItemsIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "items_itemsAndSubitems_fewerItemsIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [[{"foo":null}],[{"foo":null}]] - """, - """ - {"definitions":{"item":{"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/sub-item"},{"${'$'}ref":"#/definitions/sub-item"}]},"sub-item":{"type":"object","required":["foo"]}},"type":"array","additionalItems":false,"items":[{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"},{"${'$'}ref":"#/definitions/item"}]} + [ + [ + { + "foo": null + } + ], + [ + { + "foo": null + } + ] + ] + """, + """ + { + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/sub-item" + }, + { + "${'$'}ref": "#/definitions/sub-item" + } + ] + }, + "sub-item": { + "type": "object", + "required": [ + "foo" + ] + } + }, + "type": "array", + "additionalItems": false, + "items": [ + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + }, + { + "${'$'}ref": "#/definitions/item" + } + ] + } """, true, """items and subitems -> fewer items is valid""") @@ -7698,10 +11020,53 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[[[1]],[[2],[3]]],[[[4],[5],[6]]]] - """, - """ - {"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"number"}}}}} + [ + [ + [ + [ + 1 + ] + ], + [ + [ + 2 + ], + [ + 3 + ] + ] + ], + [ + [ + [ + 4 + ], + [ + 5 + ], + [ + 6 + ] + ] + ] + ] + """, + """ + { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "number" + } + } + } + } + } """, true, """nested items -> valid nested array""") @@ -7716,10 +11081,53 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[[["1"]],[[2],[3]]],[[[4],[5],[6]]]] - """, - """ - {"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"number"}}}}} + [ + [ + [ + [ + "1" + ] + ], + [ + [ + 2 + ], + [ + 3 + ] + ] + ], + [ + [ + [ + 4 + ], + [ + 5 + ], + [ + 6 + ] + ] + ] + ] + """, + """ + { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "number" + } + } + } + } + } """, false, """nested items -> nested array with invalid type""") @@ -7734,10 +11142,47 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[[1],[2],[3]],[[4],[5],[6]]] - """, - """ - {"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"number"}}}}} + [ + [ + [ + 1 + ], + [ + 2 + ], + [ + 3 + ] + ], + [ + [ + 4 + ], + [ + 5 + ], + [ + 6 + ] + ] + ] + """, + """ + { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "number" + } + } + } + } + } """, false, """nested items -> not deep enough""") @@ -7752,10 +11197,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null] + [ + null + ] """, """ - {"items":{"type":"null"}} + { + "items": { + "type": "null" + } + } """, true, """single-form items with null instance elements -> allows null elements""") @@ -7770,10 +11221,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [null] + [ + null + ] """, """ - {"items":[{"type":"null"}]} + { + "items": [ + { + "type": "null" + } + ] + } """, true, """array-form items with null instance elements -> allows null elements""") @@ -7787,10 +11246,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"maxItems":2} + { + "maxItems": 2 + } """, true, """maxItems validation -> shorter is valid""") @@ -7805,10 +11268,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"maxItems":2} + { + "maxItems": 2 + } """, true, """maxItems validation -> exact length is valid""") @@ -7823,10 +11291,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"maxItems":2} + { + "maxItems": 2 + } """, false, """maxItems validation -> too long is invalid""") @@ -7844,7 +11318,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"maxItems":2} + { + "maxItems": 2 + } """, true, """maxItems validation -> ignores non-arrays""") @@ -7859,10 +11335,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"maxItems":2.0} + { + "maxItems": 2.0 + } """, true, """maxItems validation with a decimal -> shorter is valid""") @@ -7877,10 +11357,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"maxItems":2.0} + { + "maxItems": 2.0 + } """, false, """maxItems validation with a decimal -> too long is invalid""") @@ -7897,7 +11383,9 @@ class SchemaSuiteTest : JsonSchemaTest { "f" """, """ - {"maxLength":2} + { + "maxLength": 2 + } """, true, """maxLength validation -> shorter is valid""") @@ -7915,7 +11403,9 @@ class SchemaSuiteTest : JsonSchemaTest { "fo" """, """ - {"maxLength":2} + { + "maxLength": 2 + } """, true, """maxLength validation -> exact length is valid""") @@ -7933,7 +11423,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"maxLength":2} + { + "maxLength": 2 + } """, false, """maxLength validation -> too long is invalid""") @@ -7951,7 +11443,9 @@ class SchemaSuiteTest : JsonSchemaTest { 100 """, """ - {"maxLength":2} + { + "maxLength": 2 + } """, true, """maxLength validation -> ignores non-strings""") @@ -7969,7 +11463,9 @@ class SchemaSuiteTest : JsonSchemaTest { "💩💩" """, """ - {"maxLength":2} + { + "maxLength": 2 + } """, true, """maxLength validation -> two graphemes is long enough""") @@ -7987,7 +11483,9 @@ class SchemaSuiteTest : JsonSchemaTest { "f" """, """ - {"maxLength":2.0} + { + "maxLength": 2.0 + } """, true, """maxLength validation with a decimal -> shorter is valid""") @@ -8005,7 +11503,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"maxLength":2.0} + { + "maxLength": 2.0 + } """, false, """maxLength validation with a decimal -> too long is invalid""") @@ -8019,10 +11519,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, true, """maxProperties validation -> shorter is valid""") @@ -8037,10 +11541,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, true, """maxProperties validation -> exact length is valid""") @@ -8055,10 +11564,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"baz":3} + { + "foo": 1, + "bar": 2, + "baz": 3 + } """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, false, """maxProperties validation -> too long is invalid""") @@ -8073,10 +11588,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, true, """maxProperties validation -> ignores arrays""") @@ -8094,7 +11615,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, true, """maxProperties validation -> ignores strings""") @@ -8112,7 +11635,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"maxProperties":2} + { + "maxProperties": 2 + } """, true, """maxProperties validation -> ignores other non-objects""") @@ -8127,10 +11652,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"maxProperties":2.0} + { + "maxProperties": 2.0 + } """, true, """maxProperties validation with a decimal -> shorter is valid""") @@ -8145,10 +11674,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"baz":3} + { + "foo": 1, + "bar": 2, + "baz": 3 + } """, """ - {"maxProperties":2.0} + { + "maxProperties": 2.0 + } """, false, """maxProperties validation with a decimal -> too long is invalid""") @@ -8163,10 +11698,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"maxProperties":0} + { + "maxProperties": 0 + } """, true, """maxProperties = 0 means the object is empty -> no properties is valid""") @@ -8181,10 +11719,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"maxProperties":0} + { + "maxProperties": 0 + } """, false, """maxProperties = 0 means the object is empty -> one property is invalid""") @@ -8201,7 +11743,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2.6 """, """ - {"maximum":3.0} + { + "maximum": 3.0 + } """, true, """maximum validation -> below the maximum is valid""") @@ -8219,7 +11763,9 @@ class SchemaSuiteTest : JsonSchemaTest { 3.0 """, """ - {"maximum":3.0} + { + "maximum": 3.0 + } """, true, """maximum validation -> boundary point is valid""") @@ -8237,7 +11783,9 @@ class SchemaSuiteTest : JsonSchemaTest { 3.5 """, """ - {"maximum":3.0} + { + "maximum": 3.0 + } """, false, """maximum validation -> above the maximum is invalid""") @@ -8255,7 +11803,9 @@ class SchemaSuiteTest : JsonSchemaTest { "x" """, """ - {"maximum":3.0} + { + "maximum": 3.0 + } """, true, """maximum validation -> ignores non-numbers""") @@ -8273,7 +11823,9 @@ class SchemaSuiteTest : JsonSchemaTest { 299.97 """, """ - {"maximum":300} + { + "maximum": 300 + } """, true, """maximum validation with unsigned integer -> below the maximum is invalid""") @@ -8291,7 +11843,9 @@ class SchemaSuiteTest : JsonSchemaTest { 300 """, """ - {"maximum":300} + { + "maximum": 300 + } """, true, """maximum validation with unsigned integer -> boundary point integer is valid""") @@ -8306,10 +11860,12 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - 300.00 + 300.0 """, """ - {"maximum":300} + { + "maximum": 300 + } """, true, """maximum validation with unsigned integer -> boundary point float is valid""") @@ -8327,7 +11883,9 @@ class SchemaSuiteTest : JsonSchemaTest { 300.5 """, """ - {"maximum":300} + { + "maximum": 300 + } """, false, """maximum validation with unsigned integer -> above the maximum is invalid""") @@ -8341,10 +11899,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"minItems":1} + { + "minItems": 1 + } """, true, """minItems validation -> longer is valid""") @@ -8359,10 +11922,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1] + [ + 1 + ] """, """ - {"minItems":1} + { + "minItems": 1 + } """, true, """minItems validation -> exact length is valid""") @@ -8377,10 +11944,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"minItems":1} + { + "minItems": 1 + } """, false, """minItems validation -> too short is invalid""") @@ -8398,7 +11968,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"minItems":1} + { + "minItems": 1 + } """, true, """minItems validation -> ignores non-arrays""") @@ -8413,10 +11985,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"minItems":1.0} + { + "minItems": 1.0 + } """, true, """minItems validation with a decimal -> longer is valid""") @@ -8431,10 +12008,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"minItems":1.0} + { + "minItems": 1.0 + } """, false, """minItems validation with a decimal -> too short is invalid""") @@ -8451,7 +12031,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"minLength":2} + { + "minLength": 2 + } """, true, """minLength validation -> longer is valid""") @@ -8469,7 +12051,9 @@ class SchemaSuiteTest : JsonSchemaTest { "fo" """, """ - {"minLength":2} + { + "minLength": 2 + } """, true, """minLength validation -> exact length is valid""") @@ -8487,7 +12071,9 @@ class SchemaSuiteTest : JsonSchemaTest { "f" """, """ - {"minLength":2} + { + "minLength": 2 + } """, false, """minLength validation -> too short is invalid""") @@ -8505,7 +12091,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"minLength":2} + { + "minLength": 2 + } """, true, """minLength validation -> ignores non-strings""") @@ -8523,7 +12111,9 @@ class SchemaSuiteTest : JsonSchemaTest { "💩" """, """ - {"minLength":2} + { + "minLength": 2 + } """, false, """minLength validation -> one grapheme is not long enough""") @@ -8541,7 +12131,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"minLength":2.0} + { + "minLength": 2.0 + } """, true, """minLength validation with a decimal -> longer is valid""") @@ -8559,7 +12151,9 @@ class SchemaSuiteTest : JsonSchemaTest { "f" """, """ - {"minLength":2.0} + { + "minLength": 2.0 + } """, false, """minLength validation with a decimal -> too short is invalid""") @@ -8573,10 +12167,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, true, """minProperties validation -> longer is valid""") @@ -8591,10 +12190,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, true, """minProperties validation -> exact length is valid""") @@ -8609,10 +12212,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, false, """minProperties validation -> too short is invalid""") @@ -8627,10 +12233,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, true, """minProperties validation -> ignores arrays""") @@ -8648,7 +12257,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, true, """minProperties validation -> ignores strings""") @@ -8666,7 +12277,9 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"minProperties":1} + { + "minProperties": 1 + } """, true, """minProperties validation -> ignores other non-objects""") @@ -8681,10 +12294,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"minProperties":1.0} + { + "minProperties": 1.0 + } """, true, """minProperties validation with a decimal -> longer is valid""") @@ -8699,10 +12317,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"minProperties":1.0} + { + "minProperties": 1.0 + } """, false, """minProperties validation with a decimal -> too short is invalid""") @@ -8719,7 +12340,9 @@ class SchemaSuiteTest : JsonSchemaTest { 2.6 """, """ - {"minimum":1.1} + { + "minimum": 1.1 + } """, true, """minimum validation -> above the minimum is valid""") @@ -8737,7 +12360,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"minimum":1.1} + { + "minimum": 1.1 + } """, true, """minimum validation -> boundary point is valid""") @@ -8755,7 +12380,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.6 """, """ - {"minimum":1.1} + { + "minimum": 1.1 + } """, false, """minimum validation -> below the minimum is invalid""") @@ -8773,7 +12400,9 @@ class SchemaSuiteTest : JsonSchemaTest { "x" """, """ - {"minimum":1.1} + { + "minimum": 1.1 + } """, true, """minimum validation -> ignores non-numbers""") @@ -8791,7 +12420,9 @@ class SchemaSuiteTest : JsonSchemaTest { -1 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, true, """minimum validation with signed integer -> negative above the minimum is valid""") @@ -8809,7 +12440,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, true, """minimum validation with signed integer -> positive above the minimum is valid""") @@ -8827,7 +12460,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, true, """minimum validation with signed integer -> boundary point is valid""") @@ -8845,7 +12480,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2.0 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, true, """minimum validation with signed integer -> boundary point with float is valid""") @@ -8863,7 +12500,9 @@ class SchemaSuiteTest : JsonSchemaTest { -2.0001 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, false, """minimum validation with signed integer -> float below the minimum is invalid""") @@ -8881,7 +12520,9 @@ class SchemaSuiteTest : JsonSchemaTest { -3 """, """ - {"minimum":-2} + { + "minimum": -2 + } """, false, """minimum validation with signed integer -> int below the minimum is invalid""") @@ -8899,7 +12540,9 @@ class SchemaSuiteTest : JsonSchemaTest { "x" """, """ - {"minimum":-2} + { + "minimum": -2 + } """, true, """minimum validation with signed integer -> ignores non-numbers""") @@ -8916,7 +12559,9 @@ class SchemaSuiteTest : JsonSchemaTest { 10 """, """ - {"multipleOf":2} + { + "multipleOf": 2 + } """, true, """by int -> int by int""") @@ -8934,7 +12579,9 @@ class SchemaSuiteTest : JsonSchemaTest { 7 """, """ - {"multipleOf":2} + { + "multipleOf": 2 + } """, false, """by int -> int by int fail""") @@ -8952,7 +12599,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"multipleOf":2} + { + "multipleOf": 2 + } """, true, """by int -> ignores non-numbers""") @@ -8970,7 +12619,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"multipleOf":1.5} + { + "multipleOf": 1.5 + } """, true, """by number -> zero is multiple of anything""") @@ -8988,7 +12639,9 @@ class SchemaSuiteTest : JsonSchemaTest { 4.5 """, """ - {"multipleOf":1.5} + { + "multipleOf": 1.5 + } """, true, """by number -> 4.5 is multiple of 1.5""") @@ -9006,7 +12659,9 @@ class SchemaSuiteTest : JsonSchemaTest { 35 """, """ - {"multipleOf":1.5} + { + "multipleOf": 1.5 + } """, false, """by number -> 35 is not multiple of 1.5""") @@ -9024,7 +12679,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.0075 """, """ - {"multipleOf":0.0001} + { + "multipleOf": 1.0E-4 + } """, true, """by small number -> 0.0075 is multiple of 0.0001""") @@ -9042,7 +12699,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0.00751 """, """ - {"multipleOf":0.0001} + { + "multipleOf": 1.0E-4 + } """, false, """by small number -> 0.00751 is not multiple of 0.0001""") @@ -9057,10 +12716,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - 1e308 + 1.0E308 """, """ - {"type":"integer","multipleOf":0.123456789} + { + "type": "integer", + "multipleOf": 0.123456789 + } """, false, """float division = inf -> always invalid, but naive implementations may raise an overflow error""") @@ -9078,7 +12740,10 @@ class SchemaSuiteTest : JsonSchemaTest { 12391239123 """, """ - {"type":"integer","multipleOf":1e-8} + { + "type": "integer", + "multipleOf": 1.0E-8 + } """, true, """small multiple of large integer -> any integer is a multiple of 1e-8""") @@ -9095,7 +12760,11 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":{"type":"integer"}} + { + "not": { + "type": "integer" + } + } """, true, """not -> allowed""") @@ -9113,7 +12782,11 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":{"type":"integer"}} + { + "not": { + "type": "integer" + } + } """, false, """not -> disallowed""") @@ -9131,7 +12804,14 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":{"type":["integer","boolean"]}} + { + "not": { + "type": [ + "integer", + "boolean" + ] + } + } """, true, """not multiple types -> valid""") @@ -9149,7 +12829,14 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":{"type":["integer","boolean"]}} + { + "not": { + "type": [ + "integer", + "boolean" + ] + } + } """, false, """not multiple types -> mismatch""") @@ -9167,7 +12854,14 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"not":{"type":["integer","boolean"]}} + { + "not": { + "type": [ + "integer", + "boolean" + ] + } + } """, false, """not multiple types -> other mismatch""") @@ -9185,7 +12879,16 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":{"type":"object","properties":{"foo":{"type":"string"}}}} + { + "not": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + } + } """, true, """not more complex schema -> match""") @@ -9200,10 +12903,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"not":{"type":"object","properties":{"foo":{"type":"string"}}}} + { + "not": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + } + } """, true, """not more complex schema -> other match""") @@ -9218,10 +12932,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"not":{"type":"object","properties":{"foo":{"type":"string"}}}} + { + "not": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + } + } """, false, """not more complex schema -> mismatch""") @@ -9236,10 +12961,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"properties":{"foo":{"not":{}}}} + { + "properties": { + "foo": { + "not": { + } + } + } + } """, false, """forbidden property -> property present""") @@ -9254,10 +12989,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":1,"baz":2} + { + "bar": 1, + "baz": 2 + } """, """ - {"properties":{"foo":{"not":{}}}} + { + "properties": { + "foo": { + "not": { + } + } + } + } """, true, """forbidden property -> property absent""") @@ -9275,7 +13020,10 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> number is invalid""") @@ -9293,7 +13041,10 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> string is invalid""") @@ -9311,7 +13062,10 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> boolean true is invalid""") @@ -9329,7 +13083,10 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> boolean false is invalid""") @@ -9347,7 +13104,10 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> null is invalid""") @@ -9362,10 +13122,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> object is invalid""") @@ -9380,10 +13145,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> empty object is invalid""") @@ -9398,10 +13167,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> array is invalid""") @@ -9416,10 +13190,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"not":{}} + { + "not": { + } + } """, false, """forbid everything with empty schema -> empty array is invalid""") @@ -9437,7 +13215,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> number is invalid""") @@ -9455,7 +13235,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> string is invalid""") @@ -9473,7 +13255,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> boolean true is invalid""") @@ -9491,7 +13275,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> boolean false is invalid""") @@ -9509,7 +13295,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> null is invalid""") @@ -9524,10 +13312,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> object is invalid""") @@ -9542,10 +13334,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> empty object is invalid""") @@ -9560,10 +13355,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> array is invalid""") @@ -9578,10 +13377,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"not":true} + { + "not": true + } """, false, """forbid everything with boolean schema true -> empty array is invalid""") @@ -9599,7 +13401,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> number is valid""") @@ -9617,7 +13421,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> string is valid""") @@ -9635,7 +13441,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> boolean true is valid""") @@ -9653,7 +13461,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> boolean false is valid""") @@ -9671,7 +13481,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> null is valid""") @@ -9686,10 +13498,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> object is valid""") @@ -9704,10 +13520,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> empty object is valid""") @@ -9722,10 +13541,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> array is valid""") @@ -9740,10 +13563,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"not":false} + { + "not": false + } """, true, """allow everything with boolean schema false -> empty array is valid""") @@ -9761,7 +13587,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"not":{"not":{}}} + { + "not": { + "not": { + } + } + } """, true, """double negation -> any value is valid""") @@ -9778,7 +13609,16 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"oneOf":[{"type":"integer"},{"minimum":2}]} + { + "oneOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, true, """oneOf -> first oneOf valid""") @@ -9796,7 +13636,16 @@ class SchemaSuiteTest : JsonSchemaTest { 2.5 """, """ - {"oneOf":[{"type":"integer"},{"minimum":2}]} + { + "oneOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, true, """oneOf -> second oneOf valid""") @@ -9814,7 +13663,16 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"oneOf":[{"type":"integer"},{"minimum":2}]} + { + "oneOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, false, """oneOf -> both oneOf valid""") @@ -9832,7 +13690,16 @@ class SchemaSuiteTest : JsonSchemaTest { 1.5 """, """ - {"oneOf":[{"type":"integer"},{"minimum":2}]} + { + "oneOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + } """, false, """oneOf -> neither oneOf valid""") @@ -9850,7 +13717,17 @@ class SchemaSuiteTest : JsonSchemaTest { 3 """, """ - {"type":"string","oneOf":[{"minLength":2},{"maxLength":4}]} + { + "type": "string", + "oneOf": [ + { + "minLength": 2 + }, + { + "maxLength": 4 + } + ] + } """, false, """oneOf with base schema -> mismatch base schema""") @@ -9868,7 +13745,17 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"type":"string","oneOf":[{"minLength":2},{"maxLength":4}]} + { + "type": "string", + "oneOf": [ + { + "minLength": 2 + }, + { + "maxLength": 4 + } + ] + } """, true, """oneOf with base schema -> one oneOf valid""") @@ -9886,7 +13773,17 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"string","oneOf":[{"minLength":2},{"maxLength":4}]} + { + "type": "string", + "oneOf": [ + { + "minLength": 2 + }, + { + "maxLength": 4 + } + ] + } """, false, """oneOf with base schema -> both oneOf valid""") @@ -9904,7 +13801,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"oneOf":[true,true,true]} + { + "oneOf": [ + true, + true, + true + ] + } """, false, """oneOf with boolean schemas, all true -> any value is invalid""") @@ -9922,7 +13825,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"oneOf":[true,false,false]} + { + "oneOf": [ + true, + false, + false + ] + } """, true, """oneOf with boolean schemas, one true -> any value is valid""") @@ -9940,7 +13849,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"oneOf":[true,true,false]} + { + "oneOf": [ + true, + true, + false + ] + } """, false, """oneOf with boolean schemas, more than one true -> any value is invalid""") @@ -9958,7 +13873,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"oneOf":[false,false,false]} + { + "oneOf": [ + false, + false, + false + ] + } """, false, """oneOf with boolean schemas, all false -> any value is invalid""") @@ -9973,10 +13894,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} - """, - """ - {"oneOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "bar": 2 + } + """, + """ + { + "oneOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """oneOf complex types -> first oneOf valid (complex)""") @@ -9991,10 +13937,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz"} - """, - """ - {"oneOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz" + } + """, + """ + { + "oneOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, true, """oneOf complex types -> second oneOf valid (complex)""") @@ -10009,10 +13980,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"baz","bar":2} - """, - """ - {"oneOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": "baz", + "bar": 2 + } + """, + """ + { + "oneOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """oneOf complex types -> both oneOf valid (complex)""") @@ -10027,10 +14024,36 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":2,"bar":"quux"} - """, - """ - {"oneOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]} + { + "foo": 2, + "bar": "quux" + } + """, + """ + { + "oneOf": [ + { + "properties": { + "bar": { + "type": "integer" + } + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ] + } """, false, """oneOf complex types -> neither oneOf valid (complex)""") @@ -10048,7 +14071,15 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"oneOf":[{"type":"number"},{}]} + { + "oneOf": [ + { + "type": "number" + }, + { + } + ] + } """, true, """oneOf with empty schema -> one valid - valid""") @@ -10066,7 +14097,15 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"oneOf":[{"type":"number"},{}]} + { + "oneOf": [ + { + "type": "number" + }, + { + } + ] + } """, false, """oneOf with empty schema -> both valid - invalid""") @@ -10081,10 +14120,28 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"type":"object","oneOf":[{"required":["foo","bar"]},{"required":["foo","baz"]}]} + { + "type": "object", + "oneOf": [ + { + "required": [ + "foo", + "bar" + ] + }, + { + "required": [ + "foo", + "baz" + ] + } + ] + } """, false, """oneOf with required -> both invalid - invalid""") @@ -10099,10 +14156,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"type":"object","oneOf":[{"required":["foo","bar"]},{"required":["foo","baz"]}]} + { + "type": "object", + "oneOf": [ + { + "required": [ + "foo", + "bar" + ] + }, + { + "required": [ + "foo", + "baz" + ] + } + ] + } """, true, """oneOf with required -> first valid - valid""") @@ -10117,10 +14193,29 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"baz":3} + { + "foo": 1, + "baz": 3 + } """, """ - {"type":"object","oneOf":[{"required":["foo","bar"]},{"required":["foo","baz"]}]} + { + "type": "object", + "oneOf": [ + { + "required": [ + "foo", + "bar" + ] + }, + { + "required": [ + "foo", + "baz" + ] + } + ] + } """, true, """oneOf with required -> second valid - valid""") @@ -10135,10 +14230,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2,"baz":3} + { + "foo": 1, + "bar": 2, + "baz": 3 + } """, """ - {"type":"object","oneOf":[{"required":["foo","bar"]},{"required":["foo","baz"]}]} + { + "type": "object", + "oneOf": [ + { + "required": [ + "foo", + "bar" + ] + }, + { + "required": [ + "foo", + "baz" + ] + } + ] + } """, false, """oneOf with required -> both valid - invalid""") @@ -10153,10 +14268,32 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":8} + { + "bar": 8 + } """, """ - {"oneOf":[{"properties":{"bar":true,"baz":true},"required":["bar"]},{"properties":{"foo":true},"required":["foo"]}]} + { + "oneOf": [ + { + "properties": { + "bar": true, + "baz": true + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": true + }, + "required": [ + "foo" + ] + } + ] + } """, true, """oneOf with missing optional property -> first oneOf valid""") @@ -10171,10 +14308,32 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foo"} + { + "foo": "foo" + } """, """ - {"oneOf":[{"properties":{"bar":true,"baz":true},"required":["bar"]},{"properties":{"foo":true},"required":["foo"]}]} + { + "oneOf": [ + { + "properties": { + "bar": true, + "baz": true + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": true + }, + "required": [ + "foo" + ] + } + ] + } """, true, """oneOf with missing optional property -> second oneOf valid""") @@ -10189,10 +14348,33 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"foo","bar":8} - """, - """ - {"oneOf":[{"properties":{"bar":true,"baz":true},"required":["bar"]},{"properties":{"foo":true},"required":["foo"]}]} + { + "foo": "foo", + "bar": 8 + } + """, + """ + { + "oneOf": [ + { + "properties": { + "bar": true, + "baz": true + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": true + }, + "required": [ + "foo" + ] + } + ] + } """, false, """oneOf with missing optional property -> both oneOf valid""") @@ -10207,10 +14389,32 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"baz":"quux"} + { + "baz": "quux" + } """, """ - {"oneOf":[{"properties":{"bar":true,"baz":true},"required":["bar"]},{"properties":{"foo":true},"required":["foo"]}]} + { + "oneOf": [ + { + "properties": { + "bar": true, + "baz": true + }, + "required": [ + "bar" + ] + }, + { + "properties": { + "foo": true + }, + "required": [ + "foo" + ] + } + ] + } """, false, """oneOf with missing optional property -> neither oneOf valid""") @@ -10228,7 +14432,17 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"oneOf":[{"oneOf":[{"type":"null"}]}]} + { + "oneOf": [ + { + "oneOf": [ + { + "type": "null" + } + ] + } + ] + } """, true, """nested oneOf, to check validation semantics -> null is valid""") @@ -10246,7 +14460,17 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"oneOf":[{"oneOf":[{"type":"null"}]}]} + { + "oneOf": [ + { + "oneOf": [ + { + "type": "null" + } + ] + } + ] + } """, false, """nested oneOf, to check validation semantics -> anything non-null is invalid""") @@ -10263,7 +14487,9 @@ class SchemaSuiteTest : JsonSchemaTest { "aaa" """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> a matching pattern is valid""") @@ -10281,7 +14507,9 @@ class SchemaSuiteTest : JsonSchemaTest { "abc" """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, false, """pattern validation -> a non-matching pattern is invalid""") @@ -10299,7 +14527,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores booleans""") @@ -10317,7 +14547,9 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores integers""") @@ -10335,7 +14567,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores floats""") @@ -10350,10 +14584,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores objects""") @@ -10368,10 +14605,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores arrays""") @@ -10389,7 +14629,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"pattern":"^a*${'$'}"} + { + "pattern": "^a*${'$'}" + } """, true, """pattern validation -> ignores null""") @@ -10407,7 +14649,9 @@ class SchemaSuiteTest : JsonSchemaTest { "xxaayy" """, """ - {"pattern":"a+"} + { + "pattern": "a+" + } """, true, """pattern is not anchored -> matches a substring""") @@ -10421,10 +14665,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, true, """patternProperties validates properties matching a regex -> a single valid match is valid""") @@ -10439,10 +14691,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"foooooo":2} + { + "foo": 1, + "foooooo": 2 + } """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, true, """patternProperties validates properties matching a regex -> multiple valid matches is valid""") @@ -10457,10 +14718,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar","fooooo":2} + { + "foo": "bar", + "fooooo": 2 + } """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, false, """patternProperties validates properties matching a regex -> a single invalid match is invalid""") @@ -10475,10 +14745,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":"bar","foooooo":"baz"} + { + "foo": "bar", + "foooooo": "baz" + } """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, false, """patternProperties validates properties matching a regex -> multiple invalid matches is invalid""") @@ -10493,10 +14772,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo"] + [ + "foo" + ] """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, true, """patternProperties validates properties matching a regex -> ignores arrays""") @@ -10514,7 +14801,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, true, """patternProperties validates properties matching a regex -> ignores strings""") @@ -10532,7 +14825,13 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"patternProperties":{"f.*o":{"type":"integer"}}} + { + "patternProperties": { + "f.*o": { + "type": "integer" + } + } + } """, true, """patternProperties validates properties matching a regex -> ignores other non-objects""") @@ -10547,10 +14846,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":21} + { + "a": 21 + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, true, """multiple simultaneous patternProperties are validated -> a single valid match is valid""") @@ -10565,10 +14875,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"aaaa":18} + { + "aaaa": 18 + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, true, """multiple simultaneous patternProperties are validated -> a simultaneous match is valid""") @@ -10583,10 +14904,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":21,"aaaa":18} + { + "a": 21, + "aaaa": 18 + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, true, """multiple simultaneous patternProperties are validated -> multiple matches is valid""") @@ -10601,10 +14934,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":"bar"} + { + "a": "bar" + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, false, """multiple simultaneous patternProperties are validated -> an invalid due to one is invalid""") @@ -10619,10 +14963,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"aaaa":31} + { + "aaaa": 31 + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, false, """multiple simultaneous patternProperties are validated -> an invalid due to the other is invalid""") @@ -10637,10 +14992,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"aaa":"foo","aaaa":31} + { + "aaa": "foo", + "aaaa": 31 + } """, """ - {"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}} + { + "patternProperties": { + "a*": { + "type": "integer" + }, + "aaa*": { + "maximum": 20 + } + } + } """, false, """multiple simultaneous patternProperties are validated -> an invalid due to both is invalid""") @@ -10655,10 +15022,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"answer 1":"42"} + { + "answer 1": "42" + } """, """ - {"patternProperties":{"[0-9]{2,}":{"type":"boolean"},"X_":{"type":"string"}}} + { + "patternProperties": { + "[0-9]{2,}": { + "type": "boolean" + }, + "X_": { + "type": "string" + } + } + } """, true, """regexes are not anchored by default and are case sensitive -> non recognized members are ignored""") @@ -10673,10 +15051,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a31b":null} + { + "a31b": null + } """, """ - {"patternProperties":{"[0-9]{2,}":{"type":"boolean"},"X_":{"type":"string"}}} + { + "patternProperties": { + "[0-9]{2,}": { + "type": "boolean" + }, + "X_": { + "type": "string" + } + } + } """, false, """regexes are not anchored by default and are case sensitive -> recognized members are accounted for""") @@ -10691,10 +15080,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a_x_3":3} + { + "a_x_3": 3 + } """, """ - {"patternProperties":{"[0-9]{2,}":{"type":"boolean"},"X_":{"type":"string"}}} + { + "patternProperties": { + "[0-9]{2,}": { + "type": "boolean" + }, + "X_": { + "type": "string" + } + } + } """, true, """regexes are not anchored by default and are case sensitive -> regexes are case sensitive""") @@ -10709,10 +15109,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a_X_3":3} + { + "a_X_3": 3 + } """, """ - {"patternProperties":{"[0-9]{2,}":{"type":"boolean"},"X_":{"type":"string"}}} + { + "patternProperties": { + "[0-9]{2,}": { + "type": "boolean" + }, + "X_": { + "type": "string" + } + } + } """, false, """regexes are not anchored by default and are case sensitive -> regexes are case sensitive, 2""") @@ -10727,10 +15138,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"patternProperties":{"f.*":true,"b.*":false}} + { + "patternProperties": { + "f.*": true, + "b.*": false + } + } """, true, """patternProperties with boolean schemas -> object with property matching schema true is valid""") @@ -10745,10 +15163,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"patternProperties":{"f.*":true,"b.*":false}} + { + "patternProperties": { + "f.*": true, + "b.*": false + } + } """, false, """patternProperties with boolean schemas -> object with property matching schema false is invalid""") @@ -10763,10 +15188,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"patternProperties":{"f.*":true,"b.*":false}} + { + "patternProperties": { + "f.*": true, + "b.*": false + } + } """, false, """patternProperties with boolean schemas -> object with both properties is invalid""") @@ -10781,10 +15214,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foobar":1} + { + "foobar": 1 + } """, """ - {"patternProperties":{"f.*":true,"b.*":false}} + { + "patternProperties": { + "f.*": true, + "b.*": false + } + } """, false, """patternProperties with boolean schemas -> object with a property matching both true and false is invalid""") @@ -10799,10 +15239,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"patternProperties":{"f.*":true,"b.*":false}} + { + "patternProperties": { + "f.*": true, + "b.*": false + } + } """, true, """patternProperties with boolean schemas -> empty object is valid""") @@ -10817,10 +15263,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foobar":null} + { + "foobar": null + } """, """ - {"patternProperties":{"^.*bar${'$'}":{"type":"null"}}} + { + "patternProperties": { + "^.*bar${'$'}": { + "type": "null" + } + } + } """, true, """patternProperties with null valued instance properties -> allows null values""") @@ -10834,10 +15288,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":"baz"} + { + "foo": 1, + "bar": "baz" + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, true, """object properties validation -> both properties present and valid is valid""") @@ -10852,10 +15318,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":{}} + { + "foo": 1, + "bar": { + } + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, false, """object properties validation -> one property invalid is invalid""") @@ -10870,10 +15349,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":[],"bar":{}} + { + "foo": [ + ], + "bar": { + } + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, false, """object properties validation -> both properties invalid is invalid""") @@ -10888,10 +15381,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"quux":[]} + { + "quux": [ + ] + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, true, """object properties validation -> doesn't invalidate other properties""") @@ -10906,10 +15411,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, true, """object properties validation -> ignores arrays""") @@ -10927,7 +15442,16 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"type":"string"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "type": "string" + } + } + } """, true, """object properties validation -> ignores other non-objects""") @@ -10942,10 +15466,33 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":[1,2]} - """, - """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "foo": [ + 1, + 2 + ] + } + """, + """ + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, true, """properties, patternProperties, additionalProperties interaction -> property validates property""") @@ -10960,10 +15507,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":[1,2,3,4]} - """, - """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "foo": [ + 1, + 2, + 3, + 4 + ] + } + """, + """ + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, false, """properties, patternProperties, additionalProperties interaction -> property invalidates property""") @@ -10978,10 +15550,31 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":[]} + { + "foo": [ + ] + } """, """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, false, """properties, patternProperties, additionalProperties interaction -> patternProperty invalidates property""") @@ -10996,10 +15589,33 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"fxo":[1,2]} - """, - """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "fxo": [ + 1, + 2 + ] + } + """, + """ + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, true, """properties, patternProperties, additionalProperties interaction -> patternProperty validates nonproperty""") @@ -11014,10 +15630,31 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"fxo":[]} + { + "fxo": [ + ] + } """, """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, false, """properties, patternProperties, additionalProperties interaction -> patternProperty invalidates nonproperty""") @@ -11032,10 +15669,31 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":[]} + { + "bar": [ + ] + } """, """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, true, """properties, patternProperties, additionalProperties interaction -> additionalProperty ignores property""") @@ -11050,10 +15708,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"quux":3} + { + "quux": 3 + } """, """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, true, """properties, patternProperties, additionalProperties interaction -> additionalProperty validates others""") @@ -11068,10 +15746,30 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"quux":"foo"} + { + "quux": "foo" + } """, """ - {"properties":{"foo":{"type":"array","maxItems":3},"bar":{"type":"array"}},"patternProperties":{"f.o":{"minItems":2}},"additionalProperties":{"type":"integer"}} + { + "properties": { + "foo": { + "type": "array", + "maxItems": 3 + }, + "bar": { + "type": "array" + } + }, + "patternProperties": { + "f.o": { + "minItems": 2 + } + }, + "additionalProperties": { + "type": "integer" + } + } """, false, """properties, patternProperties, additionalProperties interaction -> additionalProperty invalidates others""") @@ -11086,10 +15784,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"foo":true,"bar":false}} + { + "properties": { + "foo": true, + "bar": false + } + } """, true, """properties with boolean schema -> no property present is valid""") @@ -11104,10 +15808,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"properties":{"foo":true,"bar":false}} + { + "properties": { + "foo": true, + "bar": false + } + } """, true, """properties with boolean schema -> only 'true' property present is valid""") @@ -11122,10 +15833,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":2} + { + "bar": 2 + } """, """ - {"properties":{"foo":true,"bar":false}} + { + "properties": { + "foo": true, + "bar": false + } + } """, false, """properties with boolean schema -> only 'false' property present is invalid""") @@ -11140,10 +15858,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1,"bar":2} + { + "foo": 1, + "bar": 2 + } """, """ - {"properties":{"foo":true,"bar":false}} + { + "properties": { + "foo": true, + "bar": false + } + } """, false, """properties with boolean schema -> both properties present is invalid""") @@ -11158,10 +15884,38 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":1,"foo\"bar":1,"foo\\bar":1,"foo\rbar":1,"foo\tbar":1,"foo\fbar":1} - """, - """ - {"properties":{"foo\nbar":{"type":"number"},"foo\"bar":{"type":"number"},"foo\\bar":{"type":"number"},"foo\rbar":{"type":"number"},"foo\tbar":{"type":"number"},"foo\fbar":{"type":"number"}}} + { + "foo\nbar": 1, + "foo\"bar": 1, + "foo\\bar": 1, + "foo\rbar": 1, + "foo\tbar": 1, + "foo\fbar": 1 + } + """, + """ + { + "properties": { + "foo\nbar": { + "type": "number" + }, + "foo\"bar": { + "type": "number" + }, + "foo\\bar": { + "type": "number" + }, + "foo\rbar": { + "type": "number" + }, + "foo\tbar": { + "type": "number" + }, + "foo\fbar": { + "type": "number" + } + } + } """, true, """properties with escaped characters -> object with all numbers is valid""") @@ -11176,10 +15930,38 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":"1","foo\"bar":"1","foo\\bar":"1","foo\rbar":"1","foo\tbar":"1","foo\fbar":"1"} - """, - """ - {"properties":{"foo\nbar":{"type":"number"},"foo\"bar":{"type":"number"},"foo\\bar":{"type":"number"},"foo\rbar":{"type":"number"},"foo\tbar":{"type":"number"},"foo\fbar":{"type":"number"}}} + { + "foo\nbar": "1", + "foo\"bar": "1", + "foo\\bar": "1", + "foo\rbar": "1", + "foo\tbar": "1", + "foo\fbar": "1" + } + """, + """ + { + "properties": { + "foo\nbar": { + "type": "number" + }, + "foo\"bar": { + "type": "number" + }, + "foo\\bar": { + "type": "number" + }, + "foo\rbar": { + "type": "number" + }, + "foo\tbar": { + "type": "number" + }, + "foo\fbar": { + "type": "number" + } + } + } """, false, """properties with escaped characters -> object with strings is invalid""") @@ -11194,10 +15976,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":null} + { + "foo": null + } """, """ - {"properties":{"foo":{"type":"null"}}} + { + "properties": { + "foo": { + "type": "null" + } + } + } """, true, """properties with null valued instance properties -> allows null values""") @@ -11212,10 +16002,27 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, true, """properties whose names are Javascript object property names -> ignores arrays""") @@ -11233,7 +16040,23 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, true, """properties whose names are Javascript object property names -> ignores other non-objects""") @@ -11248,10 +16071,27 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, true, """properties whose names are Javascript object property names -> none of the properties mentioned""") @@ -11266,10 +16106,28 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"__proto__":"foo"} + { + "__proto__": "foo" + } """, """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, false, """properties whose names are Javascript object property names -> __proto__ not valid""") @@ -11284,10 +16142,30 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"toString":{"length":37}} - """, - """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "toString": { + "length": 37 + } + } + """, + """ + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, false, """properties whose names are Javascript object property names -> toString not valid""") @@ -11302,10 +16180,30 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"constructor":{"length":37}} - """, - """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "constructor": { + "length": 37 + } + } + """, + """ + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, false, """properties whose names are Javascript object property names -> constructor not valid""") @@ -11320,10 +16218,32 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"__proto__":12,"toString":{"length":"foo"},"constructor":37} - """, - """ - {"properties":{"__proto__":{"type":"number"},"toString":{"properties":{"length":{"type":"string"}}},"constructor":{"type":"number"}}} + { + "__proto__": 12, + "toString": { + "length": "foo" + }, + "constructor": 37 + } + """, + """ + { + "properties": { + "__proto__": { + "type": "number" + }, + "toString": { + "properties": { + "length": { + "type": "string" + } + } + }, + "constructor": { + "type": "number" + } + } + } """, true, """properties whose names are Javascript object property names -> all present and valid""") @@ -11337,10 +16257,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"f":{},"foo":{}} + { + "f": { + }, + "foo": { + } + } """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, true, """propertyNames validation -> all property names valid""") @@ -11355,10 +16284,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":{},"foobar":{}} + { + "foo": { + }, + "foobar": { + } + } """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, false, """propertyNames validation -> some property names invalid""") @@ -11373,10 +16311,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, true, """propertyNames validation -> object without properties is valid""") @@ -11391,10 +16334,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3,4] + [ + 1, + 2, + 3, + 4 + ] """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, true, """propertyNames validation -> ignores arrays""") @@ -11412,7 +16364,11 @@ class SchemaSuiteTest : JsonSchemaTest { "foobar" """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, true, """propertyNames validation -> ignores strings""") @@ -11430,7 +16386,11 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"propertyNames":{"maxLength":3}} + { + "propertyNames": { + "maxLength": 3 + } + } """, true, """propertyNames validation -> ignores other non-objects""") @@ -11445,10 +16405,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"a":{},"aa":{},"aaa":{}} + { + "a": { + }, + "aa": { + }, + "aaa": { + } + } """, """ - {"propertyNames":{"pattern":"^a+${'$'}"}} + { + "propertyNames": { + "pattern": "^a+${'$'}" + } + } """, true, """propertyNames validation with pattern -> matching property names valid""") @@ -11463,10 +16434,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"aaA":{}} + { + "aaA": { + } + } """, """ - {"propertyNames":{"pattern":"^a+${'$'}"}} + { + "propertyNames": { + "pattern": "^a+${'$'}" + } + } """, false, """propertyNames validation with pattern -> non-matching property name is invalid""") @@ -11481,10 +16459,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"propertyNames":{"pattern":"^a+${'$'}"}} + { + "propertyNames": { + "pattern": "^a+${'$'}" + } + } """, true, """propertyNames validation with pattern -> object without properties is valid""") @@ -11499,10 +16482,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"propertyNames":true} + { + "propertyNames": true + } """, true, """propertyNames with boolean schema true -> object with any properties is valid""") @@ -11517,10 +16504,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"propertyNames":true} + { + "propertyNames": true + } """, true, """propertyNames with boolean schema true -> empty object is valid""") @@ -11535,10 +16525,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"propertyNames":false} + { + "propertyNames": false + } """, false, """propertyNames with boolean schema false -> object with any properties is invalid""") @@ -11553,10 +16547,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"propertyNames":false} + { + "propertyNames": false + } """, true, """propertyNames with boolean schema false -> empty object is valid""") @@ -11567,19 +16564,22 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_rootPointerRef_match() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_rootPointerRef_match" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":false} + { + "foo": false + } """, """ - {"properties":{"foo":{"${'$'}ref":"#"}},"additionalProperties":false} + { + "properties": { + "foo": { + "${'$'}ref": "#" + } + }, + "additionalProperties": false + } """, true, """root pointer ref -> match""") @@ -11591,19 +16591,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_rootPointerRef_recursiveMatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_rootPointerRef_recursiveMatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"foo":false}} + { + "foo": { + "foo": false + } + } """, """ - {"properties":{"foo":{"${'$'}ref":"#"}},"additionalProperties":false} + { + "properties": { + "foo": { + "${'$'}ref": "#" + } + }, + "additionalProperties": false + } """, true, """root pointer ref -> recursive match""") @@ -11615,19 +16620,22 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_rootPointerRef_mismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_rootPointerRef_mismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"bar":false} + { + "bar": false + } """, """ - {"properties":{"foo":{"${'$'}ref":"#"}},"additionalProperties":false} + { + "properties": { + "foo": { + "${'$'}ref": "#" + } + }, + "additionalProperties": false + } """, false, """root pointer ref -> mismatch""") @@ -11639,19 +16647,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_rootPointerRef_recursiveMismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_rootPointerRef_recursiveMismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":false}} + { + "foo": { + "bar": false + } + } """, """ - {"properties":{"foo":{"${'$'}ref":"#"}},"additionalProperties":false} + { + "properties": { + "foo": { + "${'$'}ref": "#" + } + }, + "additionalProperties": false + } """, false, """root pointer ref -> recursive mismatch""") @@ -11663,19 +16676,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativePointerRefToObject_match() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativePointerRefToObject_match" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"bar":3} + { + "bar": 3 + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"${'$'}ref":"#/properties/foo"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "${'$'}ref": "#/properties/foo" + } + } + } """, true, """relative pointer ref to object -> match""") @@ -11687,19 +16705,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativePointerRefToObject_mismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativePointerRefToObject_mismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"bar":true} + { + "bar": true + } """, """ - {"properties":{"foo":{"type":"integer"},"bar":{"${'$'}ref":"#/properties/foo"}}} + { + "properties": { + "foo": { + "type": "integer" + }, + "bar": { + "${'$'}ref": "#/properties/foo" + } + } + } """, false, """relative pointer ref to object -> mismatch""") @@ -11711,19 +16734,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativePointerRefToArray_matchArray() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativePointerRefToArray_matchArray" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"items":[{"type":"integer"},{"${'$'}ref":"#/items/0"}]} + { + "items": [ + { + "type": "integer" + }, + { + "${'$'}ref": "#/items/0" + } + ] + } """, true, """relative pointer ref to array -> match array""") @@ -11735,19 +16764,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativePointerRefToArray_mismatchArray() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativePointerRefToArray_mismatchArray" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - [1,"foo"] + [ + 1, + "foo" + ] """, """ - {"items":[{"type":"integer"},{"${'$'}ref":"#/items/0"}]} + { + "items": [ + { + "type": "integer" + }, + { + "${'$'}ref": "#/items/0" + } + ] + } """, false, """relative pointer ref to array -> mismatch array""") @@ -11759,19 +16794,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_slashInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_slashInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"slash":"aoeu"} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "slash": "aoeu" + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, false, """escaped pointer ref -> slash invalid""") @@ -11783,19 +16837,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_tildeInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_tildeInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"tilde":"aoeu"} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "tilde": "aoeu" + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, false, """escaped pointer ref -> tilde invalid""") @@ -11807,19 +16880,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_percentInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_percentInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"percent":"aoeu"} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "percent": "aoeu" + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, false, """escaped pointer ref -> percent invalid""") @@ -11831,19 +16923,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_slashValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_slashValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"slash":123} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "slash": 123 + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, true, """escaped pointer ref -> slash valid""") @@ -11855,19 +16966,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_tildeValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_tildeValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"tilde":123} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "tilde": 123 + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, true, """escaped pointer ref -> tilde valid""") @@ -11879,19 +17009,38 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_escapedPointerRef_percentValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_escapedPointerRef_percentValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"percent":123} - """, - """ - {"definitions":{"tilde~field":{"type":"integer"},"slash/field":{"type":"integer"},"percent%field":{"type":"integer"}},"properties":{"tilde":{"${'$'}ref":"#/definitions/tilde~0field"},"slash":{"${'$'}ref":"#/definitions/slash~1field"},"percent":{"${'$'}ref":"#/definitions/percent%25field"}}} + { + "percent": 123 + } + """, + """ + { + "definitions": { + "tilde~field": { + "type": "integer" + }, + "slash/field": { + "type": "integer" + }, + "percent%field": { + "type": "integer" + } + }, + "properties": { + "tilde": { + "${'$'}ref": "#/definitions/tilde~0field" + }, + "slash": { + "${'$'}ref": "#/definitions/slash~1field" + }, + "percent": { + "${'$'}ref": "#/definitions/percent%25field" + } + } + } """, true, """escaped pointer ref -> percent valid""") @@ -11903,19 +17052,30 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_nestedRefs_nestedRefValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_nestedRefs_nestedRefValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 5 """, """ - {"definitions":{"a":{"type":"integer"},"b":{"${'$'}ref":"#/definitions/a"},"c":{"${'$'}ref":"#/definitions/b"}},"allOf":[{"${'$'}ref":"#/definitions/c"}]} + { + "definitions": { + "a": { + "type": "integer" + }, + "b": { + "${'$'}ref": "#/definitions/a" + }, + "c": { + "${'$'}ref": "#/definitions/b" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/c" + } + ] + } """, true, """nested refs -> nested ref valid""") @@ -11927,19 +17087,30 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_nestedRefs_nestedRefInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_nestedRefs_nestedRefInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"definitions":{"a":{"type":"integer"},"b":{"${'$'}ref":"#/definitions/a"},"c":{"${'$'}ref":"#/definitions/b"}},"allOf":[{"${'$'}ref":"#/definitions/c"}]} + { + "definitions": { + "a": { + "type": "integer" + }, + "b": { + "${'$'}ref": "#/definitions/a" + }, + "c": { + "${'$'}ref": "#/definitions/b" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/c" + } + ] + } """, false, """nested refs -> nested ref invalid""") @@ -11951,19 +17122,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refOverridesAnySiblingKeywords_refValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refOverridesAnySiblingKeywords_refValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":[]} + { + "foo": [ + ] + } """, """ - {"definitions":{"reffed":{"type":"array"}},"properties":{"foo":{"${'$'}ref":"#/definitions/reffed","maxItems":2}}} + { + "definitions": { + "reffed": { + "type": "array" + } + }, + "properties": { + "foo": { + "${'$'}ref": "#/definitions/reffed", + "maxItems": 2 + } + } + } """, true, """ref overrides any sibling keywords -> ref valid""") @@ -11975,19 +17155,31 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refOverridesAnySiblingKeywords_refValid_MaxItemsIgnored() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refOverridesAnySiblingKeywords_refValid_MaxItemsIgnored" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":[1,2,3]} + { + "foo": [ + 1, + 2, + 3 + ] + } """, """ - {"definitions":{"reffed":{"type":"array"}},"properties":{"foo":{"${'$'}ref":"#/definitions/reffed","maxItems":2}}} + { + "definitions": { + "reffed": { + "type": "array" + } + }, + "properties": { + "foo": { + "${'$'}ref": "#/definitions/reffed", + "maxItems": 2 + } + } + } """, true, """ref overrides any sibling keywords -> ref valid, maxItems ignored""") @@ -11999,19 +17191,27 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refOverridesAnySiblingKeywords_refInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refOverridesAnySiblingKeywords_refInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"string"} + { + "foo": "string" + } """, """ - {"definitions":{"reffed":{"type":"array"}},"properties":{"foo":{"${'$'}ref":"#/definitions/reffed","maxItems":2}}} + { + "definitions": { + "reffed": { + "type": "array" + } + }, + "properties": { + "foo": { + "${'$'}ref": "#/definitions/reffed", + "maxItems": 2 + } + } + } """, false, """ref overrides any sibling keywords -> ref invalid""") @@ -12023,19 +17223,33 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataDoesNotValidate() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataDoesNotValidate" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"http://localhost:1234/sibling_id/base/","definitions":{"foo":{"${'$'}id":"http://localhost:1234/sibling_id/foo.json","type":"string"},"base_foo":{"${'$'}comment":"this canonical uri is http://localhost:1234/sibling_id/base/foo.json","${'$'}id":"foo.json","type":"number"}},"allOf":[{"${'$'}comment":"${'$'}ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json","${'$'}id":"http://localhost:1234/sibling_id/","${'$'}ref":"foo.json"}]} + { + "${'$'}id": "http://localhost:1234/sibling_id/base/", + "definitions": { + "foo": { + "${'$'}id": "http://localhost:1234/sibling_id/foo.json", + "type": "string" + }, + "base_foo": { + "${'$'}comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", + "${'$'}id": "foo.json", + "type": "number" + } + }, + "allOf": [ + { + "${'$'}comment": "${'$'}ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", + "${'$'}id": "http://localhost:1234/sibling_id/", + "${'$'}ref": "foo.json" + } + ] + } """, false, """${'$'}ref prevents a sibling ${'$'}id from changing the base uri -> ${'$'}ref resolves to /definitions/base_foo, data does not validate""") @@ -12047,19 +17261,33 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataValidates() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______refPreventsASibling______idFromChangingTheBaseUri_______refResolvesTo_definitions_base_foo_DataValidates" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"http://localhost:1234/sibling_id/base/","definitions":{"foo":{"${'$'}id":"http://localhost:1234/sibling_id/foo.json","type":"string"},"base_foo":{"${'$'}comment":"this canonical uri is http://localhost:1234/sibling_id/base/foo.json","${'$'}id":"foo.json","type":"number"}},"allOf":[{"${'$'}comment":"${'$'}ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json","${'$'}id":"http://localhost:1234/sibling_id/","${'$'}ref":"foo.json"}]} + { + "${'$'}id": "http://localhost:1234/sibling_id/base/", + "definitions": { + "foo": { + "${'$'}id": "http://localhost:1234/sibling_id/foo.json", + "type": "string" + }, + "base_foo": { + "${'$'}comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", + "${'$'}id": "foo.json", + "type": "number" + } + }, + "allOf": [ + { + "${'$'}comment": "${'$'}ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", + "${'$'}id": "http://localhost:1234/sibling_id/", + "${'$'}ref": "foo.json" + } + ] + } """, true, """${'$'}ref prevents a sibling ${'$'}id from changing the base uri -> ${'$'}ref resolves to /definitions/base_foo, data validates""") @@ -12080,10 +17308,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"minLength":1} + { + "minLength": 1 + } """, """ - {"${'$'}ref":"http://json-schema.org/draft-07/schema#"} + { + "${'$'}ref": "http://json-schema.org/draft-07/schema#" + } """, true, """remote ref, containing refs itself -> remote ref valid""") @@ -12104,10 +17336,14 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"minLength":-1} + { + "minLength": -1 + } """, """ - {"${'$'}ref":"http://json-schema.org/draft-07/schema#"} + { + "${'$'}ref": "http://json-schema.org/draft-07/schema#" + } """, false, """remote ref, containing refs itself -> remote ref invalid""") @@ -12119,19 +17355,21 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_propertyNamed______refThatIsNotAReference_propertyNamed______refValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_propertyNamed______refThatIsNotAReference_propertyNamed______refValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"${'$'}ref":"a"} + { + "${'$'}ref": "a" + } """, """ - {"properties":{"${'$'}ref":{"type":"string"}}} + { + "properties": { + "${'$'}ref": { + "type": "string" + } + } + } """, true, """property named ${'$'}ref that is not a reference -> property named ${'$'}ref valid""") @@ -12143,19 +17381,21 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_propertyNamed______refThatIsNotAReference_propertyNamed______refInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_propertyNamed______refThatIsNotAReference_propertyNamed______refInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"${'$'}ref":2} + { + "${'$'}ref": 2 + } """, """ - {"properties":{"${'$'}ref":{"type":"string"}}} + { + "properties": { + "${'$'}ref": { + "type": "string" + } + } + } """, false, """property named ${'$'}ref that is not a reference -> property named ${'$'}ref invalid""") @@ -12167,19 +17407,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"${'$'}ref":"a"} + { + "${'$'}ref": "a" + } """, """ - {"properties":{"${'$'}ref":{"${'$'}ref":"#/definitions/is-string"}},"definitions":{"is-string":{"type":"string"}}} + { + "properties": { + "${'$'}ref": { + "${'$'}ref": "#/definitions/is-string" + } + }, + "definitions": { + "is-string": { + "type": "string" + } + } + } """, true, """property named ${'$'}ref, containing an actual ${'$'}ref -> property named ${'$'}ref valid""") @@ -12191,19 +17438,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_propertyNamed______ref_ContainingAnActual______ref_propertyNamed______refInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"${'$'}ref":2} + { + "${'$'}ref": 2 + } """, """ - {"properties":{"${'$'}ref":{"${'$'}ref":"#/definitions/is-string"}},"definitions":{"is-string":{"type":"string"}}} + { + "properties": { + "${'$'}ref": { + "${'$'}ref": "#/definitions/is-string" + } + }, + "definitions": { + "is-string": { + "type": "string" + } + } + } """, false, """property named ${'$'}ref, containing an actual ${'$'}ref -> property named ${'$'}ref invalid""") @@ -12215,19 +17469,22 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______refToBooleanSchemaTrue_anyValueIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______refToBooleanSchemaTrue_anyValueIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"allOf":[{"${'$'}ref":"#/definitions/bool"}],"definitions":{"bool":true}} + { + "allOf": [ + { + "${'$'}ref": "#/definitions/bool" + } + ], + "definitions": { + "bool": true + } + } """, true, """${'$'}ref to boolean schema true -> any value is valid""") @@ -12239,19 +17496,22 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______refToBooleanSchemaFalse_anyValueIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______refToBooleanSchemaFalse_anyValueIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"allOf":[{"${'$'}ref":"#/definitions/bool"}],"definitions":{"bool":false}} + { + "allOf": [ + { + "${'$'}ref": "#/definitions/bool" + } + ], + "definitions": { + "bool": false + } + } """, false, """${'$'}ref to boolean schema false -> any value is invalid""") @@ -12263,19 +17523,82 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_recursiveReferencesBetweenSchemas_validTree() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_recursiveReferencesBetweenSchemas_validTree" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"meta":"root","nodes":[{"value":1,"subtree":{"meta":"child","nodes":[{"value":1.1},{"value":1.2}]}},{"value":2,"subtree":{"meta":"child","nodes":[{"value":2.1},{"value":2.2}]}}]} - """, - """ - {"${'$'}id":"http://localhost:1234/tree","description":"tree of nodes","type":"object","properties":{"meta":{"type":"string"},"nodes":{"type":"array","items":{"${'$'}ref":"node"}}},"required":["meta","nodes"],"definitions":{"node":{"${'$'}id":"http://localhost:1234/node","description":"node","type":"object","properties":{"value":{"type":"number"},"subtree":{"${'$'}ref":"tree"}},"required":["value"]}}} + { + "meta": "root", + "nodes": [ + { + "value": 1, + "subtree": { + "meta": "child", + "nodes": [ + { + "value": 1.1 + }, + { + "value": 1.2 + } + ] + } + }, + { + "value": 2, + "subtree": { + "meta": "child", + "nodes": [ + { + "value": 2.1 + }, + { + "value": 2.2 + } + ] + } + } + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { + "type": "string" + }, + "nodes": { + "type": "array", + "items": { + "${'$'}ref": "node" + } + } + }, + "required": [ + "meta", + "nodes" + ], + "definitions": { + "node": { + "${'$'}id": "http://localhost:1234/node", + "description": "node", + "type": "object", + "properties": { + "value": { + "type": "number" + }, + "subtree": { + "${'$'}ref": "tree" + } + }, + "required": [ + "value" + ] + } + } + } """, true, """Recursive references between schemas -> valid tree""") @@ -12287,19 +17610,82 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_recursiveReferencesBetweenSchemas_invalidTree() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_recursiveReferencesBetweenSchemas_invalidTree" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"meta":"root","nodes":[{"value":1,"subtree":{"meta":"child","nodes":[{"value":"string is invalid"},{"value":1.2}]}},{"value":2,"subtree":{"meta":"child","nodes":[{"value":2.1},{"value":2.2}]}}]} - """, - """ - {"${'$'}id":"http://localhost:1234/tree","description":"tree of nodes","type":"object","properties":{"meta":{"type":"string"},"nodes":{"type":"array","items":{"${'$'}ref":"node"}}},"required":["meta","nodes"],"definitions":{"node":{"${'$'}id":"http://localhost:1234/node","description":"node","type":"object","properties":{"value":{"type":"number"},"subtree":{"${'$'}ref":"tree"}},"required":["value"]}}} + { + "meta": "root", + "nodes": [ + { + "value": 1, + "subtree": { + "meta": "child", + "nodes": [ + { + "value": "string is invalid" + }, + { + "value": 1.2 + } + ] + } + }, + { + "value": 2, + "subtree": { + "meta": "child", + "nodes": [ + { + "value": 2.1 + }, + { + "value": 2.2 + } + ] + } + } + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { + "type": "string" + }, + "nodes": { + "type": "array", + "items": { + "${'$'}ref": "node" + } + } + }, + "required": [ + "meta", + "nodes" + ], + "definitions": { + "node": { + "${'$'}id": "http://localhost:1234/node", + "description": "node", + "type": "object", + "properties": { + "value": { + "type": "number" + }, + "subtree": { + "${'$'}ref": "tree" + } + }, + "required": [ + "value" + ] + } + } + } """, false, """Recursive references between schemas -> invalid tree""") @@ -12311,19 +17697,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refsWithQuote_objectWithNumbersIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refsWithQuote_objectWithNumbersIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo\"bar":1} + { + "foo\"bar": 1 + } """, """ - {"properties":{"foo\"bar":{"${'$'}ref":"#/definitions/foo%22bar"}},"definitions":{"foo\"bar":{"type":"number"}}} + { + "properties": { + "foo\"bar": { + "${'$'}ref": "#/definitions/foo%22bar" + } + }, + "definitions": { + "foo\"bar": { + "type": "number" + } + } + } """, true, """refs with quote -> object with numbers is valid""") @@ -12335,19 +17728,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refsWithQuote_objectWithStringsIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refsWithQuote_objectWithStringsIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo\"bar":"1"} + { + "foo\"bar": "1" + } """, """ - {"properties":{"foo\"bar":{"${'$'}ref":"#/definitions/foo%22bar"}},"definitions":{"foo\"bar":{"type":"number"}}} + { + "properties": { + "foo\"bar": { + "${'$'}ref": "#/definitions/foo%22bar" + } + }, + "definitions": { + "foo\"bar": { + "type": "number" + } + } + } """, false, """refs with quote -> object with strings is invalid""") @@ -12359,19 +17759,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_location_independentIdentifier_match() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_location_independentIdentifier_match" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"allOf":[{"${'$'}ref":"#foo"}],"definitions":{"A":{"${'$'}id":"#foo","type":"integer"}}} + { + "allOf": [ + { + "${'$'}ref": "#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } """, true, """Location-independent identifier -> match""") @@ -12383,19 +17789,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_location_independentIdentifier_mismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_location_independentIdentifier_mismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"allOf":[{"${'$'}ref":"#foo"}],"definitions":{"A":{"${'$'}id":"#foo","type":"integer"}}} + { + "allOf": [ + { + "${'$'}ref": "#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } """, false, """Location-independent identifier -> mismatch""") @@ -12407,19 +17819,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_referenceAnAnchorWithANon_relativeURI_match() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_referenceAnAnchorWithANon_relativeURI_match" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"https://example.com/schema-with-anchor","allOf":[{"${'$'}ref":"https://example.com/schema-with-anchor#foo"}],"definitions":{"A":{"${'$'}id":"#foo","type":"integer"}}} + { + "${'$'}id": "https://example.com/schema-with-anchor", + "allOf": [ + { + "${'$'}ref": "https://example.com/schema-with-anchor#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } """, true, """Reference an anchor with a non-relative URI -> match""") @@ -12431,19 +17850,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_referenceAnAnchorWithANon_relativeURI_mismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_referenceAnAnchorWithANon_relativeURI_mismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"https://example.com/schema-with-anchor","allOf":[{"${'$'}ref":"https://example.com/schema-with-anchor#foo"}],"definitions":{"A":{"${'$'}id":"#foo","type":"integer"}}} + { + "${'$'}id": "https://example.com/schema-with-anchor", + "allOf": [ + { + "${'$'}ref": "https://example.com/schema-with-anchor#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } """, false, """Reference an anchor with a non-relative URI -> mismatch""") @@ -12455,19 +17881,31 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_location_independentIdentifierWithBaseURIChangeInSubschema_match() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_location_independentIdentifierWithBaseURIChangeInSubschema_match" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"http://localhost:1234/root","allOf":[{"${'$'}ref":"http://localhost:1234/nested.json#foo"}],"definitions":{"A":{"${'$'}id":"nested.json","definitions":{"B":{"${'$'}id":"#foo","type":"integer"}}}}} + { + "${'$'}id": "http://localhost:1234/root", + "allOf": [ + { + "${'$'}ref": "http://localhost:1234/nested.json#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "nested.json", + "definitions": { + "B": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } + } + } """, true, """Location-independent identifier with base URI change in subschema -> match""") @@ -12479,19 +17917,31 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_location_independentIdentifierWithBaseURIChangeInSubschema_mismatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_location_independentIdentifierWithBaseURIChangeInSubschema_mismatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"http://localhost:1234/root","allOf":[{"${'$'}ref":"http://localhost:1234/nested.json#foo"}],"definitions":{"A":{"${'$'}id":"nested.json","definitions":{"B":{"${'$'}id":"#foo","type":"integer"}}}}} + { + "${'$'}id": "http://localhost:1234/root", + "allOf": [ + { + "${'$'}ref": "http://localhost:1234/nested.json#foo" + } + ], + "definitions": { + "A": { + "${'$'}id": "nested.json", + "definitions": { + "B": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } + } + } """, false, """Location-independent identifier with base URI change in subschema -> mismatch""") @@ -12503,19 +17953,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_MatchingAnyString() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_MatchingAnyString" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "this is a string" """, """ - {"definitions":{"a_string":{"type":"string"}},"enum":[{"${'$'}ref":"#/definitions/a_string"}]} + { + "definitions": { + "a_string": { + "type": "string" + } + }, + "enum": [ + { + "${'$'}ref": "#/definitions/a_string" + } + ] + } """, false, """naive replacement of ${'$'}ref with its destination is not correct -> do not evaluate the ${'$'}ref inside the enum, matching any string""") @@ -12527,19 +17982,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_DefinitionExactMatch() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_doNotEvaluateThe______refInsideTheEnum_DefinitionExactMatch" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"type":"string"} + { + "type": "string" + } """, """ - {"definitions":{"a_string":{"type":"string"}},"enum":[{"${'$'}ref":"#/definitions/a_string"}]} + { + "definitions": { + "a_string": { + "type": "string" + } + }, + "enum": [ + { + "${'$'}ref": "#/definitions/a_string" + } + ] + } """, false, """naive replacement of ${'$'}ref with its destination is not correct -> do not evaluate the ${'$'}ref inside the enum, definition exact match""") @@ -12551,19 +18013,26 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_matchTheEnumExactly() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_naiveReplacementOf______refWithItsDestinationIsNotCorrect_matchTheEnumExactly" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"${'$'}ref":"#/definitions/a_string"} + { + "${'$'}ref": "#/definitions/a_string" + } """, """ - {"definitions":{"a_string":{"type":"string"}},"enum":[{"${'$'}ref":"#/definitions/a_string"}]} + { + "definitions": { + "a_string": { + "type": "string" + } + }, + "enum": [ + { + "${'$'}ref": "#/definitions/a_string" + } + ] + } """, true, """naive replacement of ${'$'}ref with its destination is not correct -> match the enum exactly""") @@ -12575,19 +18044,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refsWithRelativeUrisAndDefs_invalidOnInnerField() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refsWithRelativeUrisAndDefs_invalidOnInnerField" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":1},"bar":"a"} - """, - """ - {"${'$'}id":"http://example.com/schema-relative-uri-defs1.json","properties":{"foo":{"${'$'}id":"schema-relative-uri-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-relative-uri-defs2.json"}]} + { + "foo": { + "bar": 1 + }, + "bar": "a" + } + """, + """ + { + "${'$'}id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "${'$'}id": "schema-relative-uri-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-relative-uri-defs2.json" + } + ] + } """, false, """refs with relative uris and defs -> invalid on inner field""") @@ -12599,19 +18093,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refsWithRelativeUrisAndDefs_invalidOnOuterField() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refsWithRelativeUrisAndDefs_invalidOnOuterField" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":"a"},"bar":1} - """, - """ - {"${'$'}id":"http://example.com/schema-relative-uri-defs1.json","properties":{"foo":{"${'$'}id":"schema-relative-uri-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-relative-uri-defs2.json"}]} + { + "foo": { + "bar": "a" + }, + "bar": 1 + } + """, + """ + { + "${'$'}id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "${'$'}id": "schema-relative-uri-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-relative-uri-defs2.json" + } + ] + } """, false, """refs with relative uris and defs -> invalid on outer field""") @@ -12623,19 +18142,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refsWithRelativeUrisAndDefs_validOnBothFields() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refsWithRelativeUrisAndDefs_validOnBothFields" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":"a"},"bar":"a"} - """, - """ - {"${'$'}id":"http://example.com/schema-relative-uri-defs1.json","properties":{"foo":{"${'$'}id":"schema-relative-uri-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-relative-uri-defs2.json"}]} + { + "foo": { + "bar": "a" + }, + "bar": "a" + } + """, + """ + { + "${'$'}id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "${'$'}id": "schema-relative-uri-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-relative-uri-defs2.json" + } + ] + } """, true, """refs with relative uris and defs -> valid on both fields""") @@ -12647,19 +18191,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnInnerField() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnInnerField" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":1},"bar":"a"} - """, - """ - {"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs1.json","properties":{"foo":{"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-refs-absolute-uris-defs2.json"}]} + { + "foo": { + "bar": 1 + }, + "bar": "a" + } + """, + """ + { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-refs-absolute-uris-defs2.json" + } + ] + } """, false, """relative refs with absolute uris and defs -> invalid on inner field""") @@ -12671,19 +18240,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnOuterField() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativeRefsWithAbsoluteUrisAndDefs_invalidOnOuterField" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":"a"},"bar":1} - """, - """ - {"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs1.json","properties":{"foo":{"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-refs-absolute-uris-defs2.json"}]} + { + "foo": { + "bar": "a" + }, + "bar": 1 + } + """, + """ + { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-refs-absolute-uris-defs2.json" + } + ] + } """, false, """relative refs with absolute uris and defs -> invalid on outer field""") @@ -12695,19 +18289,44 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_relativeRefsWithAbsoluteUrisAndDefs_validOnBothFields() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_relativeRefsWithAbsoluteUrisAndDefs_validOnBothFields" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":{"bar":"a"},"bar":"a"} - """, - """ - {"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs1.json","properties":{"foo":{"${'$'}id":"http://example.com/schema-refs-absolute-uris-defs2.json","definitions":{"inner":{"properties":{"bar":{"type":"string"}}}},"allOf":[{"${'$'}ref":"#/definitions/inner"}]}},"allOf":[{"${'$'}ref":"schema-refs-absolute-uris-defs2.json"}]} + { + "foo": { + "bar": "a" + }, + "bar": "a" + } + """, + """ + { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "${'$'}id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "definitions": { + "inner": { + "properties": { + "bar": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/inner" + } + ] + } + }, + "allOf": [ + { + "${'$'}ref": "schema-refs-absolute-uris-defs2.json" + } + ] + } """, true, """relative refs with absolute uris and defs -> valid on both fields""") @@ -12719,19 +18338,33 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_numberIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_numberIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"http://example.com/a.json","definitions":{"x":{"${'$'}id":"http://example.com/b/c.json","not":{"definitions":{"y":{"${'$'}id":"d.json","type":"number"}}}}},"allOf":[{"${'$'}ref":"http://example.com/b/d.json"}]} + { + "${'$'}id": "http://example.com/a.json", + "definitions": { + "x": { + "${'$'}id": "http://example.com/b/c.json", + "not": { + "definitions": { + "y": { + "${'$'}id": "d.json", + "type": "number" + } + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "http://example.com/b/d.json" + } + ] + } """, true, """${'$'}id must be resolved against nearest parent, not just immediate parent -> number is valid""") @@ -12743,19 +18376,33 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_non_numberIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idMustBeResolvedAgainstNearestParent_NotJustImmediateParent_non_numberIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"http://example.com/a.json","definitions":{"x":{"${'$'}id":"http://example.com/b/c.json","not":{"definitions":{"y":{"${'$'}id":"d.json","type":"number"}}}}},"allOf":[{"${'$'}ref":"http://example.com/b/d.json"}]} + { + "${'$'}id": "http://example.com/a.json", + "definitions": { + "x": { + "${'$'}id": "http://example.com/b/c.json", + "not": { + "definitions": { + "y": { + "${'$'}id": "d.json", + "type": "number" + } + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "http://example.com/b/d.json" + } + ] + } """, false, """${'$'}id must be resolved against nearest parent, not just immediate parent -> non-number is invalid""") @@ -12767,19 +18414,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_simpleURNBaseURIWith______refViaTheURN_validUnderTheURNIDedSchema() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_simpleURNBaseURIWith______refViaTheURN_validUnderTheURNIDedSchema" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":37} + { + "foo": 37 + } """, """ - {"${'$'}comment":"URIs do not have to have HTTP(s) schemes","${'$'}id":"urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed","minimum":30,"properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"}}} + { + "${'$'}comment": "URIs do not have to have HTTP(s) schemes", + "${'$'}id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", + "minimum": 30, + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed" + } + } + } """, true, """simple URN base URI with ${'$'}ref via the URN -> valid under the URN IDed schema""") @@ -12791,19 +18443,24 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_simpleURNBaseURIWith______refViaTheURN_invalidUnderTheURNIDedSchema() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_simpleURNBaseURIWith______refViaTheURN_invalidUnderTheURNIDedSchema" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}comment":"URIs do not have to have HTTP(s) schemes","${'$'}id":"urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed","minimum":30,"properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"}}} + { + "${'$'}comment": "URIs do not have to have HTTP(s) schemes", + "${'$'}id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", + "minimum": 30, + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed" + } + } + } """, false, """simple URN base URI with ${'$'}ref via the URN -> invalid under the URN IDed schema""") @@ -12815,19 +18472,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_simpleURNBaseURIWithJSONPointer_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_simpleURNBaseURIWithJSONPointer_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}comment":"URIs do not have to have HTTP(s) schemes","${'$'}id":"urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "URIs do not have to have HTTP(s) schemes", + "${'$'}id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, true, """simple URN base URI with JSON pointer -> a string is valid""") @@ -12839,19 +18505,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_simpleURNBaseURIWithJSONPointer_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_simpleURNBaseURIWithJSONPointer_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}comment":"URIs do not have to have HTTP(s) schemes","${'$'}id":"urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "URIs do not have to have HTTP(s) schemes", + "${'$'}id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, false, """simple URN base URI with JSON pointer -> a non-string is invalid""") @@ -12863,19 +18538,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithNSS_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithNSS_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}comment":"RFC 8141 §2.2","${'$'}id":"urn:example:1/406/47452/2","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.2", + "${'$'}id": "urn:example:1/406/47452/2", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, true, """URN base URI with NSS -> a string is valid""") @@ -12887,19 +18571,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithNSS_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithNSS_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}comment":"RFC 8141 §2.2","${'$'}id":"urn:example:1/406/47452/2","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.2", + "${'$'}id": "urn:example:1/406/47452/2", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, false, """URN base URI with NSS -> a non-string is invalid""") @@ -12911,19 +18604,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithR_component_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithR_component_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}comment":"RFC 8141 §2.3.1","${'$'}id":"urn:example:foo-bar-baz-qux?+CCResolve:cc=uk","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.3.1", + "${'$'}id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, true, """URN base URI with r-component -> a string is valid""") @@ -12935,19 +18637,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithR_component_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithR_component_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}comment":"RFC 8141 §2.3.1","${'$'}id":"urn:example:foo-bar-baz-qux?+CCResolve:cc=uk","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.3.1", + "${'$'}id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, false, """URN base URI with r-component -> a non-string is invalid""") @@ -12959,19 +18670,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithQ_component_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithQ_component_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}comment":"RFC 8141 §2.3.2","${'$'}id":"urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.3.2", + "${'$'}id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, true, """URN base URI with q-component -> a string is valid""") @@ -12983,19 +18703,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithQ_component_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithQ_component_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}comment":"RFC 8141 §2.3.2","${'$'}id":"urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z","properties":{"foo":{"${'$'}ref":"#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}comment": "RFC 8141 §2.3.2", + "${'$'}id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", + "properties": { + "foo": { + "${'$'}ref": "#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, false, """URN base URI with q-component -> a non-string is invalid""") @@ -13007,19 +18736,27 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithURNAndJSONPointerRef_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithURNAndJSONPointerRef_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}id":"urn:uuid:deadbeef-1234-0000-0000-4321feebdaed","properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, true, """URN base URI with URN and JSON pointer ref -> a string is valid""") @@ -13031,19 +18768,27 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithURNAndJSONPointerRef_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithURNAndJSONPointerRef_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}id":"urn:uuid:deadbeef-1234-0000-0000-4321feebdaed","properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar"}},"definitions":{"bar":{"type":"string"}}} + { + "${'$'}id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar" + } + }, + "definitions": { + "bar": { + "type": "string" + } + } + } """, false, """URN base URI with URN and JSON pointer ref -> a non-string is invalid""") @@ -13055,19 +18800,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithURNAndAnchorRef_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithURNAndAnchorRef_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":"bar"} + { + "foo": "bar" + } """, """ - {"${'$'}id":"urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed","properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"}},"definitions":{"bar":{"${'$'}id":"#something","type":"string"}}} + { + "${'$'}id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something" + } + }, + "definitions": { + "bar": { + "${'$'}id": "#something", + "type": "string" + } + } + } """, true, """URN base URI with URN and anchor ref -> a string is valid""") @@ -13079,19 +18833,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_uRNBaseURIWithURNAndAnchorRef_aNon_stringIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_uRNBaseURIWithURNAndAnchorRef_aNon_stringIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ - {"foo":12} + { + "foo": 12 + } """, """ - {"${'$'}id":"urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed","properties":{"foo":{"${'$'}ref":"urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"}},"definitions":{"bar":{"${'$'}id":"#something","type":"string"}}} + { + "${'$'}id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", + "properties": { + "foo": { + "${'$'}ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something" + } + }, + "definitions": { + "bar": { + "${'$'}id": "#something", + "type": "string" + } + } + } """, false, """URN base URI with URN and anchor ref -> a non-string is invalid""") @@ -13103,19 +18866,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToIf_aNon_integerIsInvalidDueToThe______ref() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToIf_aNon_integerIsInvalidDueToThe______ref" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/if"},{"if":{"${'$'}id":"http://example.com/ref/if","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/if" + }, + { + "if": { + "${'$'}id": "http://example.com/ref/if", + "type": "integer" + } + } + ] + } """, false, """ref to if -> a non-integer is invalid due to the ${'$'}ref""") @@ -13127,19 +18896,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToIf_anIntegerIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToIf_anIntegerIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 12 """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/if"},{"if":{"${'$'}id":"http://example.com/ref/if","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/if" + }, + { + "if": { + "${'$'}id": "http://example.com/ref/if", + "type": "integer" + } + } + ] + } """, true, """ref to if -> an integer is valid""") @@ -13151,19 +18926,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToThen_aNon_integerIsInvalidDueToThe______ref() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToThen_aNon_integerIsInvalidDueToThe______ref" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/then"},{"then":{"${'$'}id":"http://example.com/ref/then","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/then" + }, + { + "then": { + "${'$'}id": "http://example.com/ref/then", + "type": "integer" + } + } + ] + } """, false, """ref to then -> a non-integer is invalid due to the ${'$'}ref""") @@ -13175,19 +18956,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToThen_anIntegerIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToThen_anIntegerIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 12 """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/then"},{"then":{"${'$'}id":"http://example.com/ref/then","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/then" + }, + { + "then": { + "${'$'}id": "http://example.com/ref/then", + "type": "integer" + } + } + ] + } """, true, """ref to then -> an integer is valid""") @@ -13199,19 +18986,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToElse_aNon_integerIsInvalidDueToThe______ref() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToElse_aNon_integerIsInvalidDueToThe______ref" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/else"},{"else":{"${'$'}id":"http://example.com/ref/else","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/else" + }, + { + "else": { + "${'$'}id": "http://example.com/ref/else", + "type": "integer" + } + } + ] + } """, false, """ref to else -> a non-integer is invalid due to the ${'$'}ref""") @@ -13223,19 +19016,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refToElse_anIntegerIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refToElse_anIntegerIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 12 """, """ - {"allOf":[{"${'$'}ref":"http://example.com/ref/else"},{"else":{"${'$'}id":"http://example.com/ref/else","type":"integer"}}]} + { + "allOf": [ + { + "${'$'}ref": "http://example.com/ref/else" + }, + { + "else": { + "${'$'}id": "http://example.com/ref/else", + "type": "integer" + } + } + ] + } """, true, """ref to else -> an integer is valid""") @@ -13247,19 +19046,30 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refWithAbsolute_path_reference_aStringIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refWithAbsolute_path_reference_aStringIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "foo" """, """ - {"${'$'}id":"http://example.com/ref/absref.json","definitions":{"a":{"${'$'}id":"http://example.com/ref/absref/foobar.json","type":"number"},"b":{"${'$'}id":"http://example.com/absref/foobar.json","type":"string"}},"allOf":[{"${'$'}ref":"/absref/foobar.json"}]} + { + "${'$'}id": "http://example.com/ref/absref.json", + "definitions": { + "a": { + "${'$'}id": "http://example.com/ref/absref/foobar.json", + "type": "number" + }, + "b": { + "${'$'}id": "http://example.com/absref/foobar.json", + "type": "string" + } + }, + "allOf": [ + { + "${'$'}ref": "/absref/foobar.json" + } + ] + } """, true, """ref with absolute-path-reference -> a string is valid""") @@ -13271,19 +19081,30 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_refWithAbsolute_path_reference_anIntegerIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_refWithAbsolute_path_reference_anIntegerIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 12 """, """ - {"${'$'}id":"http://example.com/ref/absref.json","definitions":{"a":{"${'$'}id":"http://example.com/ref/absref/foobar.json","type":"number"},"b":{"${'$'}id":"http://example.com/absref/foobar.json","type":"string"}},"allOf":[{"${'$'}ref":"/absref/foobar.json"}]} + { + "${'$'}id": "http://example.com/ref/absref.json", + "definitions": { + "a": { + "${'$'}id": "http://example.com/ref/absref/foobar.json", + "type": "number" + }, + "b": { + "${'$'}id": "http://example.com/absref/foobar.json", + "type": "string" + } + }, + "allOf": [ + { + "${'$'}ref": "/absref/foobar.json" + } + ] + } """, false, """ref with absolute-path-reference -> an integer is invalid""") @@ -13295,19 +19116,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idWithFileURIStillResolvesPointers__nix_numberIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idWithFileURIStillResolvesPointers__nix_numberIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"file:///folder/file.json","definitions":{"foo":{"type":"number"}},"allOf":[{"${'$'}ref":"#/definitions/foo"}]} + { + "${'$'}id": "file:///folder/file.json", + "definitions": { + "foo": { + "type": "number" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/foo" + } + ] + } """, true, """${'$'}id with file URI still resolves pointers - *nix -> number is valid""") @@ -13319,19 +19146,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idWithFileURIStillResolvesPointers__nix_non_numberIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idWithFileURIStillResolvesPointers__nix_non_numberIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"file:///folder/file.json","definitions":{"foo":{"type":"number"}},"allOf":[{"${'$'}ref":"#/definitions/foo"}]} + { + "${'$'}id": "file:///folder/file.json", + "definitions": { + "foo": { + "type": "number" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/foo" + } + ] + } """, false, """${'$'}id with file URI still resolves pointers - *nix -> non-number is invalid""") @@ -13343,19 +19176,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idWithFileURIStillResolvesPointers_Windows_numberIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idWithFileURIStillResolvesPointers_Windows_numberIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"${'$'}id":"file:///c:/folder/file.json","definitions":{"foo":{"type":"number"}},"allOf":[{"${'$'}ref":"#/definitions/foo"}]} + { + "${'$'}id": "file:///c:/folder/file.json", + "definitions": { + "foo": { + "type": "number" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/foo" + } + ] + } """, true, """${'$'}id with file URI still resolves pointers - windows -> number is valid""") @@ -13367,19 +19206,25 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_______idWithFileURIStillResolvesPointers_Windows_non_numberIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_______idWithFileURIStillResolvesPointers_Windows_non_numberIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"${'$'}id":"file:///c:/folder/file.json","definitions":{"foo":{"type":"number"}},"allOf":[{"${'$'}ref":"#/definitions/foo"}]} + { + "${'$'}id": "file:///c:/folder/file.json", + "definitions": { + "foo": { + "type": "number" + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions/foo" + } + ] + } """, false, """${'$'}id with file URI still resolves pointers - windows -> non-number is invalid""") @@ -13391,19 +19236,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_emptyTokensIn______refJson_pointer_numberIsValid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_emptyTokensIn______refJson_pointer_numberIsValid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ 1 """, """ - {"definitions":{"":{"definitions":{"":{"type":"number"}}}},"allOf":[{"${'$'}ref":"#/definitions//definitions/"}]} + { + "definitions": { + "": { + "definitions": { + "": { + "type": "number" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions//definitions/" + } + ] + } """, true, """empty tokens in ${'$'}ref json-pointer -> number is valid""") @@ -13415,19 +19269,28 @@ class SchemaSuiteTest : JsonSchemaTest { */ @Test fun ref_emptyTokensIn______refJson_pointer_non_numberIsInvalid() { - /** - * TODO implement the schema functionality under test here and remove this exclusion from - * "ref_emptyTokensIn______refJson_pointer_non_numberIsInvalid" from - * [org.kson.jsonsuite.schemaTestSuiteExclusions] - */ - return assertKsonEnforcesSchema( """ "a" """, """ - {"definitions":{"":{"definitions":{"":{"type":"number"}}}},"allOf":[{"${'$'}ref":"#/definitions//definitions/"}]} + { + "definitions": { + "": { + "definitions": { + "": { + "type": "number" + } + } + } + }, + "allOf": [ + { + "${'$'}ref": "#/definitions//definitions/" + } + ] + } """, false, """empty tokens in ${'$'}ref json-pointer -> non-number is invalid""") @@ -13450,7 +19313,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"${'$'}ref":"http://localhost:1234/integer.json"} + { + "${'$'}ref": "http://localhost:1234/integer.json" + } """, true, """remote ref -> remote ref valid""") @@ -13474,7 +19339,9 @@ class SchemaSuiteTest : JsonSchemaTest { "a" """, """ - {"${'$'}ref":"http://localhost:1234/integer.json"} + { + "${'$'}ref": "http://localhost:1234/integer.json" + } """, false, """remote ref -> remote ref invalid""") @@ -13498,7 +19365,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"${'$'}ref":"http://localhost:1234/subSchemas.json#/definitions/integer"} + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/integer" + } """, true, """fragment within remote ref -> remote fragment valid""") @@ -13522,7 +19391,9 @@ class SchemaSuiteTest : JsonSchemaTest { "a" """, """ - {"${'$'}ref":"http://localhost:1234/subSchemas.json#/definitions/integer"} + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/integer" + } """, false, """fragment within remote ref -> remote fragment invalid""") @@ -13546,7 +19417,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"${'$'}ref":"http://localhost:1234/subSchemas.json#/definitions/refToInteger"} + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/refToInteger" + } """, true, """ref within remote ref -> ref within ref valid""") @@ -13570,7 +19443,9 @@ class SchemaSuiteTest : JsonSchemaTest { "a" """, """ - {"${'$'}ref":"http://localhost:1234/subSchemas.json#/definitions/refToInteger"} + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/refToInteger" + } """, false, """ref within remote ref -> ref within ref invalid""") @@ -13591,10 +19466,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[1]] + [ + [ + 1 + ] + ] """, """ - {"${'$'}id":"http://localhost:1234/","items":{"${'$'}id":"baseUriChange/","items":{"${'$'}ref":"folderInteger.json"}}} + { + "${'$'}id": "http://localhost:1234/", + "items": { + "${'$'}id": "baseUriChange/", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } """, true, """base URI change -> base URI change ref valid""") @@ -13615,10 +19502,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["a"]] + [ + [ + "a" + ] + ] """, """ - {"${'$'}id":"http://localhost:1234/","items":{"${'$'}id":"baseUriChange/","items":{"${'$'}ref":"folderInteger.json"}}} + { + "${'$'}id": "http://localhost:1234/", + "items": { + "${'$'}id": "baseUriChange/", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } """, false, """base URI change -> base URI change ref invalid""") @@ -13639,10 +19538,31 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"list":[1]} + { + "list": [ + 1 + ] + } """, """ - {"${'$'}id":"http://localhost:1234/scope_change_defs1.json","type":"object","properties":{"list":{"${'$'}ref":"#/definitions/baz"}},"definitions":{"baz":{"${'$'}id":"baseUriChangeFolder/","type":"array","items":{"${'$'}ref":"folderInteger.json"}}}} + { + "${'$'}id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolder/", + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + } """, true, """base URI change - change folder -> number is valid""") @@ -13663,10 +19583,31 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"list":["a"]} + { + "list": [ + "a" + ] + } """, """ - {"${'$'}id":"http://localhost:1234/scope_change_defs1.json","type":"object","properties":{"list":{"${'$'}ref":"#/definitions/baz"}},"definitions":{"baz":{"${'$'}id":"baseUriChangeFolder/","type":"array","items":{"${'$'}ref":"folderInteger.json"}}}} + { + "${'$'}id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolder/", + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + } """, false, """base URI change - change folder -> string is invalid""") @@ -13687,10 +19628,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"list":[1]} - """, - """ - {"${'$'}id":"http://localhost:1234/scope_change_defs2.json","type":"object","properties":{"list":{"${'$'}ref":"#/definitions/baz/definitions/bar"}},"definitions":{"baz":{"${'$'}id":"baseUriChangeFolderInSubschema/","definitions":{"bar":{"type":"array","items":{"${'$'}ref":"folderInteger.json"}}}}}} + { + "list": [ + 1 + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz/definitions/bar" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + } + } + } """, true, """base URI change - change folder in subschema -> number is valid""") @@ -13711,10 +19677,35 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"list":["a"]} - """, - """ - {"${'$'}id":"http://localhost:1234/scope_change_defs2.json","type":"object","properties":{"list":{"${'$'}ref":"#/definitions/baz/definitions/bar"}},"definitions":{"baz":{"${'$'}id":"baseUriChangeFolderInSubschema/","definitions":{"bar":{"type":"array","items":{"${'$'}ref":"folderInteger.json"}}}}}} + { + "list": [ + "a" + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz/definitions/bar" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + } + } + } """, false, """base URI change - change folder in subschema -> string is invalid""") @@ -13735,10 +19726,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"name":"foo"} + { + "name": "foo" + } """, """ - {"${'$'}id":"http://localhost:1234/object","type":"object","properties":{"name":{"${'$'}ref":"name.json#/definitions/orNull"}}} + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + } + } """, true, """root ref in remote ref -> string is valid""") @@ -13759,10 +19760,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"name":null} + { + "name": null + } """, """ - {"${'$'}id":"http://localhost:1234/object","type":"object","properties":{"name":{"${'$'}ref":"name.json#/definitions/orNull"}}} + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + } + } """, true, """root ref in remote ref -> null is valid""") @@ -13783,10 +19794,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"name":{"name":null}} + { + "name": { + "name": null + } + } """, """ - {"${'$'}id":"http://localhost:1234/object","type":"object","properties":{"name":{"${'$'}ref":"name.json#/definitions/orNull"}}} + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + } + } """, false, """root ref in remote ref -> object is invalid""") @@ -13807,10 +19830,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":1} + { + "bar": 1 + } """, """ - {"${'$'}id":"http://localhost:1234/schema-remote-ref-ref-defs1.json","allOf":[{"${'$'}ref":"ref-and-definitions.json"}]} + { + "${'$'}id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [ + { + "${'$'}ref": "ref-and-definitions.json" + } + ] + } """, false, """remote ref with ref to definitions -> invalid""") @@ -13831,10 +19863,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":"a"} + { + "bar": "a" + } """, """ - {"${'$'}id":"http://localhost:1234/schema-remote-ref-ref-defs1.json","allOf":[{"${'$'}ref":"ref-and-definitions.json"}]} + { + "${'$'}id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [ + { + "${'$'}ref": "ref-and-definitions.json" + } + ] + } """, true, """remote ref with ref to definitions -> valid""") @@ -13858,7 +19899,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"${'$'}ref":"http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger"} + { + "${'$'}ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" + } """, true, """Location-independent identifier in remote ref -> integer is valid""") @@ -13882,7 +19925,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"${'$'}ref":"http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger"} + { + "${'$'}ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" + } """, false, """Location-independent identifier in remote ref -> string is invalid""") @@ -13903,10 +19948,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"name":{"foo":1}} + { + "name": { + "foo": 1 + } + } """, """ - {"${'$'}id":"http://localhost:1234/some-id","properties":{"name":{"${'$'}ref":"nested/foo-ref-string.json"}}} + { + "${'$'}id": "http://localhost:1234/some-id", + "properties": { + "name": { + "${'$'}ref": "nested/foo-ref-string.json" + } + } + } """, false, """retrieved nested refs resolve relative to their URI not ${'$'}id -> number is invalid""") @@ -13927,10 +19983,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"name":{"foo":"a"}} + { + "name": { + "foo": "a" + } + } """, """ - {"${'$'}id":"http://localhost:1234/some-id","properties":{"name":{"${'$'}ref":"nested/foo-ref-string.json"}}} + { + "${'$'}id": "http://localhost:1234/some-id", + "properties": { + "name": { + "${'$'}ref": "nested/foo-ref-string.json" + } + } + } """, true, """retrieved nested refs resolve relative to their URI not ${'$'}id -> string is valid""") @@ -13954,7 +20021,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"${'$'}ref":"http://localhost:1234/draft7/detached-ref.json#/definitions/foo"} + { + "${'$'}ref": "http://localhost:1234/draft7/detached-ref.json#/definitions/foo" + } """, true, """${'$'}ref to ${'$'}ref finds location-independent ${'$'}id -> number is valid""") @@ -13978,7 +20047,9 @@ class SchemaSuiteTest : JsonSchemaTest { "a" """, """ - {"${'$'}ref":"http://localhost:1234/draft7/detached-ref.json#/definitions/foo"} + { + "${'$'}ref": "http://localhost:1234/draft7/detached-ref.json#/definitions/foo" + } """, false, """${'$'}ref to ${'$'}ref finds location-independent ${'$'}id -> non-number is invalid""") @@ -13992,10 +20063,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":1} + { + "foo": 1 + } """, """ - {"properties":{"foo":{},"bar":{}},"required":["foo"]} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "required": [ + "foo" + ] + } """, true, """required validation -> present required property is valid""") @@ -14010,10 +20093,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"bar":1} + { + "bar": 1 + } """, """ - {"properties":{"foo":{},"bar":{}},"required":["foo"]} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "required": [ + "foo" + ] + } """, false, """required validation -> non-present required property is invalid""") @@ -14028,10 +20123,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"properties":{"foo":{},"bar":{}},"required":["foo"]} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "required": [ + "foo" + ] + } """, true, """required validation -> ignores arrays""") @@ -14049,7 +20155,17 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"properties":{"foo":{},"bar":{}},"required":["foo"]} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "required": [ + "foo" + ] + } """, true, """required validation -> ignores strings""") @@ -14067,7 +20183,17 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"properties":{"foo":{},"bar":{}},"required":["foo"]} + { + "properties": { + "foo": { + }, + "bar": { + } + }, + "required": [ + "foo" + ] + } """, true, """required validation -> ignores other non-objects""") @@ -14082,10 +20208,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"foo":{}}} + { + "properties": { + "foo": { + } + } + } """, true, """required default validation -> not required by default""") @@ -14100,10 +20232,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"properties":{"foo":{}},"required":[]} + { + "properties": { + "foo": { + } + }, + "required": [ + ] + } """, true, """required with empty array -> property not required""") @@ -14118,10 +20258,26 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":1,"foo\"bar":1,"foo\\bar":1,"foo\rbar":1,"foo\tbar":1,"foo\fbar":1} + { + "foo\nbar": 1, + "foo\"bar": 1, + "foo\\bar": 1, + "foo\rbar": 1, + "foo\tbar": 1, + "foo\fbar": 1 + } """, """ - {"required":["foo\nbar","foo\"bar","foo\\bar","foo\rbar","foo\tbar","foo\fbar"]} + { + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] + } """, true, """required with escaped characters -> object with all properties present is valid""") @@ -14136,10 +20292,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo\nbar":"1","foo\"bar":"1"} + { + "foo\nbar": "1", + "foo\"bar": "1" + } """, """ - {"required":["foo\nbar","foo\"bar","foo\\bar","foo\rbar","foo\tbar","foo\fbar"]} + { + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] + } """, false, """required with escaped characters -> object with some properties missing is invalid""") @@ -14154,10 +20322,17 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, true, """required properties whose names are Javascript object property names -> ignores arrays""") @@ -14175,7 +20350,13 @@ class SchemaSuiteTest : JsonSchemaTest { 12 """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, true, """required properties whose names are Javascript object property names -> ignores other non-objects""") @@ -14190,10 +20371,17 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, false, """required properties whose names are Javascript object property names -> none of the properties mentioned""") @@ -14208,10 +20396,18 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"__proto__":"foo"} + { + "__proto__": "foo" + } """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, false, """required properties whose names are Javascript object property names -> __proto__ present""") @@ -14226,10 +20422,20 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"toString":{"length":37}} + { + "toString": { + "length": 37 + } + } """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, false, """required properties whose names are Javascript object property names -> toString present""") @@ -14244,10 +20450,20 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"constructor":{"length":37}} + { + "constructor": { + "length": 37 + } + } """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, false, """required properties whose names are Javascript object property names -> constructor present""") @@ -14262,10 +20478,22 @@ class SchemaSuiteTest : JsonSchemaTest { // Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object. assertKsonEnforcesSchema( """ - {"__proto__":12,"toString":{"length":"foo"},"constructor":37} + { + "__proto__": 12, + "toString": { + "length": "foo" + }, + "constructor": 37 + } """, """ - {"required":["__proto__","toString","constructor"]} + { + "required": [ + "__proto__", + "toString", + "constructor" + ] + } """, true, """required properties whose names are Javascript object property names -> all present""") @@ -14282,7 +20510,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"integer"} + { + "type": "integer" + } """, true, """integer type matches integers -> an integer is an integer""") @@ -14300,7 +20530,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"type":"integer"} + { + "type": "integer" + } """, true, """integer type matches integers -> a float with zero fractional part is an integer""") @@ -14318,7 +20550,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> a float is not an integer""") @@ -14336,7 +20570,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> a string is not an integer""") @@ -14354,7 +20590,9 @@ class SchemaSuiteTest : JsonSchemaTest { "1" """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> a string is still not an integer, even if it looks like one""") @@ -14369,10 +20607,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> an object is not an integer""") @@ -14387,10 +20628,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> an array is not an integer""") @@ -14408,7 +20652,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> a boolean is not an integer""") @@ -14426,7 +20672,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"integer"} + { + "type": "integer" + } """, false, """integer type matches integers -> null is not an integer""") @@ -14444,7 +20692,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"number"} + { + "type": "number" + } """, true, """number type matches numbers -> an integer is a number""") @@ -14462,7 +20712,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.0 """, """ - {"type":"number"} + { + "type": "number" + } """, true, """number type matches numbers -> a float with zero fractional part is a number (and an integer)""") @@ -14480,7 +20732,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"number"} + { + "type": "number" + } """, true, """number type matches numbers -> a float is a number""") @@ -14498,7 +20752,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> a string is not a number""") @@ -14516,7 +20772,9 @@ class SchemaSuiteTest : JsonSchemaTest { "1" """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> a string is still not a number, even if it looks like one""") @@ -14531,10 +20789,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> an object is not a number""") @@ -14549,10 +20810,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> an array is not a number""") @@ -14570,7 +20834,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> a boolean is not a number""") @@ -14588,7 +20854,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"number"} + { + "type": "number" + } """, false, """number type matches numbers -> null is not a number""") @@ -14606,7 +20874,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> 1 is not a string""") @@ -14624,7 +20894,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> a float is not a string""") @@ -14642,7 +20914,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"string"} + { + "type": "string" + } """, true, """string type matches strings -> a string is a string""") @@ -14660,7 +20934,9 @@ class SchemaSuiteTest : JsonSchemaTest { "1" """, """ - {"type":"string"} + { + "type": "string" + } """, true, """string type matches strings -> a string is still a string, even if it looks like a number""") @@ -14678,7 +20954,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"type":"string"} + { + "type": "string" + } """, true, """string type matches strings -> an empty string is still a string""") @@ -14693,10 +20971,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> an object is not a string""") @@ -14711,10 +20992,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> an array is not a string""") @@ -14732,7 +21016,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> a boolean is not a string""") @@ -14750,7 +21036,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"string"} + { + "type": "string" + } """, false, """string type matches strings -> null is not a string""") @@ -14768,7 +21056,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> an integer is not an object""") @@ -14786,7 +21076,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> a float is not an object""") @@ -14804,7 +21096,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> a string is not an object""") @@ -14819,10 +21113,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"object"} + { + "type": "object" + } """, true, """object type matches objects -> an object is an object""") @@ -14837,10 +21134,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> an array is not an object""") @@ -14858,7 +21158,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> a boolean is not an object""") @@ -14876,7 +21178,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"object"} + { + "type": "object" + } """, false, """object type matches objects -> null is not an object""") @@ -14894,7 +21198,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> an integer is not an array""") @@ -14912,7 +21218,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> a float is not an array""") @@ -14930,7 +21238,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> a string is not an array""") @@ -14945,10 +21255,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> an object is not an array""") @@ -14963,10 +21276,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"array"} + { + "type": "array" + } """, true, """array type matches arrays -> an array is an array""") @@ -14984,7 +21300,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> a boolean is not an array""") @@ -15002,7 +21320,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"array"} + { + "type": "array" + } """, false, """array type matches arrays -> null is not an array""") @@ -15020,7 +21340,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> an integer is not a boolean""") @@ -15038,7 +21360,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> zero is not a boolean""") @@ -15056,7 +21380,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> a float is not a boolean""") @@ -15074,7 +21400,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> a string is not a boolean""") @@ -15092,7 +21420,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> an empty string is not a boolean""") @@ -15107,10 +21437,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> an object is not a boolean""") @@ -15125,10 +21458,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> an array is not a boolean""") @@ -15146,7 +21482,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, true, """boolean type matches booleans -> true is a boolean""") @@ -15164,7 +21502,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, true, """boolean type matches booleans -> false is a boolean""") @@ -15182,7 +21522,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"boolean"} + { + "type": "boolean" + } """, false, """boolean type matches booleans -> null is not a boolean""") @@ -15200,7 +21542,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> an integer is not null""") @@ -15218,7 +21562,9 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> a float is not null""") @@ -15236,7 +21582,9 @@ class SchemaSuiteTest : JsonSchemaTest { 0 """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> zero is not null""") @@ -15254,7 +21602,9 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> a string is not null""") @@ -15272,7 +21622,9 @@ class SchemaSuiteTest : JsonSchemaTest { "" """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> an empty string is not null""") @@ -15287,10 +21639,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> an object is not null""") @@ -15305,10 +21660,13 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> an array is not null""") @@ -15326,7 +21684,9 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> true is not null""") @@ -15344,7 +21704,9 @@ class SchemaSuiteTest : JsonSchemaTest { false """, """ - {"type":"null"} + { + "type": "null" + } """, false, """null type matches only the null object -> false is not null""") @@ -15362,7 +21724,9 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":"null"} + { + "type": "null" + } """, true, """null type matches only the null object -> null is null""") @@ -15380,7 +21744,12 @@ class SchemaSuiteTest : JsonSchemaTest { 1 """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, true, """multiple types can be specified in an array -> an integer is valid""") @@ -15398,7 +21767,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, true, """multiple types can be specified in an array -> a string is valid""") @@ -15416,7 +21790,12 @@ class SchemaSuiteTest : JsonSchemaTest { 1.1 """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, false, """multiple types can be specified in an array -> a float is invalid""") @@ -15431,10 +21810,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {} + { + } """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, false, """multiple types can be specified in an array -> an object is invalid""") @@ -15449,10 +21834,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [] + [ + ] """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, false, """multiple types can be specified in an array -> an array is invalid""") @@ -15470,7 +21861,12 @@ class SchemaSuiteTest : JsonSchemaTest { true """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, false, """multiple types can be specified in an array -> a boolean is invalid""") @@ -15488,7 +21884,12 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":["integer","string"]} + { + "type": [ + "integer", + "string" + ] + } """, false, """multiple types can be specified in an array -> null is invalid""") @@ -15506,7 +21907,11 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":["string"]} + { + "type": [ + "string" + ] + } """, true, """type as array with one item -> string is valid""") @@ -15524,7 +21929,11 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"type":["string"]} + { + "type": [ + "string" + ] + } """, false, """type as array with one item -> number is invalid""") @@ -15539,10 +21948,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"type":["array","object"]} + { + "type": [ + "array", + "object" + ] + } """, true, """type: array or object -> array is valid""") @@ -15557,10 +21975,17 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":123} + { + "foo": 123 + } """, """ - {"type":["array","object"]} + { + "type": [ + "array", + "object" + ] + } """, true, """type: array or object -> object is valid""") @@ -15578,7 +22003,12 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"type":["array","object"]} + { + "type": [ + "array", + "object" + ] + } """, false, """type: array or object -> number is invalid""") @@ -15596,7 +22026,12 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":["array","object"]} + { + "type": [ + "array", + "object" + ] + } """, false, """type: array or object -> string is invalid""") @@ -15614,7 +22049,12 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":["array","object"]} + { + "type": [ + "array", + "object" + ] + } """, false, """type: array or object -> null is invalid""") @@ -15629,10 +22069,20 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,3] + [ + 1, + 2, + 3 + ] """, """ - {"type":["array","object","null"]} + { + "type": [ + "array", + "object", + "null" + ] + } """, true, """type: array, object or null -> array is valid""") @@ -15647,10 +22097,18 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - {"foo":123} + { + "foo": 123 + } """, """ - {"type":["array","object","null"]} + { + "type": [ + "array", + "object", + "null" + ] + } """, true, """type: array, object or null -> object is valid""") @@ -15668,7 +22126,13 @@ class SchemaSuiteTest : JsonSchemaTest { null """, """ - {"type":["array","object","null"]} + { + "type": [ + "array", + "object", + "null" + ] + } """, true, """type: array, object or null -> null is valid""") @@ -15686,7 +22150,13 @@ class SchemaSuiteTest : JsonSchemaTest { 123 """, """ - {"type":["array","object","null"]} + { + "type": [ + "array", + "object", + "null" + ] + } """, false, """type: array, object or null -> number is invalid""") @@ -15704,7 +22174,13 @@ class SchemaSuiteTest : JsonSchemaTest { "foo" """, """ - {"type":["array","object","null"]} + { + "type": [ + "array", + "object", + "null" + ] + } """, false, """type: array, object or null -> string is invalid""") @@ -15718,10 +22194,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique array of integers is valid""") @@ -15736,10 +22217,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,1] + [ + 1, + 1 + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of integers is invalid""") @@ -15754,10 +22240,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2,1] + [ + 1, + 2, + 1 + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of more than two integers is invalid""") @@ -15772,10 +22264,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1.0,1.00,1] + [ + 1.0, + 1.0, + 1 + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> numbers are unique if mathematically unequal""") @@ -15790,10 +22288,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0,false] + [ + 0, + false + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> false is not equal to zero""") @@ -15808,10 +22311,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,true] + [ + 1, + true + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> true is not equal to one""") @@ -15826,10 +22334,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo","bar","baz"] + [ + "foo", + "bar", + "baz" + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique array of strings is valid""") @@ -15844,10 +22358,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - ["foo","bar","foo"] + [ + "foo", + "bar", + "foo" + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of strings is invalid""") @@ -15862,10 +22382,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar"},{"foo":"baz"}] + [ + { + "foo": "bar" + }, + { + "foo": "baz" + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique array of objects is valid""") @@ -15880,10 +22409,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar"},{"foo":"bar"}] + [ + { + "foo": "bar" + }, + { + "foo": "bar" + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of objects is invalid""") @@ -15898,10 +22436,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar","bar":"foo"},{"bar":"foo","foo":"bar"}] + [ + { + "foo": "bar", + "bar": "foo" + }, + { + "bar": "foo", + "foo": "bar" + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> property order of array of objects is ignored""") @@ -15916,10 +22465,27 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":false}}}] + [ + { + "foo": { + "bar": { + "baz": true + } + } + }, + { + "foo": { + "bar": { + "baz": false + } + } + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique array of nested objects is valid""") @@ -15934,10 +22500,27 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":true}}}] + [ + { + "foo": { + "bar": { + "baz": true + } + } + }, + { + "foo": { + "bar": { + "baz": true + } + } + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of nested objects is invalid""") @@ -15952,10 +22535,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["foo"],["bar"]] + [ + [ + "foo" + ], + [ + "bar" + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique array of arrays is valid""") @@ -15970,10 +22562,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["foo"],["foo"]] + [ + [ + "foo" + ], + [ + "foo" + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of arrays is invalid""") @@ -15988,10 +22589,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["foo"],["bar"],["foo"]] + [ + [ + "foo" + ], + [ + "bar" + ], + [ + "foo" + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique array of more than two arrays is invalid""") @@ -16006,10 +22619,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,true] + [ + 1, + true + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> 1 and true are unique""") @@ -16024,10 +22642,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0,false] + [ + 0, + false + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> 0 and false are unique""") @@ -16042,10 +22665,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[1],[true]] + [ + [ + 1 + ], + [ + true + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> [1] and [true] are unique""") @@ -16060,10 +22692,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[0],[false]] + [ + [ + 0 + ], + [ + false + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> [0] and [false] are unique""") @@ -16078,10 +22719,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[[1],"foo"],[[true],"foo"]] + [ + [ + [ + 1 + ], + "foo" + ], + [ + [ + true + ], + "foo" + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> nested [1] and [true] are unique""") @@ -16096,10 +22752,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [[[0],"foo"],[[false],"foo"]] + [ + [ + [ + 0 + ], + "foo" + ], + [ + [ + false + ], + "foo" + ] + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> nested [0] and [false] are unique""") @@ -16114,10 +22785,22 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{},[1],true,null,1,"{}"] + [ + { + }, + [ + 1 + ], + true, + null, + 1, + "{}" + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> unique heterogeneous types are valid""") @@ -16132,10 +22815,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{},[1],true,null,{},1] + [ + { + }, + [ + 1 + ], + true, + null, + { + }, + 1 + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> non-unique heterogeneous types are invalid""") @@ -16150,10 +22846,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"a":1,"b":2},{"a":2,"b":1}] + [ + { + "a": 1, + "b": 2 + }, + { + "a": 2, + "b": 1 + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> different objects are unique""") @@ -16168,10 +22875,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"a":1,"b":2},{"b":2,"a":1}] + [ + { + "a": 1, + "b": 2 + }, + { + "b": 2, + "a": 1 + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, false, """uniqueItems validation -> objects are non-unique despite key order""") @@ -16186,10 +22904,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"a":false},{"a":0}] + [ + { + "a": false + }, + { + "a": 0 + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> {"a": false} and {"a": 0} are unique""") @@ -16204,10 +22931,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"a":true},{"a":1}] + [ + { + "a": true + }, + { + "a": 1 + } + ] """, """ - {"uniqueItems":true} + { + "uniqueItems": true + } """, true, """uniqueItems validation -> {"a": true} and {"a": 1} are unique""") @@ -16222,10 +22958,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true] + [ + false, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, true, """uniqueItems with an array of items -> [false, true] from items array is valid""") @@ -16240,10 +22989,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false] + [ + true, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, true, """uniqueItems with an array of items -> [true, false] from items array is valid""") @@ -16258,10 +23020,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,false] + [ + false, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, false, """uniqueItems with an array of items -> [false, false] from items array is not valid""") @@ -16276,10 +23051,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,true] + [ + true, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, false, """uniqueItems with an array of items -> [true, true] from items array is not valid""") @@ -16294,10 +23082,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,"foo","bar"] + [ + false, + true, + "foo", + "bar" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, true, """uniqueItems with an array of items -> unique array extended from [false, true] is valid""") @@ -16312,10 +23115,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false,"foo","bar"] + [ + true, + false, + "foo", + "bar" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, true, """uniqueItems with an array of items -> unique array extended from [true, false] is valid""") @@ -16330,10 +23148,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,"foo","foo"] + [ + false, + true, + "foo", + "foo" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, false, """uniqueItems with an array of items -> non-unique array extended from [false, true] is not valid""") @@ -16348,10 +23181,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false,"foo","foo"] + [ + true, + false, + "foo", + "foo" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true + } """, false, """uniqueItems with an array of items -> non-unique array extended from [true, false] is not valid""") @@ -16366,10 +23214,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true] + [ + false, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true, + "additionalItems": false + } """, true, """uniqueItems with an array of items and additionalItems=false -> [false, true] from items array is valid""") @@ -16384,10 +23246,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false] + [ + true, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true, + "additionalItems": false + } """, true, """uniqueItems with an array of items and additionalItems=false -> [true, false] from items array is valid""") @@ -16402,10 +23278,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,false] + [ + false, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true, + "additionalItems": false + } """, false, """uniqueItems with an array of items and additionalItems=false -> [false, false] from items array is not valid""") @@ -16420,10 +23310,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,true] + [ + true, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true, + "additionalItems": false + } """, false, """uniqueItems with an array of items and additionalItems=false -> [true, true] from items array is not valid""") @@ -16438,10 +23342,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,null] + [ + false, + true, + null + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":true,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": true, + "additionalItems": false + } """, false, """uniqueItems with an array of items and additionalItems=false -> extra items are invalid even if unique""") @@ -16456,10 +23375,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,2] + [ + 1, + 2 + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> unique array of integers is valid""") @@ -16474,10 +23398,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,1] + [ + 1, + 1 + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> non-unique array of integers is valid""") @@ -16492,10 +23421,16 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1.0,1.00,1] + [ + 1.0, + 1.0, + 1 + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> numbers are unique if mathematically unequal""") @@ -16510,10 +23445,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0,false] + [ + 0, + false + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> false is not equal to zero""") @@ -16528,10 +23468,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,true] + [ + 1, + true + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> true is not equal to one""") @@ -16546,10 +23491,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar"},{"foo":"baz"}] + [ + { + "foo": "bar" + }, + { + "foo": "baz" + } + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> unique array of objects is valid""") @@ -16564,10 +23518,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":"bar"},{"foo":"bar"}] + [ + { + "foo": "bar" + }, + { + "foo": "bar" + } + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> non-unique array of objects is valid""") @@ -16582,10 +23545,27 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":false}}}] + [ + { + "foo": { + "bar": { + "baz": true + } + } + }, + { + "foo": { + "bar": { + "baz": false + } + } + } + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> unique array of nested objects is valid""") @@ -16600,10 +23580,27 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":true}}}] + [ + { + "foo": { + "bar": { + "baz": true + } + } + }, + { + "foo": { + "bar": { + "baz": true + } + } + } + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> non-unique array of nested objects is valid""") @@ -16618,10 +23615,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["foo"],["bar"]] + [ + [ + "foo" + ], + [ + "bar" + ] + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> unique array of arrays is valid""") @@ -16636,10 +23642,19 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [["foo"],["foo"]] + [ + [ + "foo" + ], + [ + "foo" + ] + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> non-unique array of arrays is valid""") @@ -16654,10 +23669,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [1,true] + [ + 1, + true + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> 1 and true are unique""") @@ -16672,10 +23692,15 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [0,false] + [ + 0, + false + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> 0 and false are unique""") @@ -16690,10 +23715,21 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{},[1],true,null,1] + [ + { + }, + [ + 1 + ], + true, + null, + 1 + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> unique heterogeneous types are valid""") @@ -16708,10 +23744,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [{},[1],true,null,{},1] + [ + { + }, + [ + 1 + ], + true, + null, + { + }, + 1 + ] """, """ - {"uniqueItems":false} + { + "uniqueItems": false + } """, true, """uniqueItems=false validation -> non-unique heterogeneous types are valid""") @@ -16726,10 +23775,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true] + [ + false, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> [false, true] from items array is valid""") @@ -16744,10 +23806,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false] + [ + true, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> [true, false] from items array is valid""") @@ -16762,10 +23837,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,false] + [ + false, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> [false, false] from items array is valid""") @@ -16780,10 +23868,23 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,true] + [ + true, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> [true, true] from items array is valid""") @@ -16798,10 +23899,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,"foo","bar"] + [ + false, + true, + "foo", + "bar" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> unique array extended from [false, true] is valid""") @@ -16816,10 +23932,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false,"foo","bar"] + [ + true, + false, + "foo", + "bar" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> unique array extended from [true, false] is valid""") @@ -16834,10 +23965,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,"foo","foo"] + [ + false, + true, + "foo", + "foo" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> non-unique array extended from [false, true] is valid""") @@ -16852,10 +23998,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false,"foo","foo"] + [ + true, + false, + "foo", + "foo" + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false + } """, true, """uniqueItems=false with an array of items -> non-unique array extended from [true, false] is valid""") @@ -16870,10 +24031,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true] + [ + false, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false, + "additionalItems": false + } """, true, """uniqueItems=false with an array of items and additionalItems=false -> [false, true] from items array is valid""") @@ -16888,10 +24063,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,false] + [ + true, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false, + "additionalItems": false + } """, true, """uniqueItems=false with an array of items and additionalItems=false -> [true, false] from items array is valid""") @@ -16906,10 +24095,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,false] + [ + false, + false + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false, + "additionalItems": false + } """, true, """uniqueItems=false with an array of items and additionalItems=false -> [false, false] from items array is valid""") @@ -16924,10 +24127,24 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [true,true] + [ + true, + true + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false, + "additionalItems": false + } """, true, """uniqueItems=false with an array of items and additionalItems=false -> [true, true] from items array is valid""") @@ -16942,10 +24159,25 @@ class SchemaSuiteTest : JsonSchemaTest { assertKsonEnforcesSchema( """ - [false,true,null] + [ + false, + true, + null + ] """, """ - {"items":[{"type":"boolean"},{"type":"boolean"}],"uniqueItems":false,"additionalItems":false} + { + "items": [ + { + "type": "boolean" + }, + { + "type": "boolean" + } + ], + "uniqueItems": false, + "additionalItems": false + } """, false, """uniqueItems=false with an array of items and additionalItems=false -> extra items are invalid even if unique""") diff --git a/src/commonTest/kotlin/org/kson/schema/JsonPointerParserTest.kt b/src/commonTest/kotlin/org/kson/schema/JsonPointerParserTest.kt new file mode 100644 index 00000000..e49e7255 --- /dev/null +++ b/src/commonTest/kotlin/org/kson/schema/JsonPointerParserTest.kt @@ -0,0 +1,298 @@ +package org.kson.schema + +import org.kson.parser.messages.MessageType +import org.kson.parser.messages.MessageType.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class JsonPointerParserTest { + + private fun assertParsesTo(source: String, expectedReferenceTokens: List) { + val result = JsonPointerParser(source).parse() + assertTrue(result is JsonPointerParser.ParseResult.Success) + assertEquals(expectedReferenceTokens, result.tokens) + } + + private fun assertParserRejectsSource(source: String, expectedMessage: MessageType) { + val result = JsonPointerParser(source).parse() + assertTrue(result is JsonPointerParser.ParseResult.Error) + assertEquals(expectedMessage, result.message.type) + } + + @Test + fun testEmptyPointer() { + assertParsesTo("", emptyList()) + } + + @Test + fun testSingleEmptyToken() { + assertParsesTo("/", listOf("")) + } + + @Test + fun testTwoEmptyTokens() { + assertParsesTo("//", listOf("", "")) + } + + @Test + fun testSimpleToken() { + assertParsesTo("/foo", listOf("foo")) + } + + @Test + fun testMultipleTokens() { + assertParsesTo("/foo/bar/baz", listOf("foo", "bar", "baz")) + } + + @Test + fun testTokenWithEmptyAtEnd() { + assertParsesTo("/foo/", listOf("foo", "")) + } + + @Test + fun testNumericToken() { + assertParsesTo("/foo/0", listOf("foo", "0")) + } + + @Test + fun testEscapedSlash() { + assertParsesTo("/a~1b", listOf("a/b")) + } + + @Test + fun testEscapedTilde() { + assertParsesTo("/m~0n", listOf("m~n")) + } + + @Test + fun testMultipleEscapes() { + assertParsesTo("/~1~0/~0~1", listOf("/~", "~/")) + } + + @Test + fun testComplexEscapes() { + assertParsesTo("/foo~1bar~0baz", listOf("foo/bar~baz")) + } + + @Test + fun testConsecutiveEscapes() { + assertParsesTo("/~1~1~0~0", listOf("//~~")) + } + + @Test + fun testWithoutHashPrefix() { + assertParsesTo("/foo/bar", listOf("foo", "bar")) + } + + @Test + fun testSpecialCharacters() { + assertParsesTo("/foo bar/baz@123", listOf("foo bar", "baz@123")) + } + + @Test + fun testUnicodeCharacters() { + assertParsesTo("/你好/世界", listOf("你好", "世界")) + } + + @Test + fun testInvalidEscapeSequence() { + assertParserRejectsSource("/foo~2bar", JSON_POINTER_INVALID_ESCAPE) + } + + @Test + fun testInvalidEscapeAtEnd() { + assertParserRejectsSource("/foo~", JSON_POINTER_INCOMPLETE_ESCAPE) + } + + @Test + fun testInvalidStartCharacter() { + assertParserRejectsSource("foo/bar", JSON_POINTER_BAD_START) + } + + @Test + fun testArrayIndexReference() { + assertParsesTo("/foo/0/bar/1", listOf("foo", "0", "bar", "1")) + } + + @Test + fun testDashAsArrayEnd() { + assertParsesTo("/foo/-", listOf("foo", "-")) + } + + @Test + fun testComplexNestedPath() { + assertParsesTo( + "/definitions/address/properties/street", + listOf("definitions", "address", "properties", "street") + ) + } + + @Test + fun testRFC6901ExampleTokens() { + // Examples from RFC 6901 section 5 + val testCases = mapOf( + "" to emptyList(), + "/foo" to listOf("foo"), + "/foo/0" to listOf("foo", "0"), + "/" to listOf(""), + "/a~1b" to listOf("a/b"), + "/c%d" to listOf("c%d"), + "/e^f" to listOf("e^f"), + "/g|h" to listOf("g|h"), + "/i\\j" to listOf("i\\j"), + "/k\"l" to listOf("k\"l"), + "/ " to listOf(" "), + "/m~0n" to listOf("m~n") + ) + + testCases.forEach { (pointer, expectedTokens) -> + assertParsesTo(pointer, expectedTokens) + } + } + + @Test + fun testEscapeOrderMatters() { + // According to the assignment, ~1 must be processed before ~0 + // This test verifies that "~01" becomes "~1" (not "/1") + assertParsesTo("/~01", listOf("~1")) + } + + @Test + fun testMixedValidAndEmptyTokens() { + assertParsesTo("/foo//bar/", listOf("foo", "", "bar", "")) + } + + @Test + fun testSpacesInTokensAreValid() { + // According to RFC 6901, spaces are valid unescaped characters in tokens + assertParsesTo("/foo/bar extra", listOf("foo", "bar extra")) + assertParsesTo("/path with spaces", listOf("path with spaces")) + assertParsesTo("/multi word token", listOf("multi word token")) + } + + @Test + fun testInvalidEscapeLetterAfterTilde() { + // Test invalid escape with letter after tilde + assertParserRejectsSource("/foo~abc", JSON_POINTER_INVALID_ESCAPE) + } + + @Test + fun testInvalidEscapeSpecialCharAfterTilde() { + // Test invalid escape with special character after tilde + assertParserRejectsSource("/test~@value", JSON_POINTER_INVALID_ESCAPE) + } + + @Test + fun testIncompleteEscapeAtTokenEnd() { + // Tilde at end of token before slash + assertParserRejectsSource("/foo~/bar", JSON_POINTER_INVALID_ESCAPE) + } + + @Test + fun testEscapeAtStartOfToken() { + // Escape sequences at the beginning of tokens + assertParsesTo("/~0foo", listOf("~foo")) + assertParsesTo("/~1bar", listOf("/bar")) + } + + @Test + fun testEscapeAtEndOfToken() { + // Escape sequences at the end of tokens + assertParsesTo("/foo~0", listOf("foo~")) + assertParsesTo("/bar~1", listOf("bar/")) + } + + @Test + fun testMultipleConsecutiveTildes() { + // Multiple tildes in sequence with valid escapes + assertParsesTo("/~0~0~0", listOf("~~~")) + assertParsesTo("/~1~1~1", listOf("///")) + } + + @Test + fun testMixedEscapesInSingleToken() { + // Mix of ~0 and ~1 in various positions + assertParsesTo("/start~0middle~1end", listOf("start~middle/end")) + assertParsesTo("/~1~0~1~0", listOf("/~/~")) + } + + @Test + fun testInvalidEscapeNumbers() { + // Test other numbers after tilde (not 0 or 1) + assertParserRejectsSource("/foo~3bar", JSON_POINTER_INVALID_ESCAPE) + assertParserRejectsSource("/test~9", JSON_POINTER_INVALID_ESCAPE) + } + + @Test + fun testEscapeFollowedBySlash() { + // Valid escape followed immediately by path separator + assertParsesTo("/~0/~1", listOf("~", "/")) + } + + @Test + fun testLongPath() { + // Test a deeply nested path + assertParsesTo( + "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p", + listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p") + ) + } + + @Test + fun testCharacterRangeBoundaries() { + // Test characters at boundaries of valid ranges + // 0x2E is '.', 0x2F is '/', 0x30 is '0' + assertParsesTo("/test.char", listOf("test.char")) // 0x2E is valid + // 0x2F (/) must be escaped as ~1 + assertParsesTo("/test~1char", listOf("test/char")) + assertParsesTo("/test0char", listOf("test0char")) // 0x30 is valid + + // 0x7D is '}', 0x7E is '~', 0x7F is DEL + assertParsesTo("/test}char", listOf("test}char")) // 0x7D is valid + // 0x7E (~) must be escaped as ~0 + assertParsesTo("/test~0char", listOf("test~char")) + assertParsesTo("/test\u007Fchar", listOf("test\u007Fchar")) // 0x7F (DEL) is valid + } + + @Test + fun testControlCharacters() { + // Test various control characters (0x00-0x1F) + assertParsesTo("/\u0000", listOf("\u0000")) // NULL + assertParsesTo("/\u0001", listOf("\u0001")) // SOH + assertParsesTo("/\u001F", listOf("\u001F")) // Unit Separator + assertParsesTo("/test\ttab", listOf("test\ttab")) // TAB (0x09) + assertParsesTo("/test\nline", listOf("test\nline")) // LF (0x0A) + assertParsesTo("/test\rreturn", listOf("test\rreturn")) // CR (0x0D) + } + + @Test + fun testHighUnicodeCharacters() { + // Test high Unicode characters (> 0x7F) + assertParsesTo("/test\u0080char", listOf("test\u0080char")) // First char after DEL + assertParsesTo("/test\u00FFchar", listOf("test\u00FFchar")) // Latin-1 supplement + assertParsesTo("/test\u1000char", listOf("test\u1000char")) // Myanmar + assertParsesTo("/test\uFFFFchar", listOf("test\uFFFFchar")) // High surrogate + } + + @Test + fun testAllPrintableASCII() { + // Test that all printable ASCII except / and ~ work unescaped + val printableASCII = StringBuilder() + for (c in 0x20..0x7D) { + if (c != 0x2F && c != 0x7E) { // Skip / and ~ + printableASCII.append(c.toChar()) + } + } + assertParsesTo("/$printableASCII", listOf(printableASCII.toString())) + } + + @Test + fun testSpecialPathCases() { + // Test some special cases that might be edge cases + assertParsesTo("/~1~1", listOf("//")) // Double slash escaped + assertParsesTo("/~0~0", listOf("~~")) // Double tilde escaped + assertParsesTo("/~10", listOf("/0")) // Slash followed by 0 + assertParsesTo("/~01", listOf("~1")) // Tilde followed by 1 + } +} diff --git a/src/commonTest/kotlin/org/kson/schema/JsonSchemaTest.kt b/src/commonTest/kotlin/org/kson/schema/JsonSchemaTest.kt index 92d77d7d..61aea3de 100644 --- a/src/commonTest/kotlin/org/kson/schema/JsonSchemaTest.kt +++ b/src/commonTest/kotlin/org/kson/schema/JsonSchemaTest.kt @@ -2,9 +2,7 @@ package org.kson.schema import org.kson.CoreCompileConfig import org.kson.KsonCore -import org.kson.parser.Coordinates import org.kson.parser.Location -import org.kson.parser.LoggedMessage import org.kson.parser.messages.MessageType import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -58,8 +56,11 @@ interface JsonSchemaTest { val result = KsonCore.parseSchema(source) val jsonSchema = result.jsonSchema + assertTrue( + result.messages.isEmpty(), "Should have no error messages when parsing succeeds, got: " + + result.messages.joinToString("\n") + ) assertNotNull(jsonSchema, "Should produce a non-null schema when parsing succeeds") - assertTrue(result.messages.isEmpty(), "Should have no error messages when parsing succeeds") return jsonSchema } diff --git a/src/commonTest/kotlin/org/kson/schema/JsonSchemaTestBundledRemotes.kt b/src/commonTest/kotlin/org/kson/schema/JsonSchemaTestBundledRemotes.kt new file mode 100644 index 00000000..87332a75 --- /dev/null +++ b/src/commonTest/kotlin/org/kson/schema/JsonSchemaTestBundledRemotes.kt @@ -0,0 +1,780 @@ +package org.kson.schema + +import kotlin.test.Test + +/** + * These tests are ["bundled"/Compound Schema](https://json-schema.org/blog/posts/bundling-json-schema-compound-documents) + * ports of the [org.kson.parser.json.generated.SchemaSuiteTest] tests which require fetching remote schemas. Those + * remote fetching tests are excluded in [org.kson.jsonsuite.schemaTestSuiteExclusions] because we do not current + * support remote fetching. These tests let us have most of that coverage while also doing the the important work + * of ensuring our Schema $id and $ref code effectively navigates compound schemas + */ +class JsonSchemaTestBundledRemotes : JsonSchemaTest { + /** + * "Bundled" version of [org.kson.parser.json.generated.SchemaSuiteTest.refRemote_______refTo______refFindsLocation_independent______id_non_numberIsInvalid] + */ + @Test + fun bundled_______refTo______refFindsLocation_independent______id_non_numberIsInvalid() { + assertKsonEnforcesSchema( + """ + "a" + """, + """ + { + "${'$'}ref": "http://localhost:1234/draft7/detached-ref.json#/definitions/foo", + "definitions": { + "http://localhost:1234/draft7/detached-ref.json": { + "${'$'}schema": "http://json-schema.org/draft-07/schema#", + "${'$'}id": "http://localhost:1234/draft7/detached-ref.json", + "definitions": { + "detached": { + "${'$'}id": "#detached", + "type": "integer" + }, + "foo": { + "${'$'}ref": "#detached" + } + } + } + } + } + """, + false, + """${'$'}ref to ${'$'}ref finds location-independent ${'$'}id -> non-number is invalid""" + ) + } + + // Remote ref tests + @Test + fun bundled_remoteRef_remoteRefValid() { + assertKsonEnforcesSchema( + """ + 1 + """, + """ + { + "${'$'}ref": "http://localhost:1234/integer.json", + "definitions": { + "http://localhost:1234/integer.json": { + "${'$'}id": "http://localhost:1234/integer.json", + "type": "integer" + } + } + } + """, + true, + """remote ref -> remote ref valid""" + ) + } + + @Test + fun bundled_remoteRef_remoteRefInvalid() { + assertKsonEnforcesSchema( + """ + "a" + """, + """ + { + "${'$'}ref": "http://localhost:1234/integer.json", + "definitions": { + "http://localhost:1234/integer.json": { + "${'$'}id": "http://localhost:1234/integer.json", + "type": "integer" + } + } + } + """, + false, + """remote ref -> remote ref invalid""" + ) + } + + // Fragment within remote ref tests + @Test + fun bundled_fragmentWithinRemoteRef_remoteFragmentValid() { + assertKsonEnforcesSchema( + """ + 1 + """, + """ + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/integer", + "definitions": { + "http://localhost:1234/subSchemas.json": { + "${'$'}id": "http://localhost:1234/subSchemas.json", + "definitions": { + "integer": { + "type": "integer" + }, + "refToInteger": { + "${'$'}ref": "#/definitions/integer" + } + } + } + } + } + """, + true, + """fragment within remote ref -> remote fragment valid""" + ) + } + + @Test + fun bundled_fragmentWithinRemoteRef_remoteFragmentInvalid() { + assertKsonEnforcesSchema( + """ + "a" + """, + """ + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/integer", + "definitions": { + "http://localhost:1234/subSchemas.json": { + "${'$'}id": "http://localhost:1234/subSchemas.json", + "definitions": { + "integer": { + "type": "integer" + }, + "refToInteger": { + "${'$'}ref": "#/definitions/integer" + } + } + } + } + } + """, + false, + """fragment within remote ref -> remote fragment invalid""" + ) + } + + // Ref within remote ref tests + @Test + fun bundled_refWithinRemoteRef_refWithinRefValid() { + assertKsonEnforcesSchema( + """ + 1 + """, + """ + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/refToInteger", + "definitions": { + "http://localhost:1234/subSchemas.json": { + "${'$'}id": "http://localhost:1234/subSchemas.json", + "definitions": { + "integer": { + "type": "integer" + }, + "refToInteger": { + "${'$'}ref": "#/definitions/integer" + } + } + } + } + } + """, + true, + """ref within remote ref -> ref within ref valid""" + ) + } + + @Test + fun bundled_refWithinRemoteRef_refWithinRefInvalid() { + assertKsonEnforcesSchema( + """ + "a" + """, + """ + { + "${'$'}ref": "http://localhost:1234/subSchemas.json#/definitions/refToInteger", + "definitions": { + "http://localhost:1234/subSchemas.json": { + "${'$'}id": "http://localhost:1234/subSchemas.json", + "definitions": { + "integer": { + "type": "integer" + }, + "refToInteger": { + "${'$'}ref": "#/definitions/integer" + } + } + } + } + } + """, + false, + """ref within remote ref -> ref within ref invalid""" + ) + } + + // Base URI change tests + @Test + fun bundled_baseURIChange_baseURIChangeRefValid() { + assertKsonEnforcesSchema( + """ + [ + [ + 1 + ] + ] + """, + """ + { + "${'$'}id": "http://localhost:1234/", + "items": { + "${'$'}id": "baseUriChange/", + "items": { + "${'$'}ref": "folderInteger.json" + } + }, + "definitions": { + "http://localhost:1234/baseUriChange/folderInteger.json": { + "${'$'}id": "http://localhost:1234/baseUriChange/folderInteger.json", + "type": "integer" + } + } + } + """, + true, + """base URI change -> base URI change ref valid""" + ) + } + + @Test + fun bundled_baseURIChange_baseURIChangeRefInvalid() { + assertKsonEnforcesSchema( + """ + [ + [ + "a" + ] + ] + """, + """ + { + "${'$'}id": "http://localhost:1234/", + "items": { + "${'$'}id": "baseUriChange/", + "items": { + "${'$'}ref": "folderInteger.json" + }, + "definitions": { + "folderInteger.json": { + "${'$'}id": "folderInteger.json", + "type": "integer" + } + } + } + } + """, + false, + """base URI change -> base URI change ref invalid""" + ) + } + + // Base URI change - change folder tests + @Test + fun bundled_baseURIChange_ChangeFolder_numberIsValid() { + assertKsonEnforcesSchema( + """ + { + "list": [ + 1 + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolder/", + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + }, + "http://localhost:1234/baseUriChangeFolder/folderInteger.json": { + "${'$'}id": "http://localhost:1234/baseUriChangeFolder/folderInteger.json", + "type": "integer" + } + } + } + """, + true, + """base URI change - change folder -> number is valid""" + ) + } + + @Test + fun bundled_baseURIChange_ChangeFolder_stringIsInvalid() { + assertKsonEnforcesSchema( + """ + { + "list": [ + "a" + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolder/", + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + }, + "http://localhost:1234/baseUriChangeFolder/folderInteger.json": { + "${'$'}id": "http://localhost:1234/baseUriChangeFolder/folderInteger.json", + "type": "integer" + } + } + } + """, + false, + """base URI change - change folder -> string is invalid""" + ) + } + + // Base URI change - change folder in subschema tests + @Test + fun bundled_baseURIChange_ChangeFolderInSubschema_numberIsValid() { + assertKsonEnforcesSchema( + """ + { + "list": [ + 1 + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz/definitions/bar" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + }, + "http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json": { + "${'$'}id": "http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json", + "type": "integer" + } + } + } + """, + true, + """base URI change - change folder in subschema -> number is valid""" + ) + } + + @Test + fun bundled_baseURIChange_ChangeFolderInSubschema_stringIsInvalid() { + assertKsonEnforcesSchema( + """ + { + "list": [ + "a" + ] + } + """, + """ + { + "${'$'}id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { + "list": { + "${'$'}ref": "#/definitions/baz/definitions/bar" + } + }, + "definitions": { + "baz": { + "${'$'}id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { + "type": "array", + "items": { + "${'$'}ref": "folderInteger.json" + } + } + } + }, + "http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json": { + "${'$'}id": "http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json", + "type": "integer" + } + } + } + """, + false, + """base URI change - change folder in subschema -> string is invalid""" + ) + } + + // Location-independent identifier tests + @Test + fun bundled_location_independentIdentifierInRemoteRef_integerIsValid() { + assertKsonEnforcesSchema( + """ + 1 + """, + """ + { + "${'$'}ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger", + "definitions": { + "http://localhost:1234/locationIndependentIdentifierPre2019.json": { + "${'$'}id": "http://localhost:1234/locationIndependentIdentifierPre2019.json", + "definitions": { + "refToInteger": { + "${'$'}ref": "#foo" + }, + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } + } + } + """, + true, + """Location-independent identifier in remote ref -> integer is valid""" + ) + } + + @Test + fun bundled_location_independentIdentifierInRemoteRef_stringIsInvalid() { + assertKsonEnforcesSchema( + """ + "foo" + """, + """ + { + "${'$'}ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger", + "definitions": { + "http://localhost:1234/locationIndependentIdentifierPre2019.json": { + "${'$'}id": "http://localhost:1234/locationIndependentIdentifierPre2019.json", + "definitions": { + "refToInteger": { + "${'$'}ref": "#foo" + }, + "A": { + "${'$'}id": "#foo", + "type": "integer" + } + } + } + } + } + """, + false, + """Location-independent identifier in remote ref -> string is invalid""" + ) + } + + // Remote ref with ref to definitions tests + @Test + fun bundled_remoteRefWithRefToDefinitions_valid() { + assertKsonEnforcesSchema( + """ + { + "bar": "a" + } + """, + """ + { + "${'$'}id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [ + { + "${'$'}ref": "ref-and-definitions.json" + } + ], + "definitions": { + "http://localhost:1234/ref-and-definitions.json": { + "${'$'}id": "http://localhost:1234/ref-and-definitions.json", + "definitions": { + "inner": { + "properties": { + "bar": { "type": "string" } + } + } + }, + "allOf": [ { "${'$'}ref": "#/definitions/inner" } ] + } + } + } + """, + true, + """remote ref with ref to definitions -> valid""" + ) + } + + @Test + fun bundled_remoteRefWithRefToDefinitions_invalid() { + assertKsonEnforcesSchema( + """ + { + "bar": 1 + } + """, + """ + { + "${'$'}id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [ + { + "${'$'}ref": "ref-and-definitions.json" + } + ], + "definitions": { + "http://localhost:1234/ref-and-definitions.json": { + "${'$'}id": "http://localhost:1234/ref-and-definitions.json", + "definitions": { + "inner": { + "properties": { + "bar": { "type": "string" } + } + } + }, + "allOf": [ { "${'$'}ref": "#/definitions/inner" } ] + } + } + } + """, + false, + """remote ref with ref to definitions -> invalid""" + ) + } + + // Retrieved nested refs tests + @Test + fun bundled_retrievedNestedRefsResolveRelativeToTheirURINot______id_stringIsValid() { + assertKsonEnforcesSchema( + """ + { + "name": { + "foo": "a" + } + } + """, + """ + { + "${'$'}id": "http://localhost:1234/some-id", + "properties": { + "name": { + "${'$'}ref": "nested/foo-ref-string.json" + } + }, + "definitions": { + "http://localhost:1234/nested/foo-ref-string.json": { + "${'$'}id": "http://localhost:1234/nested/foo-ref-string.json", + "type": "object", + "properties": { + "foo": {"${'$'}ref": "string.json"} + } + }, + "http://localhost:1234/nested/string.json": { + "${'$'}id": "http://localhost:1234/nested/string.json", + "type": "string" + } + } + } + """, + true, + """retrieved nested refs resolve relative to their URI not ${'$'}id -> string is valid""" + ) + } + + @Test + fun bundled_retrievedNestedRefsResolveRelativeToTheirURINot______id_numberIsInvalid() { + assertKsonEnforcesSchema( + """ + { + "name": { + "foo": 1 + } + } + """, + """ + { + "${'$'}id": "http://localhost:1234/some-id", + "properties": { + "name": { + "${'$'}ref": "nested/foo-ref-string.json" + } + }, + "definitions": { + "http://localhost:1234/nested/foo-ref-string.json": { + "${'$'}id": "http://localhost:1234/nested/foo-ref-string.json", + "type": "object", + "properties": { + "foo": {"${'$'}ref": "string.json"} + } + }, + "http://localhost:1234/nested/string.json": { + "${'$'}id": "http://localhost:1234/nested/string.json", + "type": "string" + } + } + } + """, + false, + """retrieved nested refs resolve relative to their URI not ${'$'}id -> number is invalid""" + ) + } + + // Root ref in remote ref tests + @Test + fun bundled_rootRefInRemoteRef_stringIsValid() { + assertKsonEnforcesSchema( + """ + { + "name": "foo" + } + """, + """ + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + }, + "definitions": { + "http://localhost:1234/name.json": { + "${'$'}id": "http://localhost:1234/name.json", + "definitions": { + "orNull": { + "anyOf": [ + { + "type": "null" + }, + { + "${'$'}ref": "#" + } + ] + } + }, + "type": "string" + } + } + } + """, + true, + """root ref in remote ref -> string is valid""" + ) + } + + @Test + fun bundled_rootRefInRemoteRef_nullIsValid() { + assertKsonEnforcesSchema( + """ + { + "name": null + } + """, + """ + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + }, + "definitions": { + "http://localhost:1234/name.json": { + "${'$'}id": "http://localhost:1234/name.json", + "definitions": { + "orNull": { + "anyOf": [ + { + "type": "null" + }, + { + "${'$'}ref": "#" + } + ] + } + }, + "type": "string" + } + } + } + """, + true, + """root ref in remote ref -> null is valid""" + ) + } + + @Test + fun bundled_rootRefInRemoteRef_objectIsInvalid() { + assertKsonEnforcesSchema( + """ + { + "name": { + "name": null + } + } + """, + """ + { + "${'$'}id": "http://localhost:1234/object", + "type": "object", + "properties": { + "name": { + "${'$'}ref": "name.json#/definitions/orNull" + } + }, + "definitions": { + "http://localhost:1234/name.json": { + "${'$'}id": "http://localhost:1234/name.json", + "definitions": { + "orNull": { + "anyOf": [ + { + "type": "null" + }, + { + "${'$'}ref": "#" + } + ] + } + }, + "type": "string" + } + } + } + """, + false, + """root ref in remote ref -> object is invalid""" + ) + } +} diff --git a/src/commonTest/kotlin/org/kson/schema/SchemaParserTest.kt b/src/commonTest/kotlin/org/kson/schema/SchemaParserTest.kt index 0bfa0709..91c9e922 100644 --- a/src/commonTest/kotlin/org/kson/schema/SchemaParserTest.kt +++ b/src/commonTest/kotlin/org/kson/schema/SchemaParserTest.kt @@ -205,4 +205,44 @@ class SchemaParserTest : JsonSchemaTest { listOf(MessageType.SCHEMA_INTEGER_REQUIRED) ) } + + @Test + fun testRefWithAllowedProperties() { + // Test that $ref with only title and description does not generate errors + assertValidObjectSchema( + """ + { + "definitions": { + "someType": {"type": "string"} + }, + "properties": { + "myRef": { + "${'$'}ref": "#/definitions/someType", + "title": "Reference with title", + "description": "This is allowed alongside ${'$'}ref" + } + } + } + """ + ) + } + + @Test + fun testRefOnlyWithNoOtherProperties() { + // Test that $ref alone works without errors + assertValidObjectSchema( + """ + { + "definitions": { + "simpleType": {"type": "string"} + }, + "properties": { + "myProperty": { + "${'$'}ref": "#/definitions/simpleType" + } + } + } + """ + ) + } }