Introduce typed D&D spell artifacts
This commit is contained in:
@@ -1,130 +1,62 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadResponseSchemaForSpells(t *testing.T) {
|
||||
func TestLoadResponseSchemaUsesExtractorOwnedLLMSchema(t *testing.T) {
|
||||
schema, err := loadResponseSchema()
|
||||
if err != nil {
|
||||
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
||||
}
|
||||
if schema.Key != ResponseSchemaKey {
|
||||
t.Fatalf("schema.Key = %q, want %q", schema.Key, ResponseSchemaKey)
|
||||
if schema.Key != ResponseSchemaKey || schema.ID != ResponseSchemaID || schema.Version != SchemaVersion || schema.Name != ResponseSchemaName {
|
||||
t.Fatalf("schema identity = %#v, want maintained response identity", schema)
|
||||
}
|
||||
if schema.ID != ResponseSchemaID {
|
||||
t.Fatalf("schema.ID = %q, want %q", schema.ID, ResponseSchemaID)
|
||||
}
|
||||
if schema.Version != SchemaVersion {
|
||||
t.Fatalf("schema.Version = %q, want %q", schema.Version, SchemaVersion)
|
||||
}
|
||||
if schema.Name != ResponseSchemaName {
|
||||
t.Fatalf("schema.Name = %q, want %q", schema.Name, ResponseSchemaName)
|
||||
}
|
||||
if !strings.HasPrefix(schema.SHA256, "sha256:") {
|
||||
t.Fatalf("schema.SHA256 = %q, want sha256 prefix", schema.SHA256)
|
||||
}
|
||||
if !json.Valid(schema.JSONSchema) {
|
||||
t.Fatalf("schema.JSONSchema is invalid JSON: %s", schema.JSONSchema)
|
||||
if !strings.HasPrefix(schema.SHA256, "sha256:") || !json.Valid(schema.JSONSchema) {
|
||||
t.Fatalf("schema metadata = %#v, want valid hashed JSON", schema)
|
||||
}
|
||||
|
||||
var decoded map[string]any
|
||||
if err := json.Unmarshal(schema.JSONSchema, &decoded); err != nil {
|
||||
t.Fatalf("Unmarshal(schema.JSONSchema) error = %v, want nil", err)
|
||||
t.Fatalf("Unmarshal(schema.JSONSchema) error = %v", err)
|
||||
}
|
||||
properties := decoded["properties"].(map[string]any)
|
||||
spellCastProperties := properties["spell_casts"].(map[string]any)["items"].(map[string]any)["properties"].(map[string]any)
|
||||
sourceRefProperties := spellCastProperties["source_refs"].(map[string]any)["items"].(map[string]any)["properties"].(map[string]any)
|
||||
sourceRefRequired := spellCastProperties["source_refs"].(map[string]any)["items"].(map[string]any)["required"].([]any)
|
||||
if !containsJSONField(sourceRefRequired, "source_id") {
|
||||
t.Fatalf("canonical source refs required = %#v, want source_id", sourceRefRequired)
|
||||
}
|
||||
for _, field := range []string{"start_unit_id", "end_unit_id"} {
|
||||
property := sourceRefProperties[field].(map[string]any)
|
||||
if property["type"] != "integer" {
|
||||
t.Fatalf("%s type = %#v, want integer", field, property["type"])
|
||||
}
|
||||
if property["minimum"] != float64(1) {
|
||||
t.Fatalf("%s minimum = %#v, want 1", field, property["minimum"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLLMResponseSchemaOmitsSourceID(t *testing.T) {
|
||||
raw, err := embeddedAssets.ReadFile("assets/schemas/dnd_spells_llm.v1.json")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile(LLM schema) error = %v, want nil", err)
|
||||
}
|
||||
if !json.Valid(raw) {
|
||||
t.Fatalf("LLM schema is invalid JSON: %s", raw)
|
||||
}
|
||||
|
||||
var decoded map[string]any
|
||||
if err := json.Unmarshal(raw, &decoded); err != nil {
|
||||
t.Fatalf("Unmarshal(LLM schema) error = %v, want nil", err)
|
||||
if decoded["$id"] != "notarius.dnd.spells.llm" {
|
||||
t.Fatalf("LLM schema $id = %#v, want extractor transport schema", decoded["$id"])
|
||||
}
|
||||
properties := decoded["properties"].(map[string]any)
|
||||
spellCastProperties := properties["spell_casts"].(map[string]any)["items"].(map[string]any)["properties"].(map[string]any)
|
||||
sourceRefItems := spellCastProperties["source_refs"].(map[string]any)["items"].(map[string]any)
|
||||
sourceRefProperties := sourceRefItems["properties"].(map[string]any)
|
||||
sourceRefRequired := sourceRefItems["required"].([]any)
|
||||
if _, ok := sourceRefProperties["source_id"]; ok {
|
||||
t.Fatalf("LLM source ref schema contains source_id property: %#v", sourceRefProperties)
|
||||
}
|
||||
if containsJSONField(sourceRefRequired, "source_id") {
|
||||
t.Fatalf("LLM source refs required = %#v, want no source_id", sourceRefRequired)
|
||||
t.Fatalf("LLM source ref schema contains canonical source_id: %#v", sourceRefProperties)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseSchemaJSONIsMutationSafe(t *testing.T) {
|
||||
first, err := loadResponseSchema()
|
||||
if err != nil {
|
||||
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
||||
t.Fatalf("loadResponseSchema() error = %v", err)
|
||||
}
|
||||
first.JSONSchema[0] = '['
|
||||
|
||||
second, err := loadResponseSchema()
|
||||
if err != nil {
|
||||
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
||||
}
|
||||
if !json.Valid(second.JSONSchema) {
|
||||
t.Fatalf("schema JSON was mutated: %s", second.JSONSchema)
|
||||
}
|
||||
if len(second.JSONSchema) > 0 && second.JSONSchema[0] == '[' {
|
||||
t.Fatalf("schema JSON did not use defensive copy")
|
||||
if err != nil || !json.Valid(second.JSONSchema) || bytes.Equal(first.JSONSchema, second.JSONSchema) {
|
||||
t.Fatalf("second schema = %s, %v; want defensive valid copy", second.JSONSchema, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseSchemaDiagnosticsOmitRawSchema(t *testing.T) {
|
||||
schema, err := loadResponseSchema()
|
||||
if err != nil {
|
||||
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
||||
t.Fatalf("loadResponseSchema() error = %v", err)
|
||||
}
|
||||
diagnostics := schema.DiagnosticsMap()
|
||||
|
||||
if diagnostics["key"] != ResponseSchemaKey {
|
||||
t.Fatalf("diagnostics[key] = %#v, want %q", diagnostics["key"], ResponseSchemaKey)
|
||||
}
|
||||
for _, key := range []string{"id", "version", "name", "sha256"} {
|
||||
if diagnostics[key] == "" {
|
||||
t.Fatalf("diagnostics[%q] = %#v, want value", key, diagnostics[key])
|
||||
}
|
||||
t.Fatalf("diagnostics = %#v, want response key", diagnostics)
|
||||
}
|
||||
if _, ok := diagnostics["json_schema"]; ok {
|
||||
t.Fatalf("diagnostics should omit raw schema content: %#v", diagnostics)
|
||||
}
|
||||
if _, ok := diagnostics["JSONSchema"]; ok {
|
||||
t.Fatalf("diagnostics should omit raw schema content: %#v", diagnostics)
|
||||
t.Fatalf("diagnostics include raw schema: %#v", diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
func containsJSONField(fields []any, want string) bool {
|
||||
for _, field := range fields {
|
||||
if field == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user