// Copyright 2025 The Go MCP SDK Authors. All rights reserved. // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package jsonschema import ( "encoding/json" "os" "path/filepath" "strings" "testing" ) // The test for validation uses the official test suite, expressed as a set of JSON files. // Each file is an array of group objects. // A testGroup consists of a schema and some tests on it. type testGroup struct { Description string Schema *Schema Tests []test } // A test consists of a JSON instance to be validated and the expected result. type test struct { Description string Data any Valid bool } func TestValidate(t *testing.T) { files, err := filepath.Glob(filepath.FromSlash("testdata/draft2020-12/*.json")) if err != nil { t.Fatal(err) } if len(files) == 0 { t.Fatal("no files") } for _, file := range files { base := filepath.Base(file) t.Run(base, func(t *testing.T) { f, err := os.Open(file) if err != nil { t.Fatal(err) } defer f.Close() dec := json.NewDecoder(f) var groups []testGroup if err := dec.Decode(&groups); err != nil { t.Fatal(err) } for _, g := range groups { t.Run(g.Description, func(t *testing.T) { if strings.Contains(g.Description, "remote ref") { t.Skip("remote refs not yet supported") } for s := range g.Schema.all() { if s.DynamicAnchor != "" || s.DynamicRef != "" { t.Skip("schema or subschema has unimplemented keywords") } } rs, err := g.Schema.Resolve("", nil) if err != nil { t.Fatal(err) } for _, test := range g.Tests { t.Run(test.Description, func(t *testing.T) { err = rs.Validate(test.Data) if err != nil && test.Valid { t.Errorf("wanted success, but failed with: %v", err) } if err == nil && !test.Valid { t.Error("succeeded but wanted failure") } if t.Failed() { t.Errorf("schema: %s", g.Schema.json()) t.Fatalf("instance: %v (%[1]T)", test.Data) } }) } }) } }) } } func TestStructInstance(t *testing.T) { instance := struct { I int B bool `json:"b"` u int }{1, true, 0} // The instance fails for all of these schemas, demonstrating that it // was processed correctly. for _, schema := range []*Schema{ {MinProperties: Ptr(3)}, {MaxProperties: Ptr(1)}, {Required: []string{"i"}}, // the name is "I" {Required: []string{"B"}}, // the name is "b" {PropertyNames: &Schema{MinLength: Ptr(2)}}, {Properties: map[string]*Schema{"b": {Type: "number"}}}, {Required: []string{"I"}, AdditionalProperties: falseSchema()}, {DependentRequired: map[string][]string{"b": {"u"}}}, {DependentSchemas: map[string]*Schema{"b": falseSchema()}}, {UnevaluatedProperties: falseSchema()}, } { res, err := schema.Resolve("", nil) if err != nil { t.Fatal(err) } err = res.Validate(instance) if err == nil { t.Errorf("succeeded but wanted failure; schema = %s", schema.json()) } } }