package spells import ( "encoding/json" "strings" "testing" ) func TestLoadResponseSchemaForSpells(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.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) } var decoded map[string]any if err := json.Unmarshal(schema.JSONSchema, &decoded); err != nil { t.Fatalf("Unmarshal(schema.JSONSchema) error = %v, want nil", 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) } 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) } } func TestResponseSchemaJSONIsMutationSafe(t *testing.T) { first, err := loadResponseSchema() if err != nil { t.Fatalf("loadResponseSchema() error = %v, want nil", 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") } } func TestResponseSchemaDiagnosticsOmitRawSchema(t *testing.T) { schema, err := loadResponseSchema() if err != nil { t.Fatalf("loadResponseSchema() error = %v, want nil", 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]) } } 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) } } func containsJSONField(fields []any, want string) bool { for _, field := range fields { if field == want { return true } } return false }