aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2025-07-31 16:21:41 -0700
committerGopher Robot <gobot@golang.org>2025-08-11 12:17:50 -0700
commit691af6ca28dad9c72e51346fe10c6aaadc3f940b (patch)
treea8ff08ab831d7baf77bea9c12df6a273d142333e /src/encoding/json
parent925149da2009589f6f2567564e1c7370e9f93b1b (diff)
downloadgo-691af6ca28dad9c72e51346fe10c6aaadc3f940b.tar.xz
encoding/json: fix Indent trailing whitespace regression in goexperiment.jsonv2
The Indent function preserves trailing whitespace, while the v1 emulation under v2 implementation accidentally dropped it. There was prior logic that attempted to preserve it, but it did not work correctly since it ran in a defer and accidentally mutated the dst input argument rather than the output argument. Move the logic to the end and avoid a defer. Also, add a test to both v1 and v1in2 to codify this behavior. This only modifies code that is compiled in under goexperiment.jsonv2. Updates #13520 Fixes #74806 Change-Id: I22b1a8da5185eb969e2a8a111b625d3752cfcbe8 Reviewed-on: https://go-review.googlesource.com/c/go/+/692195 Reviewed-by: Sean Liao <sean@liao.dev> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: David Chase <drchase@google.com> Auto-Submit: Sean Liao <sean@liao.dev>
Diffstat (limited to 'src/encoding/json')
-rw-r--r--src/encoding/json/scanner_test.go3
-rw-r--r--src/encoding/json/v2_indent.go16
-rw-r--r--src/encoding/json/v2_scanner_test.go3
3 files changed, 10 insertions, 12 deletions
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index fb64463599..a062e91243 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -74,6 +74,7 @@ func TestCompactAndIndent(t *testing.T) {
-5e+2
]`},
{Name(""), "{\"\":\"<>&\u2028\u2029\"}", "{\n\t\"\": \"<>&\u2028\u2029\"\n}"}, // See golang.org/issue/34070
+ {Name(""), `null`, "null \n\r\t"}, // See golang.org/issue/13520 and golang.org/issue/74806
}
var buf bytes.Buffer
for _, tt := range tests {
@@ -102,7 +103,7 @@ func TestCompactAndIndent(t *testing.T) {
buf.Reset()
if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
t.Errorf("%s: Indent error: %v", tt.Where, err)
- } else if got := buf.String(); got != tt.indent {
+ } else if got := buf.String(); got != strings.TrimRight(tt.indent, " \n\r\t") {
t.Errorf("%s: Compact:\n\tgot: %s\n\twant: %s", tt.Where, indentNewlines(got), indentNewlines(tt.indent))
}
})
diff --git a/src/encoding/json/v2_indent.go b/src/encoding/json/v2_indent.go
index 2655942b12..b2e8518471 100644
--- a/src/encoding/json/v2_indent.go
+++ b/src/encoding/json/v2_indent.go
@@ -88,17 +88,8 @@ func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
}
func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
- // In v2, trailing whitespace is discarded, while v1 preserved it.
- dstLen := len(dst)
- if n := len(src) - len(bytes.TrimRight(src, " \n\r\t")); n > 0 {
- // Append the trailing whitespace afterwards.
- defer func() {
- if len(dst) > dstLen {
- dst = append(dst, src[len(src)-n:]...)
- }
- }()
- }
// In v2, only spaces and tabs are allowed, while v1 allowed any character.
+ dstLen := len(dst)
if len(strings.Trim(prefix, " \t"))+len(strings.Trim(indent, " \t")) > 0 {
// Use placeholder spaces of correct length, and replace afterwards.
invalidPrefix, invalidIndent := prefix, indent
@@ -129,5 +120,10 @@ func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
if err != nil {
return dst[:dstLen], transformSyntacticError(err)
}
+
+ // In v2, trailing whitespace is discarded, while v1 preserved it.
+ if n := len(src) - len(bytes.TrimRight(src, " \n\r\t")); n > 0 {
+ dst = append(dst, src[len(src)-n:]...)
+ }
return dst, nil
}
diff --git a/src/encoding/json/v2_scanner_test.go b/src/encoding/json/v2_scanner_test.go
index bec5521274..8885520e6d 100644
--- a/src/encoding/json/v2_scanner_test.go
+++ b/src/encoding/json/v2_scanner_test.go
@@ -74,6 +74,7 @@ func TestCompactAndIndent(t *testing.T) {
-5e+2
]`},
{Name(""), "{\"\":\"<>&\u2028\u2029\"}", "{\n\t\"\": \"<>&\u2028\u2029\"\n}"}, // See golang.org/issue/34070
+ {Name(""), `null`, "null \n\r\t"}, // See golang.org/issue/13520 and golang.org/issue/74806
}
var buf bytes.Buffer
for _, tt := range tests {
@@ -102,7 +103,7 @@ func TestCompactAndIndent(t *testing.T) {
buf.Reset()
if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
t.Errorf("%s: Indent error: %v", tt.Where, err)
- } else if got := buf.String(); got != tt.indent {
+ } else if got := buf.String(); got != strings.TrimRight(tt.indent, " \n\r\t") {
t.Errorf("%s: Compact:\n\tgot: %s\n\twant: %s", tt.Where, indentNewlines(got), indentNewlines(tt.indent))
}
})