Avoid copying output during basic validation
This commit is contained in:
@@ -151,7 +151,8 @@ control into the rendered prompt. The
|
||||
`internal/validate` provides validators backed by an operating-system
|
||||
filesystem or an `fs.FS`. Invalid generated content is returned as a validation
|
||||
result; inability to load, register, or compile a schema is an operational
|
||||
error.
|
||||
error. Basic validation checks body emptiness on the byte slice directly
|
||||
instead of first making a response-sized string copy.
|
||||
|
||||
Every preparation operation creates one operation-local validation plan. None,
|
||||
basic, and JSON modes retain the effective output contract without source
|
||||
|
||||
@@ -188,7 +188,7 @@ func validateArtifact(ctx context.Context, artifact *domain.Artifact, contract d
|
||||
res.IsValid = true
|
||||
return res, nil
|
||||
case domain.ValidationBasic:
|
||||
empty := strings.TrimSpace(string(artifact.Body)) == ""
|
||||
empty := len(bytes.TrimSpace(artifact.Body)) == 0
|
||||
if err := ctx.Err(); err != nil {
|
||||
return domain.ValidationResult{}, err
|
||||
}
|
||||
|
||||
@@ -36,32 +36,51 @@ func TestStandardValidatorNoneSkipped(t *testing.T) {
|
||||
|
||||
func TestStandardValidatorBasicSuccess(t *testing.T) {
|
||||
v := NewStandardValidator("")
|
||||
|
||||
res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte("hello")}, domain.OutputContract{
|
||||
ValidationMode: domain.ValidationBasic,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if res.Status != domain.ValidationPassed || !res.IsValid {
|
||||
t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid)
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
body []byte
|
||||
}{
|
||||
{name: "text", body: []byte("hello")},
|
||||
{name: "invalid UTF-8 byte", body: []byte{0xff}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := v.Validate(context.Background(), &domain.Artifact{Body: tc.body}, domain.OutputContract{
|
||||
ValidationMode: domain.ValidationBasic,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if res.Status != domain.ValidationPassed || !res.IsValid {
|
||||
t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandardValidatorBasicFailureEmpty(t *testing.T) {
|
||||
v := NewStandardValidator("")
|
||||
|
||||
res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(" \n\t ")}, domain.OutputContract{
|
||||
ValidationMode: domain.ValidationBasic,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if res.Status != domain.ValidationFailed || res.IsValid {
|
||||
t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid)
|
||||
}
|
||||
if len(res.Errors) == 0 {
|
||||
t.Fatal("expected validation errors")
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
body []byte
|
||||
}{
|
||||
{name: "empty bytes", body: []byte{}},
|
||||
{name: "ASCII whitespace", body: []byte(" \n\t ")},
|
||||
{name: "Unicode whitespace", body: []byte("\u2003\u00a0\u3000")},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := v.Validate(context.Background(), &domain.Artifact{Body: tc.body}, domain.OutputContract{
|
||||
ValidationMode: domain.ValidationBasic,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if res.Status != domain.ValidationFailed || res.IsValid {
|
||||
t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid)
|
||||
}
|
||||
if len(res.Errors) == 0 {
|
||||
t.Fatal("expected validation errors")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,7 +966,8 @@ func BenchmarkBasicValidation(b *testing.B) {
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(benchmark.body)))
|
||||
// Nonempty input can be classified from its boundary bytes without
|
||||
// scanning the body, so report latency rather than bytes per second.
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
result, err := validator.Validate(ctx, artifact, contract)
|
||||
|
||||
Reference in New Issue
Block a user