87 lines
3.5 KiB
Go
87 lines
3.5 KiB
Go
package combat_semantics
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/santhosh-tekuri/jsonschema/v6"
|
|
)
|
|
|
|
func TestLoadResponseSchemaUsesStrictCombatSemanticsContract(t *testing.T) {
|
|
schema, err := loadResponseSchema()
|
|
if err != nil {
|
|
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
|
}
|
|
if schema.Key != ResponseSchemaKey || schema.ID != ResponseSchemaID || schema.Version != SchemaVersion || schema.Name != ResponseSchemaName || !strings.HasPrefix(schema.SHA256, "sha256:") || !json.Valid(schema.JSONSchema) {
|
|
t.Fatalf("schema = %#v, want private combat-semantics schema identity", schema)
|
|
}
|
|
for _, verdict := range []string{"approved", "combat_should_be_added", "combat_should_be_removed"} {
|
|
if err := validateCombatSemanticsSchema(map[string]any{"verdict": verdict, "explanation": "The chunk contains sustained attack exchanges."}, schema.JSONSchema); err != nil {
|
|
t.Fatalf("valid %q verdict rejected: %v", verdict, err)
|
|
}
|
|
}
|
|
for _, test := range []struct {
|
|
name string
|
|
response map[string]any
|
|
}{
|
|
{name: "missing explanation", response: map[string]any{"verdict": "approved"}},
|
|
{name: "missing verdict", response: map[string]any{"explanation": "The proposed kind is supported."}},
|
|
{name: "unknown property", response: map[string]any{"verdict": "approved", "explanation": "The proposed kind is supported.", "confidence": 1}},
|
|
{name: "wrong verdict type", response: map[string]any{"verdict": 1, "explanation": "The proposed kind is supported."}},
|
|
{name: "wrong explanation type", response: map[string]any{"verdict": "approved", "explanation": 1}},
|
|
{name: "unsupported verdict", response: map[string]any{"verdict": "uncertain", "explanation": "The proposed kind is supported."}},
|
|
{name: "blank explanation", response: map[string]any{"verdict": "approved", "explanation": ""}},
|
|
{name: "oversized explanation", response: map[string]any{"verdict": "approved", "explanation": strings.Repeat("a", 513)}},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if err := validateCombatSemanticsSchema(test.response, schema.JSONSchema); err == nil {
|
|
t.Fatal("invalid private response accepted")
|
|
}
|
|
})
|
|
}
|
|
if bytes.Contains(schema.JSONSchema, []byte("uniqueItems")) {
|
|
t.Fatalf("schema included unsupported uniqueItems constraint: %s", schema.JSONSchema)
|
|
}
|
|
}
|
|
|
|
func TestResponseSchemaIsMutationSafeAndDiagnosticsRedactContent(t *testing.T) {
|
|
first, err := loadResponseSchema()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
first.JSONSchema[0] = '['
|
|
second, err := loadResponseSchema()
|
|
if err != nil || !strings.HasPrefix(second.SHA256, "sha256:") || !json.Valid(second.JSONSchema) || bytes.Equal(first.JSONSchema, second.JSONSchema) {
|
|
t.Fatalf("second schema = %s, %v; want defensive copy", second.JSONSchema, err)
|
|
}
|
|
if diagnostics := second.DiagnosticsMap(); diagnostics["json_schema"] != nil {
|
|
t.Fatalf("schema diagnostics included raw content: %#v", diagnostics)
|
|
}
|
|
}
|
|
|
|
func validateCombatSemanticsSchema(instance map[string]any, schemaContent []byte) error {
|
|
instanceContent, err := json.Marshal(instance)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
parsedInstance, err := jsonschema.UnmarshalJSON(bytes.NewReader(instanceContent))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
parsedSchema, err := jsonschema.UnmarshalJSON(bytes.NewReader(schemaContent))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
compiler := jsonschema.NewCompiler()
|
|
if err := compiler.AddResource("schema.json", parsedSchema); err != nil {
|
|
return err
|
|
}
|
|
compiled, err := compiler.Compile("schema.json")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return compiled.Validate(parsedInstance)
|
|
}
|