internal/mcp/jsonschema: check that schemas form a tree
When we check the root schema during resolution, first make sure its descendants form a tree. Change-Id: Icc430e7df463aa84b961c28616be567f98960430 Reviewed-on: https://go-review.googlesource.com/c/tools/+/670776 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
895b927ee8
commit
8056e5a472
2 changed files with 29 additions and 3 deletions
|
|
@ -161,14 +161,23 @@ func (r *resolver) resolveRefs(rs *Resolved) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Schema) check() error {
|
||||
if s == nil {
|
||||
func (root *Schema) check() error {
|
||||
if root == nil {
|
||||
return errors.New("nil schema")
|
||||
}
|
||||
var errs []error
|
||||
report := func(err error) { errs = append(errs, err) }
|
||||
|
||||
for ss := range s.all() {
|
||||
seen := map[*Schema]bool{}
|
||||
for ss := range root.all() {
|
||||
if seen[ss] {
|
||||
// The schema graph rooted at s is not a tree, but it needs to
|
||||
// be because we assume a unique parent when we store a schema's base
|
||||
// in the Schema. A cycle would also put Schema.all into an infinite
|
||||
// recursion.
|
||||
return fmt.Errorf("schemas rooted at %s do not form a tree (saw %s twice)", root, ss)
|
||||
}
|
||||
seen[ss] = true
|
||||
ss.checkLocal(report)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -40,6 +41,22 @@ func TestCheckLocal(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSchemaNonTree(t *testing.T) {
|
||||
run := func(s *Schema, kind string) {
|
||||
err := s.check()
|
||||
if err == nil || !strings.Contains(err.Error(), "tree") {
|
||||
t.Fatalf("did not detect %s", kind)
|
||||
}
|
||||
}
|
||||
|
||||
s := &Schema{Type: "number"}
|
||||
run(&Schema{Items: s, Contains: s}, "DAG")
|
||||
|
||||
root := &Schema{Items: s}
|
||||
s.Items = root
|
||||
run(root, "cycle")
|
||||
}
|
||||
|
||||
func TestResolveURIs(t *testing.T) {
|
||||
for _, baseURI := range []string{"", "http://a.com"} {
|
||||
t.Run(baseURI, func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue