internal/mcp/jsonschema: validate defaults
Optionally validate a schema's defaults when resolving it. We simply walk the tree of schemas, validating each locally. This can't handle dynamic references, which require maintaing the stack from the root. It seems unlikely that a default would require one, however. Since there may be other options to Resolve, use an options struct to future-proof it. Also, fix a bug: you can't resolve a schema twice. Change-Id: I374c582d9cc49d66d4ed56233d1070b8b3263bdf Reviewed-on: https://go-review.googlesource.com/c/tools/+/676395 Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
b0d437f1c5
commit
9e88f4ff68
1 changed files with 110 additions and 28 deletions
|
|
@ -53,7 +53,7 @@ func TestValidate(t *testing.T) {
|
|||
}
|
||||
for _, g := range groups {
|
||||
t.Run(g.Description, func(t *testing.T) {
|
||||
rs, err := g.Schema.Resolve("", loadRemote)
|
||||
rs, err := g.Schema.Resolve(&ResolveOptions{Loader: loadRemote})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ func TestValidateErrors(t *testing.T) {
|
|||
schema := &Schema{
|
||||
PrefixItems: []*Schema{{Contains: &Schema{Type: "integer"}}},
|
||||
}
|
||||
rs, err := schema.Resolve("", nil)
|
||||
rs, err := schema.Resolve(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -93,6 +93,34 @@ func TestValidateErrors(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateDefaults(t *testing.T) {
|
||||
anyptr := func(x any) *any { return &x }
|
||||
|
||||
s := &Schema{
|
||||
Properties: map[string]*Schema{
|
||||
"a": {Type: "integer", Default: anyptr(3)},
|
||||
"b": {Type: "string", Default: anyptr("s")},
|
||||
},
|
||||
Default: anyptr(map[string]any{"a": 1, "b": "two"}),
|
||||
}
|
||||
if _, err := s.Resolve(&ResolveOptions{ValidateDefaults: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s = &Schema{
|
||||
Properties: map[string]*Schema{
|
||||
"a": {Type: "integer", Default: anyptr(3)},
|
||||
"b": {Type: "string", Default: anyptr("s")},
|
||||
},
|
||||
Default: anyptr(map[string]any{"a": 1, "b": 2}),
|
||||
}
|
||||
_, err := s.Resolve(&ResolveOptions{ValidateDefaults: true})
|
||||
want := `has type "integer", want "string"`
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Resolve returned error %q, want %q", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStructInstance(t *testing.T) {
|
||||
instance := struct {
|
||||
I int
|
||||
|
|
@ -174,7 +202,7 @@ func TestStructInstance(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
} {
|
||||
res, err := tt.s.Resolve("", nil)
|
||||
res, err := tt.s.Resolve(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue