// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description (Unit) Tests for schema validation. // // created 16-06-2013 package gojsonschema import ( "bytes" "fmt" "io" "io/ioutil" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) const displayErrorMessages = false const circularReference = `{ "type": "object", "properties": { "games": { "type": "array", "items": { "$ref": "#/definitions/game" } } }, "definitions": { "game": { "type": "object", "properties": { "winner": { "$ref": "#/definitions/player" }, "loser": { "$ref": "#/definitions/player" } } }, "player": { "type": "object", "properties": { "user": { "$ref": "#/definitions/user" }, "game": { "$ref": "#/definitions/game" } } }, "user": { "type": "object", "properties": { "fullName": { "type": "string" } } } } }` func TestCircularReference(t *testing.T) { loader := NewStringLoader(circularReference) // call the target function _, err := NewSchema(loader) if err != nil { t.Errorf("Got error: %s", err.Error()) } } // From http://json-schema.org/examples.html const simpleSchema = `{ "title": "Example Schema", "type": "object", "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "age": { "description": "Age in years", "type": "integer", "minimum": 0 } }, "required": ["firstName", "lastName"] }` func TestLoaders(t *testing.T) { // setup reader loader reader := bytes.NewBufferString(simpleSchema) readerLoader, wrappedReader := NewReaderLoader(reader) // drain reader by, err := ioutil.ReadAll(wrappedReader) assert.Nil(t, err) assert.Equal(t, simpleSchema, string(by)) // setup writer loaders writer := &bytes.Buffer{} writerLoader, wrappedWriter := NewWriterLoader(writer) // fill writer n, err := io.WriteString(wrappedWriter, simpleSchema) assert.Nil(t, err) assert.Equal(t, n, len(simpleSchema)) loaders := []JSONLoader{ NewStringLoader(simpleSchema), readerLoader, writerLoader, } for _, l := range loaders { _, err := NewSchema(l) assert.Nil(t, err, "loader: %T", l) } } const invalidPattern = `{ "title": "Example Pattern", "type": "object", "properties": { "invalid": { "type": "string", "pattern": 99999 } } }` func TestLoadersWithInvalidPattern(t *testing.T) { // setup reader loader reader := bytes.NewBufferString(invalidPattern) readerLoader, wrappedReader := NewReaderLoader(reader) // drain reader by, err := ioutil.ReadAll(wrappedReader) assert.Nil(t, err) assert.Equal(t, invalidPattern, string(by)) // setup writer loaders writer := &bytes.Buffer{} writerLoader, wrappedWriter := NewWriterLoader(writer) // fill writer n, err := io.WriteString(wrappedWriter, invalidPattern) assert.Nil(t, err) assert.Equal(t, n, len(invalidPattern)) loaders := []JSONLoader{ NewStringLoader(invalidPattern), readerLoader, writerLoader, } for _, l := range loaders { _, err := NewSchema(l) assert.NotNil(t, err, "expected error loading invalid pattern: %T", l) } } const refPropertySchema = `{ "$id" : "http://localhost/schema.json", "properties" : { "$id" : { "$id": "http://localhost/foo.json" }, "$ref" : { "const": { "$ref" : "hello.world" } }, "const" : { "$ref" : "#/definitions/$ref" } }, "definitions" : { "$ref" : { "const": { "$ref" : "hello.world" } } }, "dependencies" : { "$ref" : [ "const" ], "const" : [ "$ref" ] } }` func TestRefProperty(t *testing.T) { schemaLoader := NewStringLoader(refPropertySchema) documentLoader := NewStringLoader(`{ "$ref" : { "$ref" : "hello.world" }, "const" : { "$ref" : "hello.world" } }`) // call the target function s, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } result, err := s.Validate(documentLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } if !result.Valid() { for _, err := range result.Errors() { fmt.Println(err.String()) } t.Errorf("Got invalid validation result.") } } func TestFragmentLoader(t *testing.T) { wd, err := os.Getwd() if err != nil { panic(err.Error()) } fileName := filepath.Join(wd, "testdata", "extra", "fragment_schema.json") schemaLoader := NewReferenceLoader("file://" + filepath.ToSlash(fileName) + "#/definitions/x") schema, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Encountered error while loading schema: %s", err.Error()) } validDocument := NewStringLoader(`5`) invalidDocument := NewStringLoader(`"a"`) result, err := schema.Validate(validDocument) if assert.Nil(t, err, "Unexpected error while validating document: %T", err) { if !result.Valid() { t.Errorf("Got invalid validation result.") } } result, err = schema.Validate(invalidDocument) if assert.Nil(t, err, "Unexpected error while validating document: %T", err) { if len(result.Errors()) != 1 || result.Errors()[0].Type() != "invalid_type" { t.Errorf("Got invalid validation result.") } } } // Inspired by http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3 const locationIndependentSchema = `{ "definitions": { "A": { "$id": "#foo" }, "B": { "$id": "http://example.com/other.json", "definitions": { "X": { "$id": "#bar", "allOf": [false] }, "Y": { "$id": "t/inner.json" } } }, "C": { "$id" : "#frag", "$ref": "http://example.com/other.json#bar" } }, "$ref": "#frag" }` func TestLocationIndependentIdentifier(t *testing.T) { schemaLoader := NewStringLoader(locationIndependentSchema) documentLoader := NewStringLoader(`{}`) s, err := NewSchema(schemaLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } result, err := s.Validate(documentLoader) if err != nil { t.Errorf("Got error: %s", err.Error()) } if len(result.Errors()) != 2 || result.Errors()[0].Type() != "number_not" || result.Errors()[1].Type() != "number_all_of" { t.Errorf("Got invalid validation result.") } } const incorrectRefSchema = `{ "$ref" : "#/fail" }` func TestIncorrectRef(t *testing.T) { schemaLoader := NewStringLoader(incorrectRefSchema) s, err := NewSchema(schemaLoader) assert.Nil(t, s) assert.Equal(t, "Object has no key 'fail'", err.Error()) }