blob: 9a7bab4907ec9b6c10dd20fe5ad386209e269c5e [file] [log] [blame]
// 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())
}