├── .github └── workflows │ └── test.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── base64loader ├── base64loader.go └── base64loader_test.go ├── cmd └── jv │ └── main.go ├── compiler.go ├── doc.go ├── draft4.go ├── draft6.go ├── draft7.go ├── encoding.go ├── errors.go ├── extension.go ├── extension_test.go ├── fileloader └── fileloader.go ├── formats.go ├── formats_test.go ├── go.mod ├── go.sum ├── go.test.sh ├── httploader ├── httploader.go └── httploader_test.go ├── loaders.go ├── resource.go ├── schema.go ├── schema_test.go ├── testdata ├── customer.json ├── customer_schema.json ├── definitions.json ├── draft4.json ├── draft4 │ ├── additionalItems.json │ ├── additionalProperties.json │ ├── allOf.json │ ├── anyOf.json │ ├── default.json │ ├── definitions.json │ ├── dependencies.json │ ├── enum.json │ ├── items.json │ ├── maxItems.json │ ├── maxLength.json │ ├── maxProperties.json │ ├── maximum.json │ ├── minItems.json │ ├── minLength.json │ ├── minProperties.json │ ├── minimum.json │ ├── multipleOf.json │ ├── not.json │ ├── oneOf.json │ ├── optional │ │ ├── bignum.json │ │ ├── ecmascript-regex.json │ │ ├── format.json │ │ └── zeroTerminatedFloats.json │ ├── pattern.json │ ├── patternProperties.json │ ├── properties.json │ ├── ref.json │ ├── refRemote.json │ ├── required.json │ ├── santhosh.json │ ├── type.json │ └── uniqueItems.json ├── draft6.json ├── draft6 │ ├── additionalItems.json │ ├── additionalProperties.json │ ├── allOf.json │ ├── anyOf.json │ ├── boolean_schema.json │ ├── const.json │ ├── contains.json │ ├── default.json │ ├── definitions.json │ ├── dependencies.json │ ├── enum.json │ ├── exclusiveMaximum.json │ ├── exclusiveMinimum.json │ ├── items.json │ ├── maxItems.json │ ├── maxLength.json │ ├── maxProperties.json │ ├── maximum.json │ ├── minItems.json │ ├── minLength.json │ ├── minProperties.json │ ├── minimum.json │ ├── multipleOf.json │ ├── not.json │ ├── oneOf.json │ ├── optional │ │ ├── bignum.json │ │ ├── ecmascript-regex.json │ │ ├── format.json │ │ └── zeroTerminatedFloats.json │ ├── pattern.json │ ├── patternProperties.json │ ├── properties.json │ ├── propertyNames.json │ ├── ref.json │ ├── refRemote.json │ ├── required.json │ ├── type.json │ └── uniqueItems.json ├── draft7.json ├── draft7 │ ├── additionalItems.json │ ├── additionalProperties.json │ ├── allOf.json │ ├── anyOf.json │ ├── boolean_schema.json │ ├── const.json │ ├── contains.json │ ├── default.json │ ├── definitions.json │ ├── dependencies.json │ ├── enum.json │ ├── exclusiveMaximum.json │ ├── exclusiveMinimum.json │ ├── if-then-else.json │ ├── items.json │ ├── maxItems.json │ ├── maxLength.json │ ├── maxProperties.json │ ├── maximum.json │ ├── minItems.json │ ├── minLength.json │ ├── minProperties.json │ ├── minimum.json │ ├── multipleOf.json │ ├── not.json │ ├── oneOf.json │ ├── optional │ │ ├── bignum.json │ │ ├── content.json │ │ ├── ecmascript-regex.json │ │ ├── format │ │ │ ├── date-time.json │ │ │ ├── date.json │ │ │ ├── email.json │ │ │ ├── hostname.json │ │ │ ├── ipv4.json │ │ │ ├── ipv6.json │ │ │ ├── iri-reference.json │ │ │ ├── iri.json │ │ │ ├── json-pointer.json │ │ │ ├── regex.json │ │ │ ├── relative-json-pointer.json │ │ │ ├── time.json │ │ │ ├── uri-reference.json │ │ │ ├── uri-template.json │ │ │ └── uri.json │ │ └── zeroTerminatedFloats.json │ ├── pattern.json │ ├── patternProperties.json │ ├── properties.json │ ├── propertyNames.json │ ├── ref.json │ ├── refRemote.json │ ├── required.json │ ├── santhosh.json │ ├── type.json │ └── uniqueItems.json ├── empty schema.json ├── errors │ └── required.json ├── invalid_schema.json ├── invalid_schemas.json ├── reference_draft.json ├── remotes │ ├── folder │ │ └── folderInteger.json │ ├── integer.json │ ├── name.json │ └── subSchemas.json └── syntax_error.json ├── validation_context.go └── validation_context_test.go /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Run Tests and Lint Code" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | name: Run Tests and Lint Code 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | - uses: actions/setup-go@v2 19 | with: 20 | go-version: '1.24' 21 | - name: golangci-lint 22 | uses: golangci/golangci-lint-action@v2 23 | - run: go test -coverprofile=coverage.out -v -failfast -timeout=20m ./... 24 | - run: go tool gcov2lcov -infile=coverage.out -outfile=coverage.lcov 25 | - name: Coveralls 26 | uses: coverallsapp/github-action@master 27 | with: 28 | github-token: ${{ secrets.GITHUB_TOKEN }} 29 | path-to-lcov: coverage.lcov 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | coverage.txt 4 | vendor 5 | .bin 6 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - errcheck 4 | - gosimple 5 | - govet 6 | - staticcheck 7 | - typecheck 8 | - unused 9 | - bodyclose 10 | - dupl 11 | - gosec 12 | - godox 13 | 14 | run: 15 | tests: false 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash -o pipefail 2 | 3 | export PATH := .bin:${PATH} 4 | 5 | .bin/golangci-lint: Makefile 6 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .bin v1.64.8 7 | 8 | # Formats the code 9 | .PHONY: format 10 | format: 11 | go tool goimports -w -local github.com/ory *.go $$(go list -f '{{.Dir}}' ./...) 12 | 13 | # Runs tests in short mode, without database adapters 14 | .PHONY: docker 15 | docker: 16 | docker build -f .docker/Dockerfile-build -t oryd/kratos:latest . 17 | 18 | .PHONY: lint 19 | lint: .bin/golangci-lint 20 | golangci-lint run -v ./... 21 | -------------------------------------------------------------------------------- /base64loader/base64loader.go: -------------------------------------------------------------------------------- 1 | // Package base64loader (standard encoding) implements loader.Loader for base64-encoded JSON url schemes. 2 | // 3 | // The package is typically only imported for the side effect of 4 | // registering its Loaders. 5 | // 6 | // To use base64loader, link this package into your program: 7 | // 8 | // import _ "github.com/ory/jsonschema/v3/base64loader" 9 | package base64loader 10 | 11 | import ( 12 | "bytes" 13 | "context" 14 | "encoding/base64" 15 | "fmt" 16 | "io" 17 | "strings" 18 | 19 | "github.com/ory/jsonschema/v3" 20 | ) 21 | 22 | // Load implements jsonschema.Loader 23 | func Load(ctx context.Context, url string) (_ io.ReadCloser, err error) { 24 | encoded := strings.TrimPrefix(url, "base64://") 25 | 26 | var raw []byte 27 | 28 | raw, err = base64.StdEncoding.DecodeString(encoded) 29 | if err != nil { 30 | return nil, fmt.Errorf("unable to decode std encoded base64 string: %s", err) 31 | } 32 | 33 | return io.NopCloser(bytes.NewBuffer(raw)), nil 34 | } 35 | 36 | func init() { 37 | jsonschema.Loaders["base64"] = Load 38 | } 39 | -------------------------------------------------------------------------------- /base64loader/base64loader_test.go: -------------------------------------------------------------------------------- 1 | package base64loader_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/base64" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/ory/jsonschema/v3" 12 | ) 13 | 14 | func TestLoad(t *testing.T) { 15 | schema := `{ 16 | "$schema": "http://json-schema.org/draft-07/schema#", 17 | "type": "object", 18 | "properties": { 19 | "bar": { 20 | "type": "string" 21 | } 22 | }, 23 | "required": [ 24 | "bar" 25 | ] 26 | }` 27 | 28 | for _, enc := range []*base64.Encoding{ 29 | base64.StdEncoding, 30 | base64.URLEncoding, 31 | base64.RawURLEncoding, 32 | base64.RawStdEncoding, 33 | } { 34 | c, err := jsonschema.Compile(context.Background(), "base64://"+enc.EncodeToString([]byte(schema))) 35 | require.NoError(t, err) 36 | require.EqualError(t, c.Validate(bytes.NewBufferString(`{"bar": 1234}`)), "I[#/bar] S[#/properties/bar/type] expected string, but got number") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cmd/jv/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "os" 11 | 12 | "github.com/ory/jsonschema/v3" 13 | _ "github.com/ory/jsonschema/v3/httploader" 14 | ) 15 | 16 | func main() { 17 | if len(os.Args) == 1 { 18 | fmt.Fprintln(os.Stderr, "jv []...") 19 | os.Exit(1) 20 | } 21 | 22 | schema, err := jsonschema.Compile(context.Background(), os.Args[1]) 23 | if err != nil { 24 | fmt.Fprintln(os.Stderr, err) 25 | os.Exit(1) 26 | } 27 | 28 | for _, f := range os.Args[2:] { 29 | r, err := jsonschema.LoadURL(context.Background(), f) 30 | if err != nil { 31 | fmt.Fprintf(os.Stderr, "error in reading %q. reason: \n%v\n", f, err) 32 | os.Exit(1) 33 | } 34 | 35 | err = schema.Validate(r) 36 | _ = r.Close() 37 | if err != nil { 38 | fmt.Fprintf(os.Stderr, "%q does not conform to the schema specified. reason:\n%v\n", f, err) 39 | os.Exit(1) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package jsonschema provides json-schema compilation and validation. 7 | 8 | This implementation of JSON Schema, supports draft4, draft6 and draft7. 9 | Passes all tests(including optional) in https://github.com/json-schema/JSON-Schema-Test-Suite 10 | 11 | An example of using this package: 12 | 13 | schema, err := jsonschema.Compile("schemas/purchaseOrder.json") 14 | if err != nil { 15 | return err 16 | } 17 | f, err := os.Open("purchaseOrder.json") 18 | if err != nil { 19 | return err 20 | } 21 | defer f.Close() 22 | if err = schema.Validate(f); err != nil { 23 | return err 24 | } 25 | 26 | The schema is compiled against the version specified in `$schema` property. 27 | If `$schema` property is missing, it uses latest draft which currently is draft7. 28 | You can force to use draft4 when `$schema` is missing, as follows: 29 | 30 | compiler := jsonschema.NewCompiler() 31 | compler.Draft = jsonschema.Draft4 32 | 33 | you can also validate go value using schema.ValidateInterface(interface{}) method. 34 | but the argument should not be user-defined struct. 35 | 36 | This package supports loading json-schema from filePath and fileURL. 37 | 38 | To load json-schema from HTTPURL, add following import: 39 | 40 | import _ "github.com/ory/jsonschema/v3/httploader" 41 | 42 | Loading from urls for other schemes (such as ftp), can be plugged in. see package jsonschema/httploader 43 | for an example 44 | 45 | To load json-schema from in-memory: 46 | 47 | data := `{"type": "string"}` 48 | url := "sch.json" 49 | compiler := jsonschema.NewCompiler() 50 | if err := compiler.AddResource(url, strings.NewReader(data)); err != nil { 51 | return err 52 | } 53 | schema, err := compiler.Compile(url) 54 | if err != nil { 55 | return err 56 | } 57 | f, err := os.Open("doc.json") 58 | if err != nil { 59 | return err 60 | } 61 | defer f.Close() 62 | if err = schema.Validate(f); err != nil { 63 | return err 64 | } 65 | 66 | This package supports json string formats: date-time, date, time, hostname, email, ip-address, ipv4, ipv6, uri, uriref, regex, 67 | format, json-pointer, relative-json-pointer, uri-template (limited validation). Developers can register their own formats by 68 | adding them to jsonschema.Formats map. 69 | 70 | "base64" contentEncoding is supported. Custom decoders can be registered by adding them to jsonschema.Decoders map. 71 | 72 | "application/json" contentMediaType is supported. Custom mediatypes can be registered by adding them to jsonschema.MediaTypes map. 73 | 74 | The ValidationError returned by Validate method contains detailed context to understand why and where the error is. 75 | 76 | Custom Extensions can be registered as shown in extension_test.go 77 | 78 | */ 79 | package jsonschema 80 | -------------------------------------------------------------------------------- /encoding.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package jsonschema 6 | 7 | import ( 8 | "bytes" 9 | "encoding/base64" 10 | "encoding/json" 11 | ) 12 | 13 | // Decoders is a registry of functions, which know how to decode 14 | // string encoded in specific format. 15 | // 16 | // New Decoders can be registered by adding to this map. Key is encoding name, 17 | // value is function that knows how to decode string in that format. 18 | var Decoders = map[string]func(string) ([]byte, error){ 19 | "base64": base64.StdEncoding.DecodeString, 20 | } 21 | 22 | // MediaTypes is a registry of functions, which know how to validate 23 | // whether the bytes represent data of that mediaType. 24 | // 25 | // New mediaTypes can be registered by adding to this map. Key is mediaType name, 26 | // value is function that knows how to validate that mediaType. 27 | var MediaTypes = map[string]func([]byte) error{ 28 | "application/json": validateJSON, 29 | } 30 | 31 | func validateJSON(b []byte) error { 32 | decoder := json.NewDecoder(bytes.NewReader(b)) 33 | var v interface{} 34 | return decoder.Decode(&v) 35 | } 36 | -------------------------------------------------------------------------------- /extension.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package jsonschema 6 | 7 | import "context" 8 | 9 | // Extension is used to define additional keywords to standard jsonschema. 10 | // An extension can implement more than one keyword. 11 | // 12 | // Extensions are registered in Compiler.Extensions map. 13 | type Extension struct { 14 | // Meta captures the metaschema for the new keywords. 15 | // This is used to validate the schema before calling Compile. 16 | Meta *Schema 17 | 18 | // Compile compiles the schema m and returns its compiled representation. 19 | // if the schema m does not contain the keywords defined by this extension, 20 | // compiled representation nil should be returned. 21 | Compile func(ctx CompilerContext, m map[string]interface{}) (interface{}, error) 22 | 23 | // Validate validates the json value v with compiled representation s. 24 | // This is called only when compiled representation is not nil. Returned 25 | // error must be *ValidationError 26 | Validate func(ctx ValidationContext, s interface{}, v interface{}) error 27 | } 28 | 29 | // CompilerContext provides additional context required in compiling for extension. 30 | type CompilerContext struct { 31 | c *Compiler 32 | r *resource 33 | base string 34 | } 35 | 36 | // Compile compiles given value v into *Schema. This is useful in implementing 37 | // keyword like allOf/oneOf 38 | func (ctx CompilerContext) Compile(c context.Context, v interface{}) (*Schema, error) { 39 | return ctx.c.compile(c, ctx.r, nil, ctx.base, v) 40 | } 41 | 42 | // CompileRef compiles the schema referenced by ref uri 43 | func (ctx CompilerContext) CompileRef(c context.Context, ref string) (*Schema, error) { 44 | b, _ := split(ctx.base) 45 | return ctx.c.compileRef(c, ctx.r, b, ref) 46 | } 47 | 48 | // ValidationContext provides additional context required in validating for extension. 49 | type ValidationContext struct{} 50 | 51 | // Validate validates schema s with value v. Extension must use this method instead of 52 | // *Schema.ValidateInterface method. This will be useful in implementing keywords like 53 | // allOf/oneOf 54 | func (ValidationContext) Validate(s *Schema, v interface{}) error { 55 | return s.validate(v) 56 | } 57 | 58 | // Error used to construct validation error by extensions. schemaPtr is relative json pointer. 59 | func (ValidationContext) Error(schemaPtr string, format string, a ...interface{}) *ValidationError { 60 | return validationErrorf(schemaPtr, format, a...) 61 | } 62 | 63 | // Group is used by extensions to group multiple errors as causes to parent error. 64 | // This is useful in implementing keywords like allOf where each schema specified 65 | // in allOf can result a validationErrorf. 66 | func (ValidationError) Group(parent *ValidationError, causes ...error) error { 67 | return parent.add(causes...) 68 | } 69 | -------------------------------------------------------------------------------- /extension_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package jsonschema_test 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | "strconv" 11 | "strings" 12 | "testing" 13 | 14 | "github.com/ory/jsonschema/v3" 15 | ) 16 | 17 | func powerOfExt() jsonschema.Extension { 18 | meta, err := jsonschema.CompileString(ctx, "powerOf.json", `{ 19 | "properties" : { 20 | "powerOf": { 21 | "type": "integer", 22 | "exclusiveMinimum": 0 23 | } 24 | } 25 | }`) 26 | if err != nil { 27 | panic(err) 28 | } 29 | compile := func(ctx jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) { 30 | if pow, ok := m["powerOf"]; ok { 31 | return pow.(json.Number).Int64() 32 | } 33 | return nil, nil 34 | } 35 | validate := func(ctx jsonschema.ValidationContext, s interface{}, v interface{}) error { 36 | switch v.(type) { 37 | case json.Number, float64, int, int32, int64: 38 | pow := s.(int64) 39 | n, _ := strconv.ParseInt(fmt.Sprint(v), 10, 64) 40 | for n%pow == 0 { 41 | n = n / pow 42 | } 43 | if n != 1 { 44 | return ctx.Error("powerOf", "%v not powerOf %v", v, pow) 45 | } 46 | return nil 47 | default: 48 | return nil 49 | } 50 | } 51 | return jsonschema.Extension{ 52 | Meta: meta, 53 | Compile: compile, 54 | Validate: validate, 55 | } 56 | } 57 | 58 | func TestPowerOfExt(t *testing.T) { 59 | t.Run("invalidSchema", func(t *testing.T) { 60 | c := jsonschema.NewCompiler() 61 | c.Extensions["powerOf"] = powerOfExt() 62 | if err := c.AddResource("test.json", strings.NewReader(`{"powerOf": "hello"}`)); err != nil { 63 | t.Fatal(err) 64 | } 65 | _, err := c.Compile(ctx, "test.json") 66 | if err == nil { 67 | t.Fatal("error expected") 68 | } 69 | t.Log(err) 70 | }) 71 | t.Run("validSchema", func(t *testing.T) { 72 | c := jsonschema.NewCompiler() 73 | c.Extensions["powerOf"] = powerOfExt() 74 | if err := c.AddResource("test.json", strings.NewReader(`{"powerOf": 10}`)); err != nil { 75 | t.Fatal(err) 76 | } 77 | sch, err := c.Compile(ctx, "test.json") 78 | if err != nil { 79 | t.Fatal(err) 80 | } 81 | t.Run("validInstance", func(t *testing.T) { 82 | if err := sch.Validate(strings.NewReader(`100`)); err != nil { 83 | t.Fatal(err) 84 | } 85 | }) 86 | t.Run("invalidInstance", func(t *testing.T) { 87 | if err := sch.Validate(strings.NewReader(`111`)); err == nil { 88 | t.Fatal("validation must fail") 89 | } else { 90 | if !strings.Contains(err.Error(), "111 not powerOf 10") { 91 | t.Fatal("validation error expected to contain powerOf message") 92 | } 93 | t.Log(err) 94 | } 95 | }) 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /fileloader/fileloader.go: -------------------------------------------------------------------------------- 1 | // Package fileloader implements loader.Loader for file url schemes. 2 | // 3 | // The package is typically only imported for the side effect of 4 | // registering its Loaders. 5 | // 6 | // To use httploader, link this package into your program: 7 | // import _ "github.com/ory/jsonschema/v3/fileloader" 8 | // 9 | package fileloader 10 | 11 | import ( 12 | "context" 13 | "io" 14 | "os" 15 | "strings" 16 | 17 | "github.com/ory/jsonschema/v3" 18 | ) 19 | 20 | // Load implements jsonschema.Loader 21 | func Load(ctx context.Context, url string) (io.ReadCloser, error) { 22 | f, err := os.Open(strings.TrimPrefix(url, "file://")) 23 | if err != nil { 24 | return nil, err 25 | } 26 | return f, nil 27 | } 28 | 29 | func init() { 30 | jsonschema.Loaders["file"] = Load 31 | } 32 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ory/jsonschema/v3 2 | 3 | go 1.24.1 4 | 5 | require ( 6 | github.com/hashicorp/go-retryablehttp v0.7.7 7 | github.com/nyaruka/phonenumbers v1.5.0 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 14 | github.com/jandelgado/gcov2lcov v1.1.1 // indirect 15 | github.com/kr/pretty v0.3.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d // indirect 18 | golang.org/x/mod v0.24.0 // indirect 19 | golang.org/x/sync v0.12.0 // indirect 20 | golang.org/x/text v0.15.0 // indirect 21 | golang.org/x/tools v0.31.0 // indirect 22 | google.golang.org/protobuf v1.34.1 // indirect 23 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 24 | gopkg.in/yaml.v3 v3.0.1 // indirect 25 | ) 26 | 27 | tool ( 28 | github.com/jandelgado/gcov2lcov 29 | golang.org/x/tools/cmd/goimports 30 | ) 31 | -------------------------------------------------------------------------------- /go.test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "" > coverage.txt 5 | 6 | for d in $(go list ./... | grep -v vendor); do 7 | go test -v -race -coverprofile=profile.out -covermode=atomic $d 8 | if [ -f profile.out ]; then 9 | cat profile.out >> coverage.txt 10 | rm profile.out 11 | fi 12 | done 13 | -------------------------------------------------------------------------------- /httploader/httploader.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package httploader implements loader.Loader for http/https url. 6 | // 7 | // The package is typically only imported for the side effect of 8 | // registering its Loaders. 9 | // 10 | // To use httploader, link this package into your program: 11 | // 12 | // import _ "github.com/ory/jsonschema/v3/httploader" 13 | package httploader 14 | 15 | import ( 16 | "context" 17 | "fmt" 18 | "io" 19 | "net/http" 20 | 21 | "github.com/hashicorp/go-retryablehttp" 22 | 23 | "github.com/ory/jsonschema/v3" 24 | ) 25 | 26 | type key string 27 | 28 | const ContextKey key = "github.com/ory/jsonschema/v3/httploader.HTTPClient" 29 | 30 | // Load implements jsonschemav2.Loader 31 | func Load(ctx context.Context, url string) (io.ReadCloser, error) { 32 | var hc *retryablehttp.Client 33 | if v := ctx.Value(ContextKey); v == nil { 34 | return nil, fmt.Errorf("expected a client to be set for %s but received nil", ContextKey) 35 | } else if c, ok := v.(*retryablehttp.Client); ok { 36 | hc = c 37 | } else { 38 | return nil, fmt.Errorf("invalid context value for %s expected %T but got: %T", ContextKey, new(retryablehttp.Client), v) 39 | } 40 | 41 | req, err := retryablehttp.NewRequest("GET", url, nil) 42 | if err != nil { 43 | return nil, err 44 | } 45 | req = req.WithContext(ctx) 46 | resp, err := hc.Do(req) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | if resp.StatusCode != http.StatusOK { 52 | _ = resp.Body.Close() 53 | return nil, fmt.Errorf("%s returned status code %d", url, resp.StatusCode) 54 | } 55 | 56 | return resp.Body, nil 57 | } 58 | 59 | func init() { 60 | jsonschema.Loaders["http"] = Load 61 | jsonschema.Loaders["https"] = Load 62 | } 63 | -------------------------------------------------------------------------------- /httploader/httploader_test.go: -------------------------------------------------------------------------------- 1 | package httploader 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "io" 7 | "net/http" 8 | "net/http/httptest" 9 | "testing" 10 | 11 | "github.com/hashicorp/go-retryablehttp" 12 | "github.com/stretchr/testify/assert" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | var errFoo = errors.New("foo") 17 | 18 | type rt struct{} 19 | 20 | func (r rt) RoundTrip(_ *http.Request) (*http.Response, error) { 21 | return nil, errFoo 22 | } 23 | 24 | var _ http.RoundTripper = new(rt) 25 | 26 | func TestHTTPLoader(t *testing.T) { 27 | const expectedBody = "Hello, client" 28 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 29 | _, _ = w.Write([]byte(expectedBody)) 30 | })) 31 | t.Cleanup(ts.Close) 32 | 33 | mr := func(t *testing.T, ctx context.Context) string { 34 | res, err := Load(context.WithValue(context.Background(), ContextKey, retryablehttp.NewClient()), ts.URL) 35 | require.NoError(t, err) 36 | defer res.Close() 37 | body, err := io.ReadAll(res) 38 | require.NoError(t, err) 39 | return string(body) 40 | } 41 | 42 | assert.Equal(t, expectedBody, mr(t, context.Background())) 43 | 44 | hc := retryablehttp.NewClient() 45 | hc.RetryMax = 1 46 | hc.HTTPClient.Transport = new(rt) 47 | _, err := Load(context.WithValue(context.Background(), ContextKey, hc), ts.URL) 48 | require.ErrorIs(t, err, errFoo) 49 | 50 | _, err = Load(context.WithValue(context.Background(), ContextKey, new(struct{})), ts.URL) 51 | assert.ErrorContains(t, err, "invalid context value for github.com/ory/jsonschema/v3/httploader.HTTPClient expected *retryablehttp.Client but got: *struct {}") 52 | } 53 | -------------------------------------------------------------------------------- /loaders.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "net/url" 8 | "os" 9 | "path/filepath" 10 | "runtime" 11 | "strings" 12 | ) 13 | 14 | func loadFile(ctx context.Context, path string) (io.ReadCloser, error) { 15 | return os.Open(path) 16 | } 17 | 18 | func loadFileURL(ctx context.Context, s string) (io.ReadCloser, error) { 19 | u, err := url.Parse(s) 20 | if err != nil { 21 | return nil, err 22 | } 23 | f := u.Path 24 | if runtime.GOOS == "windows" { 25 | f = strings.TrimPrefix(f, "/") 26 | f = filepath.FromSlash(f) 27 | } 28 | return os.Open(f) 29 | } 30 | 31 | // Loaders is a registry of functions, which know how to load url 32 | // of specific schema. 33 | // 34 | // New loaders can be registered by adding to this map. Key is schema, 35 | // value is function that knows how to load url of that schema 36 | var Loaders = map[string]func(ctx context.Context, url string) (io.ReadCloser, error){ 37 | "": loadFile, 38 | "file": loadFileURL, 39 | } 40 | 41 | // SchemeNotRegisteredError is the error type returned by Load function. 42 | // It tells that no Loader is registered for that URL Scheme. 43 | type SchemeNotRegisteredError string 44 | 45 | func (s SchemeNotRegisteredError) Error() string { 46 | return fmt.Sprintf("no Loader registered for scheme %s", string(s)) 47 | } 48 | 49 | // LoadURL loads document at given URL. The default implementation 50 | // uses Loaders registry to lookup by schema and uses that loader. 51 | // 52 | // Users can change this variable, if they would like to take complete 53 | // responsibility of loading given URL. Used by Compiler if its LoadURL 54 | // field is nil. 55 | var LoadURL = func(ctx context.Context, s string) (io.ReadCloser, error) { 56 | u, err := url.Parse(s) 57 | if err != nil { 58 | return nil, err 59 | } 60 | loader, ok := Loaders[u.Scheme] 61 | if !ok { 62 | return nil, SchemeNotRegisteredError(u.Scheme) 63 | 64 | } 65 | return loader(ctx, s) 66 | } 67 | -------------------------------------------------------------------------------- /testdata/customer.json: -------------------------------------------------------------------------------- 1 | { 2 | "shipping_address": { 3 | "street_address": "1600 Pennsylvania Avenue NW", 4 | "city": "Washington", 5 | "state": "DC" 6 | }, 7 | "billing_address": { 8 | "street_address": "1st Street SE", 9 | "city": "Washington", 10 | "state": "DC" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /testdata/customer_schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "$schema": "http://json-schema.org/draft-04/schema#", 4 | "type": "object", 5 | "properties": { 6 | "billing_address": { "$ref": "definitions.json#/address" }, 7 | "shipping_address": { "$ref": "definitions.json#/address" } 8 | } 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /testdata/definitions.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "type": "object", 4 | "properties": { 5 | "street_address": { "type": "string" }, 6 | "city": { "type": "string" }, 7 | "state": { "type": "string" } 8 | }, 9 | "required": ["street_address", "city", "state"] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testdata/draft4/additionalItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "additionalItems as schema", 4 | "schema": { 5 | "items": [{}], 6 | "additionalItems": {"type": "integer"} 7 | }, 8 | "tests": [ 9 | { 10 | "description": "additional items match schema", 11 | "data": [ null, 2, 3, 4 ], 12 | "valid": true 13 | }, 14 | { 15 | "description": "additional items do not match schema", 16 | "data": [ null, 2, 3, "foo" ], 17 | "valid": false 18 | } 19 | ] 20 | }, 21 | { 22 | "description": "items is schema, no additionalItems", 23 | "schema": { 24 | "items": {}, 25 | "additionalItems": false 26 | }, 27 | "tests": [ 28 | { 29 | "description": "all items match schema", 30 | "data": [ 1, 2, 3, 4, 5 ], 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "array of items with no additionalItems", 37 | "schema": { 38 | "items": [{}, {}, {}], 39 | "additionalItems": false 40 | }, 41 | "tests": [ 42 | { 43 | "description": "fewer number of items present", 44 | "data": [ 1, 2 ], 45 | "valid": true 46 | }, 47 | { 48 | "description": "equal number of items present", 49 | "data": [ 1, 2, 3 ], 50 | "valid": true 51 | }, 52 | { 53 | "description": "additional items are not permitted", 54 | "data": [ 1, 2, 3, 4 ], 55 | "valid": false 56 | } 57 | ] 58 | }, 59 | { 60 | "description": "additionalItems as false without items", 61 | "schema": {"additionalItems": false}, 62 | "tests": [ 63 | { 64 | "description": 65 | "items defaults to empty schema so everything is valid", 66 | "data": [ 1, 2, 3, 4, 5 ], 67 | "valid": true 68 | }, 69 | { 70 | "description": "ignores non-arrays", 71 | "data": {"foo" : "bar"}, 72 | "valid": true 73 | } 74 | ] 75 | }, 76 | { 77 | "description": "additionalItems are allowed by default", 78 | "schema": {"items": [{"type": "integer"}]}, 79 | "tests": [ 80 | { 81 | "description": "only the first item is validated", 82 | "data": [1, "foo", false], 83 | "valid": true 84 | } 85 | ] 86 | } 87 | ] 88 | -------------------------------------------------------------------------------- /testdata/draft4/additionalProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": 4 | "additionalProperties being false does not allow other properties", 5 | "schema": { 6 | "properties": {"foo": {}, "bar": {}}, 7 | "patternProperties": { "^v": {} }, 8 | "additionalProperties": false 9 | }, 10 | "tests": [ 11 | { 12 | "description": "no additional properties is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "an additional property is invalid", 18 | "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobarbaz", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | }, 36 | { 37 | "description": "patternProperties are not additional properties", 38 | "data": {"foo":1, "vroom": 2}, 39 | "valid": true 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "non-ASCII pattern with additionalProperties", 45 | "schema": { 46 | "patternProperties": {"^á": {}}, 47 | "additionalProperties": false 48 | }, 49 | "tests": [ 50 | { 51 | "description": "matching the pattern is valid", 52 | "data": {"ármányos": 2}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "not matching the pattern is invalid", 57 | "data": {"élmény": 2}, 58 | "valid": false 59 | } 60 | ] 61 | }, 62 | { 63 | "description": 64 | "additionalProperties allows a schema which should validate", 65 | "schema": { 66 | "properties": {"foo": {}, "bar": {}}, 67 | "additionalProperties": {"type": "boolean"} 68 | }, 69 | "tests": [ 70 | { 71 | "description": "no additional properties is valid", 72 | "data": {"foo": 1}, 73 | "valid": true 74 | }, 75 | { 76 | "description": "an additional valid property is valid", 77 | "data": {"foo" : 1, "bar" : 2, "quux" : true}, 78 | "valid": true 79 | }, 80 | { 81 | "description": "an additional invalid property is invalid", 82 | "data": {"foo" : 1, "bar" : 2, "quux" : 12}, 83 | "valid": false 84 | } 85 | ] 86 | }, 87 | { 88 | "description": 89 | "additionalProperties can exist by itself", 90 | "schema": { 91 | "additionalProperties": {"type": "boolean"} 92 | }, 93 | "tests": [ 94 | { 95 | "description": "an additional valid property is valid", 96 | "data": {"foo" : true}, 97 | "valid": true 98 | }, 99 | { 100 | "description": "an additional invalid property is invalid", 101 | "data": {"foo" : 1}, 102 | "valid": false 103 | } 104 | ] 105 | }, 106 | { 107 | "description": "additionalProperties are allowed by default", 108 | "schema": {"properties": {"foo": {}, "bar": {}}}, 109 | "tests": [ 110 | { 111 | "description": "additional properties are allowed", 112 | "data": {"foo": 1, "bar": 2, "quux": true}, 113 | "valid": true 114 | } 115 | ] 116 | } 117 | ] 118 | -------------------------------------------------------------------------------- /testdata/draft4/allOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "allOf", 4 | "schema": { 5 | "allOf": [ 6 | { 7 | "properties": { 8 | "bar": {"type": "integer"} 9 | }, 10 | "required": ["bar"] 11 | }, 12 | { 13 | "properties": { 14 | "foo": {"type": "string"} 15 | }, 16 | "required": ["foo"] 17 | } 18 | ] 19 | }, 20 | "tests": [ 21 | { 22 | "description": "allOf", 23 | "data": {"foo": "baz", "bar": 2}, 24 | "valid": true 25 | }, 26 | { 27 | "description": "mismatch second", 28 | "data": {"foo": "baz"}, 29 | "valid": false 30 | }, 31 | { 32 | "description": "mismatch first", 33 | "data": {"bar": 2}, 34 | "valid": false 35 | }, 36 | { 37 | "description": "wrong type", 38 | "data": {"foo": "baz", "bar": "quux"}, 39 | "valid": false 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "allOf with base schema", 45 | "schema": { 46 | "properties": {"bar": {"type": "integer"}}, 47 | "required": ["bar"], 48 | "allOf" : [ 49 | { 50 | "properties": { 51 | "foo": {"type": "string"} 52 | }, 53 | "required": ["foo"] 54 | }, 55 | { 56 | "properties": { 57 | "baz": {"type": "null"} 58 | }, 59 | "required": ["baz"] 60 | } 61 | ] 62 | }, 63 | "tests": [ 64 | { 65 | "description": "valid", 66 | "data": {"foo": "quux", "bar": 2, "baz": null}, 67 | "valid": true 68 | }, 69 | { 70 | "description": "mismatch base schema", 71 | "data": {"foo": "quux", "baz": null}, 72 | "valid": false 73 | }, 74 | { 75 | "description": "mismatch first allOf", 76 | "data": {"bar": 2, "baz": null}, 77 | "valid": false 78 | }, 79 | { 80 | "description": "mismatch second allOf", 81 | "data": {"foo": "quux", "bar": 2}, 82 | "valid": false 83 | }, 84 | { 85 | "description": "mismatch both", 86 | "data": {"bar": 2}, 87 | "valid": false 88 | } 89 | ] 90 | }, 91 | { 92 | "description": "allOf simple types", 93 | "schema": { 94 | "allOf": [ 95 | {"maximum": 30}, 96 | {"minimum": 20} 97 | ] 98 | }, 99 | "tests": [ 100 | { 101 | "description": "valid", 102 | "data": 25, 103 | "valid": true 104 | }, 105 | { 106 | "description": "mismatch one", 107 | "data": 35, 108 | "valid": false 109 | } 110 | ] 111 | } 112 | ] 113 | -------------------------------------------------------------------------------- /testdata/draft4/anyOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "anyOf", 4 | "schema": { 5 | "anyOf": [ 6 | { 7 | "type": "integer" 8 | }, 9 | { 10 | "minimum": 2 11 | } 12 | ] 13 | }, 14 | "tests": [ 15 | { 16 | "description": "first anyOf valid", 17 | "data": 1, 18 | "valid": true 19 | }, 20 | { 21 | "description": "second anyOf valid", 22 | "data": 2.5, 23 | "valid": true 24 | }, 25 | { 26 | "description": "both anyOf valid", 27 | "data": 3, 28 | "valid": true 29 | }, 30 | { 31 | "description": "neither anyOf valid", 32 | "data": 1.5, 33 | "valid": false 34 | } 35 | ] 36 | }, 37 | { 38 | "description": "anyOf with base schema", 39 | "schema": { 40 | "type": "string", 41 | "anyOf" : [ 42 | { 43 | "maxLength": 2 44 | }, 45 | { 46 | "minLength": 4 47 | } 48 | ] 49 | }, 50 | "tests": [ 51 | { 52 | "description": "mismatch base schema", 53 | "data": 3, 54 | "valid": false 55 | }, 56 | { 57 | "description": "one anyOf valid", 58 | "data": "foobar", 59 | "valid": true 60 | }, 61 | { 62 | "description": "both anyOf invalid", 63 | "data": "foo", 64 | "valid": false 65 | } 66 | ] 67 | }, 68 | { 69 | "description": "anyOf complex types", 70 | "schema": { 71 | "anyOf": [ 72 | { 73 | "properties": { 74 | "bar": {"type": "integer"} 75 | }, 76 | "required": ["bar"] 77 | }, 78 | { 79 | "properties": { 80 | "foo": {"type": "string"} 81 | }, 82 | "required": ["foo"] 83 | } 84 | ] 85 | }, 86 | "tests": [ 87 | { 88 | "description": "first anyOf valid (complex)", 89 | "data": {"bar": 2}, 90 | "valid": true 91 | }, 92 | { 93 | "description": "second anyOf valid (complex)", 94 | "data": {"foo": "baz"}, 95 | "valid": true 96 | }, 97 | { 98 | "description": "both anyOf valid (complex)", 99 | "data": {"foo": "baz", "bar": 2}, 100 | "valid": true 101 | }, 102 | { 103 | "description": "neither anyOf valid (complex)", 104 | "data": {"foo": 2, "bar": "quux"}, 105 | "valid": false 106 | } 107 | ] 108 | } 109 | ] 110 | -------------------------------------------------------------------------------- /testdata/draft4/default.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "invalid type for default", 4 | "schema": { 5 | "properties": { 6 | "foo": { 7 | "type": "integer", 8 | "default": [] 9 | } 10 | } 11 | }, 12 | "tests": [ 13 | { 14 | "description": "valid when property is specified", 15 | "data": {"foo": 13}, 16 | "valid": true 17 | }, 18 | { 19 | "description": "still valid when the invalid default is used", 20 | "data": {}, 21 | "valid": true 22 | } 23 | ] 24 | }, 25 | { 26 | "description": "invalid string value for default", 27 | "schema": { 28 | "properties": { 29 | "bar": { 30 | "type": "string", 31 | "minLength": 4, 32 | "default": "bad" 33 | } 34 | } 35 | }, 36 | "tests": [ 37 | { 38 | "description": "valid when property is specified", 39 | "data": {"bar": "good"}, 40 | "valid": true 41 | }, 42 | { 43 | "description": "still valid when the invalid default is used", 44 | "data": {}, 45 | "valid": true 46 | } 47 | ] 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /testdata/draft4/definitions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "valid definition", 4 | "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, 5 | "tests": [ 6 | { 7 | "description": "valid definition schema", 8 | "data": { 9 | "definitions": { 10 | "foo": {"type": "integer"} 11 | } 12 | }, 13 | "valid": true 14 | } 15 | ] 16 | }, 17 | { 18 | "description": "invalid definition", 19 | "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, 20 | "tests": [ 21 | { 22 | "description": "invalid definition schema", 23 | "data": { 24 | "definitions": { 25 | "foo": {"type": 1} 26 | } 27 | }, 28 | "valid": false 29 | } 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /testdata/draft4/dependencies.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "dependencies", 4 | "schema": { 5 | "dependencies": {"bar": ["foo"]} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "neither", 10 | "data": {}, 11 | "valid": true 12 | }, 13 | { 14 | "description": "nondependant", 15 | "data": {"foo": 1}, 16 | "valid": true 17 | }, 18 | { 19 | "description": "with dependency", 20 | "data": {"foo": 1, "bar": 2}, 21 | "valid": true 22 | }, 23 | { 24 | "description": "missing dependency", 25 | "data": {"bar": 2}, 26 | "valid": false 27 | }, 28 | { 29 | "description": "ignores arrays", 30 | "data": ["bar"], 31 | "valid": true 32 | }, 33 | { 34 | "description": "ignores strings", 35 | "data": "foobar", 36 | "valid": true 37 | }, 38 | { 39 | "description": "ignores other non-objects", 40 | "data": 12, 41 | "valid": true 42 | } 43 | ] 44 | }, 45 | { 46 | "description": "multiple dependencies", 47 | "schema": { 48 | "dependencies": {"quux": ["foo", "bar"]} 49 | }, 50 | "tests": [ 51 | { 52 | "description": "neither", 53 | "data": {}, 54 | "valid": true 55 | }, 56 | { 57 | "description": "nondependants", 58 | "data": {"foo": 1, "bar": 2}, 59 | "valid": true 60 | }, 61 | { 62 | "description": "with dependencies", 63 | "data": {"foo": 1, "bar": 2, "quux": 3}, 64 | "valid": true 65 | }, 66 | { 67 | "description": "missing dependency", 68 | "data": {"foo": 1, "quux": 2}, 69 | "valid": false 70 | }, 71 | { 72 | "description": "missing other dependency", 73 | "data": {"bar": 1, "quux": 2}, 74 | "valid": false 75 | }, 76 | { 77 | "description": "missing both dependencies", 78 | "data": {"quux": 1}, 79 | "valid": false 80 | } 81 | ] 82 | }, 83 | { 84 | "description": "multiple dependencies subschema", 85 | "schema": { 86 | "dependencies": { 87 | "bar": { 88 | "properties": { 89 | "foo": {"type": "integer"}, 90 | "bar": {"type": "integer"} 91 | } 92 | } 93 | } 94 | }, 95 | "tests": [ 96 | { 97 | "description": "valid", 98 | "data": {"foo": 1, "bar": 2}, 99 | "valid": true 100 | }, 101 | { 102 | "description": "no dependency", 103 | "data": {"foo": "quux"}, 104 | "valid": true 105 | }, 106 | { 107 | "description": "wrong type", 108 | "data": {"foo": "quux", "bar": 2}, 109 | "valid": false 110 | }, 111 | { 112 | "description": "wrong type other", 113 | "data": {"foo": 2, "bar": "quux"}, 114 | "valid": false 115 | }, 116 | { 117 | "description": "wrong type both", 118 | "data": {"foo": "quux", "bar": "quux"}, 119 | "valid": false 120 | } 121 | ] 122 | } 123 | ] 124 | -------------------------------------------------------------------------------- /testdata/draft4/enum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "simple enum validation", 4 | "schema": {"enum": [1, 2, 3]}, 5 | "tests": [ 6 | { 7 | "description": "one of the enum is valid", 8 | "data": 1, 9 | "valid": true 10 | }, 11 | { 12 | "description": "something else is invalid", 13 | "data": 4, 14 | "valid": false 15 | } 16 | ] 17 | }, 18 | { 19 | "description": "heterogeneous enum validation", 20 | "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, 21 | "tests": [ 22 | { 23 | "description": "one of the enum is valid", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "something else is invalid", 29 | "data": null, 30 | "valid": false 31 | }, 32 | { 33 | "description": "objects are deep compared", 34 | "data": {"foo": false}, 35 | "valid": false 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "enums in properties", 41 | "schema": { 42 | "type":"object", 43 | "properties": { 44 | "foo": {"enum":["foo"]}, 45 | "bar": {"enum":["bar"]} 46 | }, 47 | "required": ["bar"] 48 | }, 49 | "tests": [ 50 | { 51 | "description": "both properties are valid", 52 | "data": {"foo":"foo", "bar":"bar"}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "missing optional property is valid", 57 | "data": {"bar":"bar"}, 58 | "valid": true 59 | }, 60 | { 61 | "description": "missing required property is invalid", 62 | "data": {"foo":"foo"}, 63 | "valid": false 64 | }, 65 | { 66 | "description": "missing all properties is invalid", 67 | "data": {}, 68 | "valid": false 69 | } 70 | ] 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /testdata/draft4/items.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "a schema given for items", 4 | "schema": { 5 | "items": {"type": "integer"} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "valid items", 10 | "data": [ 1, 2, 3 ], 11 | "valid": true 12 | }, 13 | { 14 | "description": "wrong type of items", 15 | "data": [1, "x"], 16 | "valid": false 17 | }, 18 | { 19 | "description": "ignores non-arrays", 20 | "data": {"foo" : "bar"}, 21 | "valid": true 22 | }, 23 | { 24 | "description": "JavaScript pseudo-array is valid", 25 | "data": { 26 | "0": "invalid", 27 | "length": 1 28 | }, 29 | "valid": true 30 | } 31 | ] 32 | }, 33 | { 34 | "description": "an array of schemas for items", 35 | "schema": { 36 | "items": [ 37 | {"type": "integer"}, 38 | {"type": "string"} 39 | ] 40 | }, 41 | "tests": [ 42 | { 43 | "description": "correct types", 44 | "data": [ 1, "foo" ], 45 | "valid": true 46 | }, 47 | { 48 | "description": "wrong types", 49 | "data": [ "foo", 1 ], 50 | "valid": false 51 | }, 52 | { 53 | "description": "incomplete array of items", 54 | "data": [ 1 ], 55 | "valid": true 56 | }, 57 | { 58 | "description": "array with additional items", 59 | "data": [ 1, "foo", true ], 60 | "valid": true 61 | }, 62 | { 63 | "description": "empty array", 64 | "data": [ ], 65 | "valid": true 66 | }, 67 | { 68 | "description": "JavaScript pseudo-array is valid", 69 | "data": { 70 | "0": "invalid", 71 | "1": "valid", 72 | "length": 2 73 | }, 74 | "valid": true 75 | } 76 | ] 77 | } 78 | ] 79 | -------------------------------------------------------------------------------- /testdata/draft4/maxItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxItems validation", 4 | "schema": {"maxItems": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": [1], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1, 2], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": [1, 2, 3], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "foobar", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft4/maxLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxLength validation", 4 | "schema": {"maxLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": "f", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": "foo", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 100, 24 | "valid": true 25 | }, 26 | { 27 | "description": "two supplementary Unicode code points is long enough", 28 | "data": "\uD83D\uDCA9\uD83D\uDCA9", 29 | "valid": true 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft4/maxProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxProperties validation", 4 | "schema": {"maxProperties": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": {"foo": 1}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1, "bar": 2}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": {"foo": 1, "bar": 2, "baz": 3}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobar", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft4/maximum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maximum validation", 4 | "schema": {"maximum": 3.0}, 5 | "tests": [ 6 | { 7 | "description": "below the maximum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 3.0, 14 | "valid": true 15 | }, 16 | { 17 | "description": "above the maximum is invalid", 18 | "data": 3.5, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | }, 28 | { 29 | "description": "maximum validation (explicit false exclusivity)", 30 | "schema": {"maximum": 3.0, "exclusiveMaximum": false}, 31 | "tests": [ 32 | { 33 | "description": "below the maximum is valid", 34 | "data": 2.6, 35 | "valid": true 36 | }, 37 | { 38 | "description": "boundary point is valid", 39 | "data": 3.0, 40 | "valid": true 41 | }, 42 | { 43 | "description": "above the maximum is invalid", 44 | "data": 3.5, 45 | "valid": false 46 | }, 47 | { 48 | "description": "ignores non-numbers", 49 | "data": "x", 50 | "valid": true 51 | } 52 | ] 53 | }, 54 | { 55 | "description": "exclusiveMaximum validation", 56 | "schema": { 57 | "maximum": 3.0, 58 | "exclusiveMaximum": true 59 | }, 60 | "tests": [ 61 | { 62 | "description": "below the maximum is still valid", 63 | "data": 2.2, 64 | "valid": true 65 | }, 66 | { 67 | "description": "boundary point is invalid", 68 | "data": 3.0, 69 | "valid": false 70 | } 71 | ] 72 | } 73 | ] 74 | -------------------------------------------------------------------------------- /testdata/draft4/minItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minItems validation", 4 | "schema": {"minItems": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": [], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft4/minLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minLength validation", 4 | "schema": {"minLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": "foo", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": "f", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 1, 24 | "valid": true 25 | }, 26 | { 27 | "description": "one supplementary Unicode code point is not long enough", 28 | "data": "\uD83D\uDCA9", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft4/minProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minProperties validation", 4 | "schema": {"minProperties": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": {"foo": 1, "bar": 2}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": {}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft4/minimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minimum validation", 4 | "schema": {"minimum": 1.1}, 5 | "tests": [ 6 | { 7 | "description": "above the minimum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 1.1, 14 | "valid": true 15 | }, 16 | { 17 | "description": "below the minimum is invalid", 18 | "data": 0.6, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | }, 28 | { 29 | "description": "minimum validation (explicit false exclusivity)", 30 | "schema": {"minimum": 1.1, "exclusiveMinimum": false}, 31 | "tests": [ 32 | { 33 | "description": "above the minimum is valid", 34 | "data": 2.6, 35 | "valid": true 36 | }, 37 | { 38 | "description": "boundary point is valid", 39 | "data": 1.1, 40 | "valid": true 41 | }, 42 | { 43 | "description": "below the minimum is invalid", 44 | "data": 0.6, 45 | "valid": false 46 | }, 47 | { 48 | "description": "ignores non-numbers", 49 | "data": "x", 50 | "valid": true 51 | } 52 | ] 53 | }, 54 | { 55 | "description": "exclusiveMinimum validation", 56 | "schema": { 57 | "minimum": 1.1, 58 | "exclusiveMinimum": true 59 | }, 60 | "tests": [ 61 | { 62 | "description": "above the minimum is still valid", 63 | "data": 1.2, 64 | "valid": true 65 | }, 66 | { 67 | "description": "boundary point is invalid", 68 | "data": 1.1, 69 | "valid": false 70 | } 71 | ] 72 | } 73 | ] 74 | -------------------------------------------------------------------------------- /testdata/draft4/multipleOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "by int", 4 | "schema": {"multipleOf": 2}, 5 | "tests": [ 6 | { 7 | "description": "int by int", 8 | "data": 10, 9 | "valid": true 10 | }, 11 | { 12 | "description": "int by int fail", 13 | "data": 7, 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-numbers", 18 | "data": "foo", 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "by number", 25 | "schema": {"multipleOf": 1.5}, 26 | "tests": [ 27 | { 28 | "description": "zero is multiple of anything", 29 | "data": 0, 30 | "valid": true 31 | }, 32 | { 33 | "description": "4.5 is multiple of 1.5", 34 | "data": 4.5, 35 | "valid": true 36 | }, 37 | { 38 | "description": "35 is not multiple of 1.5", 39 | "data": 35, 40 | "valid": false 41 | } 42 | ] 43 | }, 44 | { 45 | "description": "by small number", 46 | "schema": {"multipleOf": 0.0001}, 47 | "tests": [ 48 | { 49 | "description": "0.0075 is multiple of 0.0001", 50 | "data": 0.0075, 51 | "valid": true 52 | }, 53 | { 54 | "description": "0.00751 is not multiple of 0.0001", 55 | "data": 0.00751, 56 | "valid": false 57 | } 58 | ] 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /testdata/draft4/not.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "not", 4 | "schema": { 5 | "not": {"type": "integer"} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "allowed", 10 | "data": "foo", 11 | "valid": true 12 | }, 13 | { 14 | "description": "disallowed", 15 | "data": 1, 16 | "valid": false 17 | } 18 | ] 19 | }, 20 | { 21 | "description": "not multiple types", 22 | "schema": { 23 | "not": {"type": ["integer", "boolean"]} 24 | }, 25 | "tests": [ 26 | { 27 | "description": "valid", 28 | "data": "foo", 29 | "valid": true 30 | }, 31 | { 32 | "description": "mismatch", 33 | "data": 1, 34 | "valid": false 35 | }, 36 | { 37 | "description": "other mismatch", 38 | "data": true, 39 | "valid": false 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "not more complex schema", 45 | "schema": { 46 | "not": { 47 | "type": "object", 48 | "properties": { 49 | "foo": { 50 | "type": "string" 51 | } 52 | } 53 | } 54 | }, 55 | "tests": [ 56 | { 57 | "description": "match", 58 | "data": 1, 59 | "valid": true 60 | }, 61 | { 62 | "description": "other match", 63 | "data": {"foo": 1}, 64 | "valid": true 65 | }, 66 | { 67 | "description": "mismatch", 68 | "data": {"foo": "bar"}, 69 | "valid": false 70 | } 71 | ] 72 | }, 73 | { 74 | "description": "forbidden property", 75 | "schema": { 76 | "properties": { 77 | "foo": { 78 | "not": {} 79 | } 80 | } 81 | }, 82 | "tests": [ 83 | { 84 | "description": "property present", 85 | "data": {"foo": 1, "bar": 2}, 86 | "valid": false 87 | }, 88 | { 89 | "description": "property absent", 90 | "data": {"bar": 1, "baz": 2}, 91 | "valid": true 92 | } 93 | ] 94 | } 95 | 96 | ] 97 | -------------------------------------------------------------------------------- /testdata/draft4/oneOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "oneOf", 4 | "schema": { 5 | "oneOf": [ 6 | { 7 | "type": "integer" 8 | }, 9 | { 10 | "minimum": 2 11 | } 12 | ] 13 | }, 14 | "tests": [ 15 | { 16 | "description": "first oneOf valid", 17 | "data": 1, 18 | "valid": true 19 | }, 20 | { 21 | "description": "second oneOf valid", 22 | "data": 2.5, 23 | "valid": true 24 | }, 25 | { 26 | "description": "both oneOf valid", 27 | "data": 3, 28 | "valid": false 29 | }, 30 | { 31 | "description": "neither oneOf valid", 32 | "data": 1.5, 33 | "valid": false 34 | } 35 | ] 36 | }, 37 | { 38 | "description": "oneOf with base schema", 39 | "schema": { 40 | "type": "string", 41 | "oneOf" : [ 42 | { 43 | "minLength": 2 44 | }, 45 | { 46 | "maxLength": 4 47 | } 48 | ] 49 | }, 50 | "tests": [ 51 | { 52 | "description": "mismatch base schema", 53 | "data": 3, 54 | "valid": false 55 | }, 56 | { 57 | "description": "one oneOf valid", 58 | "data": "foobar", 59 | "valid": true 60 | }, 61 | { 62 | "description": "both oneOf valid", 63 | "data": "foo", 64 | "valid": false 65 | } 66 | ] 67 | }, 68 | { 69 | "description": "oneOf complex types", 70 | "schema": { 71 | "oneOf": [ 72 | { 73 | "properties": { 74 | "bar": {"type": "integer"} 75 | }, 76 | "required": ["bar"] 77 | }, 78 | { 79 | "properties": { 80 | "foo": {"type": "string"} 81 | }, 82 | "required": ["foo"] 83 | } 84 | ] 85 | }, 86 | "tests": [ 87 | { 88 | "description": "first oneOf valid (complex)", 89 | "data": {"bar": 2}, 90 | "valid": true 91 | }, 92 | { 93 | "description": "second oneOf valid (complex)", 94 | "data": {"foo": "baz"}, 95 | "valid": true 96 | }, 97 | { 98 | "description": "both oneOf valid (complex)", 99 | "data": {"foo": "baz", "bar": 2}, 100 | "valid": false 101 | }, 102 | { 103 | "description": "neither oneOf valid (complex)", 104 | "data": {"foo": 2, "bar": "quux"}, 105 | "valid": false 106 | } 107 | ] 108 | } 109 | ] 110 | -------------------------------------------------------------------------------- /testdata/draft4/optional/bignum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "integer", 4 | "schema": {"type": "integer"}, 5 | "tests": [ 6 | { 7 | "description": "a bignum is an integer", 8 | "data": 12345678910111213141516171819202122232425262728293031, 9 | "valid": true 10 | } 11 | ] 12 | }, 13 | { 14 | "description": "number", 15 | "schema": {"type": "number"}, 16 | "tests": [ 17 | { 18 | "description": "a bignum is a number", 19 | "data": 98249283749234923498293171823948729348710298301928331, 20 | "valid": true 21 | } 22 | ] 23 | }, 24 | { 25 | "description": "integer", 26 | "schema": {"type": "integer"}, 27 | "tests": [ 28 | { 29 | "description": "a negative bignum is an integer", 30 | "data": -12345678910111213141516171819202122232425262728293031, 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "number", 37 | "schema": {"type": "number"}, 38 | "tests": [ 39 | { 40 | "description": "a negative bignum is a number", 41 | "data": -98249283749234923498293171823948729348710298301928331, 42 | "valid": true 43 | } 44 | ] 45 | }, 46 | { 47 | "description": "string", 48 | "schema": {"type": "string"}, 49 | "tests": [ 50 | { 51 | "description": "a bignum is not a string", 52 | "data": 98249283749234923498293171823948729348710298301928331, 53 | "valid": false 54 | } 55 | ] 56 | }, 57 | { 58 | "description": "integer comparison", 59 | "schema": {"maximum": 18446744073709551615}, 60 | "tests": [ 61 | { 62 | "description": "comparison works for high numbers", 63 | "data": 18446744073709551600, 64 | "valid": true 65 | } 66 | ] 67 | }, 68 | { 69 | "description": "float comparison with high precision", 70 | "schema": { 71 | "maximum": 972783798187987123879878123.18878137, 72 | "exclusiveMaximum": true 73 | }, 74 | "tests": [ 75 | { 76 | "description": "comparison works for high numbers", 77 | "data": 972783798187987123879878123.188781371, 78 | "valid": false 79 | } 80 | ] 81 | }, 82 | { 83 | "description": "integer comparison", 84 | "schema": {"minimum": -18446744073709551615}, 85 | "tests": [ 86 | { 87 | "description": "comparison works for very negative numbers", 88 | "data": -18446744073709551600, 89 | "valid": true 90 | } 91 | ] 92 | }, 93 | { 94 | "description": "float comparison with high precision on negative numbers", 95 | "schema": { 96 | "minimum": -972783798187987123879878123.18878137, 97 | "exclusiveMinimum": true 98 | }, 99 | "tests": [ 100 | { 101 | "description": "comparison works for very negative numbers", 102 | "data": -972783798187987123879878123.188781371, 103 | "valid": false 104 | } 105 | ] 106 | } 107 | ] 108 | -------------------------------------------------------------------------------- /testdata/draft4/optional/ecmascript-regex.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "ECMA 262 regex non-compliance", 4 | "schema": { "format": "regex" }, 5 | "tests": [ 6 | { 7 | "description": "ECMA 262 has no support for \\Z anchor from .NET", 8 | "data": "^\\S(|(.|\\n)*\\S)\\Z", 9 | "valid": false 10 | } 11 | ] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /testdata/draft4/optional/zeroTerminatedFloats.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "some languages do not distinguish between different types of numeric value", 4 | "schema": { 5 | "type": "integer" 6 | }, 7 | "tests": [ 8 | { 9 | "description": "a float is not an integer even without fractional part", 10 | "data": 1.0, 11 | "valid": false 12 | } 13 | ] 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /testdata/draft4/pattern.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "pattern validation", 4 | "schema": {"pattern": "^a*$"}, 5 | "tests": [ 6 | { 7 | "description": "a matching pattern is valid", 8 | "data": "aaa", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a non-matching pattern is invalid", 13 | "data": "abc", 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-strings", 18 | "data": true, 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "pattern is not anchored", 25 | "schema": {"pattern": "a+"}, 26 | "tests": [ 27 | { 28 | "description": "matches a substring", 29 | "data": "xxaayy", 30 | "valid": true 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /testdata/draft4/patternProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": 4 | "patternProperties validates properties matching a regex", 5 | "schema": { 6 | "patternProperties": { 7 | "f.*o": {"type": "integer"} 8 | } 9 | }, 10 | "tests": [ 11 | { 12 | "description": "a single valid match is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "multiple valid matches is valid", 18 | "data": {"foo": 1, "foooooo" : 2}, 19 | "valid": true 20 | }, 21 | { 22 | "description": "a single invalid match is invalid", 23 | "data": {"foo": "bar", "fooooo": 2}, 24 | "valid": false 25 | }, 26 | { 27 | "description": "multiple invalid matches is invalid", 28 | "data": {"foo": "bar", "foooooo" : "baz"}, 29 | "valid": false 30 | }, 31 | { 32 | "description": "ignores arrays", 33 | "data": [], 34 | "valid": true 35 | }, 36 | { 37 | "description": "ignores strings", 38 | "data": "", 39 | "valid": true 40 | }, 41 | { 42 | "description": "ignores other non-objects", 43 | "data": 12, 44 | "valid": true 45 | } 46 | ] 47 | }, 48 | { 49 | "description": "multiple simultaneous patternProperties are validated", 50 | "schema": { 51 | "patternProperties": { 52 | "a*": {"type": "integer"}, 53 | "aaa*": {"maximum": 20} 54 | } 55 | }, 56 | "tests": [ 57 | { 58 | "description": "a single valid match is valid", 59 | "data": {"a": 21}, 60 | "valid": true 61 | }, 62 | { 63 | "description": "a simultaneous match is valid", 64 | "data": {"aaaa": 18}, 65 | "valid": true 66 | }, 67 | { 68 | "description": "multiple matches is valid", 69 | "data": {"a": 21, "aaaa": 18}, 70 | "valid": true 71 | }, 72 | { 73 | "description": "an invalid due to one is invalid", 74 | "data": {"a": "bar"}, 75 | "valid": false 76 | }, 77 | { 78 | "description": "an invalid due to the other is invalid", 79 | "data": {"aaaa": 31}, 80 | "valid": false 81 | }, 82 | { 83 | "description": "an invalid due to both is invalid", 84 | "data": {"aaa": "foo", "aaaa": 31}, 85 | "valid": false 86 | } 87 | ] 88 | }, 89 | { 90 | "description": "regexes are not anchored by default and are case sensitive", 91 | "schema": { 92 | "patternProperties": { 93 | "[0-9]{2,}": { "type": "boolean" }, 94 | "X_": { "type": "string" } 95 | } 96 | }, 97 | "tests": [ 98 | { 99 | "description": "non recognized members are ignored", 100 | "data": { "answer 1": "42" }, 101 | "valid": true 102 | }, 103 | { 104 | "description": "recognized members are accounted for", 105 | "data": { "a31b": null }, 106 | "valid": false 107 | }, 108 | { 109 | "description": "regexes are case sensitive", 110 | "data": { "a_x_3": 3 }, 111 | "valid": true 112 | }, 113 | { 114 | "description": "regexes are case sensitive, 2", 115 | "data": { "a_X_3": 3 }, 116 | "valid": false 117 | } 118 | ] 119 | } 120 | ] 121 | -------------------------------------------------------------------------------- /testdata/draft4/properties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "object properties validation", 4 | "schema": { 5 | "properties": { 6 | "foo": {"type": "integer"}, 7 | "bar": {"type": "string"} 8 | } 9 | }, 10 | "tests": [ 11 | { 12 | "description": "both properties present and valid is valid", 13 | "data": {"foo": 1, "bar": "baz"}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "one property invalid is invalid", 18 | "data": {"foo": 1, "bar": {}}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "both properties invalid is invalid", 23 | "data": {"foo": [], "bar": {}}, 24 | "valid": false 25 | }, 26 | { 27 | "description": "doesn't invalidate other properties", 28 | "data": {"quux": []}, 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores arrays", 33 | "data": [], 34 | "valid": true 35 | }, 36 | { 37 | "description": "ignores other non-objects", 38 | "data": 12, 39 | "valid": true 40 | } 41 | ] 42 | }, 43 | { 44 | "description": 45 | "properties, patternProperties, additionalProperties interaction", 46 | "schema": { 47 | "properties": { 48 | "foo": {"type": "array", "maxItems": 3}, 49 | "bar": {"type": "array"} 50 | }, 51 | "patternProperties": {"f.o": {"minItems": 2}}, 52 | "additionalProperties": {"type": "integer"} 53 | }, 54 | "tests": [ 55 | { 56 | "description": "property validates property", 57 | "data": {"foo": [1, 2]}, 58 | "valid": true 59 | }, 60 | { 61 | "description": "property invalidates property", 62 | "data": {"foo": [1, 2, 3, 4]}, 63 | "valid": false 64 | }, 65 | { 66 | "description": "patternProperty invalidates property", 67 | "data": {"foo": []}, 68 | "valid": false 69 | }, 70 | { 71 | "description": "patternProperty validates nonproperty", 72 | "data": {"fxo": [1, 2]}, 73 | "valid": true 74 | }, 75 | { 76 | "description": "patternProperty invalidates nonproperty", 77 | "data": {"fxo": []}, 78 | "valid": false 79 | }, 80 | { 81 | "description": "additionalProperty ignores property", 82 | "data": {"bar": []}, 83 | "valid": true 84 | }, 85 | { 86 | "description": "additionalProperty validates others", 87 | "data": {"quux": 3}, 88 | "valid": true 89 | }, 90 | { 91 | "description": "additionalProperty invalidates others", 92 | "data": {"quux": "foo"}, 93 | "valid": false 94 | } 95 | ] 96 | } 97 | ] 98 | -------------------------------------------------------------------------------- /testdata/draft4/required.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "required validation", 4 | "schema": { 5 | "properties": { 6 | "foo": {}, 7 | "bar": {} 8 | }, 9 | "required": ["foo"] 10 | }, 11 | "tests": [ 12 | { 13 | "description": "present required property is valid", 14 | "data": {"foo": 1}, 15 | "valid": true 16 | }, 17 | { 18 | "description": "non-present required property is invalid", 19 | "data": {"bar": 1}, 20 | "valid": false 21 | }, 22 | { 23 | "description": "ignores arrays", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "ignores strings", 29 | "data": "", 30 | "valid": true 31 | }, 32 | { 33 | "description": "ignores other non-objects", 34 | "data": 12, 35 | "valid": true 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "required default validation", 41 | "schema": { 42 | "properties": { 43 | "foo": {} 44 | } 45 | }, 46 | "tests": [ 47 | { 48 | "description": "not required by default", 49 | "data": {}, 50 | "valid": true 51 | } 52 | ] 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /testdata/draft4/santhosh.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "ignore unknown formats", 4 | "schema": {"type": "string", "format": "palindrome"}, 5 | "tests": [ 6 | { 7 | "description": "value is palindrome", 8 | "data": "racecar", 9 | "valid": true 10 | }, 11 | { 12 | "description": "value is not palindrome", 13 | "data": "sample", 14 | "valid": true 15 | } 16 | ] 17 | }, 18 | { 19 | "description": "multipleOf small value", 20 | "schema": {"multipleOf": 0.01}, 21 | "tests": [ 22 | { 23 | "description": "value is valid", 24 | "data": 19.99, 25 | "valid": true 26 | } 27 | ] 28 | }, 29 | { 30 | "description": "enum with single value", 31 | "schema": {"enum": [1]}, 32 | "tests": [ 33 | { 34 | "description": "value is invalid", 35 | "data": 5, 36 | "valid": false 37 | } 38 | ] 39 | }, 40 | { 41 | "description": "enum with array value", 42 | "schema": {"enum": [[ "one", "two", "three"]]}, 43 | "tests": [ 44 | { 45 | "description": "array size does not match", 46 | "data": [ "one", "two" ], 47 | "valid": false 48 | } 49 | ] 50 | }, 51 | { 52 | "description": "enum with object value", 53 | "schema": {"enum": [{ "one": 1, "two": 2, "three": 3}]}, 54 | "tests": [ 55 | { 56 | "description": "object size does not match", 57 | "data": { "one": 1 }, 58 | "valid": false 59 | } 60 | ] 61 | }, 62 | { 63 | "description": "enum with object having null property", 64 | "schema": {"enum": [{ "foo": null }]}, 65 | "tests": [ 66 | { 67 | "description": "valid", 68 | "data": { "foo": null }, 69 | "valid": true 70 | }, 71 | { 72 | "description": "no props is invalid", 73 | "data": { }, 74 | "valid": false 75 | }, 76 | { 77 | "description": "missing null prop is invalid", 78 | "data": { "bar": null }, 79 | "valid": false 80 | } 81 | ] 82 | }, 83 | { 84 | "description": "enum with empty object", 85 | "schema": {"enum": [{}]}, 86 | "tests": [ 87 | { 88 | "description": "valid", 89 | "data": {}, 90 | "valid": true 91 | }, 92 | { 93 | "description": "null prop is invalid", 94 | "data": { "foo": null }, 95 | "valid": false 96 | } 97 | ] 98 | }, 99 | { 100 | "description": "$ref to $id", 101 | "schema": { 102 | "$schema": "http://json-schema.org/draft-04/schema#", 103 | "type": "object", 104 | "definitions": { 105 | "name": { 106 | "id": "#nm", 107 | "type": "string" 108 | }, 109 | "email" : { 110 | "id": "email.json", 111 | "type": "string" 112 | } 113 | }, 114 | "properties": { 115 | "name": { "$ref": "#nm" }, 116 | "email": { "$ref": "email.json"} 117 | } 118 | }, 119 | "tests": [ 120 | { 121 | "description": "valid", 122 | "data": { 123 | "name": "Santhosh Kumar Tekuri", 124 | "email": "santhosh.tekuri@gmail.com" 125 | }, 126 | "valid": true 127 | }, 128 | { 129 | "description": "invalid1", 130 | "data": { 131 | "name": 0, 132 | "email": "santhosh.tekuri@gmail.com" 133 | }, 134 | "valid": false 135 | }, 136 | { 137 | "description": "valid", 138 | "data": { 139 | "name": "Santhosh Kumar Tekuri", 140 | "email": 0 141 | }, 142 | "valid": false 143 | } 144 | ] 145 | } 146 | ] 147 | -------------------------------------------------------------------------------- /testdata/draft4/uniqueItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "uniqueItems validation", 4 | "schema": {"uniqueItems": true}, 5 | "tests": [ 6 | { 7 | "description": "unique array of integers is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "non-unique array of integers is invalid", 13 | "data": [1, 1], 14 | "valid": false 15 | }, 16 | { 17 | "description": "numbers are unique if mathematically unequal", 18 | "data": [1.0, 1.00, 1], 19 | "valid": false 20 | }, 21 | { 22 | "description": "unique array of objects is valid", 23 | "data": [{"foo": "bar"}, {"foo": "baz"}], 24 | "valid": true 25 | }, 26 | { 27 | "description": "non-unique array of objects is invalid", 28 | "data": [{"foo": "bar"}, {"foo": "bar"}], 29 | "valid": false 30 | }, 31 | { 32 | "description": "unique array of nested objects is valid", 33 | "data": [ 34 | {"foo": {"bar" : {"baz" : true}}}, 35 | {"foo": {"bar" : {"baz" : false}}} 36 | ], 37 | "valid": true 38 | }, 39 | { 40 | "description": "non-unique array of nested objects is invalid", 41 | "data": [ 42 | {"foo": {"bar" : {"baz" : true}}}, 43 | {"foo": {"bar" : {"baz" : true}}} 44 | ], 45 | "valid": false 46 | }, 47 | { 48 | "description": "unique array of arrays is valid", 49 | "data": [["foo"], ["bar"]], 50 | "valid": true 51 | }, 52 | { 53 | "description": "non-unique array of arrays is invalid", 54 | "data": [["foo"], ["foo"]], 55 | "valid": false 56 | }, 57 | { 58 | "description": "1 and true are unique", 59 | "data": [1, true], 60 | "valid": true 61 | }, 62 | { 63 | "description": "0 and false are unique", 64 | "data": [0, false], 65 | "valid": true 66 | }, 67 | { 68 | "description": "unique heterogeneous types are valid", 69 | "data": [{}, [1], true, null, 1], 70 | "valid": true 71 | }, 72 | { 73 | "description": "non-unique heterogeneous types are invalid", 74 | "data": [{}, [1], true, null, {}, 1], 75 | "valid": false 76 | } 77 | ] 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /testdata/draft6/additionalItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "additionalItems as schema", 4 | "schema": { 5 | "items": [{}], 6 | "additionalItems": {"type": "integer"} 7 | }, 8 | "tests": [ 9 | { 10 | "description": "additional items match schema", 11 | "data": [ null, 2, 3, 4 ], 12 | "valid": true 13 | }, 14 | { 15 | "description": "additional items do not match schema", 16 | "data": [ null, 2, 3, "foo" ], 17 | "valid": false 18 | } 19 | ] 20 | }, 21 | { 22 | "description": "items is schema, no additionalItems", 23 | "schema": { 24 | "items": {}, 25 | "additionalItems": false 26 | }, 27 | "tests": [ 28 | { 29 | "description": "all items match schema", 30 | "data": [ 1, 2, 3, 4, 5 ], 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "array of items with no additionalItems", 37 | "schema": { 38 | "items": [{}, {}, {}], 39 | "additionalItems": false 40 | }, 41 | "tests": [ 42 | { 43 | "description": "fewer number of items present", 44 | "data": [ 1, 2 ], 45 | "valid": true 46 | }, 47 | { 48 | "description": "equal number of items present", 49 | "data": [ 1, 2, 3 ], 50 | "valid": true 51 | }, 52 | { 53 | "description": "additional items are not permitted", 54 | "data": [ 1, 2, 3, 4 ], 55 | "valid": false 56 | } 57 | ] 58 | }, 59 | { 60 | "description": "additionalItems as false without items", 61 | "schema": {"additionalItems": false}, 62 | "tests": [ 63 | { 64 | "description": 65 | "items defaults to empty schema so everything is valid", 66 | "data": [ 1, 2, 3, 4, 5 ], 67 | "valid": true 68 | }, 69 | { 70 | "description": "ignores non-arrays", 71 | "data": {"foo" : "bar"}, 72 | "valid": true 73 | } 74 | ] 75 | }, 76 | { 77 | "description": "additionalItems are allowed by default", 78 | "schema": {"items": [{"type": "integer"}]}, 79 | "tests": [ 80 | { 81 | "description": "only the first item is validated", 82 | "data": [1, "foo", false], 83 | "valid": true 84 | } 85 | ] 86 | } 87 | ] 88 | -------------------------------------------------------------------------------- /testdata/draft6/additionalProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": 4 | "additionalProperties being false does not allow other properties", 5 | "schema": { 6 | "properties": {"foo": {}, "bar": {}}, 7 | "patternProperties": { "^v": {} }, 8 | "additionalProperties": false 9 | }, 10 | "tests": [ 11 | { 12 | "description": "no additional properties is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "an additional property is invalid", 18 | "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobarbaz", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | }, 36 | { 37 | "description": "patternProperties are not additional properties", 38 | "data": {"foo":1, "vroom": 2}, 39 | "valid": true 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "non-ASCII pattern with additionalProperties", 45 | "schema": { 46 | "patternProperties": {"^á": {}}, 47 | "additionalProperties": false 48 | }, 49 | "tests": [ 50 | { 51 | "description": "matching the pattern is valid", 52 | "data": {"ármányos": 2}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "not matching the pattern is invalid", 57 | "data": {"élmény": 2}, 58 | "valid": false 59 | } 60 | ] 61 | }, 62 | { 63 | "description": 64 | "additionalProperties allows a schema which should validate", 65 | "schema": { 66 | "properties": {"foo": {}, "bar": {}}, 67 | "additionalProperties": {"type": "boolean"} 68 | }, 69 | "tests": [ 70 | { 71 | "description": "no additional properties is valid", 72 | "data": {"foo": 1}, 73 | "valid": true 74 | }, 75 | { 76 | "description": "an additional valid property is valid", 77 | "data": {"foo" : 1, "bar" : 2, "quux" : true}, 78 | "valid": true 79 | }, 80 | { 81 | "description": "an additional invalid property is invalid", 82 | "data": {"foo" : 1, "bar" : 2, "quux" : 12}, 83 | "valid": false 84 | } 85 | ] 86 | }, 87 | { 88 | "description": 89 | "additionalProperties can exist by itself", 90 | "schema": { 91 | "additionalProperties": {"type": "boolean"} 92 | }, 93 | "tests": [ 94 | { 95 | "description": "an additional valid property is valid", 96 | "data": {"foo" : true}, 97 | "valid": true 98 | }, 99 | { 100 | "description": "an additional invalid property is invalid", 101 | "data": {"foo" : 1}, 102 | "valid": false 103 | } 104 | ] 105 | }, 106 | { 107 | "description": "additionalProperties are allowed by default", 108 | "schema": {"properties": {"foo": {}, "bar": {}}}, 109 | "tests": [ 110 | { 111 | "description": "additional properties are allowed", 112 | "data": {"foo": 1, "bar": 2, "quux": true}, 113 | "valid": true 114 | } 115 | ] 116 | } 117 | ] 118 | -------------------------------------------------------------------------------- /testdata/draft6/boolean_schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "boolean schema 'true'", 4 | "schema": true, 5 | "tests": [ 6 | { 7 | "description": "number is valid", 8 | "data": 1, 9 | "valid": true 10 | }, 11 | { 12 | "description": "string is valid", 13 | "data": "foo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "boolean true is valid", 18 | "data": true, 19 | "valid": true 20 | }, 21 | { 22 | "description": "boolean false is valid", 23 | "data": false, 24 | "valid": true 25 | }, 26 | { 27 | "description": "null is valid", 28 | "data": null, 29 | "valid": true 30 | }, 31 | { 32 | "description": "object is valid", 33 | "data": {"foo": "bar"}, 34 | "valid": true 35 | }, 36 | { 37 | "description": "empty object is valid", 38 | "data": {}, 39 | "valid": true 40 | }, 41 | { 42 | "description": "array is valid", 43 | "data": ["foo"], 44 | "valid": true 45 | }, 46 | { 47 | "description": "empty array is valid", 48 | "data": [], 49 | "valid": true 50 | } 51 | ] 52 | }, 53 | { 54 | "description": "boolean schema 'false'", 55 | "schema": false, 56 | "tests": [ 57 | { 58 | "description": "number is invalid", 59 | "data": 1, 60 | "valid": false 61 | }, 62 | { 63 | "description": "string is invalid", 64 | "data": "foo", 65 | "valid": false 66 | }, 67 | { 68 | "description": "boolean true is invalid", 69 | "data": true, 70 | "valid": false 71 | }, 72 | { 73 | "description": "boolean false is invalid", 74 | "data": false, 75 | "valid": false 76 | }, 77 | { 78 | "description": "null is invalid", 79 | "data": null, 80 | "valid": false 81 | }, 82 | { 83 | "description": "object is invalid", 84 | "data": {"foo": "bar"}, 85 | "valid": false 86 | }, 87 | { 88 | "description": "empty object is invalid", 89 | "data": {}, 90 | "valid": false 91 | }, 92 | { 93 | "description": "array is invalid", 94 | "data": ["foo"], 95 | "valid": false 96 | }, 97 | { 98 | "description": "empty array is invalid", 99 | "data": [], 100 | "valid": false 101 | } 102 | ] 103 | } 104 | ] 105 | -------------------------------------------------------------------------------- /testdata/draft6/const.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "const validation", 4 | "schema": {"const": 2}, 5 | "tests": [ 6 | { 7 | "description": "same value is valid", 8 | "data": 2, 9 | "valid": true 10 | }, 11 | { 12 | "description": "another value is invalid", 13 | "data": 5, 14 | "valid": false 15 | }, 16 | { 17 | "description": "another type is invalid", 18 | "data": "a", 19 | "valid": false 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "const with object", 25 | "schema": {"const": {"foo": "bar", "baz": "bax"}}, 26 | "tests": [ 27 | { 28 | "description": "same object is valid", 29 | "data": {"foo": "bar", "baz": "bax"}, 30 | "valid": true 31 | }, 32 | { 33 | "description": "same object with different property order is valid", 34 | "data": {"baz": "bax", "foo": "bar"}, 35 | "valid": true 36 | }, 37 | { 38 | "description": "another object is invalid", 39 | "data": {"foo": "bar"}, 40 | "valid": false 41 | }, 42 | { 43 | "description": "another type is invalid", 44 | "data": [1, 2], 45 | "valid": false 46 | } 47 | ] 48 | }, 49 | { 50 | "description": "const with array", 51 | "schema": {"const": [{ "foo": "bar" }]}, 52 | "tests": [ 53 | { 54 | "description": "same array is valid", 55 | "data": [{"foo": "bar"}], 56 | "valid": true 57 | }, 58 | { 59 | "description": "another array item is invalid", 60 | "data": [2], 61 | "valid": false 62 | }, 63 | { 64 | "description": "array with additional items is invalid", 65 | "data": [1, 2, 3], 66 | "valid": false 67 | } 68 | ] 69 | }, 70 | { 71 | "description": "const with null", 72 | "schema": {"const": null}, 73 | "tests": [ 74 | { 75 | "description": "null is valid", 76 | "data": null, 77 | "valid": true 78 | }, 79 | { 80 | "description": "not null is invalid", 81 | "data": 0, 82 | "valid": false 83 | } 84 | ] 85 | } 86 | ] 87 | -------------------------------------------------------------------------------- /testdata/draft6/contains.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "contains keyword validation", 4 | "schema": { 5 | "contains": {"minimum": 5} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "array with item matching schema (5) is valid", 10 | "data": [3, 4, 5], 11 | "valid": true 12 | }, 13 | { 14 | "description": "array with item matching schema (6) is valid", 15 | "data": [3, 4, 6], 16 | "valid": true 17 | }, 18 | { 19 | "description": "array with two items matching schema (5, 6) is valid", 20 | "data": [3, 4, 5, 6], 21 | "valid": true 22 | }, 23 | { 24 | "description": "array without items matching schema is invalid", 25 | "data": [2, 3, 4], 26 | "valid": false 27 | }, 28 | { 29 | "description": "empty array is invalid", 30 | "data": [], 31 | "valid": false 32 | }, 33 | { 34 | "description": "not array is valid", 35 | "data": {}, 36 | "valid": true 37 | } 38 | ] 39 | }, 40 | { 41 | "description": "contains keyword with const keyword", 42 | "schema": { 43 | "contains": { "const": 5 } 44 | }, 45 | "tests": [ 46 | { 47 | "description": "array with item 5 is valid", 48 | "data": [3, 4, 5], 49 | "valid": true 50 | }, 51 | { 52 | "description": "array with two items 5 is valid", 53 | "data": [3, 4, 5, 5], 54 | "valid": true 55 | }, 56 | { 57 | "description": "array without item 5 is invalid", 58 | "data": [1, 2, 3, 4], 59 | "valid": false 60 | } 61 | ] 62 | }, 63 | { 64 | "description": "contains keyword with boolean schema true", 65 | "schema": {"contains": true}, 66 | "tests": [ 67 | { 68 | "description": "any non-empty array is valid", 69 | "data": ["foo"], 70 | "valid": true 71 | }, 72 | { 73 | "description": "empty array is invalid", 74 | "data": [], 75 | "valid": false 76 | } 77 | ] 78 | }, 79 | { 80 | "description": "contains keyword with boolean schema false", 81 | "schema": {"contains": false}, 82 | "tests": [ 83 | { 84 | "description": "any non-empty array is invalid", 85 | "data": ["foo"], 86 | "valid": false 87 | }, 88 | { 89 | "description": "empty array is invalid", 90 | "data": [], 91 | "valid": false 92 | } 93 | ] 94 | } 95 | ] 96 | -------------------------------------------------------------------------------- /testdata/draft6/default.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "invalid type for default", 4 | "schema": { 5 | "properties": { 6 | "foo": { 7 | "type": "integer", 8 | "default": [] 9 | } 10 | } 11 | }, 12 | "tests": [ 13 | { 14 | "description": "valid when property is specified", 15 | "data": {"foo": 13}, 16 | "valid": true 17 | }, 18 | { 19 | "description": "still valid when the invalid default is used", 20 | "data": {}, 21 | "valid": true 22 | } 23 | ] 24 | }, 25 | { 26 | "description": "invalid string value for default", 27 | "schema": { 28 | "properties": { 29 | "bar": { 30 | "type": "string", 31 | "minLength": 4, 32 | "default": "bad" 33 | } 34 | } 35 | }, 36 | "tests": [ 37 | { 38 | "description": "valid when property is specified", 39 | "data": {"bar": "good"}, 40 | "valid": true 41 | }, 42 | { 43 | "description": "still valid when the invalid default is used", 44 | "data": {}, 45 | "valid": true 46 | } 47 | ] 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /testdata/draft6/definitions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "valid definition", 4 | "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, 5 | "tests": [ 6 | { 7 | "description": "valid definition schema", 8 | "data": { 9 | "definitions": { 10 | "foo": {"type": "integer"} 11 | } 12 | }, 13 | "valid": true 14 | } 15 | ] 16 | }, 17 | { 18 | "description": "invalid definition", 19 | "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, 20 | "tests": [ 21 | { 22 | "description": "invalid definition schema", 23 | "data": { 24 | "definitions": { 25 | "foo": {"type": 1} 26 | } 27 | }, 28 | "valid": false 29 | } 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /testdata/draft6/enum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "simple enum validation", 4 | "schema": {"enum": [1, 2, 3]}, 5 | "tests": [ 6 | { 7 | "description": "one of the enum is valid", 8 | "data": 1, 9 | "valid": true 10 | }, 11 | { 12 | "description": "something else is invalid", 13 | "data": 4, 14 | "valid": false 15 | } 16 | ] 17 | }, 18 | { 19 | "description": "heterogeneous enum validation", 20 | "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, 21 | "tests": [ 22 | { 23 | "description": "one of the enum is valid", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "something else is invalid", 29 | "data": null, 30 | "valid": false 31 | }, 32 | { 33 | "description": "objects are deep compared", 34 | "data": {"foo": false}, 35 | "valid": false 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "enums in properties", 41 | "schema": { 42 | "type":"object", 43 | "properties": { 44 | "foo": {"enum":["foo"]}, 45 | "bar": {"enum":["bar"]} 46 | }, 47 | "required": ["bar"] 48 | }, 49 | "tests": [ 50 | { 51 | "description": "both properties are valid", 52 | "data": {"foo":"foo", "bar":"bar"}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "missing optional property is valid", 57 | "data": {"bar":"bar"}, 58 | "valid": true 59 | }, 60 | { 61 | "description": "missing required property is invalid", 62 | "data": {"foo":"foo"}, 63 | "valid": false 64 | }, 65 | { 66 | "description": "missing all properties is invalid", 67 | "data": {}, 68 | "valid": false 69 | } 70 | ] 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /testdata/draft6/exclusiveMaximum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "exclusiveMaximum validation", 4 | "schema": { 5 | "exclusiveMaximum": 3.0 6 | }, 7 | "tests": [ 8 | { 9 | "description": "below the exclusiveMaximum is valid", 10 | "data": 2.2, 11 | "valid": true 12 | }, 13 | { 14 | "description": "boundary point is invalid", 15 | "data": 3.0, 16 | "valid": false 17 | }, 18 | { 19 | "description": "above the exclusiveMaximum is invalid", 20 | "data": 3.5, 21 | "valid": false 22 | }, 23 | { 24 | "description": "ignores non-numbers", 25 | "data": "x", 26 | "valid": true 27 | } 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /testdata/draft6/exclusiveMinimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "exclusiveMinimum validation", 4 | "schema": { 5 | "exclusiveMinimum": 1.1 6 | }, 7 | "tests": [ 8 | { 9 | "description": "above the exclusiveMinimum is valid", 10 | "data": 1.2, 11 | "valid": true 12 | }, 13 | { 14 | "description": "boundary point is invalid", 15 | "data": 1.1, 16 | "valid": false 17 | }, 18 | { 19 | "description": "below the exclusiveMinimum is invalid", 20 | "data": 0.6, 21 | "valid": false 22 | }, 23 | { 24 | "description": "ignores non-numbers", 25 | "data": "x", 26 | "valid": true 27 | } 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /testdata/draft6/maxItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxItems validation", 4 | "schema": {"maxItems": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": [1], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1, 2], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": [1, 2, 3], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "foobar", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft6/maxLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxLength validation", 4 | "schema": {"maxLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": "f", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": "foo", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 100, 24 | "valid": true 25 | }, 26 | { 27 | "description": "two supplementary Unicode code points is long enough", 28 | "data": "\uD83D\uDCA9\uD83D\uDCA9", 29 | "valid": true 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft6/maxProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxProperties validation", 4 | "schema": {"maxProperties": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": {"foo": 1}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1, "bar": 2}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": {"foo": 1, "bar": 2, "baz": 3}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobar", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft6/maximum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maximum validation", 4 | "schema": {"maximum": 3.0}, 5 | "tests": [ 6 | { 7 | "description": "below the maximum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 3.0, 14 | "valid": true 15 | }, 16 | { 17 | "description": "above the maximum is invalid", 18 | "data": 3.5, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft6/minItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minItems validation", 4 | "schema": {"minItems": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": [], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft6/minLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minLength validation", 4 | "schema": {"minLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": "foo", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": "f", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 1, 24 | "valid": true 25 | }, 26 | { 27 | "description": "one supplementary Unicode code point is not long enough", 28 | "data": "\uD83D\uDCA9", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft6/minProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minProperties validation", 4 | "schema": {"minProperties": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": {"foo": 1, "bar": 2}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": {}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft6/minimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minimum validation", 4 | "schema": {"minimum": 1.1}, 5 | "tests": [ 6 | { 7 | "description": "above the minimum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 1.1, 14 | "valid": true 15 | }, 16 | { 17 | "description": "below the minimum is invalid", 18 | "data": 0.6, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft6/multipleOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "by int", 4 | "schema": {"multipleOf": 2}, 5 | "tests": [ 6 | { 7 | "description": "int by int", 8 | "data": 10, 9 | "valid": true 10 | }, 11 | { 12 | "description": "int by int fail", 13 | "data": 7, 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-numbers", 18 | "data": "foo", 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "by number", 25 | "schema": {"multipleOf": 1.5}, 26 | "tests": [ 27 | { 28 | "description": "zero is multiple of anything", 29 | "data": 0, 30 | "valid": true 31 | }, 32 | { 33 | "description": "4.5 is multiple of 1.5", 34 | "data": 4.5, 35 | "valid": true 36 | }, 37 | { 38 | "description": "35 is not multiple of 1.5", 39 | "data": 35, 40 | "valid": false 41 | } 42 | ] 43 | }, 44 | { 45 | "description": "by small number", 46 | "schema": {"multipleOf": 0.0001}, 47 | "tests": [ 48 | { 49 | "description": "0.0075 is multiple of 0.0001", 50 | "data": 0.0075, 51 | "valid": true 52 | }, 53 | { 54 | "description": "0.00751 is not multiple of 0.0001", 55 | "data": 0.00751, 56 | "valid": false 57 | } 58 | ] 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /testdata/draft6/not.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "not", 4 | "schema": { 5 | "not": {"type": "integer"} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "allowed", 10 | "data": "foo", 11 | "valid": true 12 | }, 13 | { 14 | "description": "disallowed", 15 | "data": 1, 16 | "valid": false 17 | } 18 | ] 19 | }, 20 | { 21 | "description": "not multiple types", 22 | "schema": { 23 | "not": {"type": ["integer", "boolean"]} 24 | }, 25 | "tests": [ 26 | { 27 | "description": "valid", 28 | "data": "foo", 29 | "valid": true 30 | }, 31 | { 32 | "description": "mismatch", 33 | "data": 1, 34 | "valid": false 35 | }, 36 | { 37 | "description": "other mismatch", 38 | "data": true, 39 | "valid": false 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "not more complex schema", 45 | "schema": { 46 | "not": { 47 | "type": "object", 48 | "properties": { 49 | "foo": { 50 | "type": "string" 51 | } 52 | } 53 | } 54 | }, 55 | "tests": [ 56 | { 57 | "description": "match", 58 | "data": 1, 59 | "valid": true 60 | }, 61 | { 62 | "description": "other match", 63 | "data": {"foo": 1}, 64 | "valid": true 65 | }, 66 | { 67 | "description": "mismatch", 68 | "data": {"foo": "bar"}, 69 | "valid": false 70 | } 71 | ] 72 | }, 73 | { 74 | "description": "forbidden property", 75 | "schema": { 76 | "properties": { 77 | "foo": { 78 | "not": {} 79 | } 80 | } 81 | }, 82 | "tests": [ 83 | { 84 | "description": "property present", 85 | "data": {"foo": 1, "bar": 2}, 86 | "valid": false 87 | }, 88 | { 89 | "description": "property absent", 90 | "data": {"bar": 1, "baz": 2}, 91 | "valid": true 92 | } 93 | ] 94 | }, 95 | { 96 | "description": "not with boolean schema true", 97 | "schema": {"not": true}, 98 | "tests": [ 99 | { 100 | "description": "any value is invalid", 101 | "data": "foo", 102 | "valid": false 103 | } 104 | ] 105 | }, 106 | { 107 | "description": "not with boolean schema false", 108 | "schema": {"not": false}, 109 | "tests": [ 110 | { 111 | "description": "any value is valid", 112 | "data": "foo", 113 | "valid": true 114 | } 115 | ] 116 | } 117 | ] 118 | -------------------------------------------------------------------------------- /testdata/draft6/optional/bignum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "integer", 4 | "schema": {"type": "integer"}, 5 | "tests": [ 6 | { 7 | "description": "a bignum is an integer", 8 | "data": 12345678910111213141516171819202122232425262728293031, 9 | "valid": true 10 | } 11 | ] 12 | }, 13 | { 14 | "description": "number", 15 | "schema": {"type": "number"}, 16 | "tests": [ 17 | { 18 | "description": "a bignum is a number", 19 | "data": 98249283749234923498293171823948729348710298301928331, 20 | "valid": true 21 | } 22 | ] 23 | }, 24 | { 25 | "description": "integer", 26 | "schema": {"type": "integer"}, 27 | "tests": [ 28 | { 29 | "description": "a negative bignum is an integer", 30 | "data": -12345678910111213141516171819202122232425262728293031, 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "number", 37 | "schema": {"type": "number"}, 38 | "tests": [ 39 | { 40 | "description": "a negative bignum is a number", 41 | "data": -98249283749234923498293171823948729348710298301928331, 42 | "valid": true 43 | } 44 | ] 45 | }, 46 | { 47 | "description": "string", 48 | "schema": {"type": "string"}, 49 | "tests": [ 50 | { 51 | "description": "a bignum is not a string", 52 | "data": 98249283749234923498293171823948729348710298301928331, 53 | "valid": false 54 | } 55 | ] 56 | }, 57 | { 58 | "description": "integer comparison", 59 | "schema": {"maximum": 18446744073709551615}, 60 | "tests": [ 61 | { 62 | "description": "comparison works for high numbers", 63 | "data": 18446744073709551600, 64 | "valid": true 65 | } 66 | ] 67 | }, 68 | { 69 | "description": "float comparison with high precision", 70 | "schema": { 71 | "exclusiveMaximum": 972783798187987123879878123.18878137 72 | }, 73 | "tests": [ 74 | { 75 | "description": "comparison works for high numbers", 76 | "data": 972783798187987123879878123.188781371, 77 | "valid": false 78 | } 79 | ] 80 | }, 81 | { 82 | "description": "integer comparison", 83 | "schema": {"minimum": -18446744073709551615}, 84 | "tests": [ 85 | { 86 | "description": "comparison works for very negative numbers", 87 | "data": -18446744073709551600, 88 | "valid": true 89 | } 90 | ] 91 | }, 92 | { 93 | "description": "float comparison with high precision on negative numbers", 94 | "schema": { 95 | "exclusiveMinimum": -972783798187987123879878123.18878137 96 | }, 97 | "tests": [ 98 | { 99 | "description": "comparison works for very negative numbers", 100 | "data": -972783798187987123879878123.188781371, 101 | "valid": false 102 | } 103 | ] 104 | } 105 | ] 106 | -------------------------------------------------------------------------------- /testdata/draft6/optional/ecmascript-regex.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "ECMA 262 regex non-compliance", 4 | "schema": { "format": "regex" }, 5 | "tests": [ 6 | { 7 | "description": "ECMA 262 has no support for \\Z anchor from .NET", 8 | "data": "^\\S(|(.|\\n)*\\S)\\Z", 9 | "valid": false 10 | } 11 | ] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /testdata/draft6/optional/zeroTerminatedFloats.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "some languages do not distinguish between different types of numeric value", 4 | "schema": { 5 | "type": "integer" 6 | }, 7 | "tests": [ 8 | { 9 | "description": "a float without fractional part is not an integer", 10 | "data": 1.0, 11 | "valid": false 12 | } 13 | ] 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /testdata/draft6/pattern.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "pattern validation", 4 | "schema": {"pattern": "^a*$"}, 5 | "tests": [ 6 | { 7 | "description": "a matching pattern is valid", 8 | "data": "aaa", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a non-matching pattern is invalid", 13 | "data": "abc", 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-strings", 18 | "data": true, 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "pattern is not anchored", 25 | "schema": {"pattern": "a+"}, 26 | "tests": [ 27 | { 28 | "description": "matches a substring", 29 | "data": "xxaayy", 30 | "valid": true 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /testdata/draft6/propertyNames.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "propertyNames validation", 4 | "schema": { 5 | "propertyNames": {"maxLength": 3} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "all property names valid", 10 | "data": { 11 | "f": {}, 12 | "foo": {} 13 | }, 14 | "valid": true 15 | }, 16 | { 17 | "description": "some property names invalid", 18 | "data": { 19 | "foo": {}, 20 | "foobar": {} 21 | }, 22 | "valid": false 23 | }, 24 | { 25 | "description": "object without properties is valid", 26 | "data": {}, 27 | "valid": true 28 | }, 29 | { 30 | "description": "ignores arrays", 31 | "data": [1, 2, 3, 4], 32 | "valid": true 33 | }, 34 | { 35 | "description": "ignores strings", 36 | "data": "foobar", 37 | "valid": true 38 | }, 39 | { 40 | "description": "ignores other non-objects", 41 | "data": 12, 42 | "valid": true 43 | } 44 | ] 45 | }, 46 | { 47 | "description": "propertyNames with boolean schema true", 48 | "schema": {"propertyNames": true}, 49 | "tests": [ 50 | { 51 | "description": "object with any properties is valid", 52 | "data": {"foo": 1}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "empty object is valid", 57 | "data": {}, 58 | "valid": true 59 | } 60 | ] 61 | }, 62 | { 63 | "description": "propertyNames with boolean schema false", 64 | "schema": {"propertyNames": false}, 65 | "tests": [ 66 | { 67 | "description": "object with any properties is invalid", 68 | "data": {"foo": 1}, 69 | "valid": false 70 | }, 71 | { 72 | "description": "empty object is valid", 73 | "data": {}, 74 | "valid": true 75 | } 76 | ] 77 | } 78 | ] 79 | -------------------------------------------------------------------------------- /testdata/draft6/required.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "required validation", 4 | "schema": { 5 | "properties": { 6 | "foo": {}, 7 | "bar": {} 8 | }, 9 | "required": ["foo"] 10 | }, 11 | "tests": [ 12 | { 13 | "description": "present required property is valid", 14 | "data": {"foo": 1}, 15 | "valid": true 16 | }, 17 | { 18 | "description": "non-present required property is invalid", 19 | "data": {"bar": 1}, 20 | "valid": false 21 | }, 22 | { 23 | "description": "ignores arrays", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "ignores strings", 29 | "data": "", 30 | "valid": true 31 | }, 32 | { 33 | "description": "ignores other non-objects", 34 | "data": 12, 35 | "valid": true 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "required default validation", 41 | "schema": { 42 | "properties": { 43 | "foo": {} 44 | } 45 | }, 46 | "tests": [ 47 | { 48 | "description": "not required by default", 49 | "data": {}, 50 | "valid": true 51 | } 52 | ] 53 | }, 54 | { 55 | "description": "required with empty array", 56 | "schema": { 57 | "properties": { 58 | "foo": {} 59 | }, 60 | "required": [] 61 | }, 62 | "tests": [ 63 | { 64 | "description": "property not required", 65 | "data": {}, 66 | "valid": true 67 | } 68 | ] 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /testdata/draft6/uniqueItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "uniqueItems validation", 4 | "schema": {"uniqueItems": true}, 5 | "tests": [ 6 | { 7 | "description": "unique array of integers is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "non-unique array of integers is invalid", 13 | "data": [1, 1], 14 | "valid": false 15 | }, 16 | { 17 | "description": "numbers are unique if mathematically unequal", 18 | "data": [1.0, 1.00, 1], 19 | "valid": false 20 | }, 21 | { 22 | "description": "unique array of objects is valid", 23 | "data": [{"foo": "bar"}, {"foo": "baz"}], 24 | "valid": true 25 | }, 26 | { 27 | "description": "non-unique array of objects is invalid", 28 | "data": [{"foo": "bar"}, {"foo": "bar"}], 29 | "valid": false 30 | }, 31 | { 32 | "description": "unique array of nested objects is valid", 33 | "data": [ 34 | {"foo": {"bar" : {"baz" : true}}}, 35 | {"foo": {"bar" : {"baz" : false}}} 36 | ], 37 | "valid": true 38 | }, 39 | { 40 | "description": "non-unique array of nested objects is invalid", 41 | "data": [ 42 | {"foo": {"bar" : {"baz" : true}}}, 43 | {"foo": {"bar" : {"baz" : true}}} 44 | ], 45 | "valid": false 46 | }, 47 | { 48 | "description": "unique array of arrays is valid", 49 | "data": [["foo"], ["bar"]], 50 | "valid": true 51 | }, 52 | { 53 | "description": "non-unique array of arrays is invalid", 54 | "data": [["foo"], ["foo"]], 55 | "valid": false 56 | }, 57 | { 58 | "description": "1 and true are unique", 59 | "data": [1, true], 60 | "valid": true 61 | }, 62 | { 63 | "description": "0 and false are unique", 64 | "data": [0, false], 65 | "valid": true 66 | }, 67 | { 68 | "description": "unique heterogeneous types are valid", 69 | "data": [{}, [1], true, null, 1], 70 | "valid": true 71 | }, 72 | { 73 | "description": "non-unique heterogeneous types are invalid", 74 | "data": [{}, [1], true, null, {}, 1], 75 | "valid": false 76 | } 77 | ] 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /testdata/draft7/additionalItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "additionalItems as schema", 4 | "schema": { 5 | "items": [{}], 6 | "additionalItems": {"type": "integer"} 7 | }, 8 | "tests": [ 9 | { 10 | "description": "additional items match schema", 11 | "data": [ null, 2, 3, 4 ], 12 | "valid": true 13 | }, 14 | { 15 | "description": "additional items do not match schema", 16 | "data": [ null, 2, 3, "foo" ], 17 | "valid": false 18 | } 19 | ] 20 | }, 21 | { 22 | "description": "items is schema, no additionalItems", 23 | "schema": { 24 | "items": {}, 25 | "additionalItems": false 26 | }, 27 | "tests": [ 28 | { 29 | "description": "all items match schema", 30 | "data": [ 1, 2, 3, 4, 5 ], 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "array of items with no additionalItems", 37 | "schema": { 38 | "items": [{}, {}, {}], 39 | "additionalItems": false 40 | }, 41 | "tests": [ 42 | { 43 | "description": "fewer number of items present", 44 | "data": [ 1, 2 ], 45 | "valid": true 46 | }, 47 | { 48 | "description": "equal number of items present", 49 | "data": [ 1, 2, 3 ], 50 | "valid": true 51 | }, 52 | { 53 | "description": "additional items are not permitted", 54 | "data": [ 1, 2, 3, 4 ], 55 | "valid": false 56 | } 57 | ] 58 | }, 59 | { 60 | "description": "additionalItems as false without items", 61 | "schema": {"additionalItems": false}, 62 | "tests": [ 63 | { 64 | "description": 65 | "items defaults to empty schema so everything is valid", 66 | "data": [ 1, 2, 3, 4, 5 ], 67 | "valid": true 68 | }, 69 | { 70 | "description": "ignores non-arrays", 71 | "data": {"foo" : "bar"}, 72 | "valid": true 73 | } 74 | ] 75 | }, 76 | { 77 | "description": "additionalItems are allowed by default", 78 | "schema": {"items": [{"type": "integer"}]}, 79 | "tests": [ 80 | { 81 | "description": "only the first item is validated", 82 | "data": [1, "foo", false], 83 | "valid": true 84 | } 85 | ] 86 | } 87 | ] 88 | -------------------------------------------------------------------------------- /testdata/draft7/additionalProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": 4 | "additionalProperties being false does not allow other properties", 5 | "schema": { 6 | "properties": {"foo": {}, "bar": {}}, 7 | "patternProperties": { "^v": {} }, 8 | "additionalProperties": false 9 | }, 10 | "tests": [ 11 | { 12 | "description": "no additional properties is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "an additional property is invalid", 18 | "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobarbaz", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | }, 36 | { 37 | "description": "patternProperties are not additional properties", 38 | "data": {"foo":1, "vroom": 2}, 39 | "valid": true 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "non-ASCII pattern with additionalProperties", 45 | "schema": { 46 | "patternProperties": {"^á": {}}, 47 | "additionalProperties": false 48 | }, 49 | "tests": [ 50 | { 51 | "description": "matching the pattern is valid", 52 | "data": {"ármányos": 2}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "not matching the pattern is invalid", 57 | "data": {"élmény": 2}, 58 | "valid": false 59 | } 60 | ] 61 | }, 62 | { 63 | "description": 64 | "additionalProperties allows a schema which should validate", 65 | "schema": { 66 | "properties": {"foo": {}, "bar": {}}, 67 | "additionalProperties": {"type": "boolean"} 68 | }, 69 | "tests": [ 70 | { 71 | "description": "no additional properties is valid", 72 | "data": {"foo": 1}, 73 | "valid": true 74 | }, 75 | { 76 | "description": "an additional valid property is valid", 77 | "data": {"foo" : 1, "bar" : 2, "quux" : true}, 78 | "valid": true 79 | }, 80 | { 81 | "description": "an additional invalid property is invalid", 82 | "data": {"foo" : 1, "bar" : 2, "quux" : 12}, 83 | "valid": false 84 | } 85 | ] 86 | }, 87 | { 88 | "description": 89 | "additionalProperties can exist by itself", 90 | "schema": { 91 | "additionalProperties": {"type": "boolean"} 92 | }, 93 | "tests": [ 94 | { 95 | "description": "an additional valid property is valid", 96 | "data": {"foo" : true}, 97 | "valid": true 98 | }, 99 | { 100 | "description": "an additional invalid property is invalid", 101 | "data": {"foo" : 1}, 102 | "valid": false 103 | } 104 | ] 105 | }, 106 | { 107 | "description": "additionalProperties are allowed by default", 108 | "schema": {"properties": {"foo": {}, "bar": {}}}, 109 | "tests": [ 110 | { 111 | "description": "additional properties are allowed", 112 | "data": {"foo": 1, "bar": 2, "quux": true}, 113 | "valid": true 114 | } 115 | ] 116 | } 117 | ] 118 | -------------------------------------------------------------------------------- /testdata/draft7/boolean_schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "boolean schema 'true'", 4 | "schema": true, 5 | "tests": [ 6 | { 7 | "description": "number is valid", 8 | "data": 1, 9 | "valid": true 10 | }, 11 | { 12 | "description": "string is valid", 13 | "data": "foo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "boolean true is valid", 18 | "data": true, 19 | "valid": true 20 | }, 21 | { 22 | "description": "boolean false is valid", 23 | "data": false, 24 | "valid": true 25 | }, 26 | { 27 | "description": "null is valid", 28 | "data": null, 29 | "valid": true 30 | }, 31 | { 32 | "description": "object is valid", 33 | "data": {"foo": "bar"}, 34 | "valid": true 35 | }, 36 | { 37 | "description": "empty object is valid", 38 | "data": {}, 39 | "valid": true 40 | }, 41 | { 42 | "description": "array is valid", 43 | "data": ["foo"], 44 | "valid": true 45 | }, 46 | { 47 | "description": "empty array is valid", 48 | "data": [], 49 | "valid": true 50 | } 51 | ] 52 | }, 53 | { 54 | "description": "boolean schema 'false'", 55 | "schema": false, 56 | "tests": [ 57 | { 58 | "description": "number is invalid", 59 | "data": 1, 60 | "valid": false 61 | }, 62 | { 63 | "description": "string is invalid", 64 | "data": "foo", 65 | "valid": false 66 | }, 67 | { 68 | "description": "boolean true is invalid", 69 | "data": true, 70 | "valid": false 71 | }, 72 | { 73 | "description": "boolean false is invalid", 74 | "data": false, 75 | "valid": false 76 | }, 77 | { 78 | "description": "null is invalid", 79 | "data": null, 80 | "valid": false 81 | }, 82 | { 83 | "description": "object is invalid", 84 | "data": {"foo": "bar"}, 85 | "valid": false 86 | }, 87 | { 88 | "description": "empty object is invalid", 89 | "data": {}, 90 | "valid": false 91 | }, 92 | { 93 | "description": "array is invalid", 94 | "data": ["foo"], 95 | "valid": false 96 | }, 97 | { 98 | "description": "empty array is invalid", 99 | "data": [], 100 | "valid": false 101 | } 102 | ] 103 | } 104 | ] 105 | -------------------------------------------------------------------------------- /testdata/draft7/const.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "const validation", 4 | "schema": {"const": 2}, 5 | "tests": [ 6 | { 7 | "description": "same value is valid", 8 | "data": 2, 9 | "valid": true 10 | }, 11 | { 12 | "description": "another value is invalid", 13 | "data": 5, 14 | "valid": false 15 | }, 16 | { 17 | "description": "another type is invalid", 18 | "data": "a", 19 | "valid": false 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "const with object", 25 | "schema": {"const": {"foo": "bar", "baz": "bax"}}, 26 | "tests": [ 27 | { 28 | "description": "same object is valid", 29 | "data": {"foo": "bar", "baz": "bax"}, 30 | "valid": true 31 | }, 32 | { 33 | "description": "same object with different property order is valid", 34 | "data": {"baz": "bax", "foo": "bar"}, 35 | "valid": true 36 | }, 37 | { 38 | "description": "another object is invalid", 39 | "data": {"foo": "bar"}, 40 | "valid": false 41 | }, 42 | { 43 | "description": "another type is invalid", 44 | "data": [1, 2], 45 | "valid": false 46 | } 47 | ] 48 | }, 49 | { 50 | "description": "const with array", 51 | "schema": {"const": [{ "foo": "bar" }]}, 52 | "tests": [ 53 | { 54 | "description": "same array is valid", 55 | "data": [{"foo": "bar"}], 56 | "valid": true 57 | }, 58 | { 59 | "description": "another array item is invalid", 60 | "data": [2], 61 | "valid": false 62 | }, 63 | { 64 | "description": "array with additional items is invalid", 65 | "data": [1, 2, 3], 66 | "valid": false 67 | } 68 | ] 69 | }, 70 | { 71 | "description": "const with null", 72 | "schema": {"const": null}, 73 | "tests": [ 74 | { 75 | "description": "null is valid", 76 | "data": null, 77 | "valid": true 78 | }, 79 | { 80 | "description": "not null is invalid", 81 | "data": 0, 82 | "valid": false 83 | } 84 | ] 85 | } 86 | ] 87 | -------------------------------------------------------------------------------- /testdata/draft7/contains.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "contains keyword validation", 4 | "schema": { 5 | "contains": {"minimum": 5} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "array with item matching schema (5) is valid", 10 | "data": [3, 4, 5], 11 | "valid": true 12 | }, 13 | { 14 | "description": "array with item matching schema (6) is valid", 15 | "data": [3, 4, 6], 16 | "valid": true 17 | }, 18 | { 19 | "description": "array with two items matching schema (5, 6) is valid", 20 | "data": [3, 4, 5, 6], 21 | "valid": true 22 | }, 23 | { 24 | "description": "array without items matching schema is invalid", 25 | "data": [2, 3, 4], 26 | "valid": false 27 | }, 28 | { 29 | "description": "empty array is invalid", 30 | "data": [], 31 | "valid": false 32 | }, 33 | { 34 | "description": "not array is valid", 35 | "data": {}, 36 | "valid": true 37 | } 38 | ] 39 | }, 40 | { 41 | "description": "contains keyword with const keyword", 42 | "schema": { 43 | "contains": { "const": 5 } 44 | }, 45 | "tests": [ 46 | { 47 | "description": "array with item 5 is valid", 48 | "data": [3, 4, 5], 49 | "valid": true 50 | }, 51 | { 52 | "description": "array with two items 5 is valid", 53 | "data": [3, 4, 5, 5], 54 | "valid": true 55 | }, 56 | { 57 | "description": "array without item 5 is invalid", 58 | "data": [1, 2, 3, 4], 59 | "valid": false 60 | } 61 | ] 62 | }, 63 | { 64 | "description": "contains keyword with boolean schema true", 65 | "schema": {"contains": true}, 66 | "tests": [ 67 | { 68 | "description": "any non-empty array is valid", 69 | "data": ["foo"], 70 | "valid": true 71 | }, 72 | { 73 | "description": "empty array is invalid", 74 | "data": [], 75 | "valid": false 76 | } 77 | ] 78 | }, 79 | { 80 | "description": "contains keyword with boolean schema false", 81 | "schema": {"contains": false}, 82 | "tests": [ 83 | { 84 | "description": "any non-empty array is invalid", 85 | "data": ["foo"], 86 | "valid": false 87 | }, 88 | { 89 | "description": "empty array is invalid", 90 | "data": [], 91 | "valid": false 92 | } 93 | ] 94 | } 95 | ] 96 | -------------------------------------------------------------------------------- /testdata/draft7/default.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "invalid type for default", 4 | "schema": { 5 | "properties": { 6 | "foo": { 7 | "type": "integer", 8 | "default": [] 9 | } 10 | } 11 | }, 12 | "tests": [ 13 | { 14 | "description": "valid when property is specified", 15 | "data": {"foo": 13}, 16 | "valid": true 17 | }, 18 | { 19 | "description": "still valid when the invalid default is used", 20 | "data": {}, 21 | "valid": true 22 | } 23 | ] 24 | }, 25 | { 26 | "description": "invalid string value for default", 27 | "schema": { 28 | "properties": { 29 | "bar": { 30 | "type": "string", 31 | "minLength": 4, 32 | "default": "bad" 33 | } 34 | } 35 | }, 36 | "tests": [ 37 | { 38 | "description": "valid when property is specified", 39 | "data": {"bar": "good"}, 40 | "valid": true 41 | }, 42 | { 43 | "description": "still valid when the invalid default is used", 44 | "data": {}, 45 | "valid": true 46 | } 47 | ] 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /testdata/draft7/definitions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "valid definition", 4 | "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, 5 | "tests": [ 6 | { 7 | "description": "valid definition schema", 8 | "data": { 9 | "definitions": { 10 | "foo": {"type": "integer"} 11 | } 12 | }, 13 | "valid": true 14 | } 15 | ] 16 | }, 17 | { 18 | "description": "invalid definition", 19 | "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, 20 | "tests": [ 21 | { 22 | "description": "invalid definition schema", 23 | "data": { 24 | "definitions": { 25 | "foo": {"type": 1} 26 | } 27 | }, 28 | "valid": false 29 | } 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /testdata/draft7/enum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "simple enum validation", 4 | "schema": {"enum": [1, 2, 3]}, 5 | "tests": [ 6 | { 7 | "description": "one of the enum is valid", 8 | "data": 1, 9 | "valid": true 10 | }, 11 | { 12 | "description": "something else is invalid", 13 | "data": 4, 14 | "valid": false 15 | } 16 | ] 17 | }, 18 | { 19 | "description": "heterogeneous enum validation", 20 | "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, 21 | "tests": [ 22 | { 23 | "description": "one of the enum is valid", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "something else is invalid", 29 | "data": null, 30 | "valid": false 31 | }, 32 | { 33 | "description": "objects are deep compared", 34 | "data": {"foo": false}, 35 | "valid": false 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "enums in properties", 41 | "schema": { 42 | "type":"object", 43 | "properties": { 44 | "foo": {"enum":["foo"]}, 45 | "bar": {"enum":["bar"]} 46 | }, 47 | "required": ["bar"] 48 | }, 49 | "tests": [ 50 | { 51 | "description": "both properties are valid", 52 | "data": {"foo":"foo", "bar":"bar"}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "missing optional property is valid", 57 | "data": {"bar":"bar"}, 58 | "valid": true 59 | }, 60 | { 61 | "description": "missing required property is invalid", 62 | "data": {"foo":"foo"}, 63 | "valid": false 64 | }, 65 | { 66 | "description": "missing all properties is invalid", 67 | "data": {}, 68 | "valid": false 69 | } 70 | ] 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /testdata/draft7/exclusiveMaximum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "exclusiveMaximum validation", 4 | "schema": { 5 | "exclusiveMaximum": 3.0 6 | }, 7 | "tests": [ 8 | { 9 | "description": "below the exclusiveMaximum is valid", 10 | "data": 2.2, 11 | "valid": true 12 | }, 13 | { 14 | "description": "boundary point is invalid", 15 | "data": 3.0, 16 | "valid": false 17 | }, 18 | { 19 | "description": "above the exclusiveMaximum is invalid", 20 | "data": 3.5, 21 | "valid": false 22 | }, 23 | { 24 | "description": "ignores non-numbers", 25 | "data": "x", 26 | "valid": true 27 | } 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /testdata/draft7/exclusiveMinimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "exclusiveMinimum validation", 4 | "schema": { 5 | "exclusiveMinimum": 1.1 6 | }, 7 | "tests": [ 8 | { 9 | "description": "above the exclusiveMinimum is valid", 10 | "data": 1.2, 11 | "valid": true 12 | }, 13 | { 14 | "description": "boundary point is invalid", 15 | "data": 1.1, 16 | "valid": false 17 | }, 18 | { 19 | "description": "below the exclusiveMinimum is invalid", 20 | "data": 0.6, 21 | "valid": false 22 | }, 23 | { 24 | "description": "ignores non-numbers", 25 | "data": "x", 26 | "valid": true 27 | } 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /testdata/draft7/maxItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxItems validation", 4 | "schema": {"maxItems": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": [1], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1, 2], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": [1, 2, 3], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "foobar", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft7/maxLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxLength validation", 4 | "schema": {"maxLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": "f", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": "foo", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 100, 24 | "valid": true 25 | }, 26 | { 27 | "description": "two supplementary Unicode code points is long enough", 28 | "data": "\uD83D\uDCA9\uD83D\uDCA9", 29 | "valid": true 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft7/maxProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maxProperties validation", 4 | "schema": {"maxProperties": 2}, 5 | "tests": [ 6 | { 7 | "description": "shorter is valid", 8 | "data": {"foo": 1}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1, "bar": 2}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too long is invalid", 18 | "data": {"foo": 1, "bar": 2, "baz": 3}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [1, 2, 3], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "foobar", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft7/maximum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "maximum validation", 4 | "schema": {"maximum": 3.0}, 5 | "tests": [ 6 | { 7 | "description": "below the maximum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 3.0, 14 | "valid": true 15 | }, 16 | { 17 | "description": "above the maximum is invalid", 18 | "data": 3.5, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft7/minItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minItems validation", 4 | "schema": {"minItems": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": [1], 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": [], 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-arrays", 23 | "data": "", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft7/minLength.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minLength validation", 4 | "schema": {"minLength": 2}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": "foo", 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": "fo", 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": "f", 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-strings", 23 | "data": 1, 24 | "valid": true 25 | }, 26 | { 27 | "description": "one supplementary Unicode code point is not long enough", 28 | "data": "\uD83D\uDCA9", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft7/minProperties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minProperties validation", 4 | "schema": {"minProperties": 1}, 5 | "tests": [ 6 | { 7 | "description": "longer is valid", 8 | "data": {"foo": 1, "bar": 2}, 9 | "valid": true 10 | }, 11 | { 12 | "description": "exact length is valid", 13 | "data": {"foo": 1}, 14 | "valid": true 15 | }, 16 | { 17 | "description": "too short is invalid", 18 | "data": {}, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores arrays", 23 | "data": [], 24 | "valid": true 25 | }, 26 | { 27 | "description": "ignores strings", 28 | "data": "", 29 | "valid": true 30 | }, 31 | { 32 | "description": "ignores other non-objects", 33 | "data": 12, 34 | "valid": true 35 | } 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /testdata/draft7/minimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "minimum validation", 4 | "schema": {"minimum": 1.1}, 5 | "tests": [ 6 | { 7 | "description": "above the minimum is valid", 8 | "data": 2.6, 9 | "valid": true 10 | }, 11 | { 12 | "description": "boundary point is valid", 13 | "data": 1.1, 14 | "valid": true 15 | }, 16 | { 17 | "description": "below the minimum is invalid", 18 | "data": 0.6, 19 | "valid": false 20 | }, 21 | { 22 | "description": "ignores non-numbers", 23 | "data": "x", 24 | "valid": true 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft7/multipleOf.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "by int", 4 | "schema": {"multipleOf": 2}, 5 | "tests": [ 6 | { 7 | "description": "int by int", 8 | "data": 10, 9 | "valid": true 10 | }, 11 | { 12 | "description": "int by int fail", 13 | "data": 7, 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-numbers", 18 | "data": "foo", 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "by number", 25 | "schema": {"multipleOf": 1.5}, 26 | "tests": [ 27 | { 28 | "description": "zero is multiple of anything", 29 | "data": 0, 30 | "valid": true 31 | }, 32 | { 33 | "description": "4.5 is multiple of 1.5", 34 | "data": 4.5, 35 | "valid": true 36 | }, 37 | { 38 | "description": "35 is not multiple of 1.5", 39 | "data": 35, 40 | "valid": false 41 | } 42 | ] 43 | }, 44 | { 45 | "description": "by small number", 46 | "schema": {"multipleOf": 0.0001}, 47 | "tests": [ 48 | { 49 | "description": "0.0075 is multiple of 0.0001", 50 | "data": 0.0075, 51 | "valid": true 52 | }, 53 | { 54 | "description": "0.00751 is not multiple of 0.0001", 55 | "data": 0.00751, 56 | "valid": false 57 | } 58 | ] 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /testdata/draft7/not.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "not", 4 | "schema": { 5 | "not": {"type": "integer"} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "allowed", 10 | "data": "foo", 11 | "valid": true 12 | }, 13 | { 14 | "description": "disallowed", 15 | "data": 1, 16 | "valid": false 17 | } 18 | ] 19 | }, 20 | { 21 | "description": "not multiple types", 22 | "schema": { 23 | "not": {"type": ["integer", "boolean"]} 24 | }, 25 | "tests": [ 26 | { 27 | "description": "valid", 28 | "data": "foo", 29 | "valid": true 30 | }, 31 | { 32 | "description": "mismatch", 33 | "data": 1, 34 | "valid": false 35 | }, 36 | { 37 | "description": "other mismatch", 38 | "data": true, 39 | "valid": false 40 | } 41 | ] 42 | }, 43 | { 44 | "description": "not more complex schema", 45 | "schema": { 46 | "not": { 47 | "type": "object", 48 | "properties": { 49 | "foo": { 50 | "type": "string" 51 | } 52 | } 53 | } 54 | }, 55 | "tests": [ 56 | { 57 | "description": "match", 58 | "data": 1, 59 | "valid": true 60 | }, 61 | { 62 | "description": "other match", 63 | "data": {"foo": 1}, 64 | "valid": true 65 | }, 66 | { 67 | "description": "mismatch", 68 | "data": {"foo": "bar"}, 69 | "valid": false 70 | } 71 | ] 72 | }, 73 | { 74 | "description": "forbidden property", 75 | "schema": { 76 | "properties": { 77 | "foo": { 78 | "not": {} 79 | } 80 | } 81 | }, 82 | "tests": [ 83 | { 84 | "description": "property present", 85 | "data": {"foo": 1, "bar": 2}, 86 | "valid": false 87 | }, 88 | { 89 | "description": "property absent", 90 | "data": {"bar": 1, "baz": 2}, 91 | "valid": true 92 | } 93 | ] 94 | }, 95 | { 96 | "description": "not with boolean schema true", 97 | "schema": {"not": true}, 98 | "tests": [ 99 | { 100 | "description": "any value is invalid", 101 | "data": "foo", 102 | "valid": false 103 | } 104 | ] 105 | }, 106 | { 107 | "description": "not with boolean schema false", 108 | "schema": {"not": false}, 109 | "tests": [ 110 | { 111 | "description": "any value is valid", 112 | "data": "foo", 113 | "valid": true 114 | } 115 | ] 116 | } 117 | ] 118 | -------------------------------------------------------------------------------- /testdata/draft7/optional/bignum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "integer", 4 | "schema": {"type": "integer"}, 5 | "tests": [ 6 | { 7 | "description": "a bignum is an integer", 8 | "data": 12345678910111213141516171819202122232425262728293031, 9 | "valid": true 10 | } 11 | ] 12 | }, 13 | { 14 | "description": "number", 15 | "schema": {"type": "number"}, 16 | "tests": [ 17 | { 18 | "description": "a bignum is a number", 19 | "data": 98249283749234923498293171823948729348710298301928331, 20 | "valid": true 21 | } 22 | ] 23 | }, 24 | { 25 | "description": "integer", 26 | "schema": {"type": "integer"}, 27 | "tests": [ 28 | { 29 | "description": "a negative bignum is an integer", 30 | "data": -12345678910111213141516171819202122232425262728293031, 31 | "valid": true 32 | } 33 | ] 34 | }, 35 | { 36 | "description": "number", 37 | "schema": {"type": "number"}, 38 | "tests": [ 39 | { 40 | "description": "a negative bignum is a number", 41 | "data": -98249283749234923498293171823948729348710298301928331, 42 | "valid": true 43 | } 44 | ] 45 | }, 46 | { 47 | "description": "string", 48 | "schema": {"type": "string"}, 49 | "tests": [ 50 | { 51 | "description": "a bignum is not a string", 52 | "data": 98249283749234923498293171823948729348710298301928331, 53 | "valid": false 54 | } 55 | ] 56 | }, 57 | { 58 | "description": "integer comparison", 59 | "schema": {"maximum": 18446744073709551615}, 60 | "tests": [ 61 | { 62 | "description": "comparison works for high numbers", 63 | "data": 18446744073709551600, 64 | "valid": true 65 | } 66 | ] 67 | }, 68 | { 69 | "description": "float comparison with high precision", 70 | "schema": { 71 | "exclusiveMaximum": 972783798187987123879878123.18878137 72 | }, 73 | "tests": [ 74 | { 75 | "description": "comparison works for high numbers", 76 | "data": 972783798187987123879878123.188781371, 77 | "valid": false 78 | } 79 | ] 80 | }, 81 | { 82 | "description": "integer comparison", 83 | "schema": {"minimum": -18446744073709551615}, 84 | "tests": [ 85 | { 86 | "description": "comparison works for very negative numbers", 87 | "data": -18446744073709551600, 88 | "valid": true 89 | } 90 | ] 91 | }, 92 | { 93 | "description": "float comparison with high precision on negative numbers", 94 | "schema": { 95 | "exclusiveMinimum": -972783798187987123879878123.18878137 96 | }, 97 | "tests": [ 98 | { 99 | "description": "comparison works for very negative numbers", 100 | "data": -972783798187987123879878123.188781371, 101 | "valid": false 102 | } 103 | ] 104 | } 105 | ] 106 | -------------------------------------------------------------------------------- /testdata/draft7/optional/content.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of string-encoded content based on media type", 4 | "schema": { 5 | "contentMediaType": "application/json" 6 | }, 7 | "tests": [ 8 | { 9 | "description": "a valid JSON document", 10 | "data": "{\"foo\": \"bar\"}", 11 | "valid": true 12 | }, 13 | { 14 | "description": "an invalid JSON document", 15 | "data": "{:}", 16 | "valid": false 17 | }, 18 | { 19 | "description": "ignores non-strings", 20 | "data": 100, 21 | "valid": true 22 | } 23 | ] 24 | }, 25 | { 26 | "description": "validation of binary string-encoding", 27 | "schema": { 28 | "contentEncoding": "base64" 29 | }, 30 | "tests": [ 31 | { 32 | "description": "a valid base64 string", 33 | "data": "eyJmb28iOiAiYmFyIn0K", 34 | "valid": true 35 | }, 36 | { 37 | "description": "an invalid base64 string (% is not a valid character)", 38 | "data": "eyJmb28iOi%iYmFyIn0K", 39 | "valid": false 40 | }, 41 | { 42 | "description": "ignores non-strings", 43 | "data": 100, 44 | "valid": true 45 | } 46 | ] 47 | }, 48 | { 49 | "description": "validation of binary-encoded media type documents", 50 | "schema": { 51 | "contentMediaType": "application/json", 52 | "contentEncoding": "base64" 53 | }, 54 | "tests": [ 55 | { 56 | "description": "a valid base64-encoded JSON document", 57 | "data": "eyJmb28iOiAiYmFyIn0K", 58 | "valid": true 59 | }, 60 | { 61 | "description": "a validly-encoded invalid JSON document", 62 | "data": "ezp9Cg==", 63 | "valid": false 64 | }, 65 | { 66 | "description": "an invalid base64 string that is valid JSON", 67 | "data": "{}", 68 | "valid": false 69 | }, 70 | { 71 | "description": "ignores non-strings", 72 | "data": 100, 73 | "valid": true 74 | } 75 | ] 76 | } 77 | ] 78 | -------------------------------------------------------------------------------- /testdata/draft7/optional/ecmascript-regex.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "ECMA 262 regex non-compliance", 4 | "schema": { "format": "regex" }, 5 | "tests": [ 6 | { 7 | "description": "ECMA 262 has no support for \\Z anchor from .NET", 8 | "data": "^\\S(|(.|\\n)*\\S)\\Z", 9 | "valid": false 10 | } 11 | ] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/date-time.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of date-time strings", 4 | "schema": {"format": "date-time"}, 5 | "tests": [ 6 | { 7 | "description": "a valid date-time string", 8 | "data": "1963-06-19T08:30:06.283185Z", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid date-time string without second fraction", 13 | "data": "1963-06-19T08:30:06Z", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid date-time string with plus offset", 18 | "data": "1937-01-01T12:00:27.87+00:20", 19 | "valid": true 20 | }, 21 | { 22 | "description": "a valid date-time string with minus offset", 23 | "data": "1990-12-31T15:59:50.123-08:00", 24 | "valid": true 25 | }, 26 | { 27 | "description": "a invalid day in date-time string", 28 | "data": "1990-02-31T15:59:60.123-08:00", 29 | "valid": false 30 | }, 31 | { 32 | "description": "an invalid offset in date-time string", 33 | "data": "1990-12-31T15:59:60-24:00", 34 | "valid": false 35 | }, 36 | { 37 | "description": "an invalid date-time string", 38 | "data": "06/19/1963 08:30:06 PST", 39 | "valid": false 40 | }, 41 | { 42 | "description": "case-insensitive T and Z", 43 | "data": "1963-06-19t08:30:06.283185z", 44 | "valid": true, 45 | "skip": "time.RFC3339 is case-sensitive" 46 | }, 47 | { 48 | "description": "only RFC3339 not all of ISO 8601 are valid", 49 | "data": "2013-350T01:01:01", 50 | "valid": false 51 | } 52 | ] 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/date.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of date strings", 4 | "schema": {"format": "date"}, 5 | "tests": [ 6 | { 7 | "description": "a valid date string", 8 | "data": "1963-06-19", 9 | "valid": true 10 | }, 11 | { 12 | "description": "an invalid date-time string", 13 | "data": "06/19/1963", 14 | "valid": false 15 | }, 16 | { 17 | "description": "only RFC3339 not all of ISO 8601 are valid", 18 | "data": "2013-350", 19 | "valid": false 20 | } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/email.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of e-mail addresses", 4 | "schema": {"format": "email"}, 5 | "tests": [ 6 | { 7 | "description": "a valid e-mail address", 8 | "data": "joe.bloggs@example.com", 9 | "valid": true 10 | }, 11 | { 12 | "description": "an invalid e-mail address", 13 | "data": "2962", 14 | "valid": false 15 | } 16 | ] 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/hostname.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of host names", 4 | "schema": {"format": "hostname"}, 5 | "tests": [ 6 | { 7 | "description": "a valid host name", 8 | "data": "www.example.com", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid punycoded IDN hostname", 13 | "data": "xn--4gbwdl.xn--wgbh1c", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a host name starting with an illegal character", 18 | "data": "-a-host-name-that-starts-with--", 19 | "valid": false 20 | }, 21 | { 22 | "description": "a host name containing illegal characters", 23 | "data": "not_a_valid_host_name", 24 | "valid": false 25 | }, 26 | { 27 | "description": "a host name with a component too long", 28 | "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/ipv4.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of IP addresses", 4 | "schema": {"format": "ipv4"}, 5 | "tests": [ 6 | { 7 | "description": "a valid IP address", 8 | "data": "192.168.0.1", 9 | "valid": true 10 | }, 11 | { 12 | "description": "an IP address with too many components", 13 | "data": "127.0.0.0.1", 14 | "valid": false 15 | }, 16 | { 17 | "description": "an IP address with out-of-range values", 18 | "data": "256.256.256.256", 19 | "valid": false 20 | }, 21 | { 22 | "description": "an IP address without 4 components", 23 | "data": "127.0", 24 | "valid": false 25 | }, 26 | { 27 | "description": "an IP address as an integer", 28 | "data": "0x7f000001", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/ipv6.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of IPv6 addresses", 4 | "schema": {"format": "ipv6"}, 5 | "tests": [ 6 | { 7 | "description": "a valid IPv6 address", 8 | "data": "::1", 9 | "valid": true 10 | }, 11 | { 12 | "description": "an IPv6 address with out-of-range values", 13 | "data": "12345::", 14 | "valid": false 15 | }, 16 | { 17 | "description": "an IPv6 address with too many components", 18 | "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", 19 | "valid": false 20 | }, 21 | { 22 | "description": "an IPv6 address containing illegal characters", 23 | "data": "::laptop", 24 | "valid": false 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/iri-reference.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of IRI References", 4 | "schema": {"format": "iri-reference"}, 5 | "tests": [ 6 | { 7 | "description": "a valid IRI", 8 | "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid protocol-relative IRI Reference", 13 | "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid relative IRI Reference", 18 | "data": "/âππ", 19 | "valid": true 20 | }, 21 | { 22 | "description": "an invalid IRI Reference", 23 | "data": "\\\\WINDOWS\\filëßåré", 24 | "valid": false, 25 | "skip": "does not work with net.URL" 26 | }, 27 | { 28 | "description": "a valid IRI Reference", 29 | "data": "âππ", 30 | "valid": true 31 | }, 32 | { 33 | "description": "a valid IRI fragment", 34 | "data": "#ƒrägmênt", 35 | "valid": true 36 | }, 37 | { 38 | "description": "an invalid IRI fragment", 39 | "data": "#ƒräg\\mênt", 40 | "valid": false, 41 | "skip": "does not work with net.URL" 42 | } 43 | ] 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/iri.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of IRIs", 4 | "schema": {"format": "iri"}, 5 | "tests": [ 6 | { 7 | "description": "a valid IRI with anchor tag", 8 | "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid IRI with anchor tag and parantheses", 13 | "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid IRI with URL-encoded stuff", 18 | "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", 19 | "valid": true 20 | }, 21 | { 22 | "description": "a valid IRI with many special characters", 23 | "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", 24 | "valid": true 25 | }, 26 | { 27 | "description": "a valid IRI based on IPv6", 28 | "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", 29 | "valid": true 30 | }, 31 | { 32 | "description": "an invalid IRI based on IPv6", 33 | "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", 34 | "valid": false, 35 | "skip": "does not work with net.URL" 36 | }, 37 | { 38 | "description": "an invalid relative IRI Reference", 39 | "data": "/abc", 40 | "valid": false 41 | }, 42 | { 43 | "description": "an invalid IRI", 44 | "data": "\\\\WINDOWS\\filëßåré", 45 | "valid": false 46 | }, 47 | { 48 | "description": "an invalid IRI though valid IRI reference", 49 | "data": "âππ", 50 | "valid": false 51 | } 52 | ] 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/regex.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of regular expressions", 4 | "schema": {"format": "regex"}, 5 | "tests": [ 6 | { 7 | "description": "a valid regular expression", 8 | "data": "([abc])+\\s+$", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a regular expression with unclosed parens is invalid", 13 | "data": "^(abc]", 14 | "valid": false 15 | } 16 | ] 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/relative-json-pointer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of Relative JSON Pointers (RJP)", 4 | "schema": {"format": "relative-json-pointer"}, 5 | "tests": [ 6 | { 7 | "description": "a valid upwards RJP", 8 | "data": "1", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid downwards RJP", 13 | "data": "0/foo/bar", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid up and then down RJP, with array index", 18 | "data": "2/0/baz/1/zip", 19 | "valid": true 20 | }, 21 | { 22 | "description": "a valid RJP taking the member or index name", 23 | "data": "0#", 24 | "valid": true 25 | }, 26 | { 27 | "description": "an invalid RJP that is a valid JSON Pointer", 28 | "data": "/foo/bar", 29 | "valid": false 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/time.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of time strings", 4 | "schema": {"format": "time"}, 5 | "tests": [ 6 | { 7 | "description": "a valid time string", 8 | "data": "08:30:06.283185Z", 9 | "valid": true 10 | }, 11 | { 12 | "description": "an invalid time string", 13 | "data": "08:30:06 PST", 14 | "valid": false 15 | }, 16 | { 17 | "description": "only RFC3339 not all of ISO 8601 are valid", 18 | "data": "01:01:01,1111", 19 | "valid": false 20 | } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/uri-reference.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of URI References", 4 | "schema": {"format": "uri-reference"}, 5 | "tests": [ 6 | { 7 | "description": "a valid URI", 8 | "data": "http://foo.bar/?baz=qux#quux", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid protocol-relative URI Reference", 13 | "data": "//foo.bar/?baz=qux#quux", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid relative URI Reference", 18 | "data": "/abc", 19 | "valid": true 20 | }, 21 | { 22 | "description": "an invalid URI Reference", 23 | "data": "\\\\WINDOWS\\fileshare", 24 | "valid": false, 25 | "skip": "does not work with net.URL" 26 | }, 27 | { 28 | "description": "a valid URI Reference", 29 | "data": "abc", 30 | "valid": true 31 | }, 32 | { 33 | "description": "a valid URI fragment", 34 | "data": "#fragment", 35 | "valid": true 36 | }, 37 | { 38 | "description": "an invalid URI fragment", 39 | "data": "#frag\\ment", 40 | "valid": false, 41 | "skip": "does not work with net.URL" 42 | } 43 | ] 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/uri-template.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "format: uri-template", 4 | "schema": { 5 | "format": "uri-template" 6 | }, 7 | "tests": [ 8 | { 9 | "description": "a valid uri-template", 10 | "data": "http://example.com/dictionary/{term:1}/{term}", 11 | "valid": true 12 | }, 13 | { 14 | "description": "an invalid uri-template", 15 | "data": "http://example.com/dictionary/{term:1}/{term", 16 | "valid": false 17 | }, 18 | { 19 | "description": "a valid uri-template without variables", 20 | "data": "http://example.com/dictionary", 21 | "valid": true 22 | }, 23 | { 24 | "description": "a valid relative uri-template", 25 | "data": "dictionary/{term:1}/{term}", 26 | "valid": true 27 | } 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /testdata/draft7/optional/format/uri.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "validation of URIs", 4 | "schema": {"format": "uri"}, 5 | "tests": [ 6 | { 7 | "description": "a valid URL with anchor tag", 8 | "data": "http://foo.bar/?baz=qux#quux", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a valid URL with anchor tag and parantheses", 13 | "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", 14 | "valid": true 15 | }, 16 | { 17 | "description": "a valid URL with URL-encoded stuff", 18 | "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", 19 | "valid": true 20 | }, 21 | { 22 | "description": "a valid puny-coded URL ", 23 | "data": "http://xn--nw2a.xn--j6w193g/", 24 | "valid": true 25 | }, 26 | { 27 | "description": "a valid URL with many special characters", 28 | "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", 29 | "valid": true 30 | }, 31 | { 32 | "description": "a valid URL based on IPv4", 33 | "data": "http://223.255.255.254", 34 | "valid": true 35 | }, 36 | { 37 | "description": "a valid URL with ftp scheme", 38 | "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", 39 | "valid": true 40 | }, 41 | { 42 | "description": "a valid URL for a simple text file", 43 | "data": "http://www.ietf.org/rfc/rfc2396.txt", 44 | "valid": true 45 | }, 46 | { 47 | "description": "a valid URL ", 48 | "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", 49 | "valid": true 50 | }, 51 | { 52 | "description": "a valid mailto URI", 53 | "data": "mailto:John.Doe@example.com", 54 | "valid": true 55 | }, 56 | { 57 | "description": "a valid newsgroup URI", 58 | "data": "news:comp.infosystems.www.servers.unix", 59 | "valid": true 60 | }, 61 | { 62 | "description": "a valid tel URI", 63 | "data": "tel:+1-816-555-1212", 64 | "valid": true 65 | }, 66 | { 67 | "description": "a valid URN", 68 | "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", 69 | "valid": true 70 | }, 71 | { 72 | "description": "an invalid protocol-relative URI Reference", 73 | "data": "//foo.bar/?baz=qux#quux", 74 | "valid": false 75 | }, 76 | { 77 | "description": "an invalid relative URI Reference", 78 | "data": "/abc", 79 | "valid": false 80 | }, 81 | { 82 | "description": "an invalid URI", 83 | "data": "\\\\WINDOWS\\fileshare", 84 | "valid": false 85 | }, 86 | { 87 | "description": "an invalid URI though valid URI reference", 88 | "data": "abc", 89 | "valid": false 90 | }, 91 | { 92 | "description": "an invalid URI with spaces", 93 | "data": "http:// shouldfail.com", 94 | "valid": false 95 | }, 96 | { 97 | "description": "an invalid URI with spaces and missing scheme", 98 | "data": ":// should fail", 99 | "valid": false 100 | } 101 | ] 102 | } 103 | ] 104 | -------------------------------------------------------------------------------- /testdata/draft7/optional/zeroTerminatedFloats.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "some languages do not distinguish between different types of numeric value", 4 | "schema": { 5 | "type": "integer" 6 | }, 7 | "tests": [ 8 | { 9 | "description": "a float without fractional part is not an integer", 10 | "data": 1.0, 11 | "valid": false 12 | } 13 | ] 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /testdata/draft7/pattern.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "pattern validation", 4 | "schema": {"pattern": "^a*$"}, 5 | "tests": [ 6 | { 7 | "description": "a matching pattern is valid", 8 | "data": "aaa", 9 | "valid": true 10 | }, 11 | { 12 | "description": "a non-matching pattern is invalid", 13 | "data": "abc", 14 | "valid": false 15 | }, 16 | { 17 | "description": "ignores non-strings", 18 | "data": true, 19 | "valid": true 20 | } 21 | ] 22 | }, 23 | { 24 | "description": "pattern is not anchored", 25 | "schema": {"pattern": "a+"}, 26 | "tests": [ 27 | { 28 | "description": "matches a substring", 29 | "data": "xxaayy", 30 | "valid": true 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /testdata/draft7/propertyNames.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "propertyNames validation", 4 | "schema": { 5 | "propertyNames": {"maxLength": 3} 6 | }, 7 | "tests": [ 8 | { 9 | "description": "all property names valid", 10 | "data": { 11 | "f": {}, 12 | "foo": {} 13 | }, 14 | "valid": true 15 | }, 16 | { 17 | "description": "some property names invalid", 18 | "data": { 19 | "foo": {}, 20 | "foobar": {} 21 | }, 22 | "valid": false 23 | }, 24 | { 25 | "description": "object without properties is valid", 26 | "data": {}, 27 | "valid": true 28 | }, 29 | { 30 | "description": "ignores arrays", 31 | "data": [1, 2, 3, 4], 32 | "valid": true 33 | }, 34 | { 35 | "description": "ignores strings", 36 | "data": "foobar", 37 | "valid": true 38 | }, 39 | { 40 | "description": "ignores other non-objects", 41 | "data": 12, 42 | "valid": true 43 | } 44 | ] 45 | }, 46 | { 47 | "description": "propertyNames with boolean schema true", 48 | "schema": {"propertyNames": true}, 49 | "tests": [ 50 | { 51 | "description": "object with any properties is valid", 52 | "data": {"foo": 1}, 53 | "valid": true 54 | }, 55 | { 56 | "description": "empty object is valid", 57 | "data": {}, 58 | "valid": true 59 | } 60 | ] 61 | }, 62 | { 63 | "description": "propertyNames with boolean schema false", 64 | "schema": {"propertyNames": false}, 65 | "tests": [ 66 | { 67 | "description": "object with any properties is invalid", 68 | "data": {"foo": 1}, 69 | "valid": false 70 | }, 71 | { 72 | "description": "empty object is valid", 73 | "data": {}, 74 | "valid": true 75 | } 76 | ] 77 | } 78 | ] 79 | -------------------------------------------------------------------------------- /testdata/draft7/required.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "required validation", 4 | "schema": { 5 | "properties": { 6 | "foo": {}, 7 | "bar": {} 8 | }, 9 | "required": ["foo"] 10 | }, 11 | "tests": [ 12 | { 13 | "description": "present required property is valid", 14 | "data": {"foo": 1}, 15 | "valid": true 16 | }, 17 | { 18 | "description": "non-present required property is invalid", 19 | "data": {"bar": 1}, 20 | "valid": false 21 | }, 22 | { 23 | "description": "ignores arrays", 24 | "data": [], 25 | "valid": true 26 | }, 27 | { 28 | "description": "ignores strings", 29 | "data": "", 30 | "valid": true 31 | }, 32 | { 33 | "description": "ignores other non-objects", 34 | "data": 12, 35 | "valid": true 36 | } 37 | ] 38 | }, 39 | { 40 | "description": "required default validation", 41 | "schema": { 42 | "properties": { 43 | "foo": {} 44 | } 45 | }, 46 | "tests": [ 47 | { 48 | "description": "not required by default", 49 | "data": {}, 50 | "valid": true 51 | } 52 | ] 53 | }, 54 | { 55 | "description": "required with empty array", 56 | "schema": { 57 | "properties": { 58 | "foo": {} 59 | }, 60 | "required": [] 61 | }, 62 | "tests": [ 63 | { 64 | "description": "property not required", 65 | "data": {}, 66 | "valid": true 67 | } 68 | ] 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /testdata/draft7/santhosh.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "ignore unknown contentEncoding", 4 | "schema": {"type": "string", "contentEncoding": "base32"}, 5 | "tests": [ 6 | { 7 | "description": "value is base32 encoded", 8 | "data": "ONQW24DMMU======", 9 | "valid": true 10 | }, 11 | { 12 | "description": "value is not base32 encoded", 13 | "data": "sample", 14 | "valid": true 15 | } 16 | ] 17 | }, 18 | { 19 | "description": "ignore unknown contentMediaType", 20 | "schema": {"type": "string", "contentMediaType": "application/xml"}, 21 | "tests": [ 22 | { 23 | "description": "value is xml", 24 | "data": "", 25 | "valid": true 26 | }, 27 | { 28 | "description": "value is not xml", 29 | "data": "doc", 30 | "valid": true 31 | } 32 | ] 33 | }, 34 | { 35 | "description": "known contentEncoding, known contentMediaType", 36 | "schema": {"type": "string", "contentEncoding": "base64", "contentMediaType":"application/json"}, 37 | "tests": [ 38 | { 39 | "description": "base64 encoded json", 40 | "data": "e30=", 41 | "valid": true 42 | }, 43 | { 44 | "description": "base64 encoded non-json", 45 | "data": "ew==", 46 | "valid": false 47 | } 48 | ] 49 | }, 50 | { 51 | "description": "unknown contentEncoding, known contentMediaType", 52 | "schema": {"type": "string", "contentEncoding": "base32", "contentMediaType":"application/json"}, 53 | "tests": [ 54 | { 55 | "description": "base32 encoded json", 56 | "data": "PN6Q====", 57 | "valid": true 58 | }, 59 | { 60 | "description": "base64 encoded non-json", 61 | "data": "PM======", 62 | "valid": true 63 | } 64 | ] 65 | }, 66 | { 67 | "description": "known contentEncoding, unknown contentMediaType", 68 | "schema": {"type": "string", "contentEncoding": "base64", "contentMediaType":"application/xml"}, 69 | "tests": [ 70 | { 71 | "description": "base64 encoded xml", 72 | "data": "PGRvYy8+", 73 | "valid": true 74 | }, 75 | { 76 | "description": "base64 encoded non-xml", 77 | "data": "ZG9j", 78 | "valid": true 79 | }, 80 | { 81 | "description": "base64 encoded non-xml", 82 | "data": "ZG9j", 83 | "valid": true 84 | }, 85 | { 86 | "description": "value is not base64 encoded", 87 | "data": ".", 88 | "valid": false 89 | } 90 | ] 91 | } 92 | ] 93 | -------------------------------------------------------------------------------- /testdata/draft7/uniqueItems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "uniqueItems validation", 4 | "schema": {"uniqueItems": true}, 5 | "tests": [ 6 | { 7 | "description": "unique array of integers is valid", 8 | "data": [1, 2], 9 | "valid": true 10 | }, 11 | { 12 | "description": "non-unique array of integers is invalid", 13 | "data": [1, 1], 14 | "valid": false 15 | }, 16 | { 17 | "description": "numbers are unique if mathematically unequal", 18 | "data": [1.0, 1.00, 1], 19 | "valid": false 20 | }, 21 | { 22 | "description": "unique array of objects is valid", 23 | "data": [{"foo": "bar"}, {"foo": "baz"}], 24 | "valid": true 25 | }, 26 | { 27 | "description": "non-unique array of objects is invalid", 28 | "data": [{"foo": "bar"}, {"foo": "bar"}], 29 | "valid": false 30 | }, 31 | { 32 | "description": "unique array of nested objects is valid", 33 | "data": [ 34 | {"foo": {"bar" : {"baz" : true}}}, 35 | {"foo": {"bar" : {"baz" : false}}} 36 | ], 37 | "valid": true 38 | }, 39 | { 40 | "description": "non-unique array of nested objects is invalid", 41 | "data": [ 42 | {"foo": {"bar" : {"baz" : true}}}, 43 | {"foo": {"bar" : {"baz" : true}}} 44 | ], 45 | "valid": false 46 | }, 47 | { 48 | "description": "unique array of arrays is valid", 49 | "data": [["foo"], ["bar"]], 50 | "valid": true 51 | }, 52 | { 53 | "description": "non-unique array of arrays is invalid", 54 | "data": [["foo"], ["foo"]], 55 | "valid": false 56 | }, 57 | { 58 | "description": "1 and true are unique", 59 | "data": [1, true], 60 | "valid": true 61 | }, 62 | { 63 | "description": "0 and false are unique", 64 | "data": [0, false], 65 | "valid": true 66 | }, 67 | { 68 | "description": "unique heterogeneous types are valid", 69 | "data": [{}, [1], true, null, 1], 70 | "valid": true 71 | }, 72 | { 73 | "description": "non-unique heterogeneous types are invalid", 74 | "data": [{}, [1], true, null, {}, 1], 75 | "valid": false 76 | } 77 | ] 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /testdata/empty schema.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /testdata/errors/required.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "type": "object", 5 | "properties": { 6 | "bar": { 7 | "type": "object", 8 | "properties": { 9 | "foo": { 10 | "type": "string" 11 | } 12 | }, 13 | "required": [ 14 | "foo" 15 | ] 16 | } 17 | }, 18 | "required": [ 19 | "bar" 20 | ] 21 | }, 22 | { 23 | "$schema": "http://json-schema.org/draft-07/schema#", 24 | "type": "object", 25 | "properties": { 26 | "object": { 27 | "type": "object", 28 | "properties": { 29 | "object": { 30 | "type": "object", 31 | "properties": { 32 | "foo": { 33 | "type": "string" 34 | }, 35 | "bar": { 36 | "type": "string" 37 | } 38 | }, 39 | "required": [ 40 | "foo", 41 | "bar" 42 | ] 43 | } 44 | }, 45 | "required": [ 46 | "object" 47 | ] 48 | } 49 | }, 50 | "required": [ 51 | "object" 52 | ] 53 | } 54 | ] -------------------------------------------------------------------------------- /testdata/invalid_schema.json: -------------------------------------------------------------------------------- 1 | { "type": 1 } -------------------------------------------------------------------------------- /testdata/reference_draft.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "allOf": [ 5 | { 6 | "$ref": "http://json-schema.org/draft-07/schema#" 7 | }, 8 | { 9 | "$ref": "http://json-schema.org/draft-06/schema#" 10 | }, 11 | { 12 | "$ref": "http://json-schema.org/draft-04/schema#" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /testdata/remotes/folder/folderInteger.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "integer" 3 | } -------------------------------------------------------------------------------- /testdata/remotes/integer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "integer" 3 | } -------------------------------------------------------------------------------- /testdata/remotes/name.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "orNull": { 4 | "anyOf": [ 5 | {"type": "null"}, 6 | {"$ref": "#"} 7 | ] 8 | } 9 | }, 10 | "type": "string" 11 | } 12 | -------------------------------------------------------------------------------- /testdata/remotes/subSchemas.json: -------------------------------------------------------------------------------- 1 | { 2 | "integer": { 3 | "type": "integer" 4 | }, 5 | "refToInteger": { 6 | "$ref": "#/integer" 7 | } 8 | } -------------------------------------------------------------------------------- /testdata/syntax_error.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /validation_context.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // ValidationErrorContext 10 | type ValidationErrorContext interface { 11 | AddContext(instancePtr, schemaPtr string) 12 | FinishInstanceContext() 13 | } 14 | 15 | // ValidationErrorContextRequired is used as error context when one or more required properties are missing. 16 | type ValidationErrorContextRequired struct { 17 | // Missing contains JSON Pointers to all missing properties. 18 | Missing []string 19 | } 20 | 21 | func (r *ValidationErrorContextRequired) AddContext(instancePtr, _ string) { 22 | for k, p := range r.Missing { 23 | r.Missing[k] = joinPtr(instancePtr, p) 24 | } 25 | } 26 | 27 | func (r *ValidationErrorContextRequired) FinishInstanceContext() { 28 | for k, p := range r.Missing { 29 | if len(p) == 0 { 30 | r.Missing[k] = "#" 31 | } else { 32 | r.Missing[k] = "#/" + p 33 | } 34 | } 35 | } 36 | 37 | func validationRequiredError(properties []string) *ValidationError { 38 | missing := make([]string, len(properties)) 39 | 40 | for k := range missing { 41 | missing[k] = strconv.Quote(properties[k]) 42 | properties[k] = escape(properties[k]) 43 | } 44 | 45 | return &ValidationError{ 46 | SchemaPtr: "required", 47 | Message: fmt.Sprintf("missing properties: %s", strings.Join(missing, ", ")), 48 | Context: &ValidationErrorContextRequired{Missing: properties}, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /validation_context_test.go: -------------------------------------------------------------------------------- 1 | package jsonschema_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "fmt" 7 | "reflect" 8 | "testing" 9 | 10 | "github.com/ory/jsonschema/v3" 11 | ) 12 | 13 | func TestErrorsContext(t *testing.T) { 14 | for k, tc := range []struct { 15 | path string 16 | doc string 17 | expected interface{} 18 | }{ 19 | { 20 | path: "testdata/errors/required.json#/0", 21 | doc: `{}`, 22 | expected: &jsonschema.ValidationErrorContextRequired{Missing: []string{"#/bar"}}, 23 | }, 24 | { 25 | path: "testdata/errors/required.json#/0", 26 | doc: `{"bar":{}}`, 27 | expected: &jsonschema.ValidationErrorContextRequired{ 28 | Missing: []string{"#/bar/foo"}, 29 | }, 30 | }, 31 | { 32 | path: "testdata/errors/required.json#/1", 33 | doc: `{"object":{"object":{"foo":"foo"}}}`, 34 | expected: &jsonschema.ValidationErrorContextRequired{ 35 | Missing: []string{"#/object/object/bar"}, 36 | }, 37 | }, 38 | { 39 | path: "testdata/errors/required.json#/1", 40 | doc: `{"object":{"object":{"bar":"bar"}}}`, 41 | expected: &jsonschema.ValidationErrorContextRequired{ 42 | Missing: []string{"#/object/object/foo"}, 43 | }, 44 | }, 45 | { 46 | path: "testdata/errors/required.json#/1", 47 | doc: `{"object":{"object":{}}}`, 48 | expected: &jsonschema.ValidationErrorContextRequired{ 49 | Missing: []string{"#/object/object/foo", "#/object/object/bar"}, 50 | }, 51 | }, 52 | { 53 | path: "testdata/errors/required.json#/1", 54 | doc: `{"object":{}}`, 55 | expected: &jsonschema.ValidationErrorContextRequired{ 56 | Missing: []string{"#/object/object"}, 57 | }, 58 | }, 59 | { 60 | path: "testdata/errors/required.json#/1", 61 | doc: `{}`, 62 | expected: &jsonschema.ValidationErrorContextRequired{ 63 | Missing: []string{"#/object"}, 64 | }, 65 | }, 66 | } { 67 | t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { 68 | ctx := context.Background() 69 | var ( 70 | schema = jsonschema.MustCompile(ctx, tc.path) 71 | err = schema.Validate(bytes.NewBufferString(tc.doc)) 72 | ) 73 | 74 | if err == nil { 75 | t.Errorf("Expected error but got nil") 76 | return 77 | } 78 | 79 | var ( 80 | actual = err.(*jsonschema.ValidationError).Context 81 | ) 82 | 83 | if !reflect.DeepEqual(tc.expected, actual) { 84 | t.Errorf("expected:\t%#v\n\tactual:\t%#v", tc.expected, actual) 85 | } 86 | }) 87 | } 88 | } 89 | --------------------------------------------------------------------------------