pax_global_header00006660000000000000000000000064135513507150014517gustar00rootroot0000000000000052 comment=82fcdeb203eb6ab2a67d0a623d9c19e5e5a64927 gojsonschema-1.2.0/000077500000000000000000000000001355135071500141775ustar00rootroot00000000000000gojsonschema-1.2.0/.gitignore000066400000000000000000000000311355135071500161610ustar00rootroot00000000000000*.sw[nop] *.iml .vscode/ gojsonschema-1.2.0/.travis.yml000066400000000000000000000003121355135071500163040ustar00rootroot00000000000000language: go go: - "1.11" - "1.12" - "1.13" before_install: - go get github.com/xeipuuv/gojsonreference - go get github.com/xeipuuv/gojsonpointer - go get github.com/stretchr/testify/assert gojsonschema-1.2.0/LICENSE-APACHE-2.0.txt000066400000000000000000000261121355135071500172400ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 xeipuuv Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. gojsonschema-1.2.0/README.md000066400000000000000000000362241355135071500154650ustar00rootroot00000000000000[![GoDoc](https://godoc.org/github.com/xeipuuv/gojsonschema?status.svg)](https://godoc.org/github.com/xeipuuv/gojsonschema) [![Build Status](https://travis-ci.org/xeipuuv/gojsonschema.svg)](https://travis-ci.org/xeipuuv/gojsonschema) [![Go Report Card](https://goreportcard.com/badge/github.com/xeipuuv/gojsonschema)](https://goreportcard.com/report/github.com/xeipuuv/gojsonschema) # gojsonschema ## Description An implementation of JSON Schema for the Go programming language. Supports draft-04, draft-06 and draft-07. References : * http://json-schema.org * http://json-schema.org/latest/json-schema-core.html * http://json-schema.org/latest/json-schema-validation.html ## Installation ``` go get github.com/xeipuuv/gojsonschema ``` Dependencies : * [github.com/xeipuuv/gojsonpointer](https://github.com/xeipuuv/gojsonpointer) * [github.com/xeipuuv/gojsonreference](https://github.com/xeipuuv/gojsonreference) * [github.com/stretchr/testify/assert](https://github.com/stretchr/testify#assert-package) ## Usage ### Example ```go package main import ( "fmt" "github.com/xeipuuv/gojsonschema" ) func main() { schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json") documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json") result, err := gojsonschema.Validate(schemaLoader, documentLoader) if err != nil { panic(err.Error()) } if result.Valid() { fmt.Printf("The document is valid\n") } else { fmt.Printf("The document is not valid. see errors :\n") for _, desc := range result.Errors() { fmt.Printf("- %s\n", desc) } } } ``` #### Loaders There are various ways to load your JSON data. In order to load your schemas and documents, first declare an appropriate loader : * Web / HTTP, using a reference : ```go loader := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json") ``` * Local file, using a reference : ```go loader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json") ``` References use the URI scheme, the prefix (file://) and a full path to the file are required. * JSON strings : ```go loader := gojsonschema.NewStringLoader(`{"type": "string"}`) ``` * Custom Go types : ```go m := map[string]interface{}{"type": "string"} loader := gojsonschema.NewGoLoader(m) ``` And ```go type Root struct { Users []User `json:"users"` } type User struct { Name string `json:"name"` } ... data := Root{} data.Users = append(data.Users, User{"John"}) data.Users = append(data.Users, User{"Sophia"}) data.Users = append(data.Users, User{"Bill"}) loader := gojsonschema.NewGoLoader(data) ``` #### Validation Once the loaders are set, validation is easy : ```go result, err := gojsonschema.Validate(schemaLoader, documentLoader) ``` Alternatively, you might want to load a schema only once and process to multiple validations : ```go schema, err := gojsonschema.NewSchema(schemaLoader) ... result1, err := schema.Validate(documentLoader1) ... result2, err := schema.Validate(documentLoader2) ... // etc ... ``` To check the result : ```go if result.Valid() { fmt.Printf("The document is valid\n") } else { fmt.Printf("The document is not valid. see errors :\n") for _, err := range result.Errors() { // Err implements the ResultError interface fmt.Printf("- %s\n", err) } } ``` ## Loading local schemas By default `file` and `http(s)` references to external schemas are loaded automatically via the file system or via http(s). An external schema can also be loaded using a `SchemaLoader`. ```go sl := gojsonschema.NewSchemaLoader() loader1 := gojsonschema.NewStringLoader(`{ "type" : "string" }`) err := sl.AddSchema("http://some_host.com/string.json", loader1) ``` Alternatively if your schema already has an `$id` you can use the `AddSchemas` function ```go loader2 := gojsonschema.NewStringLoader(`{ "$id" : "http://some_host.com/maxlength.json", "maxLength" : 5 }`) err = sl.AddSchemas(loader2) ``` The main schema should be passed to the `Compile` function. This main schema can then directly reference the added schemas without needing to download them. ```go loader3 := gojsonschema.NewStringLoader(`{ "$id" : "http://some_host.com/main.json", "allOf" : [ { "$ref" : "http://some_host.com/string.json" }, { "$ref" : "http://some_host.com/maxlength.json" } ] }`) schema, err := sl.Compile(loader3) documentLoader := gojsonschema.NewStringLoader(`"hello world"`) result, err := schema.Validate(documentLoader) ``` It's also possible to pass a `ReferenceLoader` to the `Compile` function that references a loaded schema. ```go err = sl.AddSchemas(loader3) schema, err := sl.Compile(gojsonschema.NewReferenceLoader("http://some_host.com/main.json")) ``` Schemas added by `AddSchema` and `AddSchemas` are only validated when the entire schema is compiled, unless meta-schema validation is used. ## Using a specific draft By default `gojsonschema` will try to detect the draft of a schema by using the `$schema` keyword and parse it in a strict draft-04, draft-06 or draft-07 mode. If `$schema` is missing, or the draft version is not explicitely set, a hybrid mode is used which merges together functionality of all drafts into one mode. Autodectection can be turned off with the `AutoDetect` property. Specific draft versions can be specified with the `Draft` property. ```go sl := gojsonschema.NewSchemaLoader() sl.Draft = gojsonschema.Draft7 sl.AutoDetect = false ``` If autodetection is on (default), a draft-07 schema can savely reference draft-04 schemas and vice-versa, as long as `$schema` is specified in all schemas. ## Meta-schema validation Schemas that are added using the `AddSchema`, `AddSchemas` and `Compile` can be validated against their meta-schema by setting the `Validate` property. The following example will produce an error as `multipleOf` must be a number. If `Validate` is off (default), this error is only returned at the `Compile` step. ```go sl := gojsonschema.NewSchemaLoader() sl.Validate = true err := sl.AddSchemas(gojsonschema.NewStringLoader(`{ $id" : "http://some_host.com/invalid.json", "$schema": "http://json-schema.org/draft-07/schema#", "multipleOf" : true }`)) ``` ``` ``` Errors returned by meta-schema validation are more readable and contain more information, which helps significantly if you are developing a schema. Meta-schema validation also works with a custom `$schema`. In case `$schema` is missing, or `AutoDetect` is set to `false`, the meta-schema of the used draft is used. ## Working with Errors The library handles string error codes which you can customize by creating your own gojsonschema.locale and setting it ```go gojsonschema.Locale = YourCustomLocale{} ``` However, each error contains additional contextual information. Newer versions of `gojsonschema` may have new additional errors, so code that uses a custom locale will need to be updated when this happens. **err.Type()**: *string* Returns the "type" of error that occurred. Note you can also type check. See below Note: An error of RequiredType has an err.Type() return value of "required" "required": RequiredError "invalid_type": InvalidTypeError "number_any_of": NumberAnyOfError "number_one_of": NumberOneOfError "number_all_of": NumberAllOfError "number_not": NumberNotError "missing_dependency": MissingDependencyError "internal": InternalError "const": ConstEror "enum": EnumError "array_no_additional_items": ArrayNoAdditionalItemsError "array_min_items": ArrayMinItemsError "array_max_items": ArrayMaxItemsError "unique": ItemsMustBeUniqueError "contains" : ArrayContainsError "array_min_properties": ArrayMinPropertiesError "array_max_properties": ArrayMaxPropertiesError "additional_property_not_allowed": AdditionalPropertyNotAllowedError "invalid_property_pattern": InvalidPropertyPatternError "invalid_property_name": InvalidPropertyNameError "string_gte": StringLengthGTEError "string_lte": StringLengthLTEError "pattern": DoesNotMatchPatternError "multiple_of": MultipleOfError "number_gte": NumberGTEError "number_gt": NumberGTError "number_lte": NumberLTEError "number_lt": NumberLTError "condition_then" : ConditionThenError "condition_else" : ConditionElseError **err.Value()**: *interface{}* Returns the value given **err.Context()**: *gojsonschema.JsonContext* Returns the context. This has a String() method that will print something like this: (root).firstName **err.Field()**: *string* Returns the fieldname in the format firstName, or for embedded properties, person.firstName. This returns the same as the String() method on *err.Context()* but removes the (root). prefix. **err.Description()**: *string* The error description. This is based on the locale you are using. See the beginning of this section for overwriting the locale with a custom implementation. **err.DescriptionFormat()**: *string* The error description format. This is relevant if you are adding custom validation errors afterwards to the result. **err.Details()**: *gojsonschema.ErrorDetails* Returns a map[string]interface{} of additional error details specific to the error. For example, GTE errors will have a "min" value, LTE will have a "max" value. See errors.go for a full description of all the error details. Every error always contains a "field" key that holds the value of *err.Field()* Note in most cases, the err.Details() will be used to generate replacement strings in your locales, and not used directly. These strings follow the text/template format i.e. ``` {{.field}} must be greater than or equal to {{.min}} ``` The library allows you to specify custom template functions, should you require more complex error message handling. ```go gojsonschema.ErrorTemplateFuncs = map[string]interface{}{ "allcaps": func(s string) string { return strings.ToUpper(s) }, } ``` Given the above definition, you can use the custom function `"allcaps"` in your localization templates: ``` {{allcaps .field}} must be greater than or equal to {{.min}} ``` The above error message would then be rendered with the `field` value in capital letters. For example: ``` "PASSWORD must be greater than or equal to 8" ``` Learn more about what types of template functions you can use in `ErrorTemplateFuncs` by referring to Go's [text/template FuncMap](https://golang.org/pkg/text/template/#FuncMap) type. ## Formats JSON Schema allows for optional "format" property to validate instances against well-known formats. gojsonschema ships with all of the formats defined in the spec that you can use like this: ````json {"type": "string", "format": "email"} ```` Not all formats defined in draft-07 are available. Implemented formats are: * `date` * `time` * `date-time` * `hostname`. Subdomains that start with a number are also supported, but this means that it doesn't strictly follow [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5) and has the implication that ipv4 addresses are also recognized as valid hostnames. * `email`. Go's email parser deviates slightly from [RFC5322](https://tools.ietf.org/html/rfc5322). Includes unicode support. * `idn-email`. Same caveat as `email`. * `ipv4` * `ipv6` * `uri`. Includes unicode support. * `uri-reference`. Includes unicode support. * `iri` * `iri-reference` * `uri-template` * `uuid` * `regex`. Go uses the [RE2](https://github.com/google/re2/wiki/Syntax) engine and is not [ECMA262](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) compatible. * `json-pointer` * `relative-json-pointer` `email`, `uri` and `uri-reference` use the same validation code as their unicode counterparts `idn-email`, `iri` and `iri-reference`. If you rely on unicode support you should use the specific unicode enabled formats for the sake of interoperability as other implementations might not support unicode in the regular formats. The validation code for `uri`, `idn-email` and their relatives use mostly standard library code. For repetitive or more complex formats, you can create custom format checkers and add them to gojsonschema like this: ```go // Define the format checker type RoleFormatChecker struct {} // Ensure it meets the gojsonschema.FormatChecker interface func (f RoleFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if ok == false { return false } return strings.HasPrefix("ROLE_", asString) } // Add it to the library gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{}) ```` Now to use in your json schema: ````json {"type": "string", "format": "role"} ```` Another example would be to check if the provided integer matches an id on database: JSON schema: ```json {"type": "integer", "format": "ValidUserId"} ``` ```go // Define the format checker type ValidUserIdFormatChecker struct {} // Ensure it meets the gojsonschema.FormatChecker interface func (f ValidUserIdFormatChecker) IsFormat(input interface{}) bool { asFloat64, ok := input.(float64) // Numbers are always float64 here if ok == false { return false } // XXX // do the magic on the database looking for the int(asFloat64) return true } // Add it to the library gojsonschema.FormatCheckers.Add("ValidUserId", ValidUserIdFormatChecker{}) ```` Formats can also be removed, for example if you want to override one of the formats that is defined by default. ```go gojsonschema.FormatCheckers.Remove("hostname") ``` ## Additional custom validation After the validation has run and you have the results, you may add additional errors using `Result.AddError`. This is useful to maintain the same format within the resultset instead of having to add special exceptions for your own errors. Below is an example. ```go type AnswerInvalidError struct { gojsonschema.ResultErrorFields } func newAnswerInvalidError(context *gojsonschema.JsonContext, value interface{}, details gojsonschema.ErrorDetails) *AnswerInvalidError { err := AnswerInvalidError{} err.SetContext(context) err.SetType("custom_invalid_error") // it is important to use SetDescriptionFormat() as this is used to call SetDescription() after it has been parsed // using the description of err will be overridden by this. err.SetDescriptionFormat("Answer to the Ultimate Question of Life, the Universe, and Everything is {{.answer}}") err.SetValue(value) err.SetDetails(details) return &err } func main() { // ... schema, err := gojsonschema.NewSchema(schemaLoader) result, err := gojsonschema.Validate(schemaLoader, documentLoader) if true { // some validation jsonContext := gojsonschema.NewJsonContext("question", nil) errDetail := gojsonschema.ErrorDetails{ "answer": 42, } result.AddError( newAnswerInvalidError( gojsonschema.NewJsonContext("answer", jsonContext), 52, errDetail, ), errDetail, ) } return result, err } ``` This is especially useful if you want to add validation beyond what the json schema drafts can provide such business specific logic. ## Uses gojsonschema uses the following test suite : https://github.com/json-schema/JSON-Schema-Test-Suite gojsonschema-1.2.0/draft.go000066400000000000000000000244231355135071500156330ustar00rootroot00000000000000// Copyright 2018 johandorland ( https://github.com/johandorland ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gojsonschema import ( "errors" "math" "reflect" "github.com/xeipuuv/gojsonreference" ) // Draft is a JSON-schema draft version type Draft int // Supported Draft versions const ( Draft4 Draft = 4 Draft6 Draft = 6 Draft7 Draft = 7 Hybrid Draft = math.MaxInt32 ) type draftConfig struct { Version Draft MetaSchemaURL string MetaSchema string } type draftConfigs []draftConfig var drafts draftConfigs func init() { drafts = []draftConfig{ { Version: Draft4, MetaSchemaURL: "http://json-schema.org/draft-04/schema", MetaSchema: `{"id":"http://json-schema.org/draft-04/schema#","$schema":"http://json-schema.org/draft-04/schema#","description":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"positiveInteger":{"type":"integer","minimum":0},"positiveIntegerDefault0":{"allOf":[{"$ref":"#/definitions/positiveInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"minItems":1,"uniqueItems":true}},"type":"object","properties":{"id":{"type":"string"},"$schema":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"multipleOf":{"type":"number","minimum":0,"exclusiveMinimum":true},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"boolean","default":false},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"boolean","default":false},"maxLength":{"$ref":"#/definitions/positiveInteger"},"minLength":{"$ref":"#/definitions/positiveIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/positiveInteger"},"minItems":{"$ref":"#/definitions/positiveIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"maxProperties":{"$ref":"#/definitions/positiveInteger"},"minProperties":{"$ref":"#/definitions/positiveIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"dependencies":{"exclusiveMaximum":["maximum"],"exclusiveMinimum":["minimum"]},"default":{}}`, }, { Version: Draft6, MetaSchemaURL: "http://json-schema.org/draft-06/schema", MetaSchema: `{"$schema":"http://json-schema.org/draft-06/schema#","$id":"http://json-schema.org/draft-06/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"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"examples":{"type":"array","items":{}},"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":{}},"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":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":{},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":{}}`, }, { Version: Draft7, MetaSchemaURL: "http://json-schema.org/draft-07/schema", MetaSchema: `{"$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},"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}`, }, } } func (dc draftConfigs) GetMetaSchema(url string) string { for _, config := range dc { if config.MetaSchemaURL == url { return config.MetaSchema } } return "" } func (dc draftConfigs) GetDraftVersion(url string) *Draft { for _, config := range dc { if config.MetaSchemaURL == url { return &config.Version } } return nil } func (dc draftConfigs) GetSchemaURL(draft Draft) string { for _, config := range dc { if config.Version == draft { return config.MetaSchemaURL } } return "" } func parseSchemaURL(documentNode interface{}) (string, *Draft, error) { if isKind(documentNode, reflect.Bool) { return "", nil, nil } if !isKind(documentNode, reflect.Map) { return "", nil, errors.New("schema is invalid") } m := documentNode.(map[string]interface{}) if existsMapKey(m, KEY_SCHEMA) { if !isKind(m[KEY_SCHEMA], reflect.String) { return "", nil, errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{ "key": KEY_SCHEMA, "type": TYPE_STRING, }, )) } schemaReference, err := gojsonreference.NewJsonReference(m[KEY_SCHEMA].(string)) if err != nil { return "", nil, err } schema := schemaReference.String() return schema, drafts.GetDraftVersion(schema), nil } return "", nil, nil } gojsonschema-1.2.0/errors.go000066400000000000000000000220531355135071500160440ustar00rootroot00000000000000package gojsonschema import ( "bytes" "sync" "text/template" ) var errorTemplates = errorTemplate{template.New("errors-new"), sync.RWMutex{}} // template.Template is not thread-safe for writing, so some locking is done // sync.RWMutex is used for efficiently locking when new templates are created type errorTemplate struct { *template.Template sync.RWMutex } type ( // FalseError. ErrorDetails: - FalseError struct { ResultErrorFields } // RequiredError indicates that a required field is missing // ErrorDetails: property string RequiredError struct { ResultErrorFields } // InvalidTypeError indicates that a field has the incorrect type // ErrorDetails: expected, given InvalidTypeError struct { ResultErrorFields } // NumberAnyOfError is produced in case of a failing "anyOf" validation // ErrorDetails: - NumberAnyOfError struct { ResultErrorFields } // NumberOneOfError is produced in case of a failing "oneOf" validation // ErrorDetails: - NumberOneOfError struct { ResultErrorFields } // NumberAllOfError is produced in case of a failing "allOf" validation // ErrorDetails: - NumberAllOfError struct { ResultErrorFields } // NumberNotError is produced if a "not" validation failed // ErrorDetails: - NumberNotError struct { ResultErrorFields } // MissingDependencyError is produced in case of a "missing dependency" problem // ErrorDetails: dependency MissingDependencyError struct { ResultErrorFields } // InternalError indicates an internal error // ErrorDetails: error InternalError struct { ResultErrorFields } // ConstError indicates a const error // ErrorDetails: allowed ConstError struct { ResultErrorFields } // EnumError indicates an enum error // ErrorDetails: allowed EnumError struct { ResultErrorFields } // ArrayNoAdditionalItemsError is produced if additional items were found, but not allowed // ErrorDetails: - ArrayNoAdditionalItemsError struct { ResultErrorFields } // ArrayMinItemsError is produced if an array contains less items than the allowed minimum // ErrorDetails: min ArrayMinItemsError struct { ResultErrorFields } // ArrayMaxItemsError is produced if an array contains more items than the allowed maximum // ErrorDetails: max ArrayMaxItemsError struct { ResultErrorFields } // ItemsMustBeUniqueError is produced if an array requires unique items, but contains non-unique items // ErrorDetails: type, i, j ItemsMustBeUniqueError struct { ResultErrorFields } // ArrayContainsError is produced if an array contains invalid items // ErrorDetails: ArrayContainsError struct { ResultErrorFields } // ArrayMinPropertiesError is produced if an object contains less properties than the allowed minimum // ErrorDetails: min ArrayMinPropertiesError struct { ResultErrorFields } // ArrayMaxPropertiesError is produced if an object contains more properties than the allowed maximum // ErrorDetails: max ArrayMaxPropertiesError struct { ResultErrorFields } // AdditionalPropertyNotAllowedError is produced if an object has additional properties, but not allowed // ErrorDetails: property AdditionalPropertyNotAllowedError struct { ResultErrorFields } // InvalidPropertyPatternError is produced if an pattern was found // ErrorDetails: property, pattern InvalidPropertyPatternError struct { ResultErrorFields } // InvalidPropertyNameError is produced if an invalid-named property was found // ErrorDetails: property InvalidPropertyNameError struct { ResultErrorFields } // StringLengthGTEError is produced if a string is shorter than the minimum required length // ErrorDetails: min StringLengthGTEError struct { ResultErrorFields } // StringLengthLTEError is produced if a string is longer than the maximum allowed length // ErrorDetails: max StringLengthLTEError struct { ResultErrorFields } // DoesNotMatchPatternError is produced if a string does not match the defined pattern // ErrorDetails: pattern DoesNotMatchPatternError struct { ResultErrorFields } // DoesNotMatchFormatError is produced if a string does not match the defined format // ErrorDetails: format DoesNotMatchFormatError struct { ResultErrorFields } // MultipleOfError is produced if a number is not a multiple of the defined multipleOf // ErrorDetails: multiple MultipleOfError struct { ResultErrorFields } // NumberGTEError is produced if a number is lower than the allowed minimum // ErrorDetails: min NumberGTEError struct { ResultErrorFields } // NumberGTError is produced if a number is lower than, or equal to the specified minimum, and exclusiveMinimum is set // ErrorDetails: min NumberGTError struct { ResultErrorFields } // NumberLTEError is produced if a number is higher than the allowed maximum // ErrorDetails: max NumberLTEError struct { ResultErrorFields } // NumberLTError is produced if a number is higher than, or equal to the specified maximum, and exclusiveMaximum is set // ErrorDetails: max NumberLTError struct { ResultErrorFields } // ConditionThenError is produced if a condition's "then" validation is invalid // ErrorDetails: - ConditionThenError struct { ResultErrorFields } // ConditionElseError is produced if a condition's "else" condition is invalid // ErrorDetails: - ConditionElseError struct { ResultErrorFields } ) // newError takes a ResultError type and sets the type, context, description, details, value, and field func newError(err ResultError, context *JsonContext, value interface{}, locale locale, details ErrorDetails) { var t string var d string switch err.(type) { case *FalseError: t = "false" d = locale.False() case *RequiredError: t = "required" d = locale.Required() case *InvalidTypeError: t = "invalid_type" d = locale.InvalidType() case *NumberAnyOfError: t = "number_any_of" d = locale.NumberAnyOf() case *NumberOneOfError: t = "number_one_of" d = locale.NumberOneOf() case *NumberAllOfError: t = "number_all_of" d = locale.NumberAllOf() case *NumberNotError: t = "number_not" d = locale.NumberNot() case *MissingDependencyError: t = "missing_dependency" d = locale.MissingDependency() case *InternalError: t = "internal" d = locale.Internal() case *ConstError: t = "const" d = locale.Const() case *EnumError: t = "enum" d = locale.Enum() case *ArrayNoAdditionalItemsError: t = "array_no_additional_items" d = locale.ArrayNoAdditionalItems() case *ArrayMinItemsError: t = "array_min_items" d = locale.ArrayMinItems() case *ArrayMaxItemsError: t = "array_max_items" d = locale.ArrayMaxItems() case *ItemsMustBeUniqueError: t = "unique" d = locale.Unique() case *ArrayContainsError: t = "contains" d = locale.ArrayContains() case *ArrayMinPropertiesError: t = "array_min_properties" d = locale.ArrayMinProperties() case *ArrayMaxPropertiesError: t = "array_max_properties" d = locale.ArrayMaxProperties() case *AdditionalPropertyNotAllowedError: t = "additional_property_not_allowed" d = locale.AdditionalPropertyNotAllowed() case *InvalidPropertyPatternError: t = "invalid_property_pattern" d = locale.InvalidPropertyPattern() case *InvalidPropertyNameError: t = "invalid_property_name" d = locale.InvalidPropertyName() case *StringLengthGTEError: t = "string_gte" d = locale.StringGTE() case *StringLengthLTEError: t = "string_lte" d = locale.StringLTE() case *DoesNotMatchPatternError: t = "pattern" d = locale.DoesNotMatchPattern() case *DoesNotMatchFormatError: t = "format" d = locale.DoesNotMatchFormat() case *MultipleOfError: t = "multiple_of" d = locale.MultipleOf() case *NumberGTEError: t = "number_gte" d = locale.NumberGTE() case *NumberGTError: t = "number_gt" d = locale.NumberGT() case *NumberLTEError: t = "number_lte" d = locale.NumberLTE() case *NumberLTError: t = "number_lt" d = locale.NumberLT() case *ConditionThenError: t = "condition_then" d = locale.ConditionThen() case *ConditionElseError: t = "condition_else" d = locale.ConditionElse() } err.SetType(t) err.SetContext(context) err.SetValue(value) err.SetDetails(details) err.SetDescriptionFormat(d) details["field"] = err.Field() if _, exists := details["context"]; !exists && context != nil { details["context"] = context.String() } err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details)) } // formatErrorDescription takes a string in the default text/template // format and converts it to a string with replacements. The fields come // from the ErrorDetails struct and vary for each type of error. func formatErrorDescription(s string, details ErrorDetails) string { var tpl *template.Template var descrAsBuffer bytes.Buffer var err error errorTemplates.RLock() tpl = errorTemplates.Lookup(s) errorTemplates.RUnlock() if tpl == nil { errorTemplates.Lock() tpl = errorTemplates.New(s) if ErrorTemplateFuncs != nil { tpl.Funcs(ErrorTemplateFuncs) } tpl, err = tpl.Parse(s) errorTemplates.Unlock() if err != nil { return err.Error() } } err = tpl.Execute(&descrAsBuffer, details) if err != nil { return err.Error() } return descrAsBuffer.String() } gojsonschema-1.2.0/format_checkers.go000066400000000000000000000233411355135071500176700ustar00rootroot00000000000000package gojsonschema import ( "net" "net/mail" "net/url" "regexp" "strings" "sync" "time" ) type ( // FormatChecker is the interface all formatters added to FormatCheckerChain must implement FormatChecker interface { // IsFormat checks if input has the correct format and type IsFormat(input interface{}) bool } // FormatCheckerChain holds the formatters FormatCheckerChain struct { formatters map[string]FormatChecker } // EmailFormatChecker verifies email address formats EmailFormatChecker struct{} // IPV4FormatChecker verifies IP addresses in the IPv4 format IPV4FormatChecker struct{} // IPV6FormatChecker verifies IP addresses in the IPv6 format IPV6FormatChecker struct{} // DateTimeFormatChecker verifies date/time formats per RFC3339 5.6 // // Valid formats: // Partial Time: HH:MM:SS // Full Date: YYYY-MM-DD // Full Time: HH:MM:SSZ-07:00 // Date Time: YYYY-MM-DDTHH:MM:SSZ-0700 // // Where // YYYY = 4DIGIT year // MM = 2DIGIT month ; 01-12 // DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year // HH = 2DIGIT hour ; 00-23 // MM = 2DIGIT ; 00-59 // SS = 2DIGIT ; 00-58, 00-60 based on leap second rules // T = Literal // Z = Literal // // Note: Nanoseconds are also suported in all formats // // http://tools.ietf.org/html/rfc3339#section-5.6 DateTimeFormatChecker struct{} // DateFormatChecker verifies date formats // // Valid format: // Full Date: YYYY-MM-DD // // Where // YYYY = 4DIGIT year // MM = 2DIGIT month ; 01-12 // DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year DateFormatChecker struct{} // TimeFormatChecker verifies time formats // // Valid formats: // Partial Time: HH:MM:SS // Full Time: HH:MM:SSZ-07:00 // // Where // HH = 2DIGIT hour ; 00-23 // MM = 2DIGIT ; 00-59 // SS = 2DIGIT ; 00-58, 00-60 based on leap second rules // T = Literal // Z = Literal TimeFormatChecker struct{} // URIFormatChecker validates a URI with a valid Scheme per RFC3986 URIFormatChecker struct{} // URIReferenceFormatChecker validates a URI or relative-reference per RFC3986 URIReferenceFormatChecker struct{} // URITemplateFormatChecker validates a URI template per RFC6570 URITemplateFormatChecker struct{} // HostnameFormatChecker validates a hostname is in the correct format HostnameFormatChecker struct{} // UUIDFormatChecker validates a UUID is in the correct format UUIDFormatChecker struct{} // RegexFormatChecker validates a regex is in the correct format RegexFormatChecker struct{} // JSONPointerFormatChecker validates a JSON Pointer per RFC6901 JSONPointerFormatChecker struct{} // RelativeJSONPointerFormatChecker validates a relative JSON Pointer is in the correct format RelativeJSONPointerFormatChecker struct{} ) var ( // FormatCheckers holds the valid formatters, and is a public variable // so library users can add custom formatters FormatCheckers = FormatCheckerChain{ formatters: map[string]FormatChecker{ "date": DateFormatChecker{}, "time": TimeFormatChecker{}, "date-time": DateTimeFormatChecker{}, "hostname": HostnameFormatChecker{}, "email": EmailFormatChecker{}, "idn-email": EmailFormatChecker{}, "ipv4": IPV4FormatChecker{}, "ipv6": IPV6FormatChecker{}, "uri": URIFormatChecker{}, "uri-reference": URIReferenceFormatChecker{}, "iri": URIFormatChecker{}, "iri-reference": URIReferenceFormatChecker{}, "uri-template": URITemplateFormatChecker{}, "uuid": UUIDFormatChecker{}, "regex": RegexFormatChecker{}, "json-pointer": JSONPointerFormatChecker{}, "relative-json-pointer": RelativeJSONPointerFormatChecker{}, }, } // Regex credit: https://www.socketloop.com/tutorials/golang-validate-hostname rxHostname = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`) // Use a regex to make sure curly brackets are balanced properly after validating it as a AURI rxURITemplate = regexp.MustCompile("^([^{]*({[^}]*})?)*$") rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$") rxJSONPointer = regexp.MustCompile("^(?:/(?:[^~/]|~0|~1)*)*$") rxRelJSONPointer = regexp.MustCompile("^(?:0|[1-9][0-9]*)(?:#|(?:/(?:[^~/]|~0|~1)*)*)$") lock = new(sync.RWMutex) ) // Add adds a FormatChecker to the FormatCheckerChain // The name used will be the value used for the format key in your json schema func (c *FormatCheckerChain) Add(name string, f FormatChecker) *FormatCheckerChain { lock.Lock() c.formatters[name] = f lock.Unlock() return c } // Remove deletes a FormatChecker from the FormatCheckerChain (if it exists) func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain { lock.Lock() delete(c.formatters, name) lock.Unlock() return c } // Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name func (c *FormatCheckerChain) Has(name string) bool { lock.RLock() _, ok := c.formatters[name] lock.RUnlock() return ok } // IsFormat will check an input against a FormatChecker with the given name // to see if it is the correct format func (c *FormatCheckerChain) IsFormat(name string, input interface{}) bool { lock.RLock() f, ok := c.formatters[name] lock.RUnlock() // If a format is unrecognized it should always pass validation if !ok { return true } return f.IsFormat(input) } // IsFormat checks if input is a correctly formatted e-mail address func (f EmailFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } _, err := mail.ParseAddress(asString) return err == nil } // IsFormat checks if input is a correctly formatted IPv4-address func (f IPV4FormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } // Credit: https://github.com/asaskevich/govalidator ip := net.ParseIP(asString) return ip != nil && strings.Contains(asString, ".") } // IsFormat checks if input is a correctly formatted IPv6=address func (f IPV6FormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } // Credit: https://github.com/asaskevich/govalidator ip := net.ParseIP(asString) return ip != nil && strings.Contains(asString, ":") } // IsFormat checks if input is a correctly formatted date/time per RFC3339 5.6 func (f DateTimeFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } formats := []string{ "15:04:05", "15:04:05Z07:00", "2006-01-02", time.RFC3339, time.RFC3339Nano, } for _, format := range formats { if _, err := time.Parse(format, asString); err == nil { return true } } return false } // IsFormat checks if input is a correctly formatted date (YYYY-MM-DD) func (f DateFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } _, err := time.Parse("2006-01-02", asString) return err == nil } // IsFormat checks if input correctly formatted time (HH:MM:SS or HH:MM:SSZ-07:00) func (f TimeFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } if _, err := time.Parse("15:04:05Z07:00", asString); err == nil { return true } _, err := time.Parse("15:04:05", asString) return err == nil } // IsFormat checks if input is correctly formatted URI with a valid Scheme per RFC3986 func (f URIFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } u, err := url.Parse(asString) if err != nil || u.Scheme == "" { return false } return !strings.Contains(asString, `\`) } // IsFormat checks if input is a correctly formatted URI or relative-reference per RFC3986 func (f URIReferenceFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } _, err := url.Parse(asString) return err == nil && !strings.Contains(asString, `\`) } // IsFormat checks if input is a correctly formatted URI template per RFC6570 func (f URITemplateFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } u, err := url.Parse(asString) if err != nil || strings.Contains(asString, `\`) { return false } return rxURITemplate.MatchString(u.Path) } // IsFormat checks if input is a correctly formatted hostname func (f HostnameFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } return rxHostname.MatchString(asString) && len(asString) < 256 } // IsFormat checks if input is a correctly formatted UUID func (f UUIDFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } return rxUUID.MatchString(asString) } // IsFormat checks if input is a correctly formatted regular expression func (f RegexFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } if asString == "" { return true } _, err := regexp.Compile(asString) return err == nil } // IsFormat checks if input is a correctly formatted JSON Pointer per RFC6901 func (f JSONPointerFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } return rxJSONPointer.MatchString(asString) } // IsFormat checks if input is a correctly formatted relative JSON Pointer func (f RelativeJSONPointerFormatChecker) IsFormat(input interface{}) bool { asString, ok := input.(string) if !ok { return false } return rxRelJSONPointer.MatchString(asString) } gojsonschema-1.2.0/format_checkers_test.go000066400000000000000000000012621355135071500207250ustar00rootroot00000000000000package gojsonschema import ( "github.com/stretchr/testify/assert" "testing" ) func TestUUIDFormatCheckerIsFormat(t *testing.T) { checker := UUIDFormatChecker{} assert.True(t, checker.IsFormat("01234567-89ab-cdef-0123-456789abcdef")) assert.True(t, checker.IsFormat("f1234567-89ab-cdef-0123-456789abcdef")) assert.False(t, checker.IsFormat("not-a-uuid")) assert.False(t, checker.IsFormat("g1234567-89ab-cdef-0123-456789abcdef")) } func TestURIReferenceFormatCheckerIsFormat(t *testing.T) { checker := URIReferenceFormatChecker{} assert.True(t, checker.IsFormat("relative")) assert.True(t, checker.IsFormat("https://dummyhost.com/dummy-path?dummy-qp-name=dummy-qp-value")) } gojsonschema-1.2.0/glide.yaml000066400000000000000000000004321355135071500161460ustar00rootroot00000000000000package: github.com/xeipuuv/gojsonschema license: Apache 2.0 import: - package: github.com/xeipuuv/gojsonschema - package: github.com/xeipuuv/gojsonpointer - package: github.com/xeipuuv/gojsonreference testImport: - package: github.com/stretchr/testify subpackages: - assert gojsonschema-1.2.0/go.mod000066400000000000000000000003601355135071500153040ustar00rootroot00000000000000module github.com/xeipuuv/gojsonschema require ( github.com/stretchr/testify v1.3.0 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 ) gojsonschema-1.2.0/go.sum000066400000000000000000000021021355135071500153250ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= gojsonschema-1.2.0/internalLog.go000066400000000000000000000021631355135071500170060ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Very simple log wrapper. // Used for debugging/testing purposes. // // created 01-01-2015 package gojsonschema import ( "log" ) const internalLogEnabled = false func internalLog(format string, v ...interface{}) { log.Printf(format, v...) } gojsonschema-1.2.0/jsonContext.go000066400000000000000000000040051355135071500170430ustar00rootroot00000000000000// Copyright 2013 MongoDB, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author tolsen // author-github https://github.com/tolsen // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context // // created 04-09-2013 package gojsonschema import "bytes" // JsonContext implements a persistent linked-list of strings type JsonContext struct { head string tail *JsonContext } // NewJsonContext creates a new JsonContext func NewJsonContext(head string, tail *JsonContext) *JsonContext { return &JsonContext{head, tail} } // String displays the context in reverse. // This plays well with the data structure's persistent nature with // Cons and a json document's tree structure. func (c *JsonContext) String(del ...string) string { byteArr := make([]byte, 0, c.stringLen()) buf := bytes.NewBuffer(byteArr) c.writeStringToBuffer(buf, del) return buf.String() } func (c *JsonContext) stringLen() int { length := 0 if c.tail != nil { length = c.tail.stringLen() + 1 // add 1 for "." } length += len(c.head) return length } func (c *JsonContext) writeStringToBuffer(buf *bytes.Buffer, del []string) { if c.tail != nil { c.tail.writeStringToBuffer(buf, del) if len(del) > 0 { buf.WriteString(del[0]) } else { buf.WriteString(".") } } buf.WriteString(c.head) } gojsonschema-1.2.0/jsonLoader.go000066400000000000000000000230351355135071500166310ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Different strategies to load JSON files. // Includes References (file and HTTP), JSON strings and Go types. // // created 01-02-2015 package gojsonschema import ( "bytes" "encoding/json" "errors" "io" "io/ioutil" "net/http" "net/url" "os" "path/filepath" "runtime" "strings" "github.com/xeipuuv/gojsonreference" ) var osFS = osFileSystem(os.Open) // JSONLoader defines the JSON loader interface type JSONLoader interface { JsonSource() interface{} LoadJSON() (interface{}, error) JsonReference() (gojsonreference.JsonReference, error) LoaderFactory() JSONLoaderFactory } // JSONLoaderFactory defines the JSON loader factory interface type JSONLoaderFactory interface { // New creates a new JSON loader for the given source New(source string) JSONLoader } // DefaultJSONLoaderFactory is the default JSON loader factory type DefaultJSONLoaderFactory struct { } // FileSystemJSONLoaderFactory is a JSON loader factory that uses http.FileSystem type FileSystemJSONLoaderFactory struct { fs http.FileSystem } // New creates a new JSON loader for the given source func (d DefaultJSONLoaderFactory) New(source string) JSONLoader { return &jsonReferenceLoader{ fs: osFS, source: source, } } // New creates a new JSON loader for the given source func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader { return &jsonReferenceLoader{ fs: f.fs, source: source, } } // osFileSystem is a functional wrapper for os.Open that implements http.FileSystem. type osFileSystem func(string) (*os.File, error) // Opens a file with the given name func (o osFileSystem) Open(name string) (http.File, error) { return o(name) } // JSON Reference loader // references are used to load JSONs from files and HTTP type jsonReferenceLoader struct { fs http.FileSystem source string } func (l *jsonReferenceLoader) JsonSource() interface{} { return l.source } func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference(l.JsonSource().(string)) } func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory { return &FileSystemJSONLoaderFactory{ fs: l.fs, } } // NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system. func NewReferenceLoader(source string) JSONLoader { return &jsonReferenceLoader{ fs: osFS, source: source, } } // NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system. func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) JSONLoader { return &jsonReferenceLoader{ fs: fs, source: source, } } func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) { var err error reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string)) if err != nil { return nil, err } refToURL := reference refToURL.GetUrl().Fragment = "" var document interface{} if reference.HasFileScheme { filename := strings.TrimPrefix(refToURL.String(), "file://") filename, err = url.QueryUnescape(filename) if err != nil { return nil, err } if runtime.GOOS == "windows" { // on Windows, a file URL may have an extra leading slash, use slashes // instead of backslashes, and have spaces escaped filename = strings.TrimPrefix(filename, "/") filename = filepath.FromSlash(filename) } document, err = l.loadFromFile(filename) if err != nil { return nil, err } } else { document, err = l.loadFromHTTP(refToURL.String()) if err != nil { return nil, err } } return document, nil } func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) { // returned cached versions for metaschemas for drafts 4, 6 and 7 // for performance and allow for easier offline use if metaSchema := drafts.GetMetaSchema(address); metaSchema != "" { return decodeJSONUsingNumber(strings.NewReader(metaSchema)) } resp, err := http.Get(address) if err != nil { return nil, err } // must return HTTP Status 200 OK if resp.StatusCode != http.StatusOK { return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status})) } bodyBuff, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } return decodeJSONUsingNumber(bytes.NewReader(bodyBuff)) } func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) { f, err := l.fs.Open(path) if err != nil { return nil, err } defer f.Close() bodyBuff, err := ioutil.ReadAll(f) if err != nil { return nil, err } return decodeJSONUsingNumber(bytes.NewReader(bodyBuff)) } // JSON string loader type jsonStringLoader struct { source string } func (l *jsonStringLoader) JsonSource() interface{} { return l.source } func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference("#") } func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory { return &DefaultJSONLoaderFactory{} } // NewStringLoader creates a new JSONLoader, taking a string as source func NewStringLoader(source string) JSONLoader { return &jsonStringLoader{source: source} } func (l *jsonStringLoader) LoadJSON() (interface{}, error) { return decodeJSONUsingNumber(strings.NewReader(l.JsonSource().(string))) } // JSON bytes loader type jsonBytesLoader struct { source []byte } func (l *jsonBytesLoader) JsonSource() interface{} { return l.source } func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference("#") } func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory { return &DefaultJSONLoaderFactory{} } // NewBytesLoader creates a new JSONLoader, taking a `[]byte` as source func NewBytesLoader(source []byte) JSONLoader { return &jsonBytesLoader{source: source} } func (l *jsonBytesLoader) LoadJSON() (interface{}, error) { return decodeJSONUsingNumber(bytes.NewReader(l.JsonSource().([]byte))) } // JSON Go (types) loader // used to load JSONs from the code as maps, interface{}, structs ... type jsonGoLoader struct { source interface{} } func (l *jsonGoLoader) JsonSource() interface{} { return l.source } func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference("#") } func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory { return &DefaultJSONLoaderFactory{} } // NewGoLoader creates a new JSONLoader from a given Go struct func NewGoLoader(source interface{}) JSONLoader { return &jsonGoLoader{source: source} } func (l *jsonGoLoader) LoadJSON() (interface{}, error) { // convert it to a compliant JSON first to avoid types "mismatches" jsonBytes, err := json.Marshal(l.JsonSource()) if err != nil { return nil, err } return decodeJSONUsingNumber(bytes.NewReader(jsonBytes)) } type jsonIOLoader struct { buf *bytes.Buffer } // NewReaderLoader creates a new JSON loader using the provided io.Reader func NewReaderLoader(source io.Reader) (JSONLoader, io.Reader) { buf := &bytes.Buffer{} return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf) } // NewWriterLoader creates a new JSON loader using the provided io.Writer func NewWriterLoader(source io.Writer) (JSONLoader, io.Writer) { buf := &bytes.Buffer{} return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf) } func (l *jsonIOLoader) JsonSource() interface{} { return l.buf.String() } func (l *jsonIOLoader) LoadJSON() (interface{}, error) { return decodeJSONUsingNumber(l.buf) } func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference("#") } func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory { return &DefaultJSONLoaderFactory{} } // JSON raw loader // In case the JSON is already marshalled to interface{} use this loader // This is used for testing as otherwise there is no guarantee the JSON is marshalled // "properly" by using https://golang.org/pkg/encoding/json/#Decoder.UseNumber type jsonRawLoader struct { source interface{} } // NewRawLoader creates a new JSON raw loader for the given source func NewRawLoader(source interface{}) JSONLoader { return &jsonRawLoader{source: source} } func (l *jsonRawLoader) JsonSource() interface{} { return l.source } func (l *jsonRawLoader) LoadJSON() (interface{}, error) { return l.source, nil } func (l *jsonRawLoader) JsonReference() (gojsonreference.JsonReference, error) { return gojsonreference.NewJsonReference("#") } func (l *jsonRawLoader) LoaderFactory() JSONLoaderFactory { return &DefaultJSONLoaderFactory{} } func decodeJSONUsingNumber(r io.Reader) (interface{}, error) { var document interface{} decoder := json.NewDecoder(r) decoder.UseNumber() err := decoder.Decode(&document) if err != nil { return nil, err } return document, nil } gojsonschema-1.2.0/jsonschema_test.go000066400000000000000000000103751355135071500177250ustar00rootroot00000000000000// Copyright 2017 johandorland ( https://github.com/johandorland ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gojsonschema import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" "path/filepath" "regexp" "strings" "testing" ) type jsonSchemaTest struct { Description string `json:"description"` // Some tests may not always pass, so some tests are manually edited to include // an extra attribute whether that specific test should be disabled and skipped Disabled bool `json:"disabled"` Schema interface{} `json:"schema"` Tests []jsonSchemaTestCase `json:"tests"` } type jsonSchemaTestCase struct { Description string `json:"description"` Data interface{} `json:"data"` Valid bool `json:"valid"` } //Skip any directories not named appropiately // filepath.Walk will also visit files in the root of the test directory var testDirectories = regexp.MustCompile(`(draft\d+)`) var draftMapping = map[string]Draft{ "draft4": Draft4, "draft6": Draft6, "draft7": Draft7, } func executeTests(t *testing.T, path string) error { file, err := os.Open(path) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } fmt.Println(file.Name()) var tests []jsonSchemaTest d := json.NewDecoder(file) d.UseNumber() err = d.Decode(&tests) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } draft := Hybrid if m := testDirectories.FindString(path); m != "" { draft = draftMapping[m] } for _, test := range tests { fmt.Println(" " + test.Description) if test.Disabled { continue } testSchemaLoader := NewRawLoader(test.Schema) sl := NewSchemaLoader() sl.Draft = draft sl.Validate = true testSchema, err := sl.Compile(testSchemaLoader) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } for _, testCase := range test.Tests { testDataLoader := NewRawLoader(testCase.Data) result, err := testSchema.Validate(testDataLoader) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } if result.Valid() != testCase.Valid { schemaString, _ := marshalToJSONString(test.Schema) testCaseString, _ := marshalToJSONString(testCase.Data) t.Errorf("Test failed : %s\n"+ "%s.\n"+ "%s.\n"+ "expects: %t, given %t\n"+ "Schema: %s\n"+ "Data: %s\n", file.Name(), test.Description, testCase.Description, testCase.Valid, result.Valid(), *schemaString, *testCaseString) } } } return nil } func TestSuite(t *testing.T) { wd, err := os.Getwd() if err != nil { panic(err.Error()) } wd = filepath.Join(wd, "testdata") go func() { err := http.ListenAndServe(":1234", http.FileServer(http.Dir(filepath.Join(wd, "remotes")))) if err != nil { panic(err.Error()) } }() err = filepath.Walk(wd, func(path string, fileInfo os.FileInfo, err error) error { if fileInfo.IsDir() && path != wd && !testDirectories.MatchString(fileInfo.Name()) { return filepath.SkipDir } if !strings.HasSuffix(fileInfo.Name(), ".json") { return nil } return executeTests(t, path) }) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } } func TestFormats(t *testing.T) { wd, err := os.Getwd() if err != nil { panic(err.Error()) } wd = filepath.Join(wd, "testdata") dirs, err := ioutil.ReadDir(wd) if err != nil { panic(err.Error()) } for _, dir := range dirs { if testDirectories.MatchString(dir.Name()) { formatsDirectory := filepath.Join(wd, dir.Name(), "optional", "format") err = filepath.Walk(formatsDirectory, func(path string, fileInfo os.FileInfo, err error) error { if fileInfo == nil || !strings.HasSuffix(fileInfo.Name(), ".json") { return nil } return executeTests(t, path) }) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } } } } gojsonschema-1.2.0/locales.go000066400000000000000000000413671355135071500161630ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Contains const string and messages. // // created 01-01-2015 package gojsonschema type ( // locale is an interface for defining custom error strings locale interface { // False returns a format-string for "false" schema validation errors False() string // Required returns a format-string for "required" schema validation errors Required() string // InvalidType returns a format-string for "invalid type" schema validation errors InvalidType() string // NumberAnyOf returns a format-string for "anyOf" schema validation errors NumberAnyOf() string // NumberOneOf returns a format-string for "oneOf" schema validation errors NumberOneOf() string // NumberAllOf returns a format-string for "allOf" schema validation errors NumberAllOf() string // NumberNot returns a format-string to format a NumberNotError NumberNot() string // MissingDependency returns a format-string for "missing dependency" schema validation errors MissingDependency() string // Internal returns a format-string for internal errors Internal() string // Const returns a format-string to format a ConstError Const() string // Enum returns a format-string to format an EnumError Enum() string // ArrayNotEnoughItems returns a format-string to format an error for arrays having not enough items to match positional list of schema ArrayNotEnoughItems() string // ArrayNoAdditionalItems returns a format-string to format an ArrayNoAdditionalItemsError ArrayNoAdditionalItems() string // ArrayMinItems returns a format-string to format an ArrayMinItemsError ArrayMinItems() string // ArrayMaxItems returns a format-string to format an ArrayMaxItemsError ArrayMaxItems() string // Unique returns a format-string to format an ItemsMustBeUniqueError Unique() string // ArrayContains returns a format-string to format an ArrayContainsError ArrayContains() string // ArrayMinProperties returns a format-string to format an ArrayMinPropertiesError ArrayMinProperties() string // ArrayMaxProperties returns a format-string to format an ArrayMaxPropertiesError ArrayMaxProperties() string // AdditionalPropertyNotAllowed returns a format-string to format an AdditionalPropertyNotAllowedError AdditionalPropertyNotAllowed() string // InvalidPropertyPattern returns a format-string to format an InvalidPropertyPatternError InvalidPropertyPattern() string // InvalidPropertyName returns a format-string to format an InvalidPropertyNameError InvalidPropertyName() string // StringGTE returns a format-string to format an StringLengthGTEError StringGTE() string // StringLTE returns a format-string to format an StringLengthLTEError StringLTE() string // DoesNotMatchPattern returns a format-string to format an DoesNotMatchPatternError DoesNotMatchPattern() string // DoesNotMatchFormat returns a format-string to format an DoesNotMatchFormatError DoesNotMatchFormat() string // MultipleOf returns a format-string to format an MultipleOfError MultipleOf() string // NumberGTE returns a format-string to format an NumberGTEError NumberGTE() string // NumberGT returns a format-string to format an NumberGTError NumberGT() string // NumberLTE returns a format-string to format an NumberLTEError NumberLTE() string // NumberLT returns a format-string to format an NumberLTError NumberLT() string // Schema validations // RegexPattern returns a format-string to format a regex-pattern error RegexPattern() string // GreaterThanZero returns a format-string to format an error where a number must be greater than zero GreaterThanZero() string // MustBeOfA returns a format-string to format an error where a value is of the wrong type MustBeOfA() string // MustBeOfAn returns a format-string to format an error where a value is of the wrong type MustBeOfAn() string // CannotBeUsedWithout returns a format-string to format a "cannot be used without" error CannotBeUsedWithout() string // CannotBeGT returns a format-string to format an error where a value are greater than allowed CannotBeGT() string // MustBeOfType returns a format-string to format an error where a value does not match the required type MustBeOfType() string // MustBeValidRegex returns a format-string to format an error where a regex is invalid MustBeValidRegex() string // MustBeValidFormat returns a format-string to format an error where a value does not match the expected format MustBeValidFormat() string // MustBeGTEZero returns a format-string to format an error where a value must be greater or equal than 0 MustBeGTEZero() string // KeyCannotBeGreaterThan returns a format-string to format an error where a key is greater than the maximum allowed KeyCannotBeGreaterThan() string // KeyItemsMustBeOfType returns a format-string to format an error where a key is of the wrong type KeyItemsMustBeOfType() string // KeyItemsMustBeUnique returns a format-string to format an error where keys are not unique KeyItemsMustBeUnique() string // ReferenceMustBeCanonical returns a format-string to format a "reference must be canonical" error ReferenceMustBeCanonical() string // NotAValidType returns a format-string to format an invalid type error NotAValidType() string // Duplicated returns a format-string to format an error where types are duplicated Duplicated() string // HttpBadStatus returns a format-string for errors when loading a schema using HTTP HttpBadStatus() string // ParseError returns a format-string for JSON parsing errors ParseError() string // ConditionThen returns a format-string for ConditionThenError errors ConditionThen() string // ConditionElse returns a format-string for ConditionElseError errors ConditionElse() string // ErrorFormat returns a format string for errors ErrorFormat() string } // DefaultLocale is the default locale for this package DefaultLocale struct{} ) // False returns a format-string for "false" schema validation errors func (l DefaultLocale) False() string { return "False always fails validation" } // Required returns a format-string for "required" schema validation errors func (l DefaultLocale) Required() string { return `{{.property}} is required` } // InvalidType returns a format-string for "invalid type" schema validation errors func (l DefaultLocale) InvalidType() string { return `Invalid type. Expected: {{.expected}}, given: {{.given}}` } // NumberAnyOf returns a format-string for "anyOf" schema validation errors func (l DefaultLocale) NumberAnyOf() string { return `Must validate at least one schema (anyOf)` } // NumberOneOf returns a format-string for "oneOf" schema validation errors func (l DefaultLocale) NumberOneOf() string { return `Must validate one and only one schema (oneOf)` } // NumberAllOf returns a format-string for "allOf" schema validation errors func (l DefaultLocale) NumberAllOf() string { return `Must validate all the schemas (allOf)` } // NumberNot returns a format-string to format a NumberNotError func (l DefaultLocale) NumberNot() string { return `Must not validate the schema (not)` } // MissingDependency returns a format-string for "missing dependency" schema validation errors func (l DefaultLocale) MissingDependency() string { return `Has a dependency on {{.dependency}}` } // Internal returns a format-string for internal errors func (l DefaultLocale) Internal() string { return `Internal Error {{.error}}` } // Const returns a format-string to format a ConstError func (l DefaultLocale) Const() string { return `{{.field}} does not match: {{.allowed}}` } // Enum returns a format-string to format an EnumError func (l DefaultLocale) Enum() string { return `{{.field}} must be one of the following: {{.allowed}}` } // ArrayNoAdditionalItems returns a format-string to format an ArrayNoAdditionalItemsError func (l DefaultLocale) ArrayNoAdditionalItems() string { return `No additional items allowed on array` } // ArrayNotEnoughItems returns a format-string to format an error for arrays having not enough items to match positional list of schema func (l DefaultLocale) ArrayNotEnoughItems() string { return `Not enough items on array to match positional list of schema` } // ArrayMinItems returns a format-string to format an ArrayMinItemsError func (l DefaultLocale) ArrayMinItems() string { return `Array must have at least {{.min}} items` } // ArrayMaxItems returns a format-string to format an ArrayMaxItemsError func (l DefaultLocale) ArrayMaxItems() string { return `Array must have at most {{.max}} items` } // Unique returns a format-string to format an ItemsMustBeUniqueError func (l DefaultLocale) Unique() string { return `{{.type}} items[{{.i}},{{.j}}] must be unique` } // ArrayContains returns a format-string to format an ArrayContainsError func (l DefaultLocale) ArrayContains() string { return `At least one of the items must match` } // ArrayMinProperties returns a format-string to format an ArrayMinPropertiesError func (l DefaultLocale) ArrayMinProperties() string { return `Must have at least {{.min}} properties` } // ArrayMaxProperties returns a format-string to format an ArrayMaxPropertiesError func (l DefaultLocale) ArrayMaxProperties() string { return `Must have at most {{.max}} properties` } // AdditionalPropertyNotAllowed returns a format-string to format an AdditionalPropertyNotAllowedError func (l DefaultLocale) AdditionalPropertyNotAllowed() string { return `Additional property {{.property}} is not allowed` } // InvalidPropertyPattern returns a format-string to format an InvalidPropertyPatternError func (l DefaultLocale) InvalidPropertyPattern() string { return `Property "{{.property}}" does not match pattern {{.pattern}}` } // InvalidPropertyName returns a format-string to format an InvalidPropertyNameError func (l DefaultLocale) InvalidPropertyName() string { return `Property name of "{{.property}}" does not match` } // StringGTE returns a format-string to format an StringLengthGTEError func (l DefaultLocale) StringGTE() string { return `String length must be greater than or equal to {{.min}}` } // StringLTE returns a format-string to format an StringLengthLTEError func (l DefaultLocale) StringLTE() string { return `String length must be less than or equal to {{.max}}` } // DoesNotMatchPattern returns a format-string to format an DoesNotMatchPatternError func (l DefaultLocale) DoesNotMatchPattern() string { return `Does not match pattern '{{.pattern}}'` } // DoesNotMatchFormat returns a format-string to format an DoesNotMatchFormatError func (l DefaultLocale) DoesNotMatchFormat() string { return `Does not match format '{{.format}}'` } // MultipleOf returns a format-string to format an MultipleOfError func (l DefaultLocale) MultipleOf() string { return `Must be a multiple of {{.multiple}}` } // NumberGTE returns the format string to format a NumberGTEError func (l DefaultLocale) NumberGTE() string { return `Must be greater than or equal to {{.min}}` } // NumberGT returns the format string to format a NumberGTError func (l DefaultLocale) NumberGT() string { return `Must be greater than {{.min}}` } // NumberLTE returns the format string to format a NumberLTEError func (l DefaultLocale) NumberLTE() string { return `Must be less than or equal to {{.max}}` } // NumberLT returns the format string to format a NumberLTError func (l DefaultLocale) NumberLT() string { return `Must be less than {{.max}}` } // Schema validators // RegexPattern returns a format-string to format a regex-pattern error func (l DefaultLocale) RegexPattern() string { return `Invalid regex pattern '{{.pattern}}'` } // GreaterThanZero returns a format-string to format an error where a number must be greater than zero func (l DefaultLocale) GreaterThanZero() string { return `{{.number}} must be strictly greater than 0` } // MustBeOfA returns a format-string to format an error where a value is of the wrong type func (l DefaultLocale) MustBeOfA() string { return `{{.x}} must be of a {{.y}}` } // MustBeOfAn returns a format-string to format an error where a value is of the wrong type func (l DefaultLocale) MustBeOfAn() string { return `{{.x}} must be of an {{.y}}` } // CannotBeUsedWithout returns a format-string to format a "cannot be used without" error func (l DefaultLocale) CannotBeUsedWithout() string { return `{{.x}} cannot be used without {{.y}}` } // CannotBeGT returns a format-string to format an error where a value are greater than allowed func (l DefaultLocale) CannotBeGT() string { return `{{.x}} cannot be greater than {{.y}}` } // MustBeOfType returns a format-string to format an error where a value does not match the required type func (l DefaultLocale) MustBeOfType() string { return `{{.key}} must be of type {{.type}}` } // MustBeValidRegex returns a format-string to format an error where a regex is invalid func (l DefaultLocale) MustBeValidRegex() string { return `{{.key}} must be a valid regex` } // MustBeValidFormat returns a format-string to format an error where a value does not match the expected format func (l DefaultLocale) MustBeValidFormat() string { return `{{.key}} must be a valid format {{.given}}` } // MustBeGTEZero returns a format-string to format an error where a value must be greater or equal than 0 func (l DefaultLocale) MustBeGTEZero() string { return `{{.key}} must be greater than or equal to 0` } // KeyCannotBeGreaterThan returns a format-string to format an error where a value is greater than the maximum allowed func (l DefaultLocale) KeyCannotBeGreaterThan() string { return `{{.key}} cannot be greater than {{.y}}` } // KeyItemsMustBeOfType returns a format-string to format an error where a key is of the wrong type func (l DefaultLocale) KeyItemsMustBeOfType() string { return `{{.key}} items must be {{.type}}` } // KeyItemsMustBeUnique returns a format-string to format an error where keys are not unique func (l DefaultLocale) KeyItemsMustBeUnique() string { return `{{.key}} items must be unique` } // ReferenceMustBeCanonical returns a format-string to format a "reference must be canonical" error func (l DefaultLocale) ReferenceMustBeCanonical() string { return `Reference {{.reference}} must be canonical` } // NotAValidType returns a format-string to format an invalid type error func (l DefaultLocale) NotAValidType() string { return `has a primitive type that is NOT VALID -- given: {{.given}} Expected valid values are:{{.expected}}` } // Duplicated returns a format-string to format an error where types are duplicated func (l DefaultLocale) Duplicated() string { return `{{.type}} type is duplicated` } // HttpBadStatus returns a format-string for errors when loading a schema using HTTP func (l DefaultLocale) HttpBadStatus() string { return `Could not read schema from HTTP, response status is {{.status}}` } // ErrorFormat returns a format string for errors // Replacement options: field, description, context, value func (l DefaultLocale) ErrorFormat() string { return `{{.field}}: {{.description}}` } // ParseError returns a format-string for JSON parsing errors func (l DefaultLocale) ParseError() string { return `Expected: {{.expected}}, given: Invalid JSON` } // ConditionThen returns a format-string for ConditionThenError errors // If/Else func (l DefaultLocale) ConditionThen() string { return `Must validate "then" as "if" was valid` } // ConditionElse returns a format-string for ConditionElseError errors func (l DefaultLocale) ConditionElse() string { return `Must validate "else" as "if" was not valid` } // constants const ( STRING_NUMBER = "number" STRING_ARRAY_OF_STRINGS = "array of strings" STRING_ARRAY_OF_SCHEMAS = "array of schemas" STRING_SCHEMA = "valid schema" STRING_SCHEMA_OR_ARRAY_OF_STRINGS = "schema or array of strings" STRING_PROPERTIES = "properties" STRING_DEPENDENCY = "dependency" STRING_PROPERTY = "property" STRING_UNDEFINED = "undefined" STRING_CONTEXT_ROOT = "(root)" STRING_ROOT_SCHEMA_PROPERTY = "(root)" ) gojsonschema-1.2.0/result.go000066400000000000000000000160411355135071500160460ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Result and ResultError implementations. // // created 01-01-2015 package gojsonschema import ( "fmt" "strings" ) type ( // ErrorDetails is a map of details specific to each error. // While the values will vary, every error will contain a "field" value ErrorDetails map[string]interface{} // ResultError is the interface that library errors must implement ResultError interface { // Field returns the field name without the root context // i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName Field() string // SetType sets the error-type SetType(string) // Type returns the error-type Type() string // SetContext sets the JSON-context for the error SetContext(*JsonContext) // Context returns the JSON-context of the error Context() *JsonContext // SetDescription sets a description for the error SetDescription(string) // Description returns the description of the error Description() string // SetDescriptionFormat sets the format for the description in the default text/template format SetDescriptionFormat(string) // DescriptionFormat returns the format for the description in the default text/template format DescriptionFormat() string // SetValue sets the value related to the error SetValue(interface{}) // Value returns the value related to the error Value() interface{} // SetDetails sets the details specific to the error SetDetails(ErrorDetails) // Details returns details about the error Details() ErrorDetails // String returns a string representation of the error String() string } // ResultErrorFields holds the fields for each ResultError implementation. // ResultErrorFields implements the ResultError interface, so custom errors // can be defined by just embedding this type ResultErrorFields struct { errorType string // A string with the type of error (i.e. invalid_type) context *JsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ... description string // A human readable error message descriptionFormat string // A format for human readable error message value interface{} // Value given by the JSON file that is the source of the error details ErrorDetails } // Result holds the result of a validation Result struct { errors []ResultError // Scores how well the validation matched. Useful in generating // better error messages for anyOf and oneOf. score int } ) // Field returns the field name without the root context // i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName func (v *ResultErrorFields) Field() string { return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".") } // SetType sets the error-type func (v *ResultErrorFields) SetType(errorType string) { v.errorType = errorType } // Type returns the error-type func (v *ResultErrorFields) Type() string { return v.errorType } // SetContext sets the JSON-context for the error func (v *ResultErrorFields) SetContext(context *JsonContext) { v.context = context } // Context returns the JSON-context of the error func (v *ResultErrorFields) Context() *JsonContext { return v.context } // SetDescription sets a description for the error func (v *ResultErrorFields) SetDescription(description string) { v.description = description } // Description returns the description of the error func (v *ResultErrorFields) Description() string { return v.description } // SetDescriptionFormat sets the format for the description in the default text/template format func (v *ResultErrorFields) SetDescriptionFormat(descriptionFormat string) { v.descriptionFormat = descriptionFormat } // DescriptionFormat returns the format for the description in the default text/template format func (v *ResultErrorFields) DescriptionFormat() string { return v.descriptionFormat } // SetValue sets the value related to the error func (v *ResultErrorFields) SetValue(value interface{}) { v.value = value } // Value returns the value related to the error func (v *ResultErrorFields) Value() interface{} { return v.value } // SetDetails sets the details specific to the error func (v *ResultErrorFields) SetDetails(details ErrorDetails) { v.details = details } // Details returns details about the error func (v *ResultErrorFields) Details() ErrorDetails { return v.details } // String returns a string representation of the error func (v ResultErrorFields) String() string { // as a fallback, the value is displayed go style valueString := fmt.Sprintf("%v", v.value) // marshal the go value value to json if v.value == nil { valueString = TYPE_NULL } else { if vs, err := marshalToJSONString(v.value); err == nil { if vs == nil { valueString = TYPE_NULL } else { valueString = *vs } } } return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{ "context": v.context.String(), "description": v.description, "value": valueString, "field": v.Field(), }) } // Valid indicates if no errors were found func (v *Result) Valid() bool { return len(v.errors) == 0 } // Errors returns the errors that were found func (v *Result) Errors() []ResultError { return v.errors } // AddError appends a fully filled error to the error set // SetDescription() will be called with the result of the parsed err.DescriptionFormat() func (v *Result) AddError(err ResultError, details ErrorDetails) { if _, exists := details["context"]; !exists && err.Context() != nil { details["context"] = err.Context().String() } err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details)) v.errors = append(v.errors, err) } func (v *Result) addInternalError(err ResultError, context *JsonContext, value interface{}, details ErrorDetails) { newError(err, context, value, Locale, details) v.errors = append(v.errors, err) v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function } // Used to copy errors from a sub-schema to the main one func (v *Result) mergeErrors(otherResult *Result) { v.errors = append(v.errors, otherResult.Errors()...) v.score += otherResult.score } func (v *Result) incrementScore() { v.score++ } gojsonschema-1.2.0/schema.go000066400000000000000000000721131355135071500157720ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Defines Schema, the main entry to every subSchema. // Contains the parsing logic and error checking. // // created 26-02-2013 package gojsonschema import ( "errors" "math/big" "reflect" "regexp" "text/template" "github.com/xeipuuv/gojsonreference" ) var ( // Locale is the default locale to use // Library users can overwrite with their own implementation Locale locale = DefaultLocale{} // ErrorTemplateFuncs allows you to define custom template funcs for use in localization. ErrorTemplateFuncs template.FuncMap ) // NewSchema instances a schema using the given JSONLoader func NewSchema(l JSONLoader) (*Schema, error) { return NewSchemaLoader().Compile(l) } // Schema holds a schema type Schema struct { documentReference gojsonreference.JsonReference rootSchema *subSchema pool *schemaPool referencePool *schemaReferencePool } func (d *Schema) parse(document interface{}, draft Draft) error { d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY, draft: &draft} return d.parseSchema(document, d.rootSchema) } // SetRootSchemaName sets the root-schema name func (d *Schema) SetRootSchemaName(name string) { d.rootSchema.property = name } // Parses a subSchema // // Pretty long function ( sorry :) )... but pretty straight forward, repetitive and boring // Not much magic involved here, most of the job is to validate the key names and their values, // then the values are copied into subSchema struct // func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error { if currentSchema.draft == nil { if currentSchema.parent == nil { return errors.New("Draft not set") } currentSchema.draft = currentSchema.parent.draft } // As of draft 6 "true" is equivalent to an empty schema "{}" and false equals "{"not":{}}" if *currentSchema.draft >= Draft6 && isKind(documentNode, reflect.Bool) { b := documentNode.(bool) currentSchema.pass = &b return nil } if !isKind(documentNode, reflect.Map) { return errors.New(formatErrorDescription( Locale.ParseError(), ErrorDetails{ "expected": STRING_SCHEMA, }, )) } m := documentNode.(map[string]interface{}) if currentSchema.parent == nil { currentSchema.ref = &d.documentReference currentSchema.id = &d.documentReference } if currentSchema.id == nil && currentSchema.parent != nil { currentSchema.id = currentSchema.parent.id } // In draft 6 the id keyword was renamed to $id // Hybrid mode uses the old id by default var keyID string switch *currentSchema.draft { case Draft4: keyID = KEY_ID case Hybrid: keyID = KEY_ID_NEW if existsMapKey(m, KEY_ID) { keyID = KEY_ID } default: keyID = KEY_ID_NEW } if existsMapKey(m, keyID) && !isKind(m[keyID], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": keyID, }, )) } if k, ok := m[keyID].(string); ok { jsonReference, err := gojsonreference.NewJsonReference(k) if err != nil { return err } if currentSchema == d.rootSchema { currentSchema.id = &jsonReference } else { ref, err := currentSchema.parent.id.Inherits(jsonReference) if err != nil { return err } currentSchema.id = ref } } // definitions if existsMapKey(m, KEY_DEFINITIONS) { if isKind(m[KEY_DEFINITIONS], reflect.Map, reflect.Bool) { for _, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) { if isKind(dv, reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema} err := d.parseSchema(dv, newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_ARRAY_OF_SCHEMAS, "given": KEY_DEFINITIONS, }, )) } } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_ARRAY_OF_SCHEMAS, "given": KEY_DEFINITIONS, }, )) } } // title if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": KEY_TITLE, }, )) } if k, ok := m[KEY_TITLE].(string); ok { currentSchema.title = &k } // description if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": KEY_DESCRIPTION, }, )) } if k, ok := m[KEY_DESCRIPTION].(string); ok { currentSchema.description = &k } // $ref if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": KEY_REF, }, )) } if k, ok := m[KEY_REF].(string); ok { jsonReference, err := gojsonreference.NewJsonReference(k) if err != nil { return err } currentSchema.ref = &jsonReference if sch, ok := d.referencePool.Get(currentSchema.ref.String()); ok { currentSchema.refSchema = sch } else { err := d.parseReference(documentNode, currentSchema) if err != nil { return err } return nil } } // type if existsMapKey(m, KEY_TYPE) { if isKind(m[KEY_TYPE], reflect.String) { if k, ok := m[KEY_TYPE].(string); ok { err := currentSchema.types.Add(k) if err != nil { return err } } } else { if isKind(m[KEY_TYPE], reflect.Slice) { arrayOfTypes := m[KEY_TYPE].([]interface{}) for _, typeInArray := range arrayOfTypes { if reflect.ValueOf(typeInArray).Kind() != reflect.String { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS, "given": KEY_TYPE, }, )) } if err := currentSchema.types.Add(typeInArray.(string)); err != nil { return err } } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS, "given": KEY_TYPE, }, )) } } } // properties if existsMapKey(m, KEY_PROPERTIES) { err := d.parseProperties(m[KEY_PROPERTIES], currentSchema) if err != nil { return err } } // additionalProperties if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) { if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) { currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool) } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) { newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref} currentSchema.additionalProperties = newSchema err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema) if err != nil { return errors.New(err.Error()) } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA, "given": KEY_ADDITIONAL_PROPERTIES, }, )) } } // patternProperties if existsMapKey(m, KEY_PATTERN_PROPERTIES) { if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) { patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{}) if len(patternPropertiesMap) > 0 { currentSchema.patternProperties = make(map[string]*subSchema) for k, v := range patternPropertiesMap { _, err := regexp.MatchString(k, "") if err != nil { return errors.New(formatErrorDescription( Locale.RegexPattern(), ErrorDetails{"pattern": k}, )) } newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref} err = d.parseSchema(v, newSchema) if err != nil { return errors.New(err.Error()) } currentSchema.patternProperties[k] = newSchema } } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_SCHEMA, "given": KEY_PATTERN_PROPERTIES, }, )) } } // propertyNames if existsMapKey(m, KEY_PROPERTY_NAMES) && *currentSchema.draft >= Draft6 { if isKind(m[KEY_PROPERTY_NAMES], reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_PROPERTY_NAMES, parent: currentSchema, ref: currentSchema.ref} currentSchema.propertyNames = newSchema err := d.parseSchema(m[KEY_PROPERTY_NAMES], newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_SCHEMA, "given": KEY_PATTERN_PROPERTIES, }, )) } } // dependencies if existsMapKey(m, KEY_DEPENDENCIES) { err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema) if err != nil { return err } } // items if existsMapKey(m, KEY_ITEMS) { if isKind(m[KEY_ITEMS], reflect.Slice) { for _, itemElement := range m[KEY_ITEMS].([]interface{}) { if isKind(itemElement, reflect.Map, reflect.Bool) { newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} newSchema.ref = currentSchema.ref currentSchema.itemsChildren = append(currentSchema.itemsChildren, newSchema) err := d.parseSchema(itemElement, newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS, "given": KEY_ITEMS, }, )) } currentSchema.itemsChildrenIsSingleSchema = false } } else if isKind(m[KEY_ITEMS], reflect.Map, reflect.Bool) { newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} newSchema.ref = currentSchema.ref currentSchema.itemsChildren = append(currentSchema.itemsChildren, newSchema) err := d.parseSchema(m[KEY_ITEMS], newSchema) if err != nil { return err } currentSchema.itemsChildrenIsSingleSchema = true } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS, "given": KEY_ITEMS, }, )) } } // additionalItems if existsMapKey(m, KEY_ADDITIONAL_ITEMS) { if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) { currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool) } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) { newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref} currentSchema.additionalItems = newSchema err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema) if err != nil { return errors.New(err.Error()) } } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA, "given": KEY_ADDITIONAL_ITEMS, }, )) } } // validation : number / integer if existsMapKey(m, KEY_MULTIPLE_OF) { multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF]) if multipleOfValue == nil { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": STRING_NUMBER, "given": KEY_MULTIPLE_OF, }, )) } if multipleOfValue.Cmp(big.NewRat(0, 1)) <= 0 { return errors.New(formatErrorDescription( Locale.GreaterThanZero(), ErrorDetails{"number": KEY_MULTIPLE_OF}, )) } currentSchema.multipleOf = multipleOfValue } if existsMapKey(m, KEY_MINIMUM) { minimumValue := mustBeNumber(m[KEY_MINIMUM]) if minimumValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER}, )) } currentSchema.minimum = minimumValue } if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) { switch *currentSchema.draft { case Draft4: if !isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN, "given": KEY_EXCLUSIVE_MINIMUM, }, )) } if currentSchema.minimum == nil { return errors.New(formatErrorDescription( Locale.CannotBeUsedWithout(), ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM}, )) } if m[KEY_EXCLUSIVE_MINIMUM].(bool) { currentSchema.exclusiveMinimum = currentSchema.minimum currentSchema.minimum = nil } case Hybrid: if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) { if currentSchema.minimum == nil { return errors.New(formatErrorDescription( Locale.CannotBeUsedWithout(), ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM}, )) } if m[KEY_EXCLUSIVE_MINIMUM].(bool) { currentSchema.exclusiveMinimum = currentSchema.minimum currentSchema.minimum = nil } } else if isJSONNumber(m[KEY_EXCLUSIVE_MINIMUM]) { currentSchema.exclusiveMinimum = mustBeNumber(m[KEY_EXCLUSIVE_MINIMUM]) } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN + "/" + TYPE_NUMBER, "given": KEY_EXCLUSIVE_MINIMUM, }, )) } default: if isJSONNumber(m[KEY_EXCLUSIVE_MINIMUM]) { currentSchema.exclusiveMinimum = mustBeNumber(m[KEY_EXCLUSIVE_MINIMUM]) } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_NUMBER, "given": KEY_EXCLUSIVE_MINIMUM, }, )) } } } if existsMapKey(m, KEY_MAXIMUM) { maximumValue := mustBeNumber(m[KEY_MAXIMUM]) if maximumValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER}, )) } currentSchema.maximum = maximumValue } if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) { switch *currentSchema.draft { case Draft4: if !isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN, "given": KEY_EXCLUSIVE_MAXIMUM, }, )) } if currentSchema.maximum == nil { return errors.New(formatErrorDescription( Locale.CannotBeUsedWithout(), ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM}, )) } if m[KEY_EXCLUSIVE_MAXIMUM].(bool) { currentSchema.exclusiveMaximum = currentSchema.maximum currentSchema.maximum = nil } case Hybrid: if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) { if currentSchema.maximum == nil { return errors.New(formatErrorDescription( Locale.CannotBeUsedWithout(), ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM}, )) } if m[KEY_EXCLUSIVE_MAXIMUM].(bool) { currentSchema.exclusiveMaximum = currentSchema.maximum currentSchema.maximum = nil } } else if isJSONNumber(m[KEY_EXCLUSIVE_MAXIMUM]) { currentSchema.exclusiveMaximum = mustBeNumber(m[KEY_EXCLUSIVE_MAXIMUM]) } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_BOOLEAN + "/" + TYPE_NUMBER, "given": KEY_EXCLUSIVE_MAXIMUM, }, )) } default: if isJSONNumber(m[KEY_EXCLUSIVE_MAXIMUM]) { currentSchema.exclusiveMaximum = mustBeNumber(m[KEY_EXCLUSIVE_MAXIMUM]) } else { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_NUMBER, "given": KEY_EXCLUSIVE_MAXIMUM, }, )) } } } // validation : string if existsMapKey(m, KEY_MIN_LENGTH) { minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH]) if minLengthIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER}, )) } if *minLengthIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MIN_LENGTH}, )) } currentSchema.minLength = minLengthIntegerValue } if existsMapKey(m, KEY_MAX_LENGTH) { maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH]) if maxLengthIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER}, )) } if *maxLengthIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MAX_LENGTH}, )) } currentSchema.maxLength = maxLengthIntegerValue } if currentSchema.minLength != nil && currentSchema.maxLength != nil { if *currentSchema.minLength > *currentSchema.maxLength { return errors.New(formatErrorDescription( Locale.CannotBeGT(), ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH}, )) } } if existsMapKey(m, KEY_PATTERN) { if isKind(m[KEY_PATTERN], reflect.String) { regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string)) if err != nil { return errors.New(formatErrorDescription( Locale.MustBeValidRegex(), ErrorDetails{"key": KEY_PATTERN}, )) } currentSchema.pattern = regexpObject } else { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING}, )) } } if existsMapKey(m, KEY_FORMAT) { formatString, ok := m[KEY_FORMAT].(string) if !ok { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{"key": KEY_FORMAT, "type": TYPE_STRING}, )) } currentSchema.format = formatString } // validation : object if existsMapKey(m, KEY_MIN_PROPERTIES) { minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES]) if minPropertiesIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER}, )) } if *minPropertiesIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MIN_PROPERTIES}, )) } currentSchema.minProperties = minPropertiesIntegerValue } if existsMapKey(m, KEY_MAX_PROPERTIES) { maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES]) if maxPropertiesIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER}, )) } if *maxPropertiesIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MAX_PROPERTIES}, )) } currentSchema.maxProperties = maxPropertiesIntegerValue } if currentSchema.minProperties != nil && currentSchema.maxProperties != nil { if *currentSchema.minProperties > *currentSchema.maxProperties { return errors.New(formatErrorDescription( Locale.KeyCannotBeGreaterThan(), ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES}, )) } } if existsMapKey(m, KEY_REQUIRED) { if isKind(m[KEY_REQUIRED], reflect.Slice) { requiredValues := m[KEY_REQUIRED].([]interface{}) for _, requiredValue := range requiredValues { if isKind(requiredValue, reflect.String) { if isStringInSlice(currentSchema.required, requiredValue.(string)) { return errors.New(formatErrorDescription( Locale.KeyItemsMustBeUnique(), ErrorDetails{"key": KEY_REQUIRED}, )) } currentSchema.required = append(currentSchema.required, requiredValue.(string)) } else { return errors.New(formatErrorDescription( Locale.KeyItemsMustBeOfType(), ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING}, )) } } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY}, )) } } // validation : array if existsMapKey(m, KEY_MIN_ITEMS) { minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS]) if minItemsIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER}, )) } if *minItemsIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MIN_ITEMS}, )) } currentSchema.minItems = minItemsIntegerValue } if existsMapKey(m, KEY_MAX_ITEMS) { maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS]) if maxItemsIntegerValue == nil { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER}, )) } if *maxItemsIntegerValue < 0 { return errors.New(formatErrorDescription( Locale.MustBeGTEZero(), ErrorDetails{"key": KEY_MAX_ITEMS}, )) } currentSchema.maxItems = maxItemsIntegerValue } if existsMapKey(m, KEY_UNIQUE_ITEMS) { if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) { currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool) } else { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN}, )) } } if existsMapKey(m, KEY_CONTAINS) && *currentSchema.draft >= Draft6 { newSchema := &subSchema{property: KEY_CONTAINS, parent: currentSchema, ref: currentSchema.ref} currentSchema.contains = newSchema err := d.parseSchema(m[KEY_CONTAINS], newSchema) if err != nil { return err } } // validation : all if existsMapKey(m, KEY_CONST) && *currentSchema.draft >= Draft6 { is, err := marshalWithoutNumber(m[KEY_CONST]) if err != nil { return err } currentSchema._const = is } if existsMapKey(m, KEY_ENUM) { if isKind(m[KEY_ENUM], reflect.Slice) { for _, v := range m[KEY_ENUM].([]interface{}) { is, err := marshalWithoutNumber(v) if err != nil { return err } if isStringInSlice(currentSchema.enum, *is) { return errors.New(formatErrorDescription( Locale.KeyItemsMustBeUnique(), ErrorDetails{"key": KEY_ENUM}, )) } currentSchema.enum = append(currentSchema.enum, *is) } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY}, )) } } // validation : subSchema if existsMapKey(m, KEY_ONE_OF) { if isKind(m[KEY_ONE_OF], reflect.Slice) { for _, v := range m[KEY_ONE_OF].([]interface{}) { newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref} currentSchema.oneOf = append(currentSchema.oneOf, newSchema) err := d.parseSchema(v, newSchema) if err != nil { return err } } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY}, )) } } if existsMapKey(m, KEY_ANY_OF) { if isKind(m[KEY_ANY_OF], reflect.Slice) { for _, v := range m[KEY_ANY_OF].([]interface{}) { newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref} currentSchema.anyOf = append(currentSchema.anyOf, newSchema) err := d.parseSchema(v, newSchema) if err != nil { return err } } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY}, )) } } if existsMapKey(m, KEY_ALL_OF) { if isKind(m[KEY_ALL_OF], reflect.Slice) { for _, v := range m[KEY_ALL_OF].([]interface{}) { newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref} currentSchema.allOf = append(currentSchema.allOf, newSchema) err := d.parseSchema(v, newSchema) if err != nil { return err } } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY}, )) } } if existsMapKey(m, KEY_NOT) { if isKind(m[KEY_NOT], reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref} currentSchema.not = newSchema err := d.parseSchema(m[KEY_NOT], newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT}, )) } } if *currentSchema.draft >= Draft7 { if existsMapKey(m, KEY_IF) { if isKind(m[KEY_IF], reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_IF, parent: currentSchema, ref: currentSchema.ref} currentSchema._if = newSchema err := d.parseSchema(m[KEY_IF], newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_IF, "y": TYPE_OBJECT}, )) } } if existsMapKey(m, KEY_THEN) { if isKind(m[KEY_THEN], reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_THEN, parent: currentSchema, ref: currentSchema.ref} currentSchema._then = newSchema err := d.parseSchema(m[KEY_THEN], newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_THEN, "y": TYPE_OBJECT}, )) } } if existsMapKey(m, KEY_ELSE) { if isKind(m[KEY_ELSE], reflect.Map, reflect.Bool) { newSchema := &subSchema{property: KEY_ELSE, parent: currentSchema, ref: currentSchema.ref} currentSchema._else = newSchema err := d.parseSchema(m[KEY_ELSE], newSchema) if err != nil { return err } } else { return errors.New(formatErrorDescription( Locale.MustBeOfAn(), ErrorDetails{"x": KEY_ELSE, "y": TYPE_OBJECT}, )) } } } return nil } func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema) error { var ( refdDocumentNode interface{} dsp *schemaPoolDocument err error ) newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref} d.referencePool.Add(currentSchema.ref.String(), newSchema) dsp, err = d.pool.GetDocument(*currentSchema.ref) if err != nil { return err } newSchema.id = currentSchema.ref refdDocumentNode = dsp.Document newSchema.draft = dsp.Draft if err != nil { return err } if !isKind(refdDocumentNode, reflect.Map, reflect.Bool) { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT}, )) } err = d.parseSchema(refdDocumentNode, newSchema) if err != nil { return err } currentSchema.refSchema = newSchema return nil } func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error { if !isKind(documentNode, reflect.Map) { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT}, )) } m := documentNode.(map[string]interface{}) for k := range m { schemaProperty := k newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref} currentSchema.propertiesChildren = append(currentSchema.propertiesChildren, newSchema) err := d.parseSchema(m[k], newSchema) if err != nil { return err } } return nil } func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error { if !isKind(documentNode, reflect.Map) { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT}, )) } m := documentNode.(map[string]interface{}) currentSchema.dependencies = make(map[string]interface{}) for k := range m { switch reflect.ValueOf(m[k]).Kind() { case reflect.Slice: values := m[k].([]interface{}) var valuesToRegister []string for _, value := range values { if !isKind(value, reflect.String) { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{ "key": STRING_DEPENDENCY, "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS, }, )) } valuesToRegister = append(valuesToRegister, value.(string)) currentSchema.dependencies[k] = valuesToRegister } case reflect.Map, reflect.Bool: depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref} err := d.parseSchema(m[k], depSchema) if err != nil { return err } currentSchema.dependencies[k] = depSchema default: return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{ "key": STRING_DEPENDENCY, "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS, }, )) } } return nil } gojsonschema-1.2.0/schemaLoader.go000066400000000000000000000107411355135071500171200ustar00rootroot00000000000000// Copyright 2018 johandorland ( https://github.com/johandorland ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gojsonschema import ( "bytes" "errors" "github.com/xeipuuv/gojsonreference" ) // SchemaLoader is used to load schemas type SchemaLoader struct { pool *schemaPool AutoDetect bool Validate bool Draft Draft } // NewSchemaLoader creates a new NewSchemaLoader func NewSchemaLoader() *SchemaLoader { ps := &SchemaLoader{ pool: &schemaPool{ schemaPoolDocuments: make(map[string]*schemaPoolDocument), }, AutoDetect: true, Validate: false, Draft: Hybrid, } ps.pool.autoDetect = &ps.AutoDetect return ps } func (sl *SchemaLoader) validateMetaschema(documentNode interface{}) error { var ( schema string err error ) if sl.AutoDetect { schema, _, err = parseSchemaURL(documentNode) if err != nil { return err } } // If no explicit "$schema" is used, use the default metaschema associated with the draft used if schema == "" { if sl.Draft == Hybrid { return nil } schema = drafts.GetSchemaURL(sl.Draft) } //Disable validation when loading the metaschema to prevent an infinite recursive loop sl.Validate = false metaSchema, err := sl.Compile(NewReferenceLoader(schema)) if err != nil { return err } sl.Validate = true result := metaSchema.validateDocument(documentNode) if !result.Valid() { var res bytes.Buffer for _, err := range result.Errors() { res.WriteString(err.String()) res.WriteString("\n") } return errors.New(res.String()) } return nil } // AddSchemas adds an arbritrary amount of schemas to the schema cache. As this function does not require // an explicit URL, every schema should contain an $id, so that it can be referenced by the main schema func (sl *SchemaLoader) AddSchemas(loaders ...JSONLoader) error { emptyRef, _ := gojsonreference.NewJsonReference("") for _, loader := range loaders { doc, err := loader.LoadJSON() if err != nil { return err } if sl.Validate { if err := sl.validateMetaschema(doc); err != nil { return err } } // Directly use the Recursive function, so that it get only added to the schema pool by $id // and not by the ref of the document as it's empty if err = sl.pool.parseReferences(doc, emptyRef, false); err != nil { return err } } return nil } //AddSchema adds a schema under the provided URL to the schema cache func (sl *SchemaLoader) AddSchema(url string, loader JSONLoader) error { ref, err := gojsonreference.NewJsonReference(url) if err != nil { return err } doc, err := loader.LoadJSON() if err != nil { return err } if sl.Validate { if err := sl.validateMetaschema(doc); err != nil { return err } } return sl.pool.parseReferences(doc, ref, true) } // Compile loads and compiles a schema func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) { ref, err := rootSchema.JsonReference() if err != nil { return nil, err } d := Schema{} d.pool = sl.pool d.pool.jsonLoaderFactory = rootSchema.LoaderFactory() d.documentReference = ref d.referencePool = newSchemaReferencePool() var doc interface{} if ref.String() != "" { // Get document from schema pool spd, err := d.pool.GetDocument(d.documentReference) if err != nil { return nil, err } doc = spd.Document } else { // Load JSON directly doc, err = rootSchema.LoadJSON() if err != nil { return nil, err } // References need only be parsed if loading JSON directly // as pool.GetDocument already does this for us if loading by reference err = sl.pool.parseReferences(doc, ref, true) if err != nil { return nil, err } } if sl.Validate { if err := sl.validateMetaschema(doc); err != nil { return nil, err } } draft := sl.Draft if sl.AutoDetect { _, detectedDraft, err := parseSchemaURL(doc) if err != nil { return nil, err } if detectedDraft != nil { draft = *detectedDraft } } err = d.parse(doc, draft) if err != nil { return nil, err } return &d, nil } gojsonschema-1.2.0/schemaLoader_test.go000066400000000000000000000117661355135071500201670ustar00rootroot00000000000000// Copyright 2018 johandorland ( https://github.com/johandorland ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gojsonschema import ( "github.com/stretchr/testify/require" "testing" "github.com/stretchr/testify/assert" ) func TestSchemaLoaderWithReferenceToAddedSchema(t *testing.T) { sl := NewSchemaLoader() err := sl.AddSchemas(NewStringLoader(`{ "$id" : "http://localhost:1234/test1.json", "type" : "integer" }`)) assert.Nil(t, err) schema, err := sl.Compile(NewReferenceLoader("http://localhost:1234/test1.json")) assert.Nil(t, err) result, err := schema.Validate(NewStringLoader(`"hello"`)) assert.Nil(t, err) if len(result.Errors()) != 1 || result.Errors()[0].Type() != "invalid_type" { t.Errorf("Expected invalid type erorr, instead got %v", result.Errors()) } } func TestCrossReference(t *testing.T) { schema1 := NewStringLoader(`{ "$ref" : "http://localhost:1234/test3.json", "definitions" : { "foo" : { "type" : "integer" } } }`) schema2 := NewStringLoader(`{ "$ref" : "http://localhost:1234/test2.json#/definitions/foo" }`) sl := NewSchemaLoader() err := sl.AddSchema("http://localhost:1234/test2.json", schema1) assert.Nil(t, err) err = sl.AddSchema("http://localhost:1234/test3.json", schema2) assert.Nil(t, err) schema, err := sl.Compile(NewStringLoader(`{"$ref" : "http://localhost:1234/test2.json"}`)) assert.Nil(t, err) result, err := schema.Validate(NewStringLoader(`"hello"`)) assert.Nil(t, err) if len(result.Errors()) != 1 || result.Errors()[0].Type() != "invalid_type" { t.Errorf("Expected invalid type erorr, instead got %v", result.Errors()) } } // Multiple schemas identifying under the same $id should throw an error func TestDoubleIDReference(t *testing.T) { sl := NewSchemaLoader() err := sl.AddSchema("http://localhost:1234/test4.json", NewStringLoader("{}")) assert.Nil(t, err) err = sl.AddSchemas(NewStringLoader(`{ "$id" : "http://localhost:1234/test4.json"}`)) assert.NotNil(t, err) } func TestCustomMetaSchema(t *testing.T) { loader := NewStringLoader(`{ "$id" : "http://localhost:1234/test5.json", "properties" : { "multipleOf" : false } }`) // Test a custom metaschema in which we disallow the use of the keyword "multipleOf" sl := NewSchemaLoader() sl.Validate = true err := sl.AddSchemas(loader) assert.Nil(t, err) _, err = sl.Compile(NewStringLoader(`{ "$id" : "http://localhost:1234/test6.json", "$schema" : "http://localhost:1234/test5.json", "type" : "string" }`)) assert.Nil(t, err) sl = NewSchemaLoader() sl.Validate = true err = sl.AddSchemas(loader) assert.Nil(t, err) _, err = sl.Compile(NewStringLoader(`{ "$id" : "http://localhost:1234/test7.json", "$schema" : "http://localhost:1234/test5.json", "multipleOf" : 5 }`)) assert.NotNil(t, err) } func TestSchemaDetection(t *testing.T) { loader := NewStringLoader(`{ "$schema" : "http://json-schema.org/draft-04/schema#", "exclusiveMinimum" : 5 }`) // The schema should produce an error in draft-04 mode _, err := NewSchema(loader) assert.NotNil(t, err) // With schema detection disabled the schema should not produce an error in hybrid mode sl := NewSchemaLoader() sl.AutoDetect = false _, err = sl.Compile(loader) assert.Nil(t, err) } func TestDraftCrossReferencing(t *testing.T) { // Tests the following cross referencing with any combination // of autodetection and preset draft version. loader1 := NewStringLoader(`{ "$schema" : "http://json-schema.org/draft-04/schema#", "id" : "http://localhost:1234/file.json", "$id" : "http://localhost:1234/file.json", "exclusiveMinimum" : 5 }`) loader2 := NewStringLoader(`{ "$schema" : "http://json-schema.org/draft-07/schema#", "id" : "http://localhost:1234/main.json", "$id" : "http://localhost:1234/main.json", "$ref" : "file.json" }`) for _, b := range []bool{true, false} { for _, draft := range []Draft{Draft4, Draft6, Draft7} { sl := NewSchemaLoader() sl.Draft = draft sl.AutoDetect = b err := sl.AddSchemas(loader1) assert.Nil(t, err) _, err = sl.Compile(loader2) // It will always fail with autodetection on as "exclusiveMinimum" : 5 // is only valid since draft-06. With autodetection off it will pass if // draft-06 or newer is used assert.Equal(t, err == nil, !b && draft >= Draft6) } } } const not_map_interface = "not map interface" func TestParseSchemaURL_NotMap(t *testing.T) { //GIVEN sl := NewGoLoader(not_map_interface) //WHEN _, err := NewSchema(sl) //THEN require.Error(t, err) assert.EqualError(t, err, "schema is invalid") } gojsonschema-1.2.0/schemaPool.go000066400000000000000000000142751355135071500166310ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Defines resources pooling. // Eases referencing and avoids downloading the same resource twice. // // created 26-02-2013 package gojsonschema import ( "errors" "fmt" "reflect" "github.com/xeipuuv/gojsonreference" ) type schemaPoolDocument struct { Document interface{} Draft *Draft } type schemaPool struct { schemaPoolDocuments map[string]*schemaPoolDocument jsonLoaderFactory JSONLoaderFactory autoDetect *bool } func (p *schemaPool) parseReferences(document interface{}, ref gojsonreference.JsonReference, pooled bool) error { var ( draft *Draft err error reference = ref.String() ) // Only the root document should be added to the schema pool if pooled is true if _, ok := p.schemaPoolDocuments[reference]; pooled && ok { return fmt.Errorf("Reference already exists: \"%s\"", reference) } if *p.autoDetect { _, draft, err = parseSchemaURL(document) if err != nil { return err } } err = p.parseReferencesRecursive(document, ref, draft) if pooled { p.schemaPoolDocuments[reference] = &schemaPoolDocument{Document: document, Draft: draft} } return err } func (p *schemaPool) parseReferencesRecursive(document interface{}, ref gojsonreference.JsonReference, draft *Draft) error { // parseReferencesRecursive parses a JSON document and resolves all $id and $ref references. // For $ref references it takes into account the $id scope it is in and replaces // the reference by the absolute resolved reference // When encountering errors it fails silently. Error handling is done when the schema // is syntactically parsed and any error encountered here should also come up there. switch m := document.(type) { case []interface{}: for _, v := range m { p.parseReferencesRecursive(v, ref, draft) } case map[string]interface{}: localRef := &ref keyID := KEY_ID_NEW if existsMapKey(m, KEY_ID) { keyID = KEY_ID } if existsMapKey(m, keyID) && isKind(m[keyID], reflect.String) { jsonReference, err := gojsonreference.NewJsonReference(m[keyID].(string)) if err == nil { localRef, err = ref.Inherits(jsonReference) if err == nil { if _, ok := p.schemaPoolDocuments[localRef.String()]; ok { return fmt.Errorf("Reference already exists: \"%s\"", localRef.String()) } p.schemaPoolDocuments[localRef.String()] = &schemaPoolDocument{Document: document, Draft: draft} } } } if existsMapKey(m, KEY_REF) && isKind(m[KEY_REF], reflect.String) { jsonReference, err := gojsonreference.NewJsonReference(m[KEY_REF].(string)) if err == nil { absoluteRef, err := localRef.Inherits(jsonReference) if err == nil { m[KEY_REF] = absoluteRef.String() } } } for k, v := range m { // const and enums should be interpreted literally, so ignore them if k == KEY_CONST || k == KEY_ENUM { continue } // Something like a property or a dependency is not a valid schema, as it might describe properties named "$ref", "$id" or "const", etc // Therefore don't treat it like a schema. if k == KEY_PROPERTIES || k == KEY_DEPENDENCIES || k == KEY_PATTERN_PROPERTIES { if child, ok := v.(map[string]interface{}); ok { for _, v := range child { p.parseReferencesRecursive(v, *localRef, draft) } } } else { p.parseReferencesRecursive(v, *localRef, draft) } } } return nil } func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) { var ( spd *schemaPoolDocument draft *Draft ok bool err error ) if internalLogEnabled { internalLog("Get Document ( %s )", reference.String()) } // Create a deep copy, so we can remove the fragment part later on without altering the original refToURL, _ := gojsonreference.NewJsonReference(reference.String()) // First check if the given fragment is a location independent identifier // http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3 if spd, ok = p.schemaPoolDocuments[refToURL.String()]; ok { if internalLogEnabled { internalLog(" From pool") } return spd, nil } // If the given reference is not a location independent identifier, // strip the fragment and look for a document with it's base URI refToURL.GetUrl().Fragment = "" if cachedSpd, ok := p.schemaPoolDocuments[refToURL.String()]; ok { document, _, err := reference.GetPointer().Get(cachedSpd.Document) if err != nil { return nil, err } if internalLogEnabled { internalLog(" From pool") } spd = &schemaPoolDocument{Document: document, Draft: cachedSpd.Draft} p.schemaPoolDocuments[reference.String()] = spd return spd, nil } // It is not possible to load anything remotely that is not canonical... if !reference.IsCanonical() { return nil, errors.New(formatErrorDescription( Locale.ReferenceMustBeCanonical(), ErrorDetails{"reference": reference.String()}, )) } jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String()) document, err := jsonReferenceLoader.LoadJSON() if err != nil { return nil, err } // add the whole document to the pool for potential re-use p.parseReferences(document, refToURL, true) _, draft, _ = parseSchemaURL(document) // resolve the potential fragment and also cache it document, _, err = reference.GetPointer().Get(document) if err != nil { return nil, err } return &schemaPoolDocument{Document: document, Draft: draft}, nil } gojsonschema-1.2.0/schemaReferencePool.go000066400000000000000000000033101355135071500204340ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Pool of referenced schemas. // // created 25-06-2013 package gojsonschema import ( "fmt" ) type schemaReferencePool struct { documents map[string]*subSchema } func newSchemaReferencePool() *schemaReferencePool { p := &schemaReferencePool{} p.documents = make(map[string]*subSchema) return p } func (p *schemaReferencePool) Get(ref string) (r *subSchema, o bool) { if internalLogEnabled { internalLog(fmt.Sprintf("Schema Reference ( %s )", ref)) } if sch, ok := p.documents[ref]; ok { if internalLogEnabled { internalLog(fmt.Sprintf(" From pool")) } return sch, true } return nil, false } func (p *schemaReferencePool) Add(ref string, sch *subSchema) { if internalLogEnabled { internalLog(fmt.Sprintf("Add Schema Reference %s to pool", ref)) } if _, ok := p.documents[ref]; !ok { p.documents[ref] = sch } } gojsonschema-1.2.0/schemaType.go000066400000000000000000000041271355135071500166340ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Helper structure to handle schema types, and the combination of them. // // created 28-02-2013 package gojsonschema import ( "errors" "fmt" "strings" ) type jsonSchemaType struct { types []string } // Is the schema typed ? that is containing at least one type // When not typed, the schema does not need any type validation func (t *jsonSchemaType) IsTyped() bool { return len(t.types) > 0 } func (t *jsonSchemaType) Add(etype string) error { if !isStringInSlice(JSON_TYPES, etype) { return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"given": "/" + etype + "/", "expected": JSON_TYPES})) } if t.Contains(etype) { return errors.New(formatErrorDescription(Locale.Duplicated(), ErrorDetails{"type": etype})) } t.types = append(t.types, etype) return nil } func (t *jsonSchemaType) Contains(etype string) bool { for _, v := range t.types { if v == etype { return true } } return false } func (t *jsonSchemaType) String() string { if len(t.types) == 0 { return STRING_UNDEFINED // should never happen } // Displayed as a list [type1,type2,...] if len(t.types) > 1 { return fmt.Sprintf("[%s]", strings.Join(t.types, ",")) } // Only one type: name only return t.types[0] } gojsonschema-1.2.0/schema_test.go000066400000000000000000000205711355135071500170320ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description (Unit) Tests for schema validation. // // created 16-06-2013 package gojsonschema import ( "bytes" "fmt" "io" "io/ioutil" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) const displayErrorMessages = false const circularReference = `{ "type": "object", "properties": { "games": { "type": "array", "items": { "$ref": "#/definitions/game" } } }, "definitions": { "game": { "type": "object", "properties": { "winner": { "$ref": "#/definitions/player" }, "loser": { "$ref": "#/definitions/player" } } }, "player": { "type": "object", "properties": { "user": { "$ref": "#/definitions/user" }, "game": { "$ref": "#/definitions/game" } } }, "user": { "type": "object", "properties": { "fullName": { "type": "string" } } } } }` func TestCircularReference(t *testing.T) { loader := NewStringLoader(circularReference) // call the target function _, err := NewSchema(loader) if err != nil { t.Errorf("Got error: %s", err.Error()) } } // From http://json-schema.org/examples.html const simpleSchema = `{ "title": "Example Schema", "type": "object", "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "age": { "description": "Age in years", "type": "integer", "minimum": 0 } }, "required": ["firstName", "lastName"] }` func TestLoaders(t *testing.T) { // setup reader loader reader := bytes.NewBufferString(simpleSchema) readerLoader, wrappedReader := NewReaderLoader(reader) // drain reader by, err := ioutil.ReadAll(wrappedReader) assert.Nil(t, err) assert.Equal(t, simpleSchema, string(by)) // setup writer loaders writer := &bytes.Buffer{} writerLoader, wrappedWriter := NewWriterLoader(writer) // fill writer n, err := io.WriteString(wrappedWriter, simpleSchema) assert.Nil(t, err) assert.Equal(t, n, len(simpleSchema)) loaders := []JSONLoader{ NewStringLoader(simpleSchema), readerLoader, writerLoader, } for _, l := range loaders { _, err := NewSchema(l) assert.Nil(t, err, "loader: %T", l) } } const invalidPattern = `{ "title": "Example Pattern", "type": "object", "properties": { "invalid": { "type": "string", "pattern": 99999 } } }` func TestLoadersWithInvalidPattern(t *testing.T) { // setup reader loader reader := bytes.NewBufferString(invalidPattern) readerLoader, wrappedReader := NewReaderLoader(reader) // drain reader by, err := ioutil.ReadAll(wrappedReader) assert.Nil(t, err) assert.Equal(t, invalidPattern, string(by)) // setup writer loaders writer := &bytes.Buffer{} writerLoader, wrappedWriter := NewWriterLoader(writer) // fill writer n, err := io.WriteString(wrappedWriter, invalidPattern) assert.Nil(t, err) assert.Equal(t, n, len(invalidPattern)) loaders := []JSONLoader{ NewStringLoader(invalidPattern), readerLoader, writerLoader, } for _, l := range loaders { _, err := NewSchema(l) assert.NotNil(t, err, "expected error loading invalid pattern: %T", l) } } const refPropertySchema = `{ "$id" : "http://localhost/schema.json", "properties" : { "$id" : { "$id": "http://localhost/foo.json" }, "$ref" : { "const": { "$ref" : "hello.world" } }, "const" : { "$ref" : "#/definitions/$ref" } }, "definitions" : { "$ref" : { "const": { "$ref" : "hello.world" } } }, "dependencies" : { "$ref" : [ "const" ], "const" : [ "$ref" ] } }` func TestRefProperty(t *testing.T) { schemaLoader := NewStringLoader(refPropertySchema) documentLoader := NewStringLoader(`{ "$ref" : { "$ref" : "hello.world" }, "const" : { "$ref" : "hello.world" } }`) // call the target function s, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } result, err := s.Validate(documentLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } if !result.Valid() { for _, err := range result.Errors() { fmt.Println(err.String()) } t.Errorf("Got invalid validation result.") } } func TestFragmentLoader(t *testing.T) { wd, err := os.Getwd() if err != nil { panic(err.Error()) } fileName := filepath.Join(wd, "testdata", "extra", "fragment_schema.json") schemaLoader := NewReferenceLoader("file://" + filepath.ToSlash(fileName) + "#/definitions/x") schema, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Encountered error while loading schema: %s", err.Error()) } validDocument := NewStringLoader(`5`) invalidDocument := NewStringLoader(`"a"`) result, err := schema.Validate(validDocument) if assert.Nil(t, err, "Unexpected error while validating document: %T", err) { if !result.Valid() { t.Errorf("Got invalid validation result.") } } result, err = schema.Validate(invalidDocument) if assert.Nil(t, err, "Unexpected error while validating document: %T", err) { if len(result.Errors()) != 1 || result.Errors()[0].Type() != "invalid_type" { t.Errorf("Got invalid validation result.") } } } func TestFileWithSpace(t *testing.T) { wd, err := os.Getwd() if err != nil { panic(err.Error()) } fileName := filepath.Join(wd, "testdata", "extra", "file with space.json") loader := NewReferenceLoader("file://" + filepath.ToSlash(fileName)) json, err := loader.LoadJSON() assert.Nil(t, err, "Unexpected error when trying to load a filepath containing a space") assert.Equal(t, map[string]interface{}{"foo": true}, json, "Contents of the file do not match") } func TestAdditionalPropertiesErrorMessage(t *testing.T) { schema := `{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "Device": { "type": "object", "additionalProperties": { "type": "string" } } } }` text := `{ "Device":{ "Color" : true } }` loader := NewBytesLoader([]byte(schema)) result, err := Validate(loader, NewBytesLoader([]byte(text))) if err != nil { t.Fatal(err) } if len(result.Errors()) != 1 { t.Fatal("Expected 1 error but got", len(result.Errors())) } expected := "Device.Color: Invalid type. Expected: string, given: boolean" actual := result.Errors()[0].String() if actual != expected { t.Fatalf("Expected '%s' but got '%s'", expected, actual) } } // Inspired by http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3 const locationIndependentSchema = `{ "definitions": { "A": { "$id": "#foo" }, "B": { "$id": "http://example.com/other.json", "definitions": { "X": { "$id": "#bar", "allOf": [false] }, "Y": { "$id": "t/inner.json" } } }, "C": { "$id" : "#frag", "$ref": "http://example.com/other.json#bar" } }, "$ref": "#frag" }` func TestLocationIndependentIdentifier(t *testing.T) { schemaLoader := NewStringLoader(locationIndependentSchema) documentLoader := NewStringLoader(`{}`) s, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } result, err := s.Validate(documentLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } if len(result.Errors()) != 2 || result.Errors()[0].Type() != "false" || result.Errors()[1].Type() != "number_all_of" { t.Errorf("Got invalid validation result.") } } const incorrectRefSchema = `{ "$ref" : "#/fail" }` func TestIncorrectRef(t *testing.T) { schemaLoader := NewStringLoader(incorrectRefSchema) s, err := NewSchema(schemaLoader) assert.Nil(t, s) assert.Equal(t, "Object has no key 'fail'", err.Error()) } gojsonschema-1.2.0/subSchema.go000066400000000000000000000102261355135071500164410ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Defines the structure of a sub-subSchema. // A sub-subSchema can contain other sub-schemas. // // created 27-02-2013 package gojsonschema import ( "github.com/xeipuuv/gojsonreference" "math/big" "regexp" ) // Constants const ( KEY_SCHEMA = "$schema" KEY_ID = "id" KEY_ID_NEW = "$id" KEY_REF = "$ref" KEY_TITLE = "title" KEY_DESCRIPTION = "description" KEY_TYPE = "type" KEY_ITEMS = "items" KEY_ADDITIONAL_ITEMS = "additionalItems" KEY_PROPERTIES = "properties" KEY_PATTERN_PROPERTIES = "patternProperties" KEY_ADDITIONAL_PROPERTIES = "additionalProperties" KEY_PROPERTY_NAMES = "propertyNames" KEY_DEFINITIONS = "definitions" KEY_MULTIPLE_OF = "multipleOf" KEY_MINIMUM = "minimum" KEY_MAXIMUM = "maximum" KEY_EXCLUSIVE_MINIMUM = "exclusiveMinimum" KEY_EXCLUSIVE_MAXIMUM = "exclusiveMaximum" KEY_MIN_LENGTH = "minLength" KEY_MAX_LENGTH = "maxLength" KEY_PATTERN = "pattern" KEY_FORMAT = "format" KEY_MIN_PROPERTIES = "minProperties" KEY_MAX_PROPERTIES = "maxProperties" KEY_DEPENDENCIES = "dependencies" KEY_REQUIRED = "required" KEY_MIN_ITEMS = "minItems" KEY_MAX_ITEMS = "maxItems" KEY_UNIQUE_ITEMS = "uniqueItems" KEY_CONTAINS = "contains" KEY_CONST = "const" KEY_ENUM = "enum" KEY_ONE_OF = "oneOf" KEY_ANY_OF = "anyOf" KEY_ALL_OF = "allOf" KEY_NOT = "not" KEY_IF = "if" KEY_THEN = "then" KEY_ELSE = "else" ) type subSchema struct { draft *Draft // basic subSchema meta properties id *gojsonreference.JsonReference title *string description *string property string // Quick pass/fail for boolean schemas pass *bool // Types associated with the subSchema types jsonSchemaType // Reference url ref *gojsonreference.JsonReference // Schema referenced refSchema *subSchema // hierarchy parent *subSchema itemsChildren []*subSchema itemsChildrenIsSingleSchema bool propertiesChildren []*subSchema // validation : number / integer multipleOf *big.Rat maximum *big.Rat exclusiveMaximum *big.Rat minimum *big.Rat exclusiveMinimum *big.Rat // validation : string minLength *int maxLength *int pattern *regexp.Regexp format string // validation : object minProperties *int maxProperties *int required []string dependencies map[string]interface{} additionalProperties interface{} patternProperties map[string]*subSchema propertyNames *subSchema // validation : array minItems *int maxItems *int uniqueItems bool contains *subSchema additionalItems interface{} // validation : all _const *string //const is a golang keyword enum []string // validation : subSchema oneOf []*subSchema anyOf []*subSchema allOf []*subSchema not *subSchema _if *subSchema // if/else are golang keywords _then *subSchema _else *subSchema } gojsonschema-1.2.0/testdata/000077500000000000000000000000001355135071500160105ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft4/000077500000000000000000000000001355135071500171745ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft4/additionalItems.json000066400000000000000000000046111355135071500232030ustar00rootroot00000000000000[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "items is schema, no additionalItems", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "fewer number of items present", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/additionalProperties.json000066400000000000000000000057311355135071500242620ustar00rootroot00000000000000[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "additionalProperties allows a schema which should validate", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/allOf.json000066400000000000000000000057211355135071500211310ustar00rootroot00000000000000[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/anyOf.json000066400000000000000000000053571355135071500211550ustar00rootroot00000000000000[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/default.json000066400000000000000000000023711355135071500215160ustar00rootroot00000000000000[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/definitions.json000066400000000000000000000015261355135071500224060ustar00rootroot00000000000000[ { "description": "valid definition", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true } ] }, { "description": "invalid definition", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, "tests": [ { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/dependencies.json000066400000000000000000000065421355135071500225240ustar00rootroot00000000000000[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/enum.json000066400000000000000000000036671355135071500210470ustar00rootroot00000000000000[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/items.json000066400000000000000000000040611355135071500212110ustar00rootroot00000000000000[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/maxItems.json000066400000000000000000000013021355135071500216520ustar00rootroot00000000000000[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/maxLength.json000066400000000000000000000016001355135071500220130ustar00rootroot00000000000000[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/maxProperties.json000066400000000000000000000020251355135071500227300ustar00rootroot00000000000000[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/maximum.json000066400000000000000000000022711355135071500215460ustar00rootroot00000000000000[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMaximum validation", "schema": { "maximum": 3.0, "exclusiveMaximum": true }, "tests": [ { "description": "below the maximum is still valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/minItems.json000066400000000000000000000012651355135071500216600ustar00rootroot00000000000000[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/minLength.json000066400000000000000000000015661355135071500220240ustar00rootroot00000000000000[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/minProperties.json000066400000000000000000000017541355135071500227360ustar00rootroot00000000000000[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/minimum.json000066400000000000000000000022711355135071500215440ustar00rootroot00000000000000[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMinimum validation", "schema": { "minimum": 1.1, "exclusiveMinimum": true }, "tests": [ { "description": "above the minimum is still valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/multipleOf.json000066400000000000000000000027651355135071500222210ustar00rootroot00000000000000[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/not.json000066400000000000000000000043321355135071500206710ustar00rootroot00000000000000[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/oneOf.json000066400000000000000000000053571355135071500211470ustar00rootroot00000000000000[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/optional/000077500000000000000000000000001355135071500210215ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft4/optional/bignum.json000066400000000000000000000060031355135071500231740ustar00rootroot00000000000000[ { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": {"type": "string"}, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "integer comparison", "schema": {"maximum": 18446744073709551615}, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "maximum": 972783798187987123879878123.18878137, "exclusiveMaximum": true }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "integer comparison", "schema": {"minimum": -18446744073709551615}, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "minimum": -972783798187987123879878123.18878137, "exclusiveMinimum": true }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/optional/ecmascript-regex.json000066400000000000000000000005151355135071500251570ustar00rootroot00000000000000[ { "description": "ECMA 262 regex non-compliance", "schema": { "format": "regex" }, "tests": [ { "description": "ECMA 262 has no support for \\Z anchor from .NET", "data": "^\\S(|(.|\\n)*\\S)\\Z", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/optional/format.json000066400000000000000000000162671355135071500232200ustar00rootroot00000000000000[ { "description": "validation of date-time strings", "schema": {"format": "date-time"}, "tests": [ { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false } ] }, { "description": "validation of URIs", "schema": {"format": "uri"}, "tests": [ { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parantheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false } ] }, { "description": "validation of e-mail addresses", "schema": {"format": "email"}, "tests": [ { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] }, { "description": "validation of IP addresses", "schema": {"format": "ipv4"}, "tests": [ { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false } ] }, { "description": "validation of IPv6 addresses", "schema": {"format": "ipv6"}, "tests": [ { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false } ] }, { "description": "validation of host names", "schema": {"format": "hostname"}, "tests": [ { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/optional/zeroTerminatedFloats.json000066400000000000000000000006001355135071500260550ustar00rootroot00000000000000[ { "description": "some languages do not distinguish between different types of numeric value", "schema": { "type": "integer" }, "tests": [ { "description": "a float is not an integer even without fractional part", "data": 1.0, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/pattern.json000066400000000000000000000015311355135071500215440ustar00rootroot00000000000000[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores non-strings", "data": true, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/patternProperties.json000066400000000000000000000070741355135071500236310ustar00rootroot00000000000000[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/properties.json000066400000000000000000000057171355135071500222750ustar00rootroot00000000000000[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/ref.json000066400000000000000000000211551355135071500206470ustar00rootroot00000000000000[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "tilda~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": { "tilda": {"$ref": "#/tilda~0field"}, "slash": {"$ref": "#/slash~1field"}, "percent": {"$ref": "#/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilda invalid", "data": {"tilda": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilda valid", "data": {"tilda": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "$ref": "#/definitions/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "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"] } } }, "tests": [ { "description": "valid tree", "data": { "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} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "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} ] } } ] }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/refRemote.json000066400000000000000000000112041355135071500220150ustar00rootroot00000000000000[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "id": "http://localhost:1234/", "items": { "id": "folder/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "id": "folder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "id": "folder/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/required.json000066400000000000000000000024771355135071500217210ustar00rootroot00000000000000[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft4/type.json000066400000000000000000000231631355135071500210550ustar00rootroot00000000000000[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "a boolean is a boolean", "data": true, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "a boolean is not null", "data": true, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft4/uniqueItems.json000066400000000000000000000050651355135071500224050ustar00rootroot00000000000000[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/000077500000000000000000000000001355135071500171765ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft6/additionalItems.json000066400000000000000000000046111355135071500232050ustar00rootroot00000000000000[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "items is schema, no additionalItems", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "fewer number of items present", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/additionalProperties.json000066400000000000000000000057311355135071500242640ustar00rootroot00000000000000[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "additionalProperties allows a schema which should validate", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/allOf.json000066400000000000000000000075031355135071500211330ustar00rootroot00000000000000[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": {"allOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": {"allOf": [true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": {"allOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/anyOf.json000066400000000000000000000071351355135071500211530ustar00rootroot00000000000000[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": {"anyOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": {"anyOf": [true, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": {"anyOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/boolean_schema.json000066400000000000000000000054021355135071500230310ustar00rootroot00000000000000[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/const.json000066400000000000000000000045111355135071500212200ustar00rootroot00000000000000[ { "description": "const validation", "schema": {"const": 2}, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": {"const": {"foo": "bar", "baz": "bax"}}, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": {"const": [{ "foo": "bar" }]}, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": {"const": null}, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/contains.json000066400000000000000000000052311355135071500217100ustar00rootroot00000000000000[ { "description": "contains keyword validation", "schema": { "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": {"contains": true}, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": {"contains": false}, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/default.json000066400000000000000000000023711355135071500215200ustar00rootroot00000000000000[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/definitions.json000066400000000000000000000015261355135071500224100ustar00rootroot00000000000000[ { "description": "valid definition", "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true } ] }, { "description": "invalid definition", "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, "tests": [ { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/dependencies.json000066400000000000000000000113011355135071500225130ustar00rootroot00000000000000[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "dependencies with empty array", "schema": { "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] }, { "description": "dependencies with boolean subschemas", "schema": { "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/enum.json000066400000000000000000000036671355135071500210510ustar00rootroot00000000000000[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/exclusiveMaximum.json000066400000000000000000000014071355135071500234400ustar00rootroot00000000000000[ { "description": "exclusiveMaximum validation", "schema": { "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/exclusiveMinimum.json000066400000000000000000000014071355135071500234360ustar00rootroot00000000000000[ { "description": "exclusiveMinimum validation", "schema": { "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/items.json000066400000000000000000000070151355135071500212150ustar00rootroot00000000000000[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": {"items": true}, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": {"items": false}, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schemas", "schema": { "items": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/maxItems.json000066400000000000000000000013021355135071500216540ustar00rootroot00000000000000[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/maxLength.json000066400000000000000000000016001355135071500220150ustar00rootroot00000000000000[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/maxProperties.json000066400000000000000000000020251355135071500227320ustar00rootroot00000000000000[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/maximum.json000066400000000000000000000013121355135071500215430ustar00rootroot00000000000000[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/minItems.json000066400000000000000000000012651355135071500216620ustar00rootroot00000000000000[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/minLength.json000066400000000000000000000015661355135071500220260ustar00rootroot00000000000000[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/minProperties.json000066400000000000000000000017541355135071500227400ustar00rootroot00000000000000[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/minimum.json000066400000000000000000000013121355135071500215410ustar00rootroot00000000000000[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/multipleOf.json000066400000000000000000000027651355135071500222230ustar00rootroot00000000000000[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/not.json000066400000000000000000000053761355135071500207040ustar00rootroot00000000000000[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": {"not": true}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": {"not": false}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/oneOf.json000066400000000000000000000076511355135071500211500ustar00rootroot00000000000000[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": {"oneOf": [true, true, true]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": {"oneOf": [true, false, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": {"oneOf": [true, true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": {"oneOf": [false, false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/optional/000077500000000000000000000000001355135071500210235ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft6/optional/bignum.json000066400000000000000000000057111355135071500232030ustar00rootroot00000000000000[ { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": {"type": "string"}, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "integer comparison", "schema": {"maximum": 18446744073709551615}, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "integer comparison", "schema": {"minimum": -18446744073709551615}, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/optional/ecmascript-regex.json000066400000000000000000000005151355135071500251610ustar00rootroot00000000000000[ { "description": "ECMA 262 regex non-compliance", "schema": { "format": "regex" }, "tests": [ { "description": "ECMA 262 has no support for \\Z anchor from .NET", "data": "^\\S(|(.|\\n)*\\S)\\Z", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/optional/format.json000066400000000000000000000356641355135071500232240ustar00rootroot00000000000000[ { "description": "validation of date-time strings", "schema": {"format": "date-time"}, "tests": [ { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false } ] }, { "description": "validation of URIs", "schema": {"format": "uri"}, "tests": [ { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parantheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false } ] }, { "description": "validation of URI References", "schema": {"format": "uri-reference"}, "tests": [ { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] }, { "description": "format: uri-template", "schema": { "format": "uri-template" }, "tests": [ { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] }, { "description": "validation of e-mail addresses", "schema": {"format": "email"}, "tests": [ { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] }, { "description": "validation of IP addresses", "schema": {"format": "ipv4"}, "tests": [ { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false } ] }, { "description": "validation of IPv6 addresses", "schema": {"format": "ipv6"}, "tests": [ { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false } ] }, { "description": "validation of host names", "schema": {"format": "hostname"}, "tests": [ { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false } ] }, { "description": "validation of JSON-pointers (JSON String Representation)", "schema": {"format": "json-pointer"}, "tests": [ { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/optional/zeroTerminatedFloats.json000066400000000000000000000005661355135071500260720ustar00rootroot00000000000000[ { "description": "some languages do not distinguish between different types of numeric value", "schema": { "type": "integer" }, "tests": [ { "description": "a float without fractional part is an integer", "data": 1.0, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/pattern.json000066400000000000000000000015311355135071500215460ustar00rootroot00000000000000[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores non-strings", "data": true, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/patternProperties.json000066400000000000000000000107461355135071500236330ustar00rootroot00000000000000[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/properties.json000066400000000000000000000075131355135071500222730ustar00rootroot00000000000000[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/propertyNames.json000066400000000000000000000041301355135071500227370ustar00rootroot00000000000000[ { "description": "propertyNames validation", "schema": { "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": {"propertyNames": true}, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": {"propertyNames": false}, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/ref.json000066400000000000000000000225621355135071500206540ustar00rootroot00000000000000[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "tilda~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": { "tilda": {"$ref": "#/tilda~0field"}, "slash": {"$ref": "#/slash~1field"}, "percent": {"$ref": "#/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilda invalid", "data": {"tilda": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilda valid", "data": {"tilda": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "$ref": "#/definitions/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$ref": "#/definitions/bool", "definitions": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$ref": "#/definitions/bool", "definitions": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$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"] } } }, "tests": [ { "description": "valid tree", "data": { "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} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "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} ] } } ] }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/refRemote.json000066400000000000000000000112131355135071500220170ustar00rootroot00000000000000[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$id": "http://localhost:1234/", "items": { "$id": "folder/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "$id": "folder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "$id": "folder/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/required.json000066400000000000000000000032521355135071500217130ustar00rootroot00000000000000[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft6/type.json000066400000000000000000000231631355135071500210570ustar00rootroot00000000000000[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "a boolean is a boolean", "data": true, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "a boolean is not null", "data": true, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft6/uniqueItems.json000066400000000000000000000050651355135071500224070ustar00rootroot00000000000000[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/000077500000000000000000000000001355135071500171775ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft7/additionalItems.json000066400000000000000000000046111355135071500232060ustar00rootroot00000000000000[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "items is schema, no additionalItems", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "fewer number of items present", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/additionalProperties.json000066400000000000000000000057311355135071500242650ustar00rootroot00000000000000[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "additionalProperties allows a schema which should validate", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/allOf.json000066400000000000000000000075031355135071500211340ustar00rootroot00000000000000[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": {"allOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": {"allOf": [true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": {"allOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/anyOf.json000066400000000000000000000071351355135071500211540ustar00rootroot00000000000000[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": {"anyOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": {"anyOf": [true, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": {"anyOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/boolean_schema.json000066400000000000000000000054021355135071500230320ustar00rootroot00000000000000[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/const.json000066400000000000000000000045111355135071500212210ustar00rootroot00000000000000[ { "description": "const validation", "schema": {"const": 2}, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": {"const": {"foo": "bar", "baz": "bax"}}, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": {"const": [{ "foo": "bar" }]}, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": {"const": null}, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/contains.json000066400000000000000000000052311355135071500217110ustar00rootroot00000000000000[ { "description": "contains keyword validation", "schema": { "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": {"contains": true}, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": {"contains": false}, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/default.json000066400000000000000000000023711355135071500215210ustar00rootroot00000000000000[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/definitions.json000066400000000000000000000015261355135071500224110ustar00rootroot00000000000000[ { "description": "valid definition", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true } ] }, { "description": "invalid definition", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/dependencies.json000066400000000000000000000113011355135071500225140ustar00rootroot00000000000000[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "dependencies with empty array", "schema": { "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] }, { "description": "dependencies with boolean subschemas", "schema": { "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/enum.json000066400000000000000000000036671355135071500210520ustar00rootroot00000000000000[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/exclusiveMaximum.json000066400000000000000000000014071355135071500234410ustar00rootroot00000000000000[ { "description": "exclusiveMaximum validation", "schema": { "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/exclusiveMinimum.json000066400000000000000000000014071355135071500234370ustar00rootroot00000000000000[ { "description": "exclusiveMinimum validation", "schema": { "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/if-then-else.json000066400000000000000000000111611355135071500223520ustar00rootroot00000000000000[ { "description": "ignore if without then or else", "schema": { "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invailid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invailid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invailid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but woud have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/items.json000066400000000000000000000070151355135071500212160ustar00rootroot00000000000000[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": {"items": true}, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": {"items": false}, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schemas", "schema": { "items": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/maxItems.json000066400000000000000000000013021355135071500216550ustar00rootroot00000000000000[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/maxLength.json000066400000000000000000000016001355135071500220160ustar00rootroot00000000000000[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/maxProperties.json000066400000000000000000000020251355135071500227330ustar00rootroot00000000000000[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/maximum.json000066400000000000000000000013121355135071500215440ustar00rootroot00000000000000[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/minItems.json000066400000000000000000000012651355135071500216630ustar00rootroot00000000000000[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/minLength.json000066400000000000000000000015661355135071500220270ustar00rootroot00000000000000[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/minProperties.json000066400000000000000000000017541355135071500227410ustar00rootroot00000000000000[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/minimum.json000066400000000000000000000013121355135071500215420ustar00rootroot00000000000000[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/multipleOf.json000066400000000000000000000027651355135071500222240ustar00rootroot00000000000000[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/not.json000066400000000000000000000053761355135071500207050ustar00rootroot00000000000000[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": {"not": true}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": {"not": false}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/oneOf.json000066400000000000000000000076511355135071500211510ustar00rootroot00000000000000[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": {"oneOf": [true, true, true]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": {"oneOf": [true, false, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": {"oneOf": [true, true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": {"oneOf": [false, false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/000077500000000000000000000000001355135071500210245ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft7/optional/bignum.json000066400000000000000000000057111355135071500232040ustar00rootroot00000000000000[ { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "integer", "schema": {"type": "integer"}, "tests": [ { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": {"type": "number"}, "tests": [ { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": {"type": "string"}, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "integer comparison", "schema": {"maximum": 18446744073709551615}, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "integer comparison", "schema": {"minimum": -18446744073709551615}, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/content.json000066400000000000000000000034221355135071500233720ustar00rootroot00000000000000[ { "description": "validation of string-encoded content based on media type", "schema": { "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document", "data": "{:}", "valid": false } ] }, { "description": "validation of binary string-encoding", "schema": { "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character)", "data": "eyJmb28iOi%iYmFyIn0K", "valid": false } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document", "data": "ezp9Cg==", "valid": false }, { "description": "an invalid base64 string that is valid JSON", "data": "{}", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/ecmascript-regex.json000066400000000000000000000005151355135071500251620ustar00rootroot00000000000000[ { "description": "ECMA 262 regex non-compliance", "schema": { "format": "regex" }, "tests": [ { "description": "ECMA 262 has no support for \\Z anchor from .NET", "data": "^\\S(|(.|\\n)*\\S)\\Z", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/000077500000000000000000000000001355135071500223145ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/draft7/optional/format/date-time.json000066400000000000000000000012411355135071500250560ustar00rootroot00000000000000[ { "description": "validation of date-time strings", "schema": {"format": "date-time"}, "tests": [ { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/date.json000066400000000000000000000011531355135071500241240ustar00rootroot00000000000000[ { "description": "validation of date strings", "schema": {"format": "date"}, "tests": [ { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "an invalid date-time string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/email.json000066400000000000000000000007121355135071500242760ustar00rootroot00000000000000[ { "description": "validation of e-mail addresses", "schema": {"format": "email"}, "tests": [ { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/hostname.json000066400000000000000000000021141355135071500250230ustar00rootroot00000000000000[ { "description": "validation of host names", "schema": {"format": "hostname"}, "tests": [ { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/idn-email.json000066400000000000000000000010051355135071500250420ustar00rootroot00000000000000[ { "description": "validation of an internationalized e-mail addresses", "schema": {"format": "idn-email"}, "tests": [ { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/idn-hostname.json000066400000000000000000000023741355135071500256030ustar00rootroot00000000000000[ { "description": "validation of internationalized host names", "schema": {"format": "idn-hostname"}, "disabled" : true, "tests": [ { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/ipv4.json000066400000000000000000000016741355135071500241010ustar00rootroot00000000000000[ { "description": "validation of IP addresses", "schema": {"format": "ipv4"}, "tests": [ { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/ipv6.json000066400000000000000000000014661355135071500241020ustar00rootroot00000000000000[ { "description": "validation of IPv6 addresses", "schema": {"format": "ipv6"}, "tests": [ { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/iri-reference.json000066400000000000000000000024411355135071500257270ustar00rootroot00000000000000[ { "description": "validation of IRI References", "schema": {"format": "iri-reference"}, "tests": [ { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#ƒrägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#ƒräg\\mênt", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/iri.json000066400000000000000000000031441355135071500237740ustar00rootroot00000000000000[ { "description": "validation of IRIs", "schema": {"format": "iri"}, "tests": [ { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parantheses", "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": true }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/json-pointer.json000066400000000000000000000132121355135071500256350ustar00rootroot00000000000000[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": {"format": "json-pointer"}, "tests": [ { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/regex.json000066400000000000000000000007451355135071500243270ustar00rootroot00000000000000[ { "description": "validation of regular expressions", "schema": {"format": "regex"}, "tests": [ { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/relative-json-pointer.json000066400000000000000000000017321355135071500274520ustar00rootroot00000000000000[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": {"format": "relative-json-pointer"}, "tests": [ { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/time.json000066400000000000000000000011631355135071500241460ustar00rootroot00000000000000[ { "description": "validation of time strings", "schema": {"format": "time"}, "tests": [ { "description": "a valid time string", "data": "08:30:06.283185Z", "valid": true }, { "description": "an invalid time string", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/uri-reference.json000066400000000000000000000023661355135071500257510ustar00rootroot00000000000000[ { "description": "validation of URI References", "schema": {"format": "uri-reference"}, "tests": [ { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/uri-template.json000066400000000000000000000016061355135071500256220ustar00rootroot00000000000000[ { "description": "format: uri-template", "schema": { "format": "uri-template" }, "tests": [ { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/format/uri.json000066400000000000000000000067121355135071500240140ustar00rootroot00000000000000[ { "description": "validation of URIs", "schema": {"format": "uri"}, "tests": [ { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parantheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/optional/zeroTerminatedFloats.json000066400000000000000000000005661355135071500260730ustar00rootroot00000000000000[ { "description": "some languages do not distinguish between different types of numeric value", "schema": { "type": "integer" }, "tests": [ { "description": "a float without fractional part is an integer", "data": 1.0, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/pattern.json000066400000000000000000000015311355135071500215470ustar00rootroot00000000000000[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores non-strings", "data": true, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/patternProperties.json000066400000000000000000000107461355135071500236340ustar00rootroot00000000000000[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/properties.json000066400000000000000000000075131355135071500222740ustar00rootroot00000000000000[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/propertyNames.json000066400000000000000000000041301355135071500227400ustar00rootroot00000000000000[ { "description": "propertyNames validation", "schema": { "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": {"propertyNames": true}, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": {"propertyNames": false}, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/ref.json000066400000000000000000000225621355135071500206550ustar00rootroot00000000000000[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "tilda~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": { "tilda": {"$ref": "#/tilda~0field"}, "slash": {"$ref": "#/slash~1field"}, "percent": {"$ref": "#/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilda invalid", "data": {"tilda": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilda valid", "data": {"tilda": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "$ref": "#/definitions/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$ref": "#/definitions/bool", "definitions": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$ref": "#/definitions/bool", "definitions": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$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"] } } }, "tests": [ { "description": "valid tree", "data": { "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} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "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} ] } } ] }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/refRemote.json000066400000000000000000000112131355135071500220200ustar00rootroot00000000000000[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$id": "http://localhost:1234/", "items": { "$id": "folder/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "$id": "folder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "$id": "folder/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/required.json000066400000000000000000000032521355135071500217140ustar00rootroot00000000000000[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] } ] gojsonschema-1.2.0/testdata/draft7/type.json000066400000000000000000000231631355135071500210600ustar00rootroot00000000000000[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "a boolean is a boolean", "data": true, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "a boolean is not null", "data": true, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] } ] gojsonschema-1.2.0/testdata/draft7/uniqueItems.json000066400000000000000000000050651355135071500224100ustar00rootroot00000000000000[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false } ] } ] gojsonschema-1.2.0/testdata/extra/000077500000000000000000000000001355135071500171335ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/extra/file with space.json000066400000000000000000000000161355135071500227520ustar00rootroot00000000000000{"foo": true} gojsonschema-1.2.0/testdata/extra/fragment_schema.json000066400000000000000000000001261355135071500231500ustar00rootroot00000000000000{"type":"object","additionalProperties":false,"definitions":{"x":{"type":"integer"}}} gojsonschema-1.2.0/testdata/remotes/000077500000000000000000000000001355135071500174665ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/remotes/folder/000077500000000000000000000000001355135071500207415ustar00rootroot00000000000000gojsonschema-1.2.0/testdata/remotes/folder/folderInteger.json000066400000000000000000000000311355135071500244170ustar00rootroot00000000000000{ "type": "integer" }gojsonschema-1.2.0/testdata/remotes/integer.json000066400000000000000000000000311355135071500220100ustar00rootroot00000000000000{ "type": "integer" }gojsonschema-1.2.0/testdata/remotes/name.json000066400000000000000000000002701355135071500213000ustar00rootroot00000000000000{ "definitions": { "orNull": { "anyOf": [ {"type": "null"}, {"$ref": "#"} ] } }, "type": "string" } gojsonschema-1.2.0/testdata/remotes/subSchemas.json000066400000000000000000000001561355135071500224600ustar00rootroot00000000000000{ "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } }gojsonschema-1.2.0/types.go000066400000000000000000000031351355135071500156740ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Contains const types for schema and JSON. // // created 28-02-2013 package gojsonschema // Type constants const ( TYPE_ARRAY = `array` TYPE_BOOLEAN = `boolean` TYPE_INTEGER = `integer` TYPE_NUMBER = `number` TYPE_NULL = `null` TYPE_OBJECT = `object` TYPE_STRING = `string` ) // JSON_TYPES hosts the list of type that are supported in JSON var JSON_TYPES []string // SCHEMA_TYPES hosts the list of type that are supported in schemas var SCHEMA_TYPES []string func init() { JSON_TYPES = []string{ TYPE_ARRAY, TYPE_BOOLEAN, TYPE_INTEGER, TYPE_NUMBER, TYPE_NULL, TYPE_OBJECT, TYPE_STRING} SCHEMA_TYPES = []string{ TYPE_ARRAY, TYPE_BOOLEAN, TYPE_INTEGER, TYPE_NUMBER, TYPE_OBJECT, TYPE_STRING} } gojsonschema-1.2.0/utils.go000066400000000000000000000100771355135071500156730ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Various utility functions. // // created 26-02-2013 package gojsonschema import ( "encoding/json" "math/big" "reflect" ) func isKind(what interface{}, kinds ...reflect.Kind) bool { target := what if isJSONNumber(what) { // JSON Numbers are strings! target = *mustBeNumber(what) } targetKind := reflect.ValueOf(target).Kind() for _, kind := range kinds { if targetKind == kind { return true } } return false } func existsMapKey(m map[string]interface{}, k string) bool { _, ok := m[k] return ok } func isStringInSlice(s []string, what string) bool { for i := range s { if s[i] == what { return true } } return false } // indexStringInSlice returns the index of the first instance of 'what' in s or -1 if it is not found in s. func indexStringInSlice(s []string, what string) int { for i := range s { if s[i] == what { return i } } return -1 } func marshalToJSONString(value interface{}) (*string, error) { mBytes, err := json.Marshal(value) if err != nil { return nil, err } sBytes := string(mBytes) return &sBytes, nil } func marshalWithoutNumber(value interface{}) (*string, error) { // The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber // This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1 // One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber // so that these differences in representation are removed jsonString, err := marshalToJSONString(value) if err != nil { return nil, err } var document interface{} err = json.Unmarshal([]byte(*jsonString), &document) if err != nil { return nil, err } return marshalToJSONString(document) } func isJSONNumber(what interface{}) bool { switch what.(type) { case json.Number: return true } return false } func checkJSONInteger(what interface{}) (isInt bool) { jsonNumber := what.(json.Number) bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber)) return isValidNumber && bigFloat.IsInt() } // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER const ( maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 ) func mustBeInteger(what interface{}) *int { if isJSONNumber(what) { number := what.(json.Number) isInt := checkJSONInteger(number) if isInt { int64Value, err := number.Int64() if err != nil { return nil } int32Value := int(int64Value) return &int32Value } } return nil } func mustBeNumber(what interface{}) *big.Rat { if isJSONNumber(what) { number := what.(json.Number) float64Value, success := new(big.Rat).SetString(string(number)) if success { return float64Value } } return nil } func convertDocumentNode(val interface{}) interface{} { if lval, ok := val.([]interface{}); ok { res := []interface{}{} for _, v := range lval { res = append(res, convertDocumentNode(v)) } return res } if mval, ok := val.(map[interface{}]interface{}); ok { res := map[string]interface{}{} for k, v := range mval { res[k.(string)] = convertDocumentNode(v) } return res } return val } gojsonschema-1.2.0/utils_test.go000066400000000000000000000032001355135071500167200ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author janmentzel // author-github https://github.com/janmentzel // author-mail ? ( forward to xeipuuv@gmail.com ) // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description (Unit) Tests for utils ( Float / Integer conversion ). // // created 08-08-2013 package gojsonschema import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" ) func TestCheckJsonNumber(t *testing.T) { var testCases = []struct { isInt bool value json.Number }{ {true, "0"}, {true, "2147483647"}, {true, "-2147483648"}, {true, "9223372036854775807"}, {true, "-9223372036854775808"}, {true, "1.0e+2"}, {true, "1.0e+10"}, {true, "-1.0e+2"}, {true, "-1.0e+10"}, {false, "1.0e-2"}, {false, "number"}, {false, "123number"}, } for _, testCase := range testCases { assert.Equal(t, testCase.isInt, checkJSONInteger(testCase.value)) assert.Equal(t, testCase.isInt, checkJSONInteger(testCase.value)) } } gojsonschema-1.2.0/validation.go000066400000000000000000000553311355135071500166670ustar00rootroot00000000000000// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Extends Schema and subSchema, implements the validation phase. // // created 28-02-2013 package gojsonschema import ( "encoding/json" "math/big" "reflect" "regexp" "strconv" "strings" "unicode/utf8" ) // Validate loads and validates a JSON schema func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) { // load schema schema, err := NewSchema(ls) if err != nil { return nil, err } return schema.Validate(ld) } // Validate loads and validates a JSON document func (v *Schema) Validate(l JSONLoader) (*Result, error) { root, err := l.LoadJSON() if err != nil { return nil, err } return v.validateDocument(root), nil } func (v *Schema) validateDocument(root interface{}) *Result { result := &Result{} context := NewJsonContext(STRING_CONTEXT_ROOT, nil) v.rootSchema.validateRecursive(v.rootSchema, root, result, context) return result } func (v *subSchema) subValidateWithContext(document interface{}, context *JsonContext) *Result { result := &Result{} v.validateRecursive(v, document, result, context) return result } // Walker function to validate the json recursively against the subSchema func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) { if internalLogEnabled { internalLog("validateRecursive %s", context.String()) internalLog(" %v", currentNode) } // Handle true/false schema as early as possible as all other fields will be nil if currentSubSchema.pass != nil { if !*currentSubSchema.pass { result.addInternalError( new(FalseError), context, currentNode, ErrorDetails{}, ) } return } // Handle referenced schemas, returns directly when a $ref is found if currentSubSchema.refSchema != nil { v.validateRecursive(currentSubSchema.refSchema, currentNode, result, context) return } // Check for null value if currentNode == nil { if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_NULL) { result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": TYPE_NULL, }, ) return } currentSubSchema.validateSchema(currentSubSchema, currentNode, result, context) v.validateCommon(currentSubSchema, currentNode, result, context) } else { // Not a null value if isJSONNumber(currentNode) { value := currentNode.(json.Number) isInt := checkJSONInteger(value) validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isInt && currentSubSchema.types.Contains(TYPE_INTEGER)) if currentSubSchema.types.IsTyped() && !validType { givenType := TYPE_INTEGER if !isInt { givenType = TYPE_NUMBER } result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": givenType, }, ) return } currentSubSchema.validateSchema(currentSubSchema, value, result, context) v.validateNumber(currentSubSchema, value, result, context) v.validateCommon(currentSubSchema, value, result, context) v.validateString(currentSubSchema, value, result, context) } else { rValue := reflect.ValueOf(currentNode) rKind := rValue.Kind() switch rKind { // Slice => JSON array case reflect.Slice: if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_ARRAY) { result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": TYPE_ARRAY, }, ) return } castCurrentNode := currentNode.([]interface{}) currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context) v.validateArray(currentSubSchema, castCurrentNode, result, context) v.validateCommon(currentSubSchema, castCurrentNode, result, context) // Map => JSON object case reflect.Map: if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_OBJECT) { result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": TYPE_OBJECT, }, ) return } castCurrentNode, ok := currentNode.(map[string]interface{}) if !ok { castCurrentNode = convertDocumentNode(currentNode).(map[string]interface{}) } currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context) v.validateObject(currentSubSchema, castCurrentNode, result, context) v.validateCommon(currentSubSchema, castCurrentNode, result, context) for _, pSchema := range currentSubSchema.propertiesChildren { nextNode, ok := castCurrentNode[pSchema.property] if ok { subContext := NewJsonContext(pSchema.property, context) v.validateRecursive(pSchema, nextNode, result, subContext) } } // Simple JSON values : string, number, boolean case reflect.Bool: if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_BOOLEAN) { result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": TYPE_BOOLEAN, }, ) return } value := currentNode.(bool) currentSubSchema.validateSchema(currentSubSchema, value, result, context) v.validateNumber(currentSubSchema, value, result, context) v.validateCommon(currentSubSchema, value, result, context) v.validateString(currentSubSchema, value, result, context) case reflect.String: if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_STRING) { result.addInternalError( new(InvalidTypeError), context, currentNode, ErrorDetails{ "expected": currentSubSchema.types.String(), "given": TYPE_STRING, }, ) return } value := currentNode.(string) currentSubSchema.validateSchema(currentSubSchema, value, result, context) v.validateNumber(currentSubSchema, value, result, context) v.validateCommon(currentSubSchema, value, result, context) v.validateString(currentSubSchema, value, result, context) } } } result.incrementScore() } // Different kinds of validation there, subSchema / common / array / object / string... func (v *subSchema) validateSchema(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) { if internalLogEnabled { internalLog("validateSchema %s", context.String()) internalLog(" %v", currentNode) } if len(currentSubSchema.anyOf) > 0 { validatedAnyOf := false var bestValidationResult *Result for _, anyOfSchema := range currentSubSchema.anyOf { if !validatedAnyOf { validationResult := anyOfSchema.subValidateWithContext(currentNode, context) validatedAnyOf = validationResult.Valid() if !validatedAnyOf && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) { bestValidationResult = validationResult } } } if !validatedAnyOf { result.addInternalError(new(NumberAnyOfError), context, currentNode, ErrorDetails{}) if bestValidationResult != nil { // add error messages of closest matching subSchema as // that's probably the one the user was trying to match result.mergeErrors(bestValidationResult) } } } if len(currentSubSchema.oneOf) > 0 { nbValidated := 0 var bestValidationResult *Result for _, oneOfSchema := range currentSubSchema.oneOf { validationResult := oneOfSchema.subValidateWithContext(currentNode, context) if validationResult.Valid() { nbValidated++ } else if nbValidated == 0 && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) { bestValidationResult = validationResult } } if nbValidated != 1 { result.addInternalError(new(NumberOneOfError), context, currentNode, ErrorDetails{}) if nbValidated == 0 { // add error messages of closest matching subSchema as // that's probably the one the user was trying to match result.mergeErrors(bestValidationResult) } } } if len(currentSubSchema.allOf) > 0 { nbValidated := 0 for _, allOfSchema := range currentSubSchema.allOf { validationResult := allOfSchema.subValidateWithContext(currentNode, context) if validationResult.Valid() { nbValidated++ } result.mergeErrors(validationResult) } if nbValidated != len(currentSubSchema.allOf) { result.addInternalError(new(NumberAllOfError), context, currentNode, ErrorDetails{}) } } if currentSubSchema.not != nil { validationResult := currentSubSchema.not.subValidateWithContext(currentNode, context) if validationResult.Valid() { result.addInternalError(new(NumberNotError), context, currentNode, ErrorDetails{}) } } if currentSubSchema.dependencies != nil && len(currentSubSchema.dependencies) > 0 { if isKind(currentNode, reflect.Map) { for elementKey := range currentNode.(map[string]interface{}) { if dependency, ok := currentSubSchema.dependencies[elementKey]; ok { switch dependency := dependency.(type) { case []string: for _, dependOnKey := range dependency { if _, dependencyResolved := currentNode.(map[string]interface{})[dependOnKey]; !dependencyResolved { result.addInternalError( new(MissingDependencyError), context, currentNode, ErrorDetails{"dependency": dependOnKey}, ) } } case *subSchema: dependency.validateRecursive(dependency, currentNode, result, context) } } } } } if currentSubSchema._if != nil { validationResultIf := currentSubSchema._if.subValidateWithContext(currentNode, context) if currentSubSchema._then != nil && validationResultIf.Valid() { validationResultThen := currentSubSchema._then.subValidateWithContext(currentNode, context) if !validationResultThen.Valid() { result.addInternalError(new(ConditionThenError), context, currentNode, ErrorDetails{}) result.mergeErrors(validationResultThen) } } if currentSubSchema._else != nil && !validationResultIf.Valid() { validationResultElse := currentSubSchema._else.subValidateWithContext(currentNode, context) if !validationResultElse.Valid() { result.addInternalError(new(ConditionElseError), context, currentNode, ErrorDetails{}) result.mergeErrors(validationResultElse) } } } result.incrementScore() } func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { if internalLogEnabled { internalLog("validateCommon %s", context.String()) internalLog(" %v", value) } // const: if currentSubSchema._const != nil { vString, err := marshalWithoutNumber(value) if err != nil { result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err}) } if *vString != *currentSubSchema._const { result.addInternalError(new(ConstError), context, value, ErrorDetails{ "allowed": *currentSubSchema._const, }, ) } } // enum: if len(currentSubSchema.enum) > 0 { vString, err := marshalWithoutNumber(value) if err != nil { result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err}) } if !isStringInSlice(currentSubSchema.enum, *vString) { result.addInternalError( new(EnumError), context, value, ErrorDetails{ "allowed": strings.Join(currentSubSchema.enum, ", "), }, ) } } result.incrementScore() } func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface{}, result *Result, context *JsonContext) { if internalLogEnabled { internalLog("validateArray %s", context.String()) internalLog(" %v", value) } nbValues := len(value) // TODO explain if currentSubSchema.itemsChildrenIsSingleSchema { for i := range value { subContext := NewJsonContext(strconv.Itoa(i), context) validationResult := currentSubSchema.itemsChildren[0].subValidateWithContext(value[i], subContext) result.mergeErrors(validationResult) } } else { if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 { nbItems := len(currentSubSchema.itemsChildren) // while we have both schemas and values, check them against each other for i := 0; i != nbItems && i != nbValues; i++ { subContext := NewJsonContext(strconv.Itoa(i), context) validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext) result.mergeErrors(validationResult) } if nbItems < nbValues { // we have less schemas than elements in the instance array, // but that might be ok if "additionalItems" is specified. switch currentSubSchema.additionalItems.(type) { case bool: if !currentSubSchema.additionalItems.(bool) { result.addInternalError(new(ArrayNoAdditionalItemsError), context, value, ErrorDetails{}) } case *subSchema: additionalItemSchema := currentSubSchema.additionalItems.(*subSchema) for i := nbItems; i != nbValues; i++ { subContext := NewJsonContext(strconv.Itoa(i), context) validationResult := additionalItemSchema.subValidateWithContext(value[i], subContext) result.mergeErrors(validationResult) } } } } } // minItems & maxItems if currentSubSchema.minItems != nil { if nbValues < int(*currentSubSchema.minItems) { result.addInternalError( new(ArrayMinItemsError), context, value, ErrorDetails{"min": *currentSubSchema.minItems}, ) } } if currentSubSchema.maxItems != nil { if nbValues > int(*currentSubSchema.maxItems) { result.addInternalError( new(ArrayMaxItemsError), context, value, ErrorDetails{"max": *currentSubSchema.maxItems}, ) } } // uniqueItems: if currentSubSchema.uniqueItems { var stringifiedItems = make(map[string]int) for j, v := range value { vString, err := marshalWithoutNumber(v) if err != nil { result.addInternalError(new(InternalError), context, value, ErrorDetails{"err": err}) } if i, ok := stringifiedItems[*vString]; ok { result.addInternalError( new(ItemsMustBeUniqueError), context, value, ErrorDetails{"type": TYPE_ARRAY, "i": i, "j": j}, ) } stringifiedItems[*vString] = j } } // contains: if currentSubSchema.contains != nil { validatedOne := false var bestValidationResult *Result for i, v := range value { subContext := NewJsonContext(strconv.Itoa(i), context) validationResult := currentSubSchema.contains.subValidateWithContext(v, subContext) if validationResult.Valid() { validatedOne = true break } else { if bestValidationResult == nil || validationResult.score > bestValidationResult.score { bestValidationResult = validationResult } } } if !validatedOne { result.addInternalError( new(ArrayContainsError), context, value, ErrorDetails{}, ) if bestValidationResult != nil { result.mergeErrors(bestValidationResult) } } } result.incrementScore() } func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string]interface{}, result *Result, context *JsonContext) { if internalLogEnabled { internalLog("validateObject %s", context.String()) internalLog(" %v", value) } // minProperties & maxProperties: if currentSubSchema.minProperties != nil { if len(value) < int(*currentSubSchema.minProperties) { result.addInternalError( new(ArrayMinPropertiesError), context, value, ErrorDetails{"min": *currentSubSchema.minProperties}, ) } } if currentSubSchema.maxProperties != nil { if len(value) > int(*currentSubSchema.maxProperties) { result.addInternalError( new(ArrayMaxPropertiesError), context, value, ErrorDetails{"max": *currentSubSchema.maxProperties}, ) } } // required: for _, requiredProperty := range currentSubSchema.required { _, ok := value[requiredProperty] if ok { result.incrementScore() } else { result.addInternalError( new(RequiredError), context, value, ErrorDetails{"property": requiredProperty}, ) } } // additionalProperty & patternProperty: for pk := range value { // Check whether this property is described by "properties" found := false for _, spValue := range currentSubSchema.propertiesChildren { if pk == spValue.property { found = true } } // Check whether this property is described by "patternProperties" ppMatch := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) // If it is not described by neither "properties" nor "patternProperties" it must pass "additionalProperties" if !found && !ppMatch { switch ap := currentSubSchema.additionalProperties.(type) { case bool: // Handle the boolean case separately as it's cleaner to return a specific error than failing to pass the false schema if !ap { result.addInternalError( new(AdditionalPropertyNotAllowedError), context, value[pk], ErrorDetails{"property": pk}, ) } case *subSchema: validationResult := ap.subValidateWithContext(value[pk], NewJsonContext(pk, context)) result.mergeErrors(validationResult) } } } // propertyNames: if currentSubSchema.propertyNames != nil { for pk := range value { validationResult := currentSubSchema.propertyNames.subValidateWithContext(pk, context) if !validationResult.Valid() { result.addInternalError(new(InvalidPropertyNameError), context, value, ErrorDetails{ "property": pk, }) result.mergeErrors(validationResult) } } } result.incrementScore() } func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *JsonContext) bool { if internalLogEnabled { internalLog("validatePatternProperty %s", context.String()) internalLog(" %s %v", key, value) } validated := false for pk, pv := range currentSubSchema.patternProperties { if matches, _ := regexp.MatchString(pk, key); matches { validated = true subContext := NewJsonContext(key, context) validationResult := pv.subValidateWithContext(value, subContext) result.mergeErrors(validationResult) } } if !validated { return false } result.incrementScore() return true } func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { // Ignore JSON numbers if isJSONNumber(value) { return } // Ignore non strings if !isKind(value, reflect.String) { return } if internalLogEnabled { internalLog("validateString %s", context.String()) internalLog(" %v", value) } stringValue := value.(string) // minLength & maxLength: if currentSubSchema.minLength != nil { if utf8.RuneCount([]byte(stringValue)) < int(*currentSubSchema.minLength) { result.addInternalError( new(StringLengthGTEError), context, value, ErrorDetails{"min": *currentSubSchema.minLength}, ) } } if currentSubSchema.maxLength != nil { if utf8.RuneCount([]byte(stringValue)) > int(*currentSubSchema.maxLength) { result.addInternalError( new(StringLengthLTEError), context, value, ErrorDetails{"max": *currentSubSchema.maxLength}, ) } } // pattern: if currentSubSchema.pattern != nil { if !currentSubSchema.pattern.MatchString(stringValue) { result.addInternalError( new(DoesNotMatchPatternError), context, value, ErrorDetails{"pattern": currentSubSchema.pattern}, ) } } // format if currentSubSchema.format != "" { if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) { result.addInternalError( new(DoesNotMatchFormatError), context, value, ErrorDetails{"format": currentSubSchema.format}, ) } } result.incrementScore() } func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { // Ignore non numbers if !isJSONNumber(value) { return } if internalLogEnabled { internalLog("validateNumber %s", context.String()) internalLog(" %v", value) } number := value.(json.Number) float64Value, _ := new(big.Rat).SetString(string(number)) // multipleOf: if currentSubSchema.multipleOf != nil { if q := new(big.Rat).Quo(float64Value, currentSubSchema.multipleOf); !q.IsInt() { result.addInternalError( new(MultipleOfError), context, number, ErrorDetails{ "multiple": new(big.Float).SetRat(currentSubSchema.multipleOf), }, ) } } //maximum & exclusiveMaximum: if currentSubSchema.maximum != nil { if float64Value.Cmp(currentSubSchema.maximum) == 1 { result.addInternalError( new(NumberLTEError), context, number, ErrorDetails{ "max": new(big.Float).SetRat(currentSubSchema.maximum), }, ) } } if currentSubSchema.exclusiveMaximum != nil { if float64Value.Cmp(currentSubSchema.exclusiveMaximum) >= 0 { result.addInternalError( new(NumberLTError), context, number, ErrorDetails{ "max": new(big.Float).SetRat(currentSubSchema.exclusiveMaximum), }, ) } } //minimum & exclusiveMinimum: if currentSubSchema.minimum != nil { if float64Value.Cmp(currentSubSchema.minimum) == -1 { result.addInternalError( new(NumberGTEError), context, number, ErrorDetails{ "min": new(big.Float).SetRat(currentSubSchema.minimum), }, ) } } if currentSubSchema.exclusiveMinimum != nil { if float64Value.Cmp(currentSubSchema.exclusiveMinimum) <= 0 { result.addInternalError( new(NumberGTError), context, number, ErrorDetails{ "min": new(big.Float).SetRat(currentSubSchema.exclusiveMinimum), }, ) } } // format if currentSubSchema.format != "" { if !FormatCheckers.IsFormat(currentSubSchema.format, float64Value) { result.addInternalError( new(DoesNotMatchFormatError), context, value, ErrorDetails{"format": currentSubSchema.format}, ) } } result.incrementScore() }