Make item event responses compatible with strict schemas
This commit is contained in:
85
internal/modules/dnd/register/schema_compatibility_test.go
Normal file
85
internal/modules/dnd/register/schema_compatibility_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
|
||||
)
|
||||
|
||||
func TestRegisteredResponseSchemasRequireEveryObjectProperty(t *testing.T) {
|
||||
assets := llm.NewAssetRegistry()
|
||||
if err := Register(completeRegistries(), assets); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
schemaFS, err := assets.SchemaFS()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
count := 0
|
||||
err = fs.WalkDir(schemaFS, ".", func(path string, entry fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if entry.IsDir() || !strings.HasSuffix(path, ".json") {
|
||||
return nil
|
||||
}
|
||||
content, err := fs.ReadFile(schemaFS, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var schema any
|
||||
if err := json.Unmarshal(content, &schema); err != nil {
|
||||
t.Errorf("decode response schema %q: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
count++
|
||||
assertRequiredObjectProperties(t, path, "$", schema)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count == 0 {
|
||||
t.Fatal("no registered response schemas found")
|
||||
}
|
||||
}
|
||||
|
||||
func assertRequiredObjectProperties(t *testing.T, schemaPath, nodePath string, value any) {
|
||||
t.Helper()
|
||||
switch node := value.(type) {
|
||||
case map[string]any:
|
||||
if properties, ok := node["properties"].(map[string]any); ok {
|
||||
required := make(map[string]struct{})
|
||||
if values, ok := node["required"].([]any); ok {
|
||||
for _, value := range values {
|
||||
if name, ok := value.(string); ok {
|
||||
required[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
propertyNames := make([]string, 0, len(properties))
|
||||
for name := range properties {
|
||||
propertyNames = append(propertyNames, name)
|
||||
}
|
||||
sort.Strings(propertyNames)
|
||||
for _, name := range propertyNames {
|
||||
if _, ok := required[name]; !ok {
|
||||
t.Errorf("response schema %q object %s declares property %q without requiring it", schemaPath, nodePath, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
for name, child := range node {
|
||||
assertRequiredObjectProperties(t, schemaPath, nodePath+"."+name, child)
|
||||
}
|
||||
case []any:
|
||||
for index, child := range node {
|
||||
assertRequiredObjectProperties(t, schemaPath, nodePath+"["+strconv.Itoa(index)+"]", child)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user