Add bounded diagnostic prefix encoding

This commit is contained in:
2026-11-05 14:06:09 +00:00
parent a4901cbb0e
commit e834e7d806
3 changed files with 86 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
package usecase
import (
"encoding/json"
"strings"
"unicode/utf8"
)
// boundedDiagnosticJSON returns a JSON string prefix and whether it represents
// the complete normalized input. It retains at most the useful prefix.
func boundedDiagnosticJSON(value string, maxBytes int) ([]byte, bool) {
if maxBytes < 2 {
return nil, false
}
limit := maxBytes - 2
var prefix strings.Builder
used := 0
more := false
for i := 0; i < len(value); {
r, size := utf8.DecodeRuneInString(value[i:])
piece := value[i : i+size]
if r == utf8.RuneError && size == 1 {
piece = "\uFFFD"
i++
for i < len(value) {
r, size = utf8.DecodeRuneInString(value[i:])
if r != utf8.RuneError || size != 1 {
break
}
i++
}
} else {
i += size
}
if used+len(piece) > limit {
more = true
break
}
prefix.WriteString(piece)
used += len(piece)
}
normalized := prefix.String()
encoded, _ := json.Marshal(normalized)
if len(encoded) > maxBytes {
return truncateDiagnosticJSONValue(normalized, maxBytes), false
}
return encoded, !more
}

View File

@@ -0,0 +1,33 @@
package usecase
import (
"encoding/json"
"strings"
"testing"
"unicode/utf8"
)
func TestBoundedDiagnosticJSON(t *testing.T) {
for _, input := range []string{"", "plain", "<&>\n\"", "雪☃", "a\xff\xfe\xffb", "\xff\xfe" + strings.Repeat("z", 100)} {
for budget := 0; budget <= 30; budget++ {
encoded, complete := boundedDiagnosticJSON(input, budget)
if budget < 2 {
if encoded != nil || complete {
t.Fatalf("budget %d: %q %v", budget, encoded, complete)
}
continue
}
if len(encoded) > budget || !utf8.Valid(encoded) {
t.Fatalf("budget %d: %q", budget, encoded)
}
var decoded string
if err := json.Unmarshal(encoded, &decoded); err != nil {
t.Fatal(err)
}
normalized := strings.ToValidUTF8(input, "\uFFFD")
if !strings.HasPrefix(normalized, decoded) || complete != (decoded == normalized) {
t.Fatalf("input %q budget %d: %q complete=%v normalized=%q", input, budget, decoded, complete, normalized)
}
}
}
}