Centralize output contract validation

This commit is contained in:
2026-08-11 21:21:33 +00:00
parent 8cfc71c351
commit 1cb07c7d91
11 changed files with 432 additions and 49 deletions

View File

@@ -479,6 +479,77 @@ output:
}
}
func TestPromptRepositoriesApplyOutputContractRules(t *testing.T) {
tests := []struct {
name string
output string
useFilesystem bool
wantErr bool
wantDiagnostic string
wantSchemaPath string
}{
{
name: "operating-system source rejects unsupported format",
output: " format: binary\n validation_mode: none\n",
useFilesystem: true,
wantErr: true,
wantDiagnostic: "format",
},
{
name: "fs source rejects negative repair attempts",
output: " format: text\n validation_mode: none\n repair_attempts: -1\n",
wantErr: true,
wantDiagnostic: "repair_attempts",
},
{
name: "source normalization trims a valid schema path",
output: " format: json\n validation_mode: json_schema\n schema_path: ' schema.json '\n",
useFilesystem: true,
wantSchemaPath: "schema.json",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
data := `id: output-contract
version: "1"
messages:
- role: user
content: test
output:
` + tt.output
var repo Repository
if tt.useFilesystem {
dir := t.TempDir()
writePromptTestFile(t, filepath.Join(dir, "output-contract.yaml"), data)
repo = NewFilesystemRepository(dir)
} else {
repo = NewFSRepository(fstest.MapFS{
"output-contract.yaml": &fstest.MapFile{Data: []byte(data)},
}, ".")
}
got, err := repo.GetPromptDefinition(context.Background(), "output-contract", "")
if tt.wantErr {
if !errors.Is(err, ErrInvalidPromptDefinition) {
t.Fatalf("expected ErrInvalidPromptDefinition, got %v", err)
}
if !strings.Contains(err.Error(), tt.wantDiagnostic) {
t.Fatalf("expected error containing %q, got %v", tt.wantDiagnostic, err)
}
return
}
if err != nil {
t.Fatalf("load prompt definition: %v", err)
}
if got.Validation.SchemaPath != tt.wantSchemaPath {
t.Fatalf("schema path = %q, want %q", got.Validation.SchemaPath, tt.wantSchemaPath)
}
})
}
}
func assertCacheControl(t *testing.T, got *domain.CacheControl, wantType domain.CacheControlType, wantTTL string) {
t.Helper()
if got == nil {