pax_global_header00006660000000000000000000000064130474471660014526gustar00rootroot0000000000000052 comment=6b67b3fab74d992bd07f72550006ab2c6907c416 gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/000077500000000000000000000000001304744716600210455ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/.gitignore000066400000000000000000000000121304744716600230260ustar00rootroot00000000000000*.sw[nop] gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/.travis.yml000066400000000000000000000002631304744716600231570ustar00rootroot00000000000000language: go go: - 1.3 before_install: - go get github.com/sigu-399/gojsonreference - go get github.com/sigu-399/gojsonpointer - go get github.com/stretchr/testify/assert gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/LICENSE-APACHE-2.0.txt000066400000000000000000000261121304744716600241060ustar00rootroot00000000000000 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-6b67b3fab74d992bd07f72550006ab2c6907c416/README.md000066400000000000000000000151511304744716600223270ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/xeipuuv/gojsonschema.svg)](https://travis-ci.org/xeipuuv/gojsonschema) # gojsonschema ## Description An implementation of JSON Schema, based on IETF's draft v4 - Go language 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) } } ``` ## 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. **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 "enum": EnumError "array_no_additional_items": ArrayNoAdditionalItemsError "array_min_items": ArrayMinItemsError "array_max_items": ArrayMaxItemsError "unique": ItemsMustBeUniqueError "array_min_properties": ArrayMinPropertiesError "array_max_properties": ArrayMaxPropertiesError "additional_property_not_allowed": AdditionalPropertyNotAllowedError "invalid_property_pattern": InvalidPropertyPatternError "string_gte": StringLengthGTEError "string_lte": StringLengthLTEError "pattern": DoesNotMatchPatternError "multiple_of": MultipleOfError "number_gte": NumberGTEError "number_gt": NumberGTError "number_lte": NumberLTEError "number_lt": NumberLTError **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.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}} ``` ## Formats JSON Schema allows for optional "format" property to validate strings 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"} ```` Available formats: date-time, hostname, email, ipv4, ipv6, uri. 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 string) bool { return strings.HasPrefix("ROLE_", input) } // Add it to the library gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{}) ```` Now to use in your json schema: ````json {"type": "string", "format": "role"} ```` ## Uses gojsonschema uses the following test suite : https://github.com/json-schema/JSON-Schema-Test-Suite gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/errors.go000066400000000000000000000140131304744716600227070ustar00rootroot00000000000000package gojsonschema import ( "bytes" "sync" "text/template" ) var errorTemplates errorTemplate = 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 ( // RequiredError. ErrorDetails: property string RequiredError struct { ResultErrorFields } // InvalidTypeError. ErrorDetails: expected, given InvalidTypeError struct { ResultErrorFields } // NumberAnyOfError. ErrorDetails: - NumberAnyOfError struct { ResultErrorFields } // NumberOneOfError. ErrorDetails: - NumberOneOfError struct { ResultErrorFields } // NumberAllOfError. ErrorDetails: - NumberAllOfError struct { ResultErrorFields } // NumberNotError. ErrorDetails: - NumberNotError struct { ResultErrorFields } // MissingDependencyError. ErrorDetails: dependency MissingDependencyError struct { ResultErrorFields } // InternalError. ErrorDetails: error InternalError struct { ResultErrorFields } // EnumError. ErrorDetails: allowed EnumError struct { ResultErrorFields } // ArrayNoAdditionalItemsError. ErrorDetails: - ArrayNoAdditionalItemsError struct { ResultErrorFields } // ArrayMinItemsError. ErrorDetails: min ArrayMinItemsError struct { ResultErrorFields } // ArrayMaxItemsError. ErrorDetails: max ArrayMaxItemsError struct { ResultErrorFields } // ItemsMustBeUniqueError. ErrorDetails: type ItemsMustBeUniqueError struct { ResultErrorFields } // ArrayMinPropertiesError. ErrorDetails: min ArrayMinPropertiesError struct { ResultErrorFields } // ArrayMaxPropertiesError. ErrorDetails: max ArrayMaxPropertiesError struct { ResultErrorFields } // AdditionalPropertyNotAllowedError. ErrorDetails: property AdditionalPropertyNotAllowedError struct { ResultErrorFields } // InvalidPropertyPatternError. ErrorDetails: property, pattern InvalidPropertyPatternError struct { ResultErrorFields } // StringLengthGTEError. ErrorDetails: min StringLengthGTEError struct { ResultErrorFields } // StringLengthLTEError. ErrorDetails: max StringLengthLTEError struct { ResultErrorFields } // DoesNotMatchPatternError. ErrorDetails: pattern DoesNotMatchPatternError struct { ResultErrorFields } // DoesNotMatchFormatError. ErrorDetails: format DoesNotMatchFormatError struct { ResultErrorFields } // MultipleOfError. ErrorDetails: multiple MultipleOfError struct { ResultErrorFields } // NumberGTEError. ErrorDetails: min NumberGTEError struct { ResultErrorFields } // NumberGTError. ErrorDetails: min NumberGTError struct { ResultErrorFields } // NumberLTEError. ErrorDetails: max NumberLTEError struct { ResultErrorFields } // NumberLTError. ErrorDetails: max NumberLTError 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 *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 *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 *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 *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() } err.SetType(t) err.SetContext(context) err.SetValue(value) err.SetDetails(details) details["field"] = err.Field() err.SetDescription(formatErrorDescription(d, 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) 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-6b67b3fab74d992bd07f72550006ab2c6907c416/format_checkers.go000066400000000000000000000141121304744716600245320ustar00rootroot00000000000000package gojsonschema import ( "net" "net/url" "reflect" "regexp" "strings" "time" ) type ( // FormatChecker is the interface all formatters added to FormatCheckerChain must implement FormatChecker interface { IsFormat(input string) bool } // FormatCheckerChain holds the formatters FormatCheckerChain struct { formatters map[string]FormatChecker } // EmailFormatter 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{} // URIFormatCheckers validates a URI with a valid Scheme per RFC3986 URIFormatChecker 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{} ) var ( // Formatters holds the valid formatters, and is a public variable // so library users can add custom formatters FormatCheckers = FormatCheckerChain{ formatters: map[string]FormatChecker{ "date-time": DateTimeFormatChecker{}, "hostname": HostnameFormatChecker{}, "email": EmailFormatChecker{}, "ipv4": IPV4FormatChecker{}, "ipv6": IPV6FormatChecker{}, "uri": URIFormatChecker{}, "uuid": UUIDFormatChecker{}, "regex": RegexFormatChecker{}, }, } // Regex credit: https://github.com/asaskevich/govalidator rxEmail = regexp.MustCompile("^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$") // 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]))*$`) rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$") ) // 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 { c.formatters[name] = f return c } // Remove deletes a FormatChecker from the FormatCheckerChain (if it exists) func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain { delete(c.formatters, name) return c } // Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name func (c *FormatCheckerChain) Has(name string) bool { _, ok := c.formatters[name] 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 { f, ok := c.formatters[name] if !ok { return false } if !isKind(input, reflect.String) { return false } inputString := input.(string) return f.IsFormat(inputString) } func (f EmailFormatChecker) IsFormat(input string) bool { return rxEmail.MatchString(input) } // Credit: https://github.com/asaskevich/govalidator func (f IPV4FormatChecker) IsFormat(input string) bool { ip := net.ParseIP(input) return ip != nil && strings.Contains(input, ".") } // Credit: https://github.com/asaskevich/govalidator func (f IPV6FormatChecker) IsFormat(input string) bool { ip := net.ParseIP(input) return ip != nil && strings.Contains(input, ":") } func (f DateTimeFormatChecker) IsFormat(input string) bool { 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, input); err == nil { return true } } return false } func (f URIFormatChecker) IsFormat(input string) bool { u, err := url.Parse(input) if err != nil || u.Scheme == "" { return false } return true } func (f HostnameFormatChecker) IsFormat(input string) bool { return rxHostname.MatchString(input) && len(input) < 256 } func (f UUIDFormatChecker) IsFormat(input string) bool { return rxUUID.MatchString(input) } // IsFormat implements FormatChecker interface. func (f RegexFormatChecker) IsFormat(input string) bool { if input == "" { return true } _, err := regexp.Compile(input) if err != nil { return false } return true } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/format_checkers_test.go000066400000000000000000000006721304744716600255770ustar00rootroot00000000000000package 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")) } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/glide.yaml000066400000000000000000000004161304744716600230160ustar00rootroot00000000000000package: github.com/xeipuuv/gojsonschema license: Apache 2.0 import: - package: github.com/xeipuuv/gojsonschema - package: github.com/xeipuuv/gojsonpointer - package: github.com/xeipuuv/gojsonreference - package: github.com/stretchr/testify/assert version: ^1.1.3 gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/internalLog.go000066400000000000000000000021631304744716600236540ustar00rootroot00000000000000// 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-6b67b3fab74d992bd07f72550006ab2c6907c416/jsonContext.go000066400000000000000000000037311304744716600237160ustar00rootroot00000000000000// 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 } 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-6b67b3fab74d992bd07f72550006ab2c6907c416/jsonLoader.go000066400000000000000000000172541304744716600235050ustar00rootroot00000000000000// 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" "os" "path/filepath" "runtime" "strings" "github.com/xeipuuv/gojsonreference" ) var osFS = osFileSystem(os.Open) // JSON loader interface type JSONLoader interface { JsonSource() interface{} LoadJSON() (interface{}, error) JsonReference() (gojsonreference.JsonReference, error) LoaderFactory() JSONLoaderFactory } type JSONLoaderFactory interface { New(source string) JSONLoader } type DefaultJSONLoaderFactory struct { } type FileSystemJSONLoaderFactory struct { fs http.FileSystem } func (d DefaultJSONLoaderFactory) New(source string) JSONLoader { return &jsonReferenceLoader{ fs: osFS, source: 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) 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) *jsonReferenceLoader { 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) *jsonReferenceLoader { 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.Replace(refToUrl.GetUrl().Path, "file://", "", -1) if runtime.GOOS == "windows" { // on Windows, a file URL may have an extra leading slash, use slashes // instead of backslashes, and have spaces escaped if strings.HasPrefix(filename, "/") { filename = filename[1:] } 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) { 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{} } func NewStringLoader(source string) *jsonStringLoader { 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{} } func NewBytesLoader(source []byte) *jsonBytesLoader { 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{} } func NewGoLoader(source interface{}) *jsonGoLoader { 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 } func NewReaderLoader(source io.Reader) (*jsonIOLoader, io.Reader) { buf := &bytes.Buffer{} return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf) } func NewWriterLoader(source io.Writer) (*jsonIOLoader, 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{} } 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-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/000077500000000000000000000000001304744716600256065ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/LICENSE000066400000000000000000000020411304744716600266100ustar00rootroot00000000000000Copyright (c) 2012 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems/000077500000000000000000000000001304744716600307205ustar00rootroot00000000000000data_00.json000066400000000000000000000000141304744716600327370ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[null,2,3,4]data_01.json000066400000000000000000000000201304744716600327350ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[null,2,3,"foo"]data_10.json000066400000000000000000000000131304744716600327370ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[1,2,3,4,5]data_20.json000066400000000000000000000000071304744716600327430ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[1,2,3]data_21.json000066400000000000000000000000111304744716600327370ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[1,2,3,4]data_30.json000066400000000000000000000000131304744716600327410ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[1,2,3,4,5]data_31.json000066400000000000000000000000151304744716600327440ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"foo":"bar"}data_40.json000066400000000000000000000000171304744716600327460ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems[1,"foo",false]schema_0.json000066400000000000000000000000631304744716600332120ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"additionalItems":{"type":"integer"},"items":[{}]}schema_1.json000066400000000000000000000000441304744716600332120ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"additionalItems":false,"items":{}}schema_2.json000066400000000000000000000000541304744716600332140ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"additionalItems":false,"items":[{},{},{}]}schema_3.json000066400000000000000000000000311304744716600332100ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"additionalItems":false}schema_4.json000066400000000000000000000000361304744716600332160ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalItems{"items":[{"type":"integer"}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties/000077500000000000000000000000001304744716600317735ustar00rootroot00000000000000data_00.json000066400000000000000000000000111304744716600340070ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"foo":1}data_01.json000066400000000000000000000000371304744716600340200ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"bar":2,"foo":1,"quux":"boom"}data_02.json000066400000000000000000000000071304744716600340160ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties[1,2,3]data_03.json000066400000000000000000000000261304744716600340200ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"foo":1, "vroom": 2} data_10.json000066400000000000000000000000111304744716600340100ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"foo":1}data_11.json000066400000000000000000000000351304744716600340170ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"bar":2,"foo":1,"quux":true}data_12.json000066400000000000000000000000331304744716600340160ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"bar":2,"foo":1,"quux":12}data_20.json000066400000000000000000000000351304744716600340170ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"bar":2,"foo":1,"quux":true}schema_0.json000066400000000000000000000001421304744716600342630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"additionalProperties":false,"properties":{"bar":{},"foo":{}},"patternProperties": { "^v": {} }} schema_1.json000066400000000000000000000001141304744716600342630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"additionalProperties":{"type":"boolean"},"properties":{"bar":{},"foo":{}}}schema_2.json000066400000000000000000000000421304744716600342640ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/additionalProperties{"properties":{"bar":{},"foo":{}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/000077500000000000000000000000001304744716600266435ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_00.json000066400000000000000000000000251304744716600307430ustar00rootroot00000000000000{"bar":2,"foo":"baz"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_01.json000066400000000000000000000000151304744716600307430ustar00rootroot00000000000000{"foo":"baz"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_02.json000066400000000000000000000000111304744716600307400ustar00rootroot00000000000000{"bar":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_03.json000066400000000000000000000000321304744716600307440ustar00rootroot00000000000000{"bar":"quux","foo":"baz"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_10.json000066400000000000000000000000411304744716600307420ustar00rootroot00000000000000{"bar":2,"baz":null,"foo":"quux"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_11.json000066400000000000000000000000311304744716600307420ustar00rootroot00000000000000{"baz":null,"foo":"quux"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_12.json000066400000000000000000000000241304744716600307450ustar00rootroot00000000000000{"bar":2,"baz":null}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_13.json000066400000000000000000000000261304744716600307500ustar00rootroot00000000000000{"bar":2,"foo":"quux"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_14.json000066400000000000000000000000111304744716600307430ustar00rootroot00000000000000{"bar":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_20.json000066400000000000000000000000021304744716600307400ustar00rootroot0000000000000025gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/data_21.json000066400000000000000000000000021304744716600307410ustar00rootroot0000000000000035gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/schema_0.json000066400000000000000000000002041304744716600312110ustar00rootroot00000000000000{"allOf":[{"properties":{"bar":{"type":"integer"}},"required":["bar"]},{"properties":{"foo":{"type":"string"}},"required":["foo"]}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/schema_1.json000066400000000000000000000002741304744716600312210ustar00rootroot00000000000000{"allOf":[{"properties":{"foo":{"type":"string"}},"required":["foo"]},{"properties":{"baz":{"type":"null"}},"required":["baz"]}],"properties":{"bar":{"type":"integer"}},"required":["bar"]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/allOf/schema_2.json000066400000000000000000000000511304744716600312130ustar00rootroot00000000000000{"allOf":[{"maximum":30},{"minimum":20}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/000077500000000000000000000000001304744716600266625ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_00.json000066400000000000000000000000011304744716600307540ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_01.json000066400000000000000000000000031304744716600307570ustar00rootroot000000000000002.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_02.json000066400000000000000000000000011304744716600307560ustar00rootroot000000000000003gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_03.json000066400000000000000000000000031304744716600307610ustar00rootroot000000000000001.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_10.json000066400000000000000000000000011304744716600307550ustar00rootroot000000000000003gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_11.json000066400000000000000000000000101304744716600307560ustar00rootroot00000000000000"foobar"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/data_12.json000066400000000000000000000000051304744716600307630ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/schema_0.json000066400000000000000000000000541304744716600312330ustar00rootroot00000000000000{"anyOf":[{"type":"integer"},{"minimum":2}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/anyOf/schema_1.json000066400000000000000000000000731304744716600312350ustar00rootroot00000000000000{"anyOf":[{"maxLength":2},{"minLength":4}],"type":"string"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/definitions/000077500000000000000000000000001304744716600301215ustar00rootroot00000000000000data_00.json000066400000000000000000000000521304744716600321420ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/definitions{"definitions":{"foo":{"type":"integer"}}}data_10.json000066400000000000000000000000421304744716600321420ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/definitions{"definitions":{"foo":{"type":1}}}schema_0.json000066400000000000000000000000621304744716600324120ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/definitions{"$ref":"http://json-schema.org/draft-04/schema#"}schema_1.json000066400000000000000000000000621304744716600324130ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/definitions{"$ref":"http://json-schema.org/draft-04/schema#"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies/000077500000000000000000000000001304744716600302345ustar00rootroot00000000000000data_00.json000066400000000000000000000000021304744716600322500ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{}data_01.json000066400000000000000000000000111304744716600322510ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"foo":1}data_02.json000066400000000000000000000000211304744716600322530ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2,"foo":1}data_03.json000066400000000000000000000000111304744716600322530ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2}data_04.json000066400000000000000000000000051304744716600322570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies"foo"data_10.json000066400000000000000000000000021304744716600322510ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{}data_11.json000066400000000000000000000000211304744716600322530ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2,"foo":1}data_12.json000066400000000000000000000000321304744716600322560ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2,"foo":1,"quux":3}data_13.json000066400000000000000000000000221304744716600322560ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"foo":1,"quux":2}data_14.json000066400000000000000000000000221304744716600322570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":1,"quux":2}data_15.json000066400000000000000000000000121304744716600322570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"quux":1}data_20.json000066400000000000000000000000211304744716600322530ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2,"foo":1}data_21.json000066400000000000000000000000161304744716600322600ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"foo":"quux"}data_22.json000066400000000000000000000000261304744716600322620ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":2,"foo":"quux"}data_23.json000066400000000000000000000000261304744716600322630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":"quux","foo":2}data_24.json000066400000000000000000000000331304744716600322620ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"bar":"quux","foo":"quux"}schema_0.json000066400000000000000000000000401304744716600325210ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"dependencies":{"bar":["foo"]}}schema_1.json000066400000000000000000000000471304744716600325310ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"dependencies":{"quux":["foo","bar"]}}schema_2.json000066400000000000000000000001331304744716600325260ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/dependencies{"dependencies":{"bar":{"properties":{"bar":{"type":"integer"},"foo":{"type":"integer"}}}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/000077500000000000000000000000001304744716600265525ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/data_00.json000066400000000000000000000000011304744716600306440ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/data_01.json000066400000000000000000000000011304744716600306450ustar00rootroot000000000000004gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/data_10.json000066400000000000000000000000021304744716600306460ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/data_11.json000066400000000000000000000000041304744716600306510ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/data_12.json000066400000000000000000000000151304744716600306540ustar00rootroot00000000000000{"foo":false}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/schema_0.json000066400000000000000000000000201304744716600311140ustar00rootroot00000000000000{"enum":[1,2,3]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/enum/schema_1.json000066400000000000000000000000451304744716600311240ustar00rootroot00000000000000{"enum":[6,"foo",[],true,{"foo":12}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/000077500000000000000000000000001304744716600270765ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_00.json000066400000000000000000000000061304744716600311750ustar00rootroot00000000000000"test"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_01.json000066400000000000000000000000071304744716600311770ustar00rootroot00000000000000"test@"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_02.json000066400000000000000000000000171304744716600312010ustar00rootroot00000000000000"test@test.com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_03.json000066400000000000000000000000121304744716600311750ustar00rootroot00000000000000"AB-10105"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_04.json000066400000000000000000000000121304744716600311760ustar00rootroot00000000000000"ABC10105"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_05.json000066400000000000000000000000121304744716600311770ustar00rootroot00000000000000"05:15:37"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_06.json000066400000000000000000000000141304744716600312020ustar00rootroot00000000000000"2015-05-13"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_07.json000066400000000000000000000000131304744716600312020ustar00rootroot00000000000000"2015-6-31"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_08.json000066400000000000000000000000251304744716600312060ustar00rootroot00000000000000"2015-01-30 19:08:06"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_09.json000066400000000000000000000000201304744716600312020ustar00rootroot00000000000000"18:31:24-05:00"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_10.json000066400000000000000000000000331304744716600311760ustar00rootroot00000000000000"2002-10-02T10:00:00-05:00"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_11.json000066400000000000000000000000261304744716600312010ustar00rootroot00000000000000"2002-10-02T15:00:00Z"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_12.json000066400000000000000000000000311304744716600311760ustar00rootroot00000000000000"2002-10-02T15:00:00.05Z"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_13.json000066400000000000000000000000151304744716600312010ustar00rootroot00000000000000"example.com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_14.json000066400000000000000000000000211304744716600311770ustar00rootroot00000000000000"sub.example.com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_15.json000066400000000000000000000000151304744716600312030ustar00rootroot00000000000000"hello.co.uk"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_16.json000066400000000000000000000000241304744716600312040ustar00rootroot00000000000000"http://example.com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_17.json000066400000000000000000000000151304744716600312050ustar00rootroot00000000000000"example_com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_18.json000066400000000000000000000000111304744716600312020ustar00rootroot00000000000000"4.2.2.4"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_19.json000066400000000000000000000000151304744716600312070ustar00rootroot00000000000000"4.1.1111.45"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_20.json000066400000000000000000000000511304744716600311770ustar00rootroot00000000000000"FE80:0000:0000:0000:0202:B3FF:FE1E:8329"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_21.json000066400000000000000000000000331304744716600312000ustar00rootroot00000000000000"FE80::0202:B3FF:FE1E:8329"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_22.json000066400000000000000000000000411304744716600312000ustar00rootroot00000000000000"1200::AB00:1234::2552:7777:1313"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_23.json000066400000000000000000000000511304744716600312020ustar00rootroot00000000000000"1200:0000:AB00:1234:O000:2552:7777:1313"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_24.json000066400000000000000000000000441304744716600312050ustar00rootroot00000000000000"ftp://ftp.is.co.za/rfc/rfc1808.txt"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_25.json000066400000000000000000000000351304744716600312060ustar00rootroot00000000000000"mailto:john.doe@example.com"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_26.json000066400000000000000000000000251304744716600312060ustar00rootroot00000000000000"tel:+1-816-555-1212"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_27.json000066400000000000000000000000451304744716600312110ustar00rootroot00000000000000"http://www.ietf.org/rfc/rfc2396.txt"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/data_28.json000066400000000000000000000000321304744716600312060ustar00rootroot00000000000000"example.com/path/to/file"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_0.json000066400000000000000000000000451304744716600314470ustar00rootroot00000000000000{"type": "string", "format": "email"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_1.json000066400000000000000000000000471304744716600314520ustar00rootroot00000000000000{"type": "string", "format": "invoice"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_2.json000066400000000000000000000000511304744716600314460ustar00rootroot00000000000000{"type": "string", "format": "date-time"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_3.json000066400000000000000000000000501304744716600314460ustar00rootroot00000000000000{"type": "string", "format": "hostname"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_4.json000066400000000000000000000000441304744716600314520ustar00rootroot00000000000000{"type": "string", "format": "ipv4"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_5.json000066400000000000000000000000441304744716600314530ustar00rootroot00000000000000{"type": "string", "format": "ipv6"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/format/schema_6.json000066400000000000000000000000431304744716600314530ustar00rootroot00000000000000{"type": "string", "format": "uri"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/000077500000000000000000000000001304744716600267275ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/data_00.json000066400000000000000000000000071304744716600310270ustar00rootroot00000000000000[1,2,3]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/data_01.json000066400000000000000000000000071304744716600310300ustar00rootroot00000000000000[1,"x"]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/data_02.json000066400000000000000000000000151304744716600310300ustar00rootroot00000000000000{"foo":"bar"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/data_10.json000066400000000000000000000000111304744716600310230ustar00rootroot00000000000000[1,"foo"]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/data_11.json000066400000000000000000000000111304744716600310240ustar00rootroot00000000000000["foo",1]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/schema_0.json000066400000000000000000000000341304744716600312760ustar00rootroot00000000000000{"items":{"type":"integer"}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/items/schema_1.json000066400000000000000000000000601304744716600312760ustar00rootroot00000000000000{"items":[{"type":"integer"},{"type":"string"}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/000077500000000000000000000000001304744716600273755ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/data_00.json000066400000000000000000000000031304744716600314710ustar00rootroot00000000000000[1]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/data_01.json000066400000000000000000000000051304744716600314740ustar00rootroot00000000000000[1,2]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/data_02.json000066400000000000000000000000071304744716600314770ustar00rootroot00000000000000[1,2,3]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/data_03.json000066400000000000000000000000101304744716600314720ustar00rootroot00000000000000"foobar"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxItems/schema_0.json000066400000000000000000000000161304744716600317440ustar00rootroot00000000000000{"maxItems":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/000077500000000000000000000000001304744716600275355ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/data_00.json000066400000000000000000000000031304744716600316310ustar00rootroot00000000000000"f"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/data_01.json000066400000000000000000000000041304744716600316330ustar00rootroot00000000000000"fo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/data_02.json000066400000000000000000000000051304744716600316350ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/data_03.json000066400000000000000000000000021304744716600316330ustar00rootroot0000000000000010gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/data_04.json000066400000000000000000000000101304744716600316330ustar00rootroot00000000000000"世界"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxLength/schema_0.json000066400000000000000000000000171304744716600321050ustar00rootroot00000000000000{"maxLength":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties/000077500000000000000000000000001304744716600304505ustar00rootroot00000000000000data_00.json000066400000000000000000000000111304744716600324640ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties{"foo":1}data_01.json000066400000000000000000000000211304744716600324660ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties{"bar":2,"foo":1}data_02.json000066400000000000000000000000311304744716600324700ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties{"bar":2,"baz":3,"foo":1}data_03.json000066400000000000000000000000101304744716600324660ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties"foobar"schema_0.json000066400000000000000000000000231304744716600327360ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maxProperties{"maxProperties":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/000077500000000000000000000000001304744716600272635ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/data_00.json000066400000000000000000000000031304744716600313570ustar00rootroot000000000000002.6gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/data_01.json000066400000000000000000000000031304744716600313600ustar00rootroot000000000000003.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/data_02.json000066400000000000000000000000031304744716600313610ustar00rootroot00000000000000"x"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/data_10.json000066400000000000000000000000031304744716600313600ustar00rootroot000000000000002.2gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/data_11.json000066400000000000000000000000011304744716600313570ustar00rootroot000000000000003gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/schema_0.json000066400000000000000000000000151304744716600316310ustar00rootroot00000000000000{"maximum":3}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/maximum/schema_1.json000066400000000000000000000000451304744716600316350ustar00rootroot00000000000000{"exclusiveMaximum":true,"maximum":3}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/000077500000000000000000000000001304744716600273735ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/data_00.json000066400000000000000000000000051304744716600314710ustar00rootroot00000000000000[1,2]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/data_01.json000066400000000000000000000000031304744716600314700ustar00rootroot00000000000000[1]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/data_02.json000066400000000000000000000000021304744716600314700ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/data_03.json000066400000000000000000000000021304744716600314710ustar00rootroot00000000000000""gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minItems/schema_0.json000066400000000000000000000000161304744716600317420ustar00rootroot00000000000000{"minItems":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/000077500000000000000000000000001304744716600275335ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/data_00.json000066400000000000000000000000051304744716600316310ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/data_01.json000066400000000000000000000000041304744716600316310ustar00rootroot00000000000000"fo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/data_02.json000066400000000000000000000000031304744716600316310ustar00rootroot00000000000000"f"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/data_03.json000066400000000000000000000000011304744716600316300ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/data_04.json000066400000000000000000000000051304744716600316350ustar00rootroot00000000000000"世"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minLength/schema_0.json000066400000000000000000000000171304744716600321030ustar00rootroot00000000000000{"minLength":2}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties/000077500000000000000000000000001304744716600304465ustar00rootroot00000000000000data_00.json000066400000000000000000000000211304744716600324630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties{"bar":2,"foo":1}data_01.json000066400000000000000000000000111304744716600324630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties{"foo":1}data_02.json000066400000000000000000000000021304744716600324640ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties{}data_03.json000066400000000000000000000000021304744716600324650ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties""schema_0.json000066400000000000000000000000231304744716600327340ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minProperties{"minProperties":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/000077500000000000000000000000001304744716600272615ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/data_00.json000066400000000000000000000000031304744716600313550ustar00rootroot000000000000002.6gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/data_01.json000066400000000000000000000000031304744716600313560ustar00rootroot000000000000000.6gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/data_02.json000066400000000000000000000000031304744716600313570ustar00rootroot00000000000000"x"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/data_10.json000066400000000000000000000000031304744716600313560ustar00rootroot000000000000001.2gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/data_11.json000066400000000000000000000000031304744716600313570ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/schema_0.json000066400000000000000000000000171304744716600316310ustar00rootroot00000000000000{"minimum":1.1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/minimum/schema_1.json000066400000000000000000000000471304744716600316350ustar00rootroot00000000000000{"exclusiveMinimum":true,"minimum":1.1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/000077500000000000000000000000001304744716600277265ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_00.json000066400000000000000000000000021304744716600320210ustar00rootroot0000000000000010gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_01.json000066400000000000000000000000011304744716600320210ustar00rootroot000000000000007gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_02.json000066400000000000000000000000051304744716600320260ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_10.json000066400000000000000000000000011304744716600320210ustar00rootroot000000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_11.json000066400000000000000000000000031304744716600320240ustar00rootroot000000000000004.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_12.json000066400000000000000000000000021304744716600320240ustar00rootroot0000000000000035gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_20.json000066400000000000000000000000061304744716600320270ustar00rootroot000000000000000.0075gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf/data_21.json000066400000000000000000000000071304744716600320310ustar00rootroot000000000000000.00751schema_0.json000066400000000000000000000000201304744716600322110ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf{"multipleOf":2}schema_1.json000066400000000000000000000000221304744716600322140ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf{"multipleOf":1.5}schema_2.json000066400000000000000000000000251304744716600322200ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/multipleOf{"multipleOf":0.0001}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/000077500000000000000000000000001304744716600264065ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_00.json000066400000000000000000000000051304744716600305040ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_01.json000066400000000000000000000000011304744716600305010ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_10.json000066400000000000000000000000051304744716600305050ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_11.json000066400000000000000000000000011304744716600305020ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_12.json000066400000000000000000000000041304744716600305060ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_20.json000066400000000000000000000000011304744716600305020ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_21.json000066400000000000000000000000111304744716600305040ustar00rootroot00000000000000{"foo":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/data_22.json000066400000000000000000000000151304744716600305110ustar00rootroot00000000000000{"foo":"bar"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/schema_0.json000066400000000000000000000000321304744716600307530ustar00rootroot00000000000000{"not":{"type":"integer"}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/schema_1.json000066400000000000000000000000461304744716600307610ustar00rootroot00000000000000{"not":{"type":["integer","boolean"]}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/not/schema_2.json000066400000000000000000000001001304744716600307510ustar00rootroot00000000000000{"not":{"properties":{"foo":{"type":"string"}},"type":"object"}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/000077500000000000000000000000001304744716600266545ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_00.json000066400000000000000000000000011304744716600307460ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_01.json000066400000000000000000000000031304744716600307510ustar00rootroot000000000000002.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_02.json000066400000000000000000000000011304744716600307500ustar00rootroot000000000000003gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_03.json000066400000000000000000000000031304744716600307530ustar00rootroot000000000000001.5gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_10.json000066400000000000000000000000011304744716600307470ustar00rootroot000000000000003gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_11.json000066400000000000000000000000101304744716600307500ustar00rootroot00000000000000"foobar"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/data_12.json000066400000000000000000000000051304744716600307550ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/schema_0.json000066400000000000000000000000541304744716600312250ustar00rootroot00000000000000{"oneOf":[{"type":"integer"},{"minimum":2}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/oneOf/schema_1.json000066400000000000000000000000731304744716600312270ustar00rootroot00000000000000{"oneOf":[{"minLength":2},{"maxLength":4}],"type":"string"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/pattern/000077500000000000000000000000001304744716600272635ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/pattern/data_00.json000066400000000000000000000000051304744716600313610ustar00rootroot00000000000000"aaa"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/pattern/data_01.json000066400000000000000000000000051304744716600313620ustar00rootroot00000000000000"abc"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/pattern/data_02.json000066400000000000000000000000041304744716600313620ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/pattern/schema_0.json000066400000000000000000000000221304744716600316270ustar00rootroot00000000000000{"pattern":"^a*$"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties/000077500000000000000000000000001304744716600313405ustar00rootroot00000000000000data_00.json000066400000000000000000000000111304744716600333540ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"foo":1}data_01.json000066400000000000000000000000251304744716600333620ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"foo":1,"foooooo":2}data_02.json000066400000000000000000000000301304744716600333570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"foo":"bar","fooooo":2}data_03.json000066400000000000000000000000351304744716600333650ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"foo":"bar","foooooo":"baz"}data_04.json000066400000000000000000000000021304744716600333600ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties12data_10.json000066400000000000000000000000101304744716600333540ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a":21}data_11.json000066400000000000000000000000131304744716600333600ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"aaaa":18}data_12.json000066400000000000000000000000221304744716600333610ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a":21,"aaaa":18}data_13.json000066400000000000000000000000131304744716600333620ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a":"bar"}data_14.json000066400000000000000000000000131304744716600333630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"aaaa":31}data_15.json000066400000000000000000000000271304744716600333710ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"aaa":"foo","aaaa":31}data_20.json000066400000000000000000000000211304744716600333570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"answer 1":"42"}data_21.json000066400000000000000000000000151304744716600333630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a31b":null}data_22.json000066400000000000000000000000131304744716600333620ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a_x_3":3}data_23.json000066400000000000000000000000131304744716600333630ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"a_X_3":3}data_24.json000066400000000000000000000000661304744716600333740ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{ "a": "hello", "aaaaaaaaaaaaaaaaaaa": null } data_25.json000066400000000000000000000000441304744716600333710ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{ "aaaaaaaaaaaaaaaaaaa": null } data_26.json000066400000000000000000000001161304744716600333720ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{ "dictionary": { "aaaaaaaaaaaaaaaaaaaa": null, "b": "hello" } }schema_0.json000066400000000000000000000000611304744716600336300ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"patternProperties":{"f.*o":{"type":"integer"}}}schema_1.json000066400000000000000000000001051304744716600336300ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"patternProperties":{"a*":{"type":"integer"},"aaa*":{"maximum":20}}}schema_2.json000066400000000000000000000001151304744716600336320ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{"patternProperties":{"X_":{"type":"string"},"[0-9]{2,}":{"type":"boolean"}}}schema_3.json000066400000000000000000000003131304744716600336330ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "patternProperties": { "^[a-zA-Z0-9]{1,10}$": { "type": "string" } }, "additionalProperties": false }schema_4.json000066400000000000000000000005501304744716600336370ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/patternProperties{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "dictionary": { "type": "object", "patternProperties": { "^[a-zA-Z0-9]{1,10}$": { "type": "string" } }, "additionalProperties": false } }, "additionalProperties": false }gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/000077500000000000000000000000001304744716600300025ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_00.json000066400000000000000000000000251304744716600321020ustar00rootroot00000000000000{"bar":"baz","foo":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_01.json000066400000000000000000000000221304744716600321000ustar00rootroot00000000000000{"bar":{},"foo":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_02.json000066400000000000000000000000231304744716600321020ustar00rootroot00000000000000{"bar":{},"foo":[]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_03.json000066400000000000000000000000131304744716600321020ustar00rootroot00000000000000{"quux":[]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_04.json000066400000000000000000000000021304744716600321010ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_10.json000066400000000000000000000000151304744716600321020ustar00rootroot00000000000000{"foo":[1,2]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_11.json000066400000000000000000000000211304744716600321000ustar00rootroot00000000000000{"foo":[1,2,3,4]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_12.json000066400000000000000000000000121304744716600321010ustar00rootroot00000000000000{"foo":[]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_13.json000066400000000000000000000000151304744716600321050ustar00rootroot00000000000000{"fxo":[1,2]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_14.json000066400000000000000000000000121304744716600321030ustar00rootroot00000000000000{"fxo":[]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_15.json000066400000000000000000000000121304744716600321040ustar00rootroot00000000000000{"bar":[]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_16.json000066400000000000000000000000121304744716600321050ustar00rootroot00000000000000{"quux":3}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties/data_17.json000066400000000000000000000000161304744716600321120ustar00rootroot00000000000000{"quux":"foo"}schema_0.json000066400000000000000000000001011304744716600322650ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties{"properties":{"bar":{"type":"string"},"foo":{"type":"integer"}}}schema_1.json000066400000000000000000000002401304744716600322720ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/properties{"additionalProperties":{"type":"integer"},"patternProperties":{"f.o":{"minItems":2}},"properties":{"bar":{"type":"array"},"foo":{"maxItems":3,"type":"array"}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/000077500000000000000000000000001304744716600263625ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_00.json000066400000000000000000000000151304744716600304610ustar00rootroot00000000000000{"foo":false}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_01.json000066400000000000000000000000251304744716600304630ustar00rootroot00000000000000{"foo":{"foo":false}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_02.json000066400000000000000000000000151304744716600304630ustar00rootroot00000000000000{"bar":false}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_03.json000066400000000000000000000000251304744716600304650ustar00rootroot00000000000000{"foo":{"bar":false}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_10.json000066400000000000000000000000111304744716600304560ustar00rootroot00000000000000{"bar":3}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_11.json000066400000000000000000000000141304744716600304620ustar00rootroot00000000000000{"bar":true}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_20.json000066400000000000000000000000051304744716600304620ustar00rootroot00000000000000[1,2]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_21.json000066400000000000000000000000111304744716600304600ustar00rootroot00000000000000[1,"foo"]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_30.json000066400000000000000000000000201304744716600304600ustar00rootroot00000000000000{"slash":"aoeu"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_31.json000066400000000000000000000000201304744716600304610ustar00rootroot00000000000000{"tilda":"aoeu"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_32.json000066400000000000000000000000221304744716600304640ustar00rootroot00000000000000{"percent":"aoeu"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_40.json000066400000000000000000000000011304744716600304600ustar00rootroot000000000000005gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_41.json000066400000000000000000000000031304744716600304630ustar00rootroot00000000000000"a"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_50.json000066400000000000000000000000171304744716600304700ustar00rootroot00000000000000{"minLength":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/data_51.json000066400000000000000000000000201304744716600304630ustar00rootroot00000000000000{"minLength":-1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_0.json000066400000000000000000000001001304744716600307230ustar00rootroot00000000000000{"additionalProperties":false,"properties":{"foo":{"$ref":"#"}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_1.json000066400000000000000000000001131304744716600307300ustar00rootroot00000000000000{"properties":{"bar":{"$ref":"#/properties/foo"},"foo":{"type":"integer"}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_2.json000066400000000000000000000000631304744716600307350ustar00rootroot00000000000000{"items":[{"type":"integer"},{"$ref":"#/items/0"}]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_3.json000066400000000000000000000003401304744716600307340ustar00rootroot00000000000000{"percent%field":{"type":"integer"},"properties":{"percent":{"$ref":"#/percent%25field"},"slash":{"$ref":"#/slash~1field"},"tilda":{"$ref":"#/tilda~0field"}},"slash/field":{"type":"integer"},"tilda~field":{"type":"integer"}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_4.json000066400000000000000000000001771304744716600307450ustar00rootroot00000000000000{"$ref":"#/definitions/c","definitions":{"a":{"type":"integer"},"b":{"$ref":"#/definitions/a"},"c":{"$ref":"#/definitions/b"}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/ref/schema_5.json000066400000000000000000000000621304744716600307370ustar00rootroot00000000000000{"$ref":"http://json-schema.org/draft-04/schema#"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/000077500000000000000000000000001304744716600275365ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_00.json000066400000000000000000000000011304744716600316300ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_01.json000066400000000000000000000000031304744716600316330ustar00rootroot00000000000000"a"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_10.json000066400000000000000000000000011304744716600316310ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_11.json000066400000000000000000000000031304744716600316340ustar00rootroot00000000000000"a"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_20.json000066400000000000000000000000011304744716600316320ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_21.json000066400000000000000000000000031304744716600316350ustar00rootroot00000000000000"a"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_30.json000066400000000000000000000000051304744716600316370ustar00rootroot00000000000000[[1]]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/data_31.json000066400000000000000000000000071304744716600316420ustar00rootroot00000000000000[["a"]]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/remoteFiles/000077500000000000000000000000001304744716600320145ustar00rootroot00000000000000000077500000000000000000000000001304744716600332105ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/remoteFiles/folderfolderInteger.json000066400000000000000000000000311304744716600366660ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/remoteFiles/folder{ "type": "integer" }integer.json000066400000000000000000000000311304744716600342570ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/remoteFiles{ "type": "integer" }subSchemas.json000066400000000000000000000001561304744716600347270ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/remoteFiles{ "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } }gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/schema_0.json000066400000000000000000000000551304744716600321100ustar00rootroot00000000000000{"$ref":"http://localhost:1234/integer.json"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/schema_1.json000066400000000000000000000000711304744716600321070ustar00rootroot00000000000000{"$ref":"http://localhost:1234/subSchemas.json#/integer"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/schema_2.json000066400000000000000000000000761304744716600321150ustar00rootroot00000000000000{"$ref":"http://localhost:1234/subSchemas.json#/refToInteger"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/refRemote/schema_3.json000066400000000000000000000001351304744716600321120ustar00rootroot00000000000000{"id":"http://localhost:1234","items":{"id":"folder/","items":{"$ref":"folderInteger.json"}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/000077500000000000000000000000001304744716600274265ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/data_00.json000066400000000000000000000000111304744716600315210ustar00rootroot00000000000000{"foo":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/data_01.json000066400000000000000000000000111304744716600315220ustar00rootroot00000000000000{"bar":1}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/data_10.json000066400000000000000000000000021304744716600315220ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/schema_0.json000066400000000000000000000000651304744716600320010ustar00rootroot00000000000000{"properties":{"bar":{},"foo":{}},"required":["foo"]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/required/schema_1.json000066400000000000000000000000311304744716600317730ustar00rootroot00000000000000{"properties":{"foo":{}}}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/000077500000000000000000000000001304744716600265675ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_00.json000066400000000000000000000000011304744716600306610ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_01.json000066400000000000000000000000031304744716600306640ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_02.json000066400000000000000000000000051304744716600306670ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_03.json000066400000000000000000000000021304744716600306650ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_04.json000066400000000000000000000000021304744716600306660ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_05.json000066400000000000000000000000041304744716600306710ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_06.json000066400000000000000000000000041304744716600306720ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_10.json000066400000000000000000000000011304744716600306620ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_11.json000066400000000000000000000000031304744716600306650ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_12.json000066400000000000000000000000051304744716600306700ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_13.json000066400000000000000000000000021304744716600306660ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_14.json000066400000000000000000000000021304744716600306670ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_15.json000066400000000000000000000000041304744716600306720ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_16.json000066400000000000000000000000041304744716600306730ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_20.json000066400000000000000000000000011304744716600306630ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_21.json000066400000000000000000000000031304744716600306660ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_22.json000066400000000000000000000000051304744716600306710ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_23.json000066400000000000000000000000021304744716600306670ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_24.json000066400000000000000000000000021304744716600306700ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_25.json000066400000000000000000000000041304744716600306730ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_26.json000066400000000000000000000000041304744716600306740ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_30.json000066400000000000000000000000011304744716600306640ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_31.json000066400000000000000000000000031304744716600306670ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_32.json000066400000000000000000000000051304744716600306720ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_33.json000066400000000000000000000000021304744716600306700ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_34.json000066400000000000000000000000021304744716600306710ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_35.json000066400000000000000000000000041304744716600306740ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_36.json000066400000000000000000000000041304744716600306750ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_40.json000066400000000000000000000000011304744716600306650ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_41.json000066400000000000000000000000031304744716600306700ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_42.json000066400000000000000000000000051304744716600306730ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_43.json000066400000000000000000000000021304744716600306710ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_44.json000066400000000000000000000000021304744716600306720ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_45.json000066400000000000000000000000041304744716600306750ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_46.json000066400000000000000000000000041304744716600306760ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_50.json000066400000000000000000000000011304744716600306660ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_51.json000066400000000000000000000000031304744716600306710ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_52.json000066400000000000000000000000051304744716600306740ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_53.json000066400000000000000000000000021304744716600306720ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_54.json000066400000000000000000000000021304744716600306730ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_55.json000066400000000000000000000000041304744716600306760ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_56.json000066400000000000000000000000041304744716600306770ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_60.json000066400000000000000000000000011304744716600306670ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_61.json000066400000000000000000000000031304744716600306720ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_62.json000066400000000000000000000000051304744716600306750ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_63.json000066400000000000000000000000021304744716600306730ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_64.json000066400000000000000000000000021304744716600306740ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_65.json000066400000000000000000000000041304744716600306770ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_66.json000066400000000000000000000000041304744716600307000ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_70.json000066400000000000000000000000011304744716600306700ustar00rootroot000000000000001gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_71.json000066400000000000000000000000051304744716600306750ustar00rootroot00000000000000"foo"gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_72.json000066400000000000000000000000031304744716600306740ustar00rootroot000000000000001.1gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_73.json000066400000000000000000000000021304744716600306740ustar00rootroot00000000000000{}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_74.json000066400000000000000000000000021304744716600306750ustar00rootroot00000000000000[]gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_75.json000066400000000000000000000000041304744716600307000ustar00rootroot00000000000000truegojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/data_76.json000066400000000000000000000000041304744716600307010ustar00rootroot00000000000000nullgojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_0.json000066400000000000000000000000221304744716600311330ustar00rootroot00000000000000{"type":"integer"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_1.json000066400000000000000000000000211304744716600311330ustar00rootroot00000000000000{"type":"number"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_2.json000066400000000000000000000000211304744716600311340ustar00rootroot00000000000000{"type":"string"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_3.json000066400000000000000000000000211304744716600311350ustar00rootroot00000000000000{"type":"object"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_4.json000066400000000000000000000000201304744716600311350ustar00rootroot00000000000000{"type":"array"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_5.json000066400000000000000000000000221304744716600311400ustar00rootroot00000000000000{"type":"boolean"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_6.json000066400000000000000000000000171304744716600311450ustar00rootroot00000000000000{"type":"null"}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/type/schema_7.json000066400000000000000000000000351304744716600311460ustar00rootroot00000000000000{"type":["integer","string"]}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems/000077500000000000000000000000001304744716600301165ustar00rootroot00000000000000data_00.json000066400000000000000000000000051304744716600321350ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[1,2]data_01.json000066400000000000000000000000051304744716600321360ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[1,1]data_010.json000066400000000000000000000000111304744716600322130ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[0,false]data_011.json000066400000000000000000000000241304744716600322200ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{},[1],true,null,1]data_012.json000066400000000000000000000000271304744716600322240ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{},[1],true,null,{},1]data_02.json000066400000000000000000000000071304744716600321410ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[1,1,1]data_03.json000066400000000000000000000000351304744716600321430ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{"foo":"bar"},{"foo":"baz"}]data_04.json000066400000000000000000000000351304744716600321440ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{"foo":"bar"},{"foo":"bar"}]data_05.json000066400000000000000000000000741304744716600321500ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":false}}}]data_06.json000066400000000000000000000000731304744716600321500ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[{"foo":{"bar":{"baz":true}}},{"foo":{"bar":{"baz":true}}}]data_07.json000066400000000000000000000000211304744716600321420ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[["foo"],["bar"]]data_08.json000066400000000000000000000000211304744716600321430ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[["foo"],["foo"]]data_09.json000066400000000000000000000000101304744716600321420ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems[1,true]schema_0.json000066400000000000000000000000241304744716600324050ustar00rootroot00000000000000gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/json_schema_test_suite/uniqueItems{"uniqueItems":true}gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/locales.go000066400000000000000000000165731304744716600230320ustar00rootroot00000000000000// 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 definining custom error strings locale interface { Required() string InvalidType() string NumberAnyOf() string NumberOneOf() string NumberAllOf() string NumberNot() string MissingDependency() string Internal() string Enum() string ArrayNotEnoughItems() string ArrayNoAdditionalItems() string ArrayMinItems() string ArrayMaxItems() string Unique() string ArrayMinProperties() string ArrayMaxProperties() string AdditionalPropertyNotAllowed() string InvalidPropertyPattern() string StringGTE() string StringLTE() string DoesNotMatchPattern() string DoesNotMatchFormat() string MultipleOf() string NumberGTE() string NumberGT() string NumberLTE() string NumberLT() string // Schema validations RegexPattern() string GreaterThanZero() string MustBeOfA() string MustBeOfAn() string CannotBeUsedWithout() string CannotBeGT() string MustBeOfType() string MustBeValidRegex() string MustBeValidFormat() string MustBeGTEZero() string KeyCannotBeGreaterThan() string KeyItemsMustBeOfType() string KeyItemsMustBeUnique() string ReferenceMustBeCanonical() string NotAValidType() string Duplicated() string httpBadStatus() string // ErrorFormat ErrorFormat() string } // DefaultLocale is the default locale for this package DefaultLocale struct{} ) func (l DefaultLocale) Required() string { return `{{.property}} is required` } func (l DefaultLocale) InvalidType() string { return `Invalid type. Expected: {{.expected}}, given: {{.given}}` } func (l DefaultLocale) NumberAnyOf() string { return `Must validate at least one schema (anyOf)` } func (l DefaultLocale) NumberOneOf() string { return `Must validate one and only one schema (oneOf)` } func (l DefaultLocale) NumberAllOf() string { return `Must validate all the schemas (allOf)` } func (l DefaultLocale) NumberNot() string { return `Must not validate the schema (not)` } func (l DefaultLocale) MissingDependency() string { return `Has a dependency on {{.dependency}}` } func (l DefaultLocale) Internal() string { return `Internal Error {{.error}}` } func (l DefaultLocale) Enum() string { return `{{.field}} must be one of the following: {{.allowed}}` } func (l DefaultLocale) ArrayNoAdditionalItems() string { return `No additional items allowed on array` } func (l DefaultLocale) ArrayNotEnoughItems() string { return `Not enough items on array to match positional list of schema` } func (l DefaultLocale) ArrayMinItems() string { return `Array must have at least {{.min}} items` } func (l DefaultLocale) ArrayMaxItems() string { return `Array must have at most {{.max}} items` } func (l DefaultLocale) Unique() string { return `{{.type}} items must be unique` } func (l DefaultLocale) ArrayMinProperties() string { return `Must have at least {{.min}} properties` } func (l DefaultLocale) ArrayMaxProperties() string { return `Must have at most {{.max}} properties` } func (l DefaultLocale) AdditionalPropertyNotAllowed() string { return `Additional property {{.property}} is not allowed` } func (l DefaultLocale) InvalidPropertyPattern() string { return `Property "{{.property}}" does not match pattern {{.pattern}}` } func (l DefaultLocale) StringGTE() string { return `String length must be greater than or equal to {{.min}}` } func (l DefaultLocale) StringLTE() string { return `String length must be less than or equal to {{.max}}` } func (l DefaultLocale) DoesNotMatchPattern() string { return `Does not match pattern '{{.pattern}}'` } func (l DefaultLocale) DoesNotMatchFormat() string { return `Does not match format '{{.format}}'` } func (l DefaultLocale) MultipleOf() string { return `Must be a multiple of {{.multiple}}` } func (l DefaultLocale) NumberGTE() string { return `Must be greater than or equal to {{.min}}` } func (l DefaultLocale) NumberGT() string { return `Must be greater than {{.min}}` } func (l DefaultLocale) NumberLTE() string { return `Must be less than or equal to {{.max}}` } func (l DefaultLocale) NumberLT() string { return `Must be less than {{.max}}` } // Schema validators func (l DefaultLocale) RegexPattern() string { return `Invalid regex pattern '{{.pattern}}'` } func (l DefaultLocale) GreaterThanZero() string { return `{{.number}} must be strictly greater than 0` } func (l DefaultLocale) MustBeOfA() string { return `{{.x}} must be of a {{.y}}` } func (l DefaultLocale) MustBeOfAn() string { return `{{.x}} must be of an {{.y}}` } func (l DefaultLocale) CannotBeUsedWithout() string { return `{{.x}} cannot be used without {{.y}}` } func (l DefaultLocale) CannotBeGT() string { return `{{.x}} cannot be greater than {{.y}}` } func (l DefaultLocale) MustBeOfType() string { return `{{.key}} must be of type {{.type}}` } func (l DefaultLocale) MustBeValidRegex() string { return `{{.key}} must be a valid regex` } func (l DefaultLocale) MustBeValidFormat() string { return `{{.key}} must be a valid format {{.given}}` } func (l DefaultLocale) MustBeGTEZero() string { return `{{.key}} must be greater than or equal to 0` } func (l DefaultLocale) KeyCannotBeGreaterThan() string { return `{{.key}} cannot be greater than {{.y}}` } func (l DefaultLocale) KeyItemsMustBeOfType() string { return `{{.key}} items must be {{.type}}` } func (l DefaultLocale) KeyItemsMustBeUnique() string { return `{{.key}} items must be unique` } func (l DefaultLocale) ReferenceMustBeCanonical() string { return `Reference {{.reference}} must be canonical` } func (l DefaultLocale) NotAValidType() string { return `{{.type}} is not a valid type -- ` } func (l DefaultLocale) Duplicated() string { return `{{.type}} type is duplicated` } func (l DefaultLocale) httpBadStatus() string { return `Could not read schema from HTTP, response status is {{.status}}` } // Replacement options: field, description, context, value func (l DefaultLocale) ErrorFormat() string { return `{{.field}}: {{.description}}` } const ( STRING_NUMBER = "number" STRING_ARRAY_OF_STRINGS = "array of strings" STRING_ARRAY_OF_SCHEMAS = "array of schemas" STRING_SCHEMA = "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-6b67b3fab74d992bd07f72550006ab2c6907c416/result.go000066400000000000000000000112251304744716600227130ustar00rootroot00000000000000// 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() string SetType(string) Type() string SetContext(*jsonContext) Context() *jsonContext SetDescription(string) Description() string SetValue(interface{}) Value() interface{} SetDetails(ErrorDetails) Details() ErrorDetails 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 value interface{} // Value given by the JSON file that is the source of the error details ErrorDetails } Result struct { errors []ResultError // Scores how well the validation matched. Useful in generating // better error messages for anyOf and oneOf. score int } ) // Field outputs 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 { if p, ok := v.Details()["property"]; ok { if str, isString := p.(string); isString { return str } } return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".") } func (v *ResultErrorFields) SetType(errorType string) { v.errorType = errorType } func (v *ResultErrorFields) Type() string { return v.errorType } func (v *ResultErrorFields) SetContext(context *jsonContext) { v.context = context } func (v *ResultErrorFields) Context() *jsonContext { return v.context } func (v *ResultErrorFields) SetDescription(description string) { v.description = description } func (v *ResultErrorFields) Description() string { return v.description } func (v *ResultErrorFields) SetValue(value interface{}) { v.value = value } func (v *ResultErrorFields) Value() interface{} { return v.value } func (v *ResultErrorFields) SetDetails(details ErrorDetails) { v.details = details } func (v *ResultErrorFields) Details() ErrorDetails { return v.details } 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(), }) } func (v *Result) Valid() bool { return len(v.errors) == 0 } func (v *Result) Errors() []ResultError { return v.errors } func (v *Result) addError(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-6b67b3fab74d992bd07f72550006ab2c6907c416/schema.go000066400000000000000000000603161304744716600226420ustar00rootroot00000000000000// 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 ( // "encoding/json" "errors" "reflect" "regexp" "github.com/xeipuuv/gojsonreference" ) var ( // Locale is the default locale to use // Library users can overwrite with their own implementation Locale locale = DefaultLocale{} ) func NewSchema(l JSONLoader) (*Schema, error) { ref, err := l.JsonReference() if err != nil { return nil, err } d := Schema{} d.pool = newSchemaPool(l.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 = l.LoadJSON() if err != nil { return nil, err } d.pool.SetStandaloneDocument(doc) } err = d.parse(doc) if err != nil { return nil, err } return &d, nil } type Schema struct { documentReference gojsonreference.JsonReference rootSchema *subSchema pool *schemaPool referencePool *schemaReferencePool } func (d *Schema) parse(document interface{}) error { d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY} return d.parseSchema(document, d.rootSchema) } 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 !isKind(documentNode, reflect.Map) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_OBJECT, "given": STRING_SCHEMA, }, )) } m := documentNode.(map[string]interface{}) if currentSchema == d.rootSchema { currentSchema.ref = &d.documentReference } // $subSchema if existsMapKey(m, KEY_SCHEMA) { if !isKind(m[KEY_SCHEMA], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": KEY_SCHEMA, }, )) } schemaRef := m[KEY_SCHEMA].(string) schemaReference, err := gojsonreference.NewJsonReference(schemaRef) currentSchema.subSchema = &schemaReference if err != nil { return err } } // $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 } if jsonReference.HasFullUrl { currentSchema.ref = &jsonReference } else { inheritedReference, err := currentSchema.ref.Inherits(jsonReference) if err != nil { return err } currentSchema.ref = inheritedReference } if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok { currentSchema.refSchema = sch } else { err := d.parseReference(documentNode, currentSchema, k) if err != nil { return err } return nil } } // definitions if existsMapKey(m, KEY_DEFINITIONS) { if isKind(m[KEY_DEFINITIONS], reflect.Map) { currentSchema.definitions = make(map[string]*subSchema) for dk, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) { if isKind(dv, reflect.Map) { newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema, ref: currentSchema.ref} currentSchema.definitions[dk] = newSchema err := d.parseSchema(dv, newSchema) if err != nil { return errors.New(err.Error()) } } 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, }, )) } } // id if existsMapKey(m, KEY_ID) && !isKind(m[KEY_ID], reflect.String) { return errors.New(formatErrorDescription( Locale.InvalidType(), ErrorDetails{ "expected": TYPE_STRING, "given": KEY_ID, }, )) } if k, ok := m[KEY_ID].(string); ok { currentSchema.id = &k } // 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 } // 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, }, )) } else { currentSchema.types.Add(typeInArray.(string)) } } } 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, }, )) } } // 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) { newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} newSchema.ref = currentSchema.ref currentSchema.AddItemsChild(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) { newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} newSchema.ref = currentSchema.ref currentSchema.AddItemsChild(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 <= 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) { 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}, )) } exclusiveMinimumValue := m[KEY_EXCLUSIVE_MINIMUM].(bool) currentSchema.exclusiveMinimum = exclusiveMinimumValue } else { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": TYPE_BOOLEAN}, )) } } 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) { 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}, )) } exclusiveMaximumValue := m[KEY_EXCLUSIVE_MAXIMUM].(bool) currentSchema.exclusiveMaximum = exclusiveMaximumValue } else { return errors.New(formatErrorDescription( Locale.MustBeOfA(), ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": STRING_NUMBER}, )) } } if currentSchema.minimum != nil && currentSchema.maximum != nil { if *currentSchema.minimum > *currentSchema.maximum { return errors.New(formatErrorDescription( Locale.CannotBeGT(), ErrorDetails{"x": KEY_MINIMUM, "y": KEY_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 && FormatCheckers.Has(formatString) { currentSchema.format = formatString } else { return errors.New(formatErrorDescription( Locale.MustBeValidFormat(), ErrorDetails{"key": KEY_FORMAT, "given": m[KEY_FORMAT]}, )) } } // 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) { err := currentSchema.AddRequired(requiredValue.(string)) if err != nil { return err } } 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}, )) } } // validation : all if existsMapKey(m, KEY_ENUM) { if isKind(m[KEY_ENUM], reflect.Slice) { for _, v := range m[KEY_ENUM].([]interface{}) { err := currentSchema.AddEnum(v) if err != nil { return err } } } 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.AddOneOf(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.AddAnyOf(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.AddAllOf(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) { newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref} currentSchema.SetNot(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}, )) } } return nil } func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) error { var refdDocumentNode interface{} jsonPointer := currentSchema.ref.GetPointer() standaloneDocument := d.pool.GetStandaloneDocument() if standaloneDocument != nil { var err error refdDocumentNode, _, err = jsonPointer.Get(standaloneDocument) if err != nil { return err } } else { dsp, err := d.pool.GetDocument(*currentSchema.ref) if err != nil { return err } refdDocumentNode, _, err = jsonPointer.Get(dsp.Document) if err != nil { return err } } if !isKind(refdDocumentNode, reflect.Map) { return errors.New(formatErrorDescription( Locale.MustBeOfType(), ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT}, )) } // returns the loaded referenced subSchema for the caller to update its current subSchema newSchemaDocument := refdDocumentNode.(map[string]interface{}) newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref} d.referencePool.Add(currentSchema.ref.String()+reference, newSchema) err := d.parseSchema(newSchemaDocument, 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.AddPropertiesChild(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, }, )) } else { valuesToRegister = append(valuesToRegister, value.(string)) } currentSchema.dependencies[k] = valuesToRegister } case reflect.Map: 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-6b67b3fab74d992bd07f72550006ab2c6907c416/schemaPool.go000066400000000000000000000054331304744716600234730ustar00rootroot00000000000000// 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" "github.com/xeipuuv/gojsonreference" ) type schemaPoolDocument struct { Document interface{} } type schemaPool struct { schemaPoolDocuments map[string]*schemaPoolDocument standaloneDocument interface{} jsonLoaderFactory JSONLoaderFactory } func newSchemaPool(f JSONLoaderFactory) *schemaPool { p := &schemaPool{} p.schemaPoolDocuments = make(map[string]*schemaPoolDocument) p.standaloneDocument = nil p.jsonLoaderFactory = f return p } func (p *schemaPool) SetStandaloneDocument(document interface{}) { p.standaloneDocument = document } func (p *schemaPool) GetStandaloneDocument() (document interface{}) { return p.standaloneDocument } func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) { if internalLogEnabled { internalLog("Get Document ( %s )", reference.String()) } var err error // It is not possible to load anything that is not canonical... if !reference.IsCanonical() { return nil, errors.New(formatErrorDescription( Locale.ReferenceMustBeCanonical(), ErrorDetails{"reference": reference}, )) } refToUrl := reference refToUrl.GetUrl().Fragment = "" var spd *schemaPoolDocument // Try to find the requested document in the pool for k := range p.schemaPoolDocuments { if k == refToUrl.String() { spd = p.schemaPoolDocuments[k] } } if spd != nil { if internalLogEnabled { internalLog(" From pool") } return spd, nil } jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String()) document, err := jsonReferenceLoader.LoadJSON() if err != nil { return nil, err } spd = &schemaPoolDocument{Document: document} // add the document to the pool for potential later use p.schemaPoolDocuments[refToUrl.String()] = spd return spd, nil } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/schemaReferencePool.go000066400000000000000000000032401304744716600253040ustar00rootroot00000000000000// 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)) } p.documents[ref] = sch } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/schemaType.go000066400000000000000000000040621304744716600235000ustar00rootroot00000000000000// 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{"type": etype})) } 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-6b67b3fab74d992bd07f72550006ab2c6907c416/schema_test.go000066400000000000000000001600231304744716600236750ustar00rootroot00000000000000// 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" "net/http" "os" "reflect" "regexp" "sort" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" ) const displayErrorMessages = false var rxInvoice = regexp.MustCompile("^[A-Z]{2}-[0-9]{5}") var rxSplitErrors = regexp.MustCompile(", ?") // Used for remote schema in ref/schema_5.json that defines "uri" and "regex" types type alwaysTrueFormatChecker struct{} type invoiceFormatChecker struct{} func (a alwaysTrueFormatChecker) IsFormat(input string) bool { return true } func (a invoiceFormatChecker) IsFormat(input string) bool { return rxInvoice.MatchString(input) } func TestJsonSchemaTestSuite(t *testing.T) { JsonSchemaTestSuiteMap := []map[string]string{ {"phase": "integer type matches integers", "test": "an integer is an integer", "schema": "type/schema_0.json", "data": "type/data_00.json", "valid": "true"}, {"phase": "integer type matches integers", "test": "a float is not an integer", "schema": "type/schema_0.json", "data": "type/data_01.json", "valid": "false", "errors": "invalid_type"}, {"phase": "integer type matches integers", "test": "a string is not an integer", "schema": "type/schema_0.json", "data": "type/data_02.json", "valid": "false", "errors": "invalid_type"}, {"phase": "integer type matches integers", "test": "an object is not an integer", "schema": "type/schema_0.json", "data": "type/data_03.json", "valid": "false", "errors": "invalid_type"}, {"phase": "integer type matches integers", "test": "an array is not an integer", "schema": "type/schema_0.json", "data": "type/data_04.json", "valid": "false", "errors": "invalid_type"}, {"phase": "integer type matches integers", "test": "a boolean is not an integer", "schema": "type/schema_0.json", "data": "type/data_05.json", "valid": "false", "errors": "invalid_type"}, {"phase": "integer type matches integers", "test": "null is not an integer", "schema": "type/schema_0.json", "data": "type/data_06.json", "valid": "false", "errors": "invalid_type"}, {"phase": "number type matches numbers", "test": "an integer is a number", "schema": "type/schema_1.json", "data": "type/data_10.json", "valid": "true"}, {"phase": "number type matches numbers", "test": "a float is a number", "schema": "type/schema_1.json", "data": "type/data_11.json", "valid": "true"}, {"phase": "number type matches numbers", "test": "a string is not a number", "schema": "type/schema_1.json", "data": "type/data_12.json", "valid": "false", "errors": "invalid_type"}, {"phase": "number type matches numbers", "test": "an object is not a number", "schema": "type/schema_1.json", "data": "type/data_13.json", "valid": "false", "errors": "invalid_type"}, {"phase": "number type matches numbers", "test": "an array is not a number", "schema": "type/schema_1.json", "data": "type/data_14.json", "valid": "false", "errors": "invalid_type"}, {"phase": "number type matches numbers", "test": "a boolean is not a number", "schema": "type/schema_1.json", "data": "type/data_15.json", "valid": "false", "errors": "invalid_type"}, {"phase": "number type matches numbers", "test": "null is not a number", "schema": "type/schema_1.json", "data": "type/data_16.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "1 is not a string", "schema": "type/schema_2.json", "data": "type/data_20.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "a float is not a string", "schema": "type/schema_2.json", "data": "type/data_21.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "a string is a string", "schema": "type/schema_2.json", "data": "type/data_22.json", "valid": "true"}, {"phase": "string type matches strings", "test": "an object is not a string", "schema": "type/schema_2.json", "data": "type/data_23.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "an array is not a string", "schema": "type/schema_2.json", "data": "type/data_24.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "a boolean is not a string", "schema": "type/schema_2.json", "data": "type/data_25.json", "valid": "false", "errors": "invalid_type"}, {"phase": "string type matches strings", "test": "null is not a string", "schema": "type/schema_2.json", "data": "type/data_26.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "an integer is not an object", "schema": "type/schema_3.json", "data": "type/data_30.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "a float is not an object", "schema": "type/schema_3.json", "data": "type/data_31.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "a string is not an object", "schema": "type/schema_3.json", "data": "type/data_32.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "an object is an object", "schema": "type/schema_3.json", "data": "type/data_33.json", "valid": "true"}, {"phase": "object type matches objects", "test": "an array is not an object", "schema": "type/schema_3.json", "data": "type/data_34.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "a boolean is not an object", "schema": "type/schema_3.json", "data": "type/data_35.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object type matches objects", "test": "null is not an object", "schema": "type/schema_3.json", "data": "type/data_36.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "an integer is not an array", "schema": "type/schema_4.json", "data": "type/data_40.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "a float is not an array", "schema": "type/schema_4.json", "data": "type/data_41.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "a string is not an array", "schema": "type/schema_4.json", "data": "type/data_42.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "an object is not an array", "schema": "type/schema_4.json", "data": "type/data_43.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "an array is not an array", "schema": "type/schema_4.json", "data": "type/data_44.json", "valid": "true"}, {"phase": "array type matches arrays", "test": "a boolean is not an array", "schema": "type/schema_4.json", "data": "type/data_45.json", "valid": "false", "errors": "invalid_type"}, {"phase": "array type matches arrays", "test": "null is not an array", "schema": "type/schema_4.json", "data": "type/data_46.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "an integer is not a boolean", "schema": "type/schema_5.json", "data": "type/data_50.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "a float is not a boolean", "schema": "type/schema_5.json", "data": "type/data_51.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "a string is not a boolean", "schema": "type/schema_5.json", "data": "type/data_52.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "an object is not a boolean", "schema": "type/schema_5.json", "data": "type/data_53.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "an array is not a boolean", "schema": "type/schema_5.json", "data": "type/data_54.json", "valid": "false", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "a boolean is not a boolean", "schema": "type/schema_5.json", "data": "type/data_55.json", "valid": "true", "errors": "invalid_type"}, {"phase": "boolean type matches booleans", "test": "null is not a boolean", "schema": "type/schema_5.json", "data": "type/data_56.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "an integer is not null", "schema": "type/schema_6.json", "data": "type/data_60.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "a float is not null", "schema": "type/schema_6.json", "data": "type/data_61.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "a string is not null", "schema": "type/schema_6.json", "data": "type/data_62.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "an object is not null", "schema": "type/schema_6.json", "data": "type/data_63.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "an array is not null", "schema": "type/schema_6.json", "data": "type/data_64.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "a boolean is not null", "schema": "type/schema_6.json", "data": "type/data_65.json", "valid": "false", "errors": "invalid_type"}, {"phase": "null type matches only the null object", "test": "null is null", "schema": "type/schema_6.json", "data": "type/data_66.json", "valid": "true"}, {"phase": "multiple types can be specified in an array", "test": "an integer is valid", "schema": "type/schema_7.json", "data": "type/data_70.json", "valid": "true"}, {"phase": "multiple types can be specified in an array", "test": "a string is valid", "schema": "type/schema_7.json", "data": "type/data_71.json", "valid": "true"}, {"phase": "multiple types can be specified in an array", "test": "a float is invalid", "schema": "type/schema_7.json", "data": "type/data_72.json", "valid": "false", "errors": "invalid_type"}, {"phase": "multiple types can be specified in an array", "test": "an object is invalid", "schema": "type/schema_7.json", "data": "type/data_73.json", "valid": "false", "errors": "invalid_type"}, {"phase": "multiple types can be specified in an array", "test": "an array is invalid", "schema": "type/schema_7.json", "data": "type/data_74.json", "valid": "false", "errors": "invalid_type"}, {"phase": "multiple types can be specified in an array", "test": "a boolean is invalid", "schema": "type/schema_7.json", "data": "type/data_75.json", "valid": "false", "errors": "invalid_type"}, {"phase": "multiple types can be specified in an array", "test": "null is invalid", "schema": "type/schema_7.json", "data": "type/data_76.json", "valid": "false", "errors": "invalid_type"}, {"phase": "required validation", "test": "present required property is valid", "schema": "required/schema_0.json", "data": "required/data_00.json", "valid": "true"}, {"phase": "required validation", "test": "non-present required property is invalid", "schema": "required/schema_0.json", "data": "required/data_01.json", "valid": "false", "errors": "required"}, {"phase": "required default validation", "test": "not required by default", "schema": "required/schema_1.json", "data": "required/data_10.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "unique array of integers is valid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_00.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "non-unique array of integers is invalid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_01.json", "valid": "false", "errors": "unique"}, {"phase": "uniqueItems validation", "test": "numbers are unique if mathematically unequal", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_02.json", "valid": "false", "errors": "unique, unique"}, {"phase": "uniqueItems validation", "test": "unique array of objects is valid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_03.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "non-unique array of objects is invalid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_04.json", "valid": "false", "errors": "unique"}, {"phase": "uniqueItems validation", "test": "unique array of nested objects is valid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_05.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "non-unique array of nested objects is invalid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_06.json", "valid": "false", "errors": "unique"}, {"phase": "uniqueItems validation", "test": "unique array of arrays is valid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_07.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "non-unique array of arrays is invalid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_08.json", "valid": "false", "errors": "unique"}, {"phase": "uniqueItems validation", "test": "1 and true are unique", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_09.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "0 and false are unique", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_010.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "unique heterogeneous types are valid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_011.json", "valid": "true"}, {"phase": "uniqueItems validation", "test": "non-unique heterogeneous types are invalid", "schema": "uniqueItems/schema_0.json", "data": "uniqueItems/data_012.json", "valid": "false", "errors": "unique"}, {"phase": "pattern validation", "test": "a matching pattern is valid", "schema": "pattern/schema_0.json", "data": "pattern/data_00.json", "valid": "true"}, {"phase": "pattern validation", "test": "a non-matching pattern is invalid", "schema": "pattern/schema_0.json", "data": "pattern/data_01.json", "valid": "false", "errors": "pattern"}, {"phase": "pattern validation", "test": "ignores non-strings", "schema": "pattern/schema_0.json", "data": "pattern/data_02.json", "valid": "true"}, {"phase": "simple enum validation", "test": "one of the enum is valid", "schema": "enum/schema_0.json", "data": "enum/data_00.json", "valid": "true"}, {"phase": "simple enum validation", "test": "something else is invalid", "schema": "enum/schema_0.json", "data": "enum/data_01.json", "valid": "false", "errors": "enum"}, {"phase": "heterogeneous enum validation", "test": "one of the enum is valid", "schema": "enum/schema_1.json", "data": "enum/data_10.json", "valid": "true"}, {"phase": "heterogeneous enum validation", "test": "something else is invalid", "schema": "enum/schema_1.json", "data": "enum/data_11.json", "valid": "false", "errors": "enum"}, {"phase": "heterogeneous enum validation", "test": "objects are deep compared", "schema": "enum/schema_1.json", "data": "enum/data_12.json", "valid": "false", "errors": "enum"}, {"phase": "minLength validation", "test": "longer is valid", "schema": "minLength/schema_0.json", "data": "minLength/data_00.json", "valid": "true"}, {"phase": "minLength validation", "test": "exact length is valid", "schema": "minLength/schema_0.json", "data": "minLength/data_01.json", "valid": "true"}, {"phase": "minLength validation", "test": "too short is invalid", "schema": "minLength/schema_0.json", "data": "minLength/data_02.json", "valid": "false", "errors": "string_gte"}, {"phase": "minLength validation", "test": "ignores non-strings", "schema": "minLength/schema_0.json", "data": "minLength/data_03.json", "valid": "true"}, {"phase": "minLength validation", "test": "counts utf8 length correctly", "schema": "minLength/schema_0.json", "data": "minLength/data_04.json", "valid": "false", "errors": "string_gte"}, {"phase": "maxLength validation", "test": "shorter is valid", "schema": "maxLength/schema_0.json", "data": "maxLength/data_00.json", "valid": "true"}, {"phase": "maxLength validation", "test": "exact length is valid", "schema": "maxLength/schema_0.json", "data": "maxLength/data_01.json", "valid": "true"}, {"phase": "maxLength validation", "test": "too long is invalid", "schema": "maxLength/schema_0.json", "data": "maxLength/data_02.json", "valid": "false", "errors": "string_lte"}, {"phase": "maxLength validation", "test": "ignores non-strings", "schema": "maxLength/schema_0.json", "data": "maxLength/data_03.json", "valid": "true"}, {"phase": "maxLength validation", "test": "counts utf8 length correctly", "schema": "maxLength/schema_0.json", "data": "maxLength/data_04.json", "valid": "true"}, {"phase": "minimum validation", "test": "above the minimum is valid", "schema": "minimum/schema_0.json", "data": "minimum/data_00.json", "valid": "true"}, {"phase": "minimum validation", "test": "below the minimum is invalid", "schema": "minimum/schema_0.json", "data": "minimum/data_01.json", "valid": "false", "errors": "number_gte"}, {"phase": "minimum validation", "test": "ignores non-numbers", "schema": "minimum/schema_0.json", "data": "minimum/data_02.json", "valid": "true"}, {"phase": "exclusiveMinimum validation", "test": "above the minimum is still valid", "schema": "minimum/schema_1.json", "data": "minimum/data_10.json", "valid": "true"}, {"phase": "exclusiveMinimum validation", "test": "boundary point is invalid", "schema": "minimum/schema_1.json", "data": "minimum/data_11.json", "valid": "false", "errors": "number_gt"}, {"phase": "maximum validation", "test": "below the maximum is valid", "schema": "maximum/schema_0.json", "data": "maximum/data_00.json", "valid": "true"}, {"phase": "maximum validation", "test": "above the maximum is invalid", "schema": "maximum/schema_0.json", "data": "maximum/data_01.json", "valid": "false", "errors": "number_lte"}, {"phase": "maximum validation", "test": "ignores non-numbers", "schema": "maximum/schema_0.json", "data": "maximum/data_02.json", "valid": "true"}, {"phase": "exclusiveMaximum validation", "test": "below the maximum is still valid", "schema": "maximum/schema_1.json", "data": "maximum/data_10.json", "valid": "true"}, {"phase": "exclusiveMaximum validation", "test": "boundary point is invalid", "schema": "maximum/schema_1.json", "data": "maximum/data_11.json", "valid": "false", "errors": "number_lt"}, {"phase": "allOf", "test": "allOf", "schema": "allOf/schema_0.json", "data": "allOf/data_00.json", "valid": "true"}, {"phase": "allOf", "test": "mismatch second", "schema": "allOf/schema_0.json", "data": "allOf/data_01.json", "valid": "false", "errors": "number_all_of, required"}, {"phase": "allOf", "test": "mismatch first", "schema": "allOf/schema_0.json", "data": "allOf/data_02.json", "valid": "false", "errors": "number_all_of, required"}, {"phase": "allOf", "test": "wrong type", "schema": "allOf/schema_0.json", "data": "allOf/data_03.json", "valid": "false", "errors": "number_all_of, invalid_type"}, {"phase": "allOf with base schema", "test": "valid", "schema": "allOf/schema_1.json", "data": "allOf/data_10.json", "valid": "true"}, {"phase": "allOf with base schema", "test": "mismatch base schema", "schema": "allOf/schema_1.json", "data": "allOf/data_11.json", "valid": "false", "errors": "required"}, {"phase": "allOf with base schema", "test": "mismatch first allOf", "schema": "allOf/schema_1.json", "data": "allOf/data_12.json", "valid": "false", "errors": "number_all_of, required"}, {"phase": "allOf with base schema", "test": "mismatch second allOf", "schema": "allOf/schema_1.json", "data": "allOf/data_13.json", "valid": "false", "errors": "number_all_of, required"}, {"phase": "allOf with base schema", "test": "mismatch both", "schema": "allOf/schema_1.json", "data": "allOf/data_14.json", "valid": "false", "errors": "number_all_of, required, required"}, {"phase": "allOf simple types", "test": "valid", "schema": "allOf/schema_2.json", "data": "allOf/data_20.json", "valid": "true"}, {"phase": "allOf simple types", "test": "mismatch one", "schema": "allOf/schema_2.json", "data": "allOf/data_21.json", "valid": "false", "errors": "number_all_of, number_lte"}, {"phase": "oneOf", "test": "first oneOf valid", "schema": "oneOf/schema_0.json", "data": "oneOf/data_00.json", "valid": "true"}, {"phase": "oneOf", "test": "second oneOf valid", "schema": "oneOf/schema_0.json", "data": "oneOf/data_01.json", "valid": "true"}, {"phase": "oneOf", "test": "both oneOf valid", "schema": "oneOf/schema_0.json", "data": "oneOf/data_02.json", "valid": "false", "errors": "number_one_of"}, {"phase": "oneOf", "test": "neither oneOf valid", "schema": "oneOf/schema_0.json", "data": "oneOf/data_03.json", "valid": "false"}, {"phase": "oneOf with base schema", "test": "mismatch base schema", "schema": "oneOf/schema_1.json", "data": "oneOf/data_10.json", "valid": "false", "errors": "invalid_type"}, {"phase": "oneOf with base schema", "test": "one oneOf valid", "schema": "oneOf/schema_1.json", "data": "oneOf/data_11.json", "valid": "true"}, {"phase": "oneOf with base schema", "test": "both oneOf valid", "schema": "oneOf/schema_1.json", "data": "oneOf/data_12.json", "valid": "false", "errors": "number_one_of"}, {"phase": "anyOf", "test": "first anyOf valid", "schema": "anyOf/schema_0.json", "data": "anyOf/data_00.json", "valid": "true"}, {"phase": "anyOf", "test": "second anyOf valid", "schema": "anyOf/schema_0.json", "data": "anyOf/data_01.json", "valid": "true"}, {"phase": "anyOf", "test": "both anyOf valid", "schema": "anyOf/schema_0.json", "data": "anyOf/data_02.json", "valid": "true"}, {"phase": "anyOf", "test": "neither anyOf valid", "schema": "anyOf/schema_0.json", "data": "anyOf/data_03.json", "valid": "false", "errors": "number_any_of, number_gte"}, {"phase": "anyOf with base schema", "test": "mismatch base schema", "schema": "anyOf/schema_1.json", "data": "anyOf/data_10.json", "valid": "false", "errors": "invalid_type"}, {"phase": "anyOf with base schema", "test": "one anyOf valid", "schema": "anyOf/schema_1.json", "data": "anyOf/data_11.json", "valid": "true"}, {"phase": "anyOf with base schema", "test": "both anyOf invalid", "schema": "anyOf/schema_1.json", "data": "anyOf/data_12.json", "valid": "false", "errors": "number_any_of, string_lte"}, {"phase": "not", "test": "allowed", "schema": "not/schema_0.json", "data": "not/data_00.json", "valid": "true"}, {"phase": "not", "test": "disallowed", "schema": "not/schema_0.json", "data": "not/data_01.json", "valid": "false", "errors": "number_not"}, {"phase": "not multiple types", "test": "valid", "schema": "not/schema_1.json", "data": "not/data_10.json", "valid": "true"}, {"phase": "not multiple types", "test": "mismatch", "schema": "not/schema_1.json", "data": "not/data_11.json", "valid": "false", "errors": "number_not"}, {"phase": "not multiple types", "test": "other mismatch", "schema": "not/schema_1.json", "data": "not/data_12.json", "valid": "false", "errors": "number_not"}, {"phase": "not more complex schema", "test": "match", "schema": "not/schema_2.json", "data": "not/data_20.json", "valid": "true"}, {"phase": "not more complex schema", "test": "other match", "schema": "not/schema_2.json", "data": "not/data_21.json", "valid": "true"}, {"phase": "not more complex schema", "test": "mismatch", "schema": "not/schema_2.json", "data": "not/data_22.json", "valid": "false", "errors": "number_not"}, {"phase": "minProperties validation", "test": "longer is valid", "schema": "minProperties/schema_0.json", "data": "minProperties/data_00.json", "valid": "true"}, {"phase": "minProperties validation", "test": "exact length is valid", "schema": "minProperties/schema_0.json", "data": "minProperties/data_01.json", "valid": "true"}, {"phase": "minProperties validation", "test": "too short is invalid", "schema": "minProperties/schema_0.json", "data": "minProperties/data_02.json", "valid": "false", "errors": "array_min_properties"}, {"phase": "minProperties validation", "test": "ignores non-objects", "schema": "minProperties/schema_0.json", "data": "minProperties/data_03.json", "valid": "true"}, {"phase": "maxProperties validation", "test": "shorter is valid", "schema": "maxProperties/schema_0.json", "data": "maxProperties/data_00.json", "valid": "true"}, {"phase": "maxProperties validation", "test": "exact length is valid", "schema": "maxProperties/schema_0.json", "data": "maxProperties/data_01.json", "valid": "true"}, {"phase": "maxProperties validation", "test": "too long is invalid", "schema": "maxProperties/schema_0.json", "data": "maxProperties/data_02.json", "valid": "false", "errors": "array_max_properties"}, {"phase": "maxProperties validation", "test": "ignores non-objects", "schema": "maxProperties/schema_0.json", "data": "maxProperties/data_03.json", "valid": "true"}, {"phase": "by int", "test": "int by int", "schema": "multipleOf/schema_0.json", "data": "multipleOf/data_00.json", "valid": "true"}, {"phase": "by int", "test": "int by int fail", "schema": "multipleOf/schema_0.json", "data": "multipleOf/data_01.json", "valid": "false", "errors": "multiple_of"}, {"phase": "by int", "test": "ignores non-numbers", "schema": "multipleOf/schema_0.json", "data": "multipleOf/data_02.json", "valid": "true"}, {"phase": "by number", "test": "zero is multiple of anything", "schema": "multipleOf/schema_1.json", "data": "multipleOf/data_10.json", "valid": "true"}, {"phase": "by number", "test": "4.5 is multiple of 1.5", "schema": "multipleOf/schema_1.json", "data": "multipleOf/data_11.json", "valid": "true"}, {"phase": "by number", "test": "35 is not multiple of 1.5", "schema": "multipleOf/schema_1.json", "data": "multipleOf/data_12.json", "valid": "false", "errors": "multiple_of"}, {"phase": "by small number", "test": "0.0075 is multiple of 0.0001", "schema": "multipleOf/schema_2.json", "data": "multipleOf/data_20.json", "valid": "true"}, {"phase": "by small number", "test": "0.00751 is not multiple of 0.0001", "schema": "multipleOf/schema_2.json", "data": "multipleOf/data_21.json", "valid": "false", "errors": "multiple_of"}, {"phase": "minItems validation", "test": "longer is valid", "schema": "minItems/schema_0.json", "data": "minItems/data_00.json", "valid": "true"}, {"phase": "minItems validation", "test": "exact length is valid", "schema": "minItems/schema_0.json", "data": "minItems/data_01.json", "valid": "true"}, {"phase": "minItems validation", "test": "too short is invalid", "schema": "minItems/schema_0.json", "data": "minItems/data_02.json", "valid": "false", "errors": "array_min_items"}, {"phase": "minItems validation", "test": "ignores non-arrays", "schema": "minItems/schema_0.json", "data": "minItems/data_03.json", "valid": "true"}, {"phase": "maxItems validation", "test": "shorter is valid", "schema": "maxItems/schema_0.json", "data": "maxItems/data_00.json", "valid": "true"}, {"phase": "maxItems validation", "test": "exact length is valid", "schema": "maxItems/schema_0.json", "data": "maxItems/data_01.json", "valid": "true"}, {"phase": "maxItems validation", "test": "too long is invalid", "schema": "maxItems/schema_0.json", "data": "maxItems/data_02.json", "valid": "false", "errors": "array_max_items"}, {"phase": "maxItems validation", "test": "ignores non-arrays", "schema": "maxItems/schema_0.json", "data": "maxItems/data_03.json", "valid": "true"}, {"phase": "object properties validation", "test": "both properties present and valid is valid", "schema": "properties/schema_0.json", "data": "properties/data_00.json", "valid": "true"}, {"phase": "object properties validation", "test": "one property invalid is invalid", "schema": "properties/schema_0.json", "data": "properties/data_01.json", "valid": "false", "errors": "invalid_type"}, {"phase": "object properties validation", "test": "both properties invalid is invalid", "schema": "properties/schema_0.json", "data": "properties/data_02.json", "valid": "false", "errors": "invalid_type, invalid_type"}, {"phase": "object properties validation", "test": "doesn't invalidate other properties", "schema": "properties/schema_0.json", "data": "properties/data_03.json", "valid": "true"}, {"phase": "object properties validation", "test": "ignores non-objects", "schema": "properties/schema_0.json", "data": "properties/data_04.json", "valid": "true"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "property validates property", "schema": "properties/schema_1.json", "data": "properties/data_10.json", "valid": "true"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "property invalidates property", "schema": "properties/schema_1.json", "data": "properties/data_11.json", "valid": "false", "errors": "array_max_items"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "patternProperty invalidates property", "schema": "properties/schema_1.json", "data": "properties/data_12.json", "valid": "false", "errors": "array_min_items, invalid_type"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "patternProperty validates nonproperty", "schema": "properties/schema_1.json", "data": "properties/data_13.json", "valid": "true"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "patternProperty invalidates nonproperty", "schema": "properties/schema_1.json", "data": "properties/data_14.json", "valid": "false", "errors": "array_min_items, invalid_type"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "additionalProperty ignores property", "schema": "properties/schema_1.json", "data": "properties/data_15.json", "valid": "true"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "additionalProperty validates others", "schema": "properties/schema_1.json", "data": "properties/data_16.json", "valid": "true"}, {"phase": "properties, patternProperties, additionalProperties interaction", "test": "additionalProperty invalidates others", "schema": "properties/schema_1.json", "data": "properties/data_17.json", "valid": "false", "errors": "invalid_type"}, {"phase": "root pointer ref", "test": "match", "schema": "ref/schema_0.json", "data": "ref/data_00.json", "valid": "true"}, {"phase": "root pointer ref", "test": "recursive match", "schema": "ref/schema_0.json", "data": "ref/data_01.json", "valid": "true"}, {"phase": "root pointer ref", "test": "mismatch", "schema": "ref/schema_0.json", "data": "ref/data_02.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "root pointer ref", "test": "recursive mismatch", "schema": "ref/schema_0.json", "data": "ref/data_03.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "relative pointer ref to object", "test": "match", "schema": "ref/schema_1.json", "data": "ref/data_10.json", "valid": "true"}, {"phase": "relative pointer ref to object", "test": "mismatch", "schema": "ref/schema_1.json", "data": "ref/data_11.json", "valid": "false", "errors": "invalid_type"}, {"phase": "relative pointer ref to array", "test": "match array", "schema": "ref/schema_2.json", "data": "ref/data_20.json", "valid": "true"}, {"phase": "relative pointer ref to array", "test": "mismatch array", "schema": "ref/schema_2.json", "data": "ref/data_21.json", "valid": "false", "errors": "invalid_type"}, {"phase": "escaped pointer ref", "test": "slash", "schema": "ref/schema_3.json", "data": "ref/data_30.json", "valid": "false", "errors": "invalid_type"}, {"phase": "escaped pointer ref", "test": "tilda", "schema": "ref/schema_3.json", "data": "ref/data_31.json", "valid": "false", "errors": "invalid_type"}, {"phase": "escaped pointer ref", "test": "percent", "schema": "ref/schema_3.json", "data": "ref/data_32.json", "valid": "false", "errors": "invalid_type"}, {"phase": "nested refs", "test": "nested ref valid", "schema": "ref/schema_4.json", "data": "ref/data_40.json", "valid": "true"}, {"phase": "nested refs", "test": "nested ref invalid", "schema": "ref/schema_4.json", "data": "ref/data_41.json", "valid": "false", "errors": "invalid_type"}, {"phase": "remote ref, containing refs itself", "test": "remote ref valid", "schema": "ref/schema_5.json", "data": "ref/data_50.json", "valid": "true"}, {"phase": "remote ref, containing refs itself", "test": "remote ref invalid", "schema": "ref/schema_5.json", "data": "ref/data_51.json", "valid": "false", "errors": "number_all_of, number_gte"}, {"phase": "a schema given for items", "test": "valid items", "schema": "items/schema_0.json", "data": "items/data_00.json", "valid": "true"}, {"phase": "a schema given for items", "test": "wrong type of items", "schema": "items/schema_0.json", "data": "items/data_01.json", "valid": "false", "errors": "invalid_type"}, {"phase": "a schema given for items", "test": "ignores non-arrays", "schema": "items/schema_0.json", "data": "items/data_02.json", "valid": "true"}, {"phase": "an array of schemas for items", "test": "correct types", "schema": "items/schema_1.json", "data": "items/data_10.json", "valid": "true"}, {"phase": "an array of schemas for items", "test": "wrong types", "schema": "items/schema_1.json", "data": "items/data_11.json", "valid": "false", "errors": "invalid_type, invalid_type"}, {"phase": "valid definition", "test": "valid definition schema", "schema": "definitions/schema_0.json", "data": "definitions/data_00.json", "valid": "true"}, {"phase": "invalid definition", "test": "invalid definition schema", "schema": "definitions/schema_1.json", "data": "definitions/data_10.json", "valid": "false", "errors": "number_any_of, enum"}, {"phase": "additionalItems as schema", "test": "additional items match schema", "schema": "additionalItems/schema_0.json", "data": "additionalItems/data_00.json", "valid": "true"}, {"phase": "additionalItems as schema", "test": "additional items do not match schema", "schema": "additionalItems/schema_0.json", "data": "additionalItems/data_01.json", "valid": "false", "errors": "invalid_type"}, {"phase": "items is schema, no additionalItems", "test": "all items match schema", "schema": "additionalItems/schema_1.json", "data": "additionalItems/data_10.json", "valid": "true"}, {"phase": "array of items with no additionalItems", "test": "no additional items present", "schema": "additionalItems/schema_2.json", "data": "additionalItems/data_20.json", "valid": "true"}, {"phase": "array of items with no additionalItems", "test": "additional items are not permitted", "schema": "additionalItems/schema_2.json", "data": "additionalItems/data_21.json", "valid": "false", "errors": "array_no_additional_items"}, {"phase": "additionalItems as false without items", "test": "items defaults to empty schema so everything is valid", "schema": "additionalItems/schema_3.json", "data": "additionalItems/data_30.json", "valid": "true"}, {"phase": "additionalItems as false without items", "test": "ignores non-arrays", "schema": "additionalItems/schema_3.json", "data": "additionalItems/data_31.json", "valid": "true"}, {"phase": "additionalItems are allowed by default", "test": "only the first item is validated", "schema": "additionalItems/schema_4.json", "data": "additionalItems/data_40.json", "valid": "true"}, {"phase": "additionalProperties being false does not allow other properties", "test": "no additional properties is valid", "schema": "additionalProperties/schema_0.json", "data": "additionalProperties/data_00.json", "valid": "true"}, {"phase": "additionalProperties being false does not allow other properties", "test": "an additional property is invalid", "schema": "additionalProperties/schema_0.json", "data": "additionalProperties/data_01.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "additionalProperties being false does not allow other properties", "test": "ignores non-objects", "schema": "additionalProperties/schema_0.json", "data": "additionalProperties/data_02.json", "valid": "true"}, {"phase": "additionalProperties being false does not allow other properties", "test": "patternProperties are not additional properties", "schema": "additionalProperties/schema_0.json", "data": "additionalProperties/data_03.json", "valid": "true"}, {"phase": "additionalProperties allows a schema which should validate", "test": "no additional properties is valid", "schema": "additionalProperties/schema_1.json", "data": "additionalProperties/data_10.json", "valid": "true"}, {"phase": "additionalProperties allows a schema which should validate", "test": "an additional valid property is valid", "schema": "additionalProperties/schema_1.json", "data": "additionalProperties/data_11.json", "valid": "true"}, {"phase": "additionalProperties allows a schema which should validate", "test": "an additional invalid property is invalid", "schema": "additionalProperties/schema_1.json", "data": "additionalProperties/data_12.json", "valid": "false", "errors": "invalid_type"}, {"phase": "additionalProperties are allowed by default", "test": "additional properties are allowed", "schema": "additionalProperties/schema_2.json", "data": "additionalProperties/data_20.json", "valid": "true"}, {"phase": "dependencies", "test": "neither", "schema": "dependencies/schema_0.json", "data": "dependencies/data_00.json", "valid": "true"}, {"phase": "dependencies", "test": "nondependant", "schema": "dependencies/schema_0.json", "data": "dependencies/data_01.json", "valid": "true"}, {"phase": "dependencies", "test": "with dependency", "schema": "dependencies/schema_0.json", "data": "dependencies/data_02.json", "valid": "true"}, {"phase": "dependencies", "test": "missing dependency", "schema": "dependencies/schema_0.json", "data": "dependencies/data_03.json", "valid": "false", "errors": "missing_dependency"}, {"phase": "dependencies", "test": "ignores non-objects", "schema": "dependencies/schema_0.json", "data": "dependencies/data_04.json", "valid": "true"}, {"phase": "multiple dependencies", "test": "neither", "schema": "dependencies/schema_1.json", "data": "dependencies/data_10.json", "valid": "true"}, {"phase": "multiple dependencies", "test": "nondependants", "schema": "dependencies/schema_1.json", "data": "dependencies/data_11.json", "valid": "true"}, {"phase": "multiple dependencies", "test": "with dependencies", "schema": "dependencies/schema_1.json", "data": "dependencies/data_12.json", "valid": "true"}, {"phase": "multiple dependencies", "test": "missing dependency", "schema": "dependencies/schema_1.json", "data": "dependencies/data_13.json", "valid": "false", "errors": "missing_dependency"}, {"phase": "multiple dependencies", "test": "missing other dependency", "schema": "dependencies/schema_1.json", "data": "dependencies/data_14.json", "valid": "false", "errors": "missing_dependency"}, {"phase": "multiple dependencies", "test": "missing both dependencies", "schema": "dependencies/schema_1.json", "data": "dependencies/data_15.json", "valid": "false", "errors": "missing_dependency, missing_dependency"}, {"phase": "multiple dependencies subschema", "test": "valid", "schema": "dependencies/schema_2.json", "data": "dependencies/data_20.json", "valid": "true"}, {"phase": "multiple dependencies subschema", "test": "no dependency", "schema": "dependencies/schema_2.json", "data": "dependencies/data_21.json", "valid": "true"}, {"phase": "multiple dependencies subschema", "test": "wrong type", "schema": "dependencies/schema_2.json", "data": "dependencies/data_22.json", "valid": "false"}, {"phase": "multiple dependencies subschema", "test": "wrong type other", "schema": "dependencies/schema_2.json", "data": "dependencies/data_23.json", "valid": "false", "errors": "invalid_type"}, {"phase": "multiple dependencies subschema", "test": "wrong type both", "schema": "dependencies/schema_2.json", "data": "dependencies/data_24.json", "valid": "false", "errors": "invalid_type, invalid_type"}, {"phase": "patternProperties validates properties matching a regex", "test": "a single valid match is valid", "schema": "patternProperties/schema_0.json", "data": "patternProperties/data_00.json", "valid": "true"}, {"phase": "patternProperties validates properties matching a regex", "test": "multiple valid matches is valid", "schema": "patternProperties/schema_0.json", "data": "patternProperties/data_01.json", "valid": "true"}, {"phase": "patternProperties validates properties matching a regex", "test": "a single invalid match is invalid", "schema": "patternProperties/schema_0.json", "data": "patternProperties/data_02.json", "valid": "false", "errors": "invalid_property_pattern, invalid_type"}, {"phase": "patternProperties validates properties matching a regex", "test": "multiple invalid matches is invalid", "schema": "patternProperties/schema_0.json", "data": "patternProperties/data_03.json", "valid": "false", "errors": "invalid_property_pattern, invalid_property_pattern, invalid_type, invalid_type"}, {"phase": "patternProperties validates properties matching a regex", "test": "ignores non-objects", "schema": "patternProperties/schema_0.json", "data": "patternProperties/data_04.json", "valid": "true"}, {"phase": "patternProperties validates properties matching a regex", "test": "with additionalProperties combination", "schema": "patternProperties/schema_3.json", "data": "patternProperties/data_24.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "patternProperties validates properties matching a regex", "test": "with additionalProperties combination", "schema": "patternProperties/schema_3.json", "data": "patternProperties/data_25.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "patternProperties validates properties matching a regex", "test": "with additionalProperties combination", "schema": "patternProperties/schema_4.json", "data": "patternProperties/data_26.json", "valid": "false", "errors": "additional_property_not_allowed"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "a single valid match is valid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_10.json", "valid": "true"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "a simultaneous match is valid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_11.json", "valid": "true"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "multiple matches is valid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_12.json", "valid": "true"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "an invalid due to one is invalid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_13.json", "valid": "false", "errors": "invalid_property_pattern, invalid_type"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "an invalid due to the other is invalid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_14.json", "valid": "false", "errors": "number_lte"}, {"phase": "multiple simultaneous patternProperties are validated", "test": "an invalid due to both is invalid", "schema": "patternProperties/schema_1.json", "data": "patternProperties/data_15.json", "valid": "false", "errors": "invalid_type, number_lte"}, {"phase": "regexes are not anchored by default and are case sensitive", "test": "non recognized members are ignored", "schema": "patternProperties/schema_2.json", "data": "patternProperties/data_20.json", "valid": "true"}, {"phase": "regexes are not anchored by default and are case sensitive", "test": "recognized members are accounted for", "schema": "patternProperties/schema_2.json", "data": "patternProperties/data_21.json", "valid": "false", "errors": "invalid_property_pattern, invalid_type"}, {"phase": "regexes are not anchored by default and are case sensitive", "test": "regexes are case sensitive", "schema": "patternProperties/schema_2.json", "data": "patternProperties/data_22.json", "valid": "true"}, {"phase": "regexes are not anchored by default and are case sensitive", "test": "regexes are case sensitive, 2", "schema": "patternProperties/schema_2.json", "data": "patternProperties/data_23.json", "valid": "false", "errors": "invalid_property_pattern, invalid_type"}, {"phase": "remote ref", "test": "remote ref valid", "schema": "refRemote/schema_0.json", "data": "refRemote/data_00.json", "valid": "true"}, {"phase": "remote ref", "test": "remote ref invalid", "schema": "refRemote/schema_0.json", "data": "refRemote/data_01.json", "valid": "false", "errors": "invalid_type"}, {"phase": "fragment within remote ref", "test": "remote fragment valid", "schema": "refRemote/schema_1.json", "data": "refRemote/data_10.json", "valid": "true"}, {"phase": "fragment within remote ref", "test": "remote fragment invalid", "schema": "refRemote/schema_1.json", "data": "refRemote/data_11.json", "valid": "false", "errors": "invalid_type"}, {"phase": "ref within remote ref", "test": "ref within ref valid", "schema": "refRemote/schema_2.json", "data": "refRemote/data_20.json", "valid": "true"}, {"phase": "ref within remote ref", "test": "ref within ref invalid", "schema": "refRemote/schema_2.json", "data": "refRemote/data_21.json", "valid": "false", "errors": "invalid_type"}, {"phase": "format validation", "test": "email format is invalid", "schema": "format/schema_0.json", "data": "format/data_00.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "email format is invalid", "schema": "format/schema_0.json", "data": "format/data_01.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "email format valid", "schema": "format/schema_0.json", "data": "format/data_02.json", "valid": "true"}, {"phase": "format validation", "test": "invoice format valid", "schema": "format/schema_1.json", "data": "format/data_03.json", "valid": "true"}, {"phase": "format validation", "test": "invoice format is invalid", "schema": "format/schema_1.json", "data": "format/data_04.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_05.json", "valid": "true"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_06.json", "valid": "true"}, {"phase": "format validation", "test": "date-time format is invalid", "schema": "format/schema_2.json", "data": "format/data_07.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_08.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_09.json", "valid": "true"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_10.json", "valid": "true"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_11.json", "valid": "true"}, {"phase": "format validation", "test": "date-time format is valid", "schema": "format/schema_2.json", "data": "format/data_12.json", "valid": "true"}, {"phase": "format validation", "test": "hostname format is valid", "schema": "format/schema_3.json", "data": "format/data_13.json", "valid": "true"}, {"phase": "format validation", "test": "hostname format is valid", "schema": "format/schema_3.json", "data": "format/data_14.json", "valid": "true"}, {"phase": "format validation", "test": "hostname format is valid", "schema": "format/schema_3.json", "data": "format/data_15.json", "valid": "true"}, {"phase": "format validation", "test": "hostname format is invalid", "schema": "format/schema_3.json", "data": "format/data_16.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "hostname format is invalid", "schema": "format/schema_3.json", "data": "format/data_17.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "ipv4 format is valid", "schema": "format/schema_4.json", "data": "format/data_18.json", "valid": "true"}, {"phase": "format validation", "test": "ipv4 format is invalid", "schema": "format/schema_4.json", "data": "format/data_19.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "ipv6 format is valid", "schema": "format/schema_5.json", "data": "format/data_20.json", "valid": "true"}, {"phase": "format validation", "test": "ipv6 format is valid", "schema": "format/schema_5.json", "data": "format/data_21.json", "valid": "true"}, {"phase": "format validation", "test": "ipv6 format is invalid", "schema": "format/schema_5.json", "data": "format/data_22.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "ipv6 format is invalid", "schema": "format/schema_5.json", "data": "format/data_23.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "uri format is valid", "schema": "format/schema_6.json", "data": "format/data_24.json", "valid": "true"}, {"phase": "format validation", "test": "uri format is valid", "schema": "format/schema_6.json", "data": "format/data_25.json", "valid": "true"}, {"phase": "format validation", "test": "uri format is valid", "schema": "format/schema_6.json", "data": "format/data_26.json", "valid": "true"}, {"phase": "format validation", "test": "uri format is valid", "schema": "format/schema_6.json", "data": "format/data_27.json", "valid": "true"}, {"phase": "format validation", "test": "uri format is invalid", "schema": "format/schema_6.json", "data": "format/data_28.json", "valid": "false", "errors": "format"}, {"phase": "format validation", "test": "uri format is invalid", "schema": "format/schema_6.json", "data": "format/data_13.json", "valid": "false", "errors": "format"}, } //TODO Pass failed tests : id(s) as scope for references is not implemented yet //map[string]string{"phase": "change resolution scope", "test": "changed scope ref valid", "schema": "refRemote/schema_3.json", "data": "refRemote/data_30.json", "valid": "true"}, //map[string]string{"phase": "change resolution scope", "test": "changed scope ref invalid", "schema": "refRemote/schema_3.json", "data": "refRemote/data_31.json", "valid": "false"}} // Setup a small http server on localhost:1234 for testing purposes wd, err := os.Getwd() if err != nil { panic(err.Error()) } testwd := wd + "/json_schema_test_suite" go func() { err := http.ListenAndServe(":1234", http.FileServer(http.Dir(testwd+"/refRemote/remoteFiles"))) if err != nil { panic(err.Error()) } }() // Used for remote schema in ref/schema_5.json that defines "regex" type FormatCheckers.Add("regex", alwaysTrueFormatChecker{}) // Custom Formatter FormatCheckers.Add("invoice", invoiceFormatChecker{}) // Launch tests for testJsonIndex, testJson := range JsonSchemaTestSuiteMap { fmt.Printf("Test (%d) | %s :: %s\n", testJsonIndex, testJson["phase"], testJson["test"]) schemaLoader := NewReferenceLoader("file://" + testwd + "/" + testJson["schema"]) documentLoader := NewReferenceLoader("file://" + testwd + "/" + testJson["data"]) // validate result, err := Validate(schemaLoader, documentLoader) if err != nil { t.Errorf("Error (%s)\n", err.Error()) } givenValid := result.Valid() if displayErrorMessages { for vErrI, vErr := range result.Errors() { fmt.Printf(" Error (%d) | %s\n", vErrI, vErr) } } expectedValid, _ := strconv.ParseBool(testJson["valid"]) if givenValid != expectedValid { t.Errorf("Test failed : %s :: %s, expects %t, given %t\n", testJson["phase"], testJson["test"], expectedValid, givenValid) } if !givenValid && testJson["errors"] != "" { expectedErrors := rxSplitErrors.Split(testJson["errors"], -1) errors := result.Errors() if len(errors) != len(expectedErrors) { t.Errorf("Test failed : %s :: %s, expects %d errors, given %d errors\n", testJson["phase"], testJson["test"], len(expectedErrors), len(errors)) } actualErrors := make([]string, 0) for _, e := range result.Errors() { actualErrors = append(actualErrors, e.Type()) } sort.Strings(actualErrors) sort.Strings(expectedErrors) if !reflect.DeepEqual(actualErrors, expectedErrors) { t.Errorf("Test failed : %s :: %s, expected '%s' errors, given '%s' errors\n", testJson["phase"], testJson["test"], strings.Join(expectedErrors, ", "), strings.Join(actualErrors, ", ")) } } } fmt.Printf("\n%d tests performed / %d total tests to perform ( %.2f %% )\n", len(JsonSchemaTestSuiteMap), 248, float32(len(JsonSchemaTestSuiteMap))/248.0*100.0) } 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) } } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/subSchema.go000066400000000000000000000133121304744716600233060ustar00rootroot00000000000000// 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 ( "errors" "regexp" "strings" "github.com/xeipuuv/gojsonreference" ) const ( KEY_SCHEMA = "$subSchema" KEY_ID = "$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_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_ENUM = "enum" KEY_ONE_OF = "oneOf" KEY_ANY_OF = "anyOf" KEY_ALL_OF = "allOf" KEY_NOT = "not" ) type subSchema struct { // basic subSchema meta properties id *string title *string description *string property string // Types associated with the subSchema types jsonSchemaType // Reference url ref *gojsonreference.JsonReference // Schema referenced refSchema *subSchema // Json reference subSchema *gojsonreference.JsonReference // hierarchy parent *subSchema definitions map[string]*subSchema definitionsChildren []*subSchema itemsChildren []*subSchema itemsChildrenIsSingleSchema bool propertiesChildren []*subSchema // validation : number / integer multipleOf *float64 maximum *float64 exclusiveMaximum bool minimum *float64 exclusiveMinimum bool // 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 // validation : array minItems *int maxItems *int uniqueItems bool additionalItems interface{} // validation : all enum []string // validation : subSchema oneOf []*subSchema anyOf []*subSchema allOf []*subSchema not *subSchema } func (s *subSchema) AddEnum(i interface{}) error { is, err := marshalToJsonString(i) if err != nil { return err } if isStringInSlice(s.enum, *is) { return errors.New(formatErrorDescription( Locale.KeyItemsMustBeUnique(), ErrorDetails{"key": KEY_ENUM}, )) } s.enum = append(s.enum, *is) return nil } func (s *subSchema) ContainsEnum(i interface{}) (bool, error) { is, err := marshalToJsonString(i) if err != nil { return false, err } return isStringInSlice(s.enum, *is), nil } func (s *subSchema) AddOneOf(subSchema *subSchema) { s.oneOf = append(s.oneOf, subSchema) } func (s *subSchema) AddAllOf(subSchema *subSchema) { s.allOf = append(s.allOf, subSchema) } func (s *subSchema) AddAnyOf(subSchema *subSchema) { s.anyOf = append(s.anyOf, subSchema) } func (s *subSchema) SetNot(subSchema *subSchema) { s.not = subSchema } func (s *subSchema) AddRequired(value string) error { if isStringInSlice(s.required, value) { return errors.New(formatErrorDescription( Locale.KeyItemsMustBeUnique(), ErrorDetails{"key": KEY_REQUIRED}, )) } s.required = append(s.required, value) return nil } func (s *subSchema) AddDefinitionChild(child *subSchema) { s.definitionsChildren = append(s.definitionsChildren, child) } func (s *subSchema) AddItemsChild(child *subSchema) { s.itemsChildren = append(s.itemsChildren, child) } func (s *subSchema) AddPropertiesChild(child *subSchema) { s.propertiesChildren = append(s.propertiesChildren, child) } func (s *subSchema) PatternPropertiesString() string { if s.patternProperties == nil || len(s.patternProperties) == 0 { return STRING_UNDEFINED // should never happen } patternPropertiesKeySlice := []string{} for pk := range s.patternProperties { patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`) } if len(patternPropertiesKeySlice) == 1 { return patternPropertiesKeySlice[0] } return "[" + strings.Join(patternPropertiesKeySlice, ",") + "]" } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/types.go000066400000000000000000000027051304744716600225440ustar00rootroot00000000000000// 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 const ( TYPE_ARRAY = `array` TYPE_BOOLEAN = `boolean` TYPE_INTEGER = `integer` TYPE_NUMBER = `number` TYPE_NULL = `null` TYPE_OBJECT = `object` TYPE_STRING = `string` ) var JSON_TYPES []string 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-6b67b3fab74d992bd07f72550006ab2c6907c416/utils.go000066400000000000000000000101341304744716600225330ustar00rootroot00000000000000// 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" "fmt" "math" "reflect" "strconv" ) func isKind(what interface{}, kind reflect.Kind) bool { target := what if isJsonNumber(what) { // JSON Numbers are strings! target = *mustBeNumber(what) } return reflect.ValueOf(target).Kind() == kind } 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 } func marshalToJsonString(value interface{}) (*string, error) { mBytes, err := json.Marshal(value) if err != nil { return nil, err } sBytes := string(mBytes) return &sBytes, nil } func isJsonNumber(what interface{}) bool { switch what.(type) { case json.Number: return true } return false } func checkJsonNumber(what interface{}) (isValidFloat64 bool, isValidInt64 bool, isValidInt32 bool) { jsonNumber := what.(json.Number) f64, errFloat64 := jsonNumber.Float64() s64 := strconv.FormatFloat(f64, 'f', -1, 64) _, errInt64 := strconv.ParseInt(s64, 10, 64) isValidFloat64 = errFloat64 == nil isValidInt64 = errInt64 == nil _, errInt32 := strconv.ParseInt(s64, 10, 32) isValidInt32 = isValidInt64 && errInt32 == nil return } // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER const ( max_json_float = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 min_json_float = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 ) func isFloat64AnInteger(f float64) bool { if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float { return false } return f == float64(int64(f)) || f == float64(uint64(f)) } func mustBeInteger(what interface{}) *int { if isJsonNumber(what) { number := what.(json.Number) _, _, isValidInt32 := checkJsonNumber(number) if isValidInt32 { int64Value, err := number.Int64() if err != nil { return nil } int32Value := int(int64Value) return &int32Value } else { return nil } } return nil } func mustBeNumber(what interface{}) *float64 { if isJsonNumber(what) { number := what.(json.Number) float64Value, err := number.Float64() if err == nil { return &float64Value } else { return nil } } return nil } // formats a number so that it is displayed as the smallest string possible func resultErrorFormatJsonNumber(n json.Number) string { if int64Value, err := n.Int64(); err == nil { return fmt.Sprintf("%d", int64Value) } float64Value, _ := n.Float64() return fmt.Sprintf("%g", float64Value) } // formats a number so that it is displayed as the smallest string possible func resultErrorFormatNumber(n float64) string { if isFloat64AnInteger(n) { return fmt.Sprintf("%d", int64(n)) } return fmt.Sprintf("%g", n) } 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-6b67b3fab74d992bd07f72550006ab2c6907c416/utils_test.go000066400000000000000000000050641304744716600236000ustar00rootroot00000000000000// 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 ( "github.com/stretchr/testify/assert" "math" "testing" ) func TestResultErrorFormatNumber(t *testing.T) { assert.Equal(t, "1", resultErrorFormatNumber(1)) assert.Equal(t, "-1", resultErrorFormatNumber(-1)) assert.Equal(t, "0", resultErrorFormatNumber(0)) // unfortunately, can not be recognized as float assert.Equal(t, "0", resultErrorFormatNumber(0.0)) assert.Equal(t, "1.001", resultErrorFormatNumber(1.001)) assert.Equal(t, "-1.001", resultErrorFormatNumber(-1.001)) assert.Equal(t, "0.0001", resultErrorFormatNumber(0.0001)) // casting math.MaxInt64 (1<<63 -1) to float back to int64 // becomes negative. obviousely because of bit missinterpretation. // so simply test a slightly smaller "large" integer here assert.Equal(t, "4.611686018427388e+18", resultErrorFormatNumber(1<<62)) // with negative int64 max works assert.Equal(t, "-9.223372036854776e+18", resultErrorFormatNumber(math.MinInt64)) assert.Equal(t, "-4.611686018427388e+18", resultErrorFormatNumber(-1<<62)) assert.Equal(t, "10000000000", resultErrorFormatNumber(1e10)) assert.Equal(t, "-10000000000", resultErrorFormatNumber(-1e10)) assert.Equal(t, "1.000000000001", resultErrorFormatNumber(1.000000000001)) assert.Equal(t, "-1.000000000001", resultErrorFormatNumber(-1.000000000001)) assert.Equal(t, "1e-10", resultErrorFormatNumber(1e-10)) assert.Equal(t, "-1e-10", resultErrorFormatNumber(-1e-10)) assert.Equal(t, "4.6116860184273876e+07", resultErrorFormatNumber(4.611686018427387904e7)) assert.Equal(t, "-4.6116860184273876e+07", resultErrorFormatNumber(-4.611686018427387904e7)) } gojsonschema-6b67b3fab74d992bd07f72550006ab2c6907c416/validation.go000066400000000000000000000513011304744716600235260ustar00rootroot00000000000000// 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" "reflect" "regexp" "strconv" "strings" "unicode/utf8" ) func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) { var err error // load schema schema, err := NewSchema(ls) if err != nil { return nil, err } // begine validation return schema.Validate(ld) } func (v *Schema) Validate(l JSONLoader) (*Result, error) { // load document root, err := l.LoadJSON() if err != nil { return nil, err } // begin validation result := &Result{} context := newJsonContext(STRING_CONTEXT_ROOT, nil) v.rootSchema.validateRecursive(v.rootSchema, root, result, context) return result, nil } 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 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.addError( 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) _, isValidInt64, _ := checkJsonNumber(value) validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isValidInt64 && currentSubSchema.types.Contains(TYPE_INTEGER)) if currentSubSchema.types.IsTyped() && !validType { givenType := TYPE_INTEGER if !isValidInt64 { givenType = TYPE_NUMBER } result.addError( 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.addError( 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.addError( 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.addError( 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.addError( 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.addError(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.addError(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.addError(new(NumberAllOfError), context, currentNode, ErrorDetails{}) } } if currentSubSchema.not != nil { validationResult := currentSubSchema.not.subValidateWithContext(currentNode, context) if validationResult.Valid() { result.addError(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.addError( new(MissingDependencyError), context, currentNode, ErrorDetails{"dependency": dependOnKey}, ) } } case *subSchema: dependency.validateRecursive(dependency, currentNode, result, context) } } } } } result.incrementScore() } func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{}, result *Result, context *jsonContext) { if internalLogEnabled { internalLog("validateCommon %s", context.String()) internalLog(" %v", value) } // enum: if len(currentSubSchema.enum) > 0 { has, err := currentSubSchema.ContainsEnum(value) if err != nil { result.addError(new(InternalError), context, value, ErrorDetails{"error": err}) } if !has { result.addError( 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.addError(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.addError( new(ArrayMinItemsError), context, value, ErrorDetails{"min": *currentSubSchema.minItems}, ) } } if currentSubSchema.maxItems != nil { if nbValues > int(*currentSubSchema.maxItems) { result.addError( new(ArrayMaxItemsError), context, value, ErrorDetails{"max": *currentSubSchema.maxItems}, ) } } // uniqueItems: if currentSubSchema.uniqueItems { var stringifiedItems []string for _, v := range value { vString, err := marshalToJsonString(v) if err != nil { result.addError(new(InternalError), context, value, ErrorDetails{"err": err}) } if isStringInSlice(stringifiedItems, *vString) { result.addError( new(ItemsMustBeUniqueError), context, value, ErrorDetails{"type": TYPE_ARRAY}, ) } stringifiedItems = append(stringifiedItems, *vString) } } 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.addError( new(ArrayMinPropertiesError), context, value, ErrorDetails{"min": *currentSubSchema.minProperties}, ) } } if currentSubSchema.maxProperties != nil { if len(value) > int(*currentSubSchema.maxProperties) { result.addError( new(ArrayMaxPropertiesError), context, value, ErrorDetails{"max": *currentSubSchema.maxProperties}, ) } } // required: for _, requiredProperty := range currentSubSchema.required { _, ok := value[requiredProperty] if ok { result.incrementScore() } else { result.addError( new(RequiredError), context, value, ErrorDetails{"property": requiredProperty}, ) } } // additionalProperty & patternProperty: if currentSubSchema.additionalProperties != nil { switch currentSubSchema.additionalProperties.(type) { case bool: if !currentSubSchema.additionalProperties.(bool) { for pk := range value { found := false for _, spValue := range currentSubSchema.propertiesChildren { if pk == spValue.property { found = true } } pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) if found { if pp_has && !pp_match { result.addError( new(AdditionalPropertyNotAllowedError), context, value, ErrorDetails{"property": pk}, ) } } else { if !pp_has || !pp_match { result.addError( new(AdditionalPropertyNotAllowedError), context, value, ErrorDetails{"property": pk}, ) } } } } case *subSchema: additionalPropertiesSchema := currentSubSchema.additionalProperties.(*subSchema) for pk := range value { found := false for _, spValue := range currentSubSchema.propertiesChildren { if pk == spValue.property { found = true } } pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) if found { if pp_has && !pp_match { validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) result.mergeErrors(validationResult) } } else { if !pp_has || !pp_match { validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) result.mergeErrors(validationResult) } } } } } else { for pk := range value { pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) if pp_has && !pp_match { result.addError( new(InvalidPropertyPatternError), context, value, ErrorDetails{ "property": pk, "pattern": currentSubSchema.PatternPropertiesString(), }, ) } } } result.incrementScore() } func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *jsonContext) (has bool, matched bool) { if internalLogEnabled { internalLog("validatePatternProperty %s", context.String()) internalLog(" %s %v", key, value) } has = false validatedkey := false for pk, pv := range currentSubSchema.patternProperties { if matches, _ := regexp.MatchString(pk, key); matches { has = true subContext := newJsonContext(key, context) validationResult := pv.subValidateWithContext(value, subContext) result.mergeErrors(validationResult) if validationResult.Valid() { validatedkey = true } } } if !validatedkey { return has, false } result.incrementScore() return has, 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.addError( new(StringLengthGTEError), context, value, ErrorDetails{"min": *currentSubSchema.minLength}, ) } } if currentSubSchema.maxLength != nil { if utf8.RuneCount([]byte(stringValue)) > int(*currentSubSchema.maxLength) { result.addError( new(StringLengthLTEError), context, value, ErrorDetails{"max": *currentSubSchema.maxLength}, ) } } // pattern: if currentSubSchema.pattern != nil { if !currentSubSchema.pattern.MatchString(stringValue) { result.addError( new(DoesNotMatchPatternError), context, value, ErrorDetails{"pattern": currentSubSchema.pattern}, ) } } // format if currentSubSchema.format != "" { if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) { result.addError( 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, _ := number.Float64() // multipleOf: if currentSubSchema.multipleOf != nil { if !isFloat64AnInteger(float64Value / *currentSubSchema.multipleOf) { result.addError( new(MultipleOfError), context, resultErrorFormatJsonNumber(number), ErrorDetails{"multiple": *currentSubSchema.multipleOf}, ) } } //maximum & exclusiveMaximum: if currentSubSchema.maximum != nil { if currentSubSchema.exclusiveMaximum { if float64Value >= *currentSubSchema.maximum { result.addError( new(NumberLTError), context, resultErrorFormatJsonNumber(number), ErrorDetails{ "max": resultErrorFormatNumber(*currentSubSchema.maximum), }, ) } } else { if float64Value > *currentSubSchema.maximum { result.addError( new(NumberLTEError), context, resultErrorFormatJsonNumber(number), ErrorDetails{ "max": resultErrorFormatNumber(*currentSubSchema.maximum), }, ) } } } //minimum & exclusiveMinimum: if currentSubSchema.minimum != nil { if currentSubSchema.exclusiveMinimum { if float64Value <= *currentSubSchema.minimum { result.addError( new(NumberGTError), context, resultErrorFormatJsonNumber(number), ErrorDetails{ "min": resultErrorFormatNumber(*currentSubSchema.minimum), }, ) } } else { if float64Value < *currentSubSchema.minimum { result.addError( new(NumberGTEError), context, resultErrorFormatJsonNumber(number), ErrorDetails{ "min": resultErrorFormatNumber(*currentSubSchema.minimum), }, ) } } } result.incrementScore() }