mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-25 06:35:21 +00:00
9b3d97c473
* Fixes golang/protobuf#842. Unmarshal can now parse singular or repeated message fields without the field separator. * Fixes golang/protobuf#1011. Handles negative 0 properly. * For unknown fields with fixed 32-bit and 64-bit wire types, output is now in hex format with 0x prefix similar to C++ lib output. Previous Go implementation simply outputs these as decimal numbers %d. * All parsing errors, except for unexpected EOF should now contain line and column number info. * Fixed following conformance-related features: * Parse nan,inf,-inf,infinity,-infinity as case-insensitive. * Interpret float32 overflows as inf or -inf. * Parse large int-like number as proto float. * Discard unknown map field if DiscardUnknown=true. * Allow whitespaces/comments in Any type URL and extension field names per spec. * Improves performance and memory usage. It is now as fast and efficient as protojson, if not better on most benchmarks. name old time/op new time/op delta Text/Unmarshal/google_message1_proto2-4 14.1µs ±43% 8.7µs ±12% -38.27% (p=0.000 n=10+10) Text/Unmarshal/google_message1_proto3-4 11.6µs ±18% 7.7µs ± 9% -33.69% (p=0.000 n=10+10) Text/Unmarshal/google_message2-4 6.20ms ±27% 4.10ms ± 5% -33.95% (p=0.000 n=10+10) Text/Marshal/google_message1_proto2-4 12.8µs ± 6% 10.3µs ±23% -19.54% (p=0.000 n=9+10) Text/Marshal/google_message1_proto3-4 11.9µs ±16% 8.6µs ±10% -27.45% (p=0.000 n=10+10) Text/Marshal/google_message2-4 5.59ms ± 5% 5.30ms ±22% ~ (p=0.356 n=9+10) JSON/Unmarshal/google_message1_proto2-4 12.3µs ±61% 13.9µs ±26% ~ (p=0.190 n=10+10) JSON/Unmarshal/google_message1_proto3-4 7.51µs ± 6% 7.86µs ± 1% +4.66% (p=0.010 n=10+9) JSON/Unmarshal/google_message2-4 3.74ms ± 2% 3.94ms ± 2% +5.32% (p=0.000 n=10+10) JSON/Marshal/google_message1_proto2-4 9.90µs ±12% 9.95µs ± 4% ~ (p=0.315 n=9+10) JSON/Marshal/google_message1_proto3-4 7.55µs ± 4% 7.93µs ± 3% +4.98% (p=0.000 n=10+10) JSON/Marshal/google_message2-4 4.29ms ± 5% 4.49ms ± 2% +4.53% (p=0.001 n=10+10) name old alloc/op new alloc/op delta Text/Unmarshal/google_message1_proto2-4 12.5kB ± 0% 2.0kB ± 0% -83.87% (p=0.000 n=10+10) Text/Unmarshal/google_message1_proto3-4 12.2kB ± 0% 1.8kB ± 0% -85.33% (p=0.000 n=10+10) Text/Unmarshal/google_message2-4 5.35MB ± 0% 0.89MB ± 0% -83.28% (p=0.000 n=10+9) Text/Marshal/google_message1_proto2-4 12.0kB ± 0% 1.4kB ± 0% -88.15% (p=0.000 n=10+10) Text/Marshal/google_message1_proto3-4 12.4kB ± 0% 1.9kB ± 0% -84.91% (p=0.000 n=10+10) Text/Marshal/google_message2-4 5.64MB ± 0% 1.02MB ± 0% -81.85% (p=0.000 n=10+9) JSON/Unmarshal/google_message1_proto2-4 2.29kB ± 0% 2.29kB ± 0% ~ (all equal) JSON/Unmarshal/google_message1_proto3-4 2.08kB ± 0% 2.08kB ± 0% ~ (all equal) JSON/Unmarshal/google_message2-4 899kB ± 0% 899kB ± 0% ~ (p=1.000 n=10+10) JSON/Marshal/google_message1_proto2-4 1.46kB ± 0% 1.46kB ± 0% ~ (all equal) JSON/Marshal/google_message1_proto3-4 1.36kB ± 0% 1.36kB ± 0% ~ (all equal) JSON/Marshal/google_message2-4 1.19MB ± 0% 1.19MB ± 0% ~ (p=0.197 n=10+10) name old allocs/op new allocs/op delta Text/Unmarshal/google_message1_proto2-4 133 ± 0% 89 ± 0% -33.08% (p=0.000 n=10+10) Text/Unmarshal/google_message1_proto3-4 108 ± 0% 67 ± 0% -37.96% (p=0.000 n=10+10) Text/Unmarshal/google_message2-4 60.0k ± 0% 38.7k ± 0% -35.52% (p=0.000 n=10+10) Text/Marshal/google_message1_proto2-4 65.0 ± 0% 25.0 ± 0% -61.54% (p=0.000 n=10+10) Text/Marshal/google_message1_proto3-4 59.0 ± 0% 22.0 ± 0% -62.71% (p=0.000 n=10+10) Text/Marshal/google_message2-4 27.4k ± 0% 7.3k ± 0% -73.39% (p=0.000 n=10+10) JSON/Unmarshal/google_message1_proto2-4 95.0 ± 0% 95.0 ± 0% ~ (all equal) JSON/Unmarshal/google_message1_proto3-4 74.0 ± 0% 74.0 ± 0% ~ (all equal) JSON/Unmarshal/google_message2-4 36.3k ± 0% 36.3k ± 0% ~ (all equal) JSON/Marshal/google_message1_proto2-4 27.0 ± 0% 27.0 ± 0% ~ (all equal) JSON/Marshal/google_message1_proto3-4 30.0 ± 0% 30.0 ± 0% ~ (all equal) JSON/Marshal/google_message2-4 11.3k ± 0% 11.3k ± 0% ~ (p=1.000 n=10+10) Change-Id: I377925facde5535f06333b6f25e9c9b358dc062f Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/204602 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
550 lines
12 KiB
Go
550 lines
12 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package text_test
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf8"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"google.golang.org/protobuf/internal/detrand"
|
|
"google.golang.org/protobuf/internal/encoding/text"
|
|
)
|
|
|
|
// Disable detrand to enable direct comparisons on outputs.
|
|
func init() { detrand.Disable() }
|
|
|
|
func TestEncoder(t *testing.T) {
|
|
tests := []encoderTestCase{
|
|
{
|
|
desc: "no-opt",
|
|
write: func(e *text.Encoder) {},
|
|
wantOut: ``,
|
|
wantOutIndent: ``,
|
|
},
|
|
{
|
|
desc: "true",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("bool")
|
|
e.WriteBool(true)
|
|
},
|
|
wantOut: `bool:true`,
|
|
wantOutIndent: `bool: true`,
|
|
},
|
|
{
|
|
desc: "false",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("bool")
|
|
e.WriteBool(false)
|
|
},
|
|
wantOut: `bool:false`,
|
|
wantOutIndent: `bool: false`,
|
|
},
|
|
{
|
|
desc: "bracket name",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("[extension]")
|
|
e.WriteString("hello")
|
|
},
|
|
wantOut: `[extension]:"hello"`,
|
|
wantOutIndent: `[extension]: "hello"`,
|
|
},
|
|
{
|
|
desc: "numeric name",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("01234")
|
|
e.WriteString("hello")
|
|
},
|
|
wantOut: `01234:"hello"`,
|
|
wantOutIndent: `01234: "hello"`,
|
|
},
|
|
{
|
|
desc: "string",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("str")
|
|
e.WriteString("hello world")
|
|
},
|
|
wantOut: `str:"hello world"`,
|
|
wantOutIndent: `str: "hello world"`,
|
|
},
|
|
{
|
|
desc: "enum",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("enum")
|
|
e.WriteLiteral("ENUM_VALUE")
|
|
},
|
|
wantOut: `enum:ENUM_VALUE`,
|
|
wantOutIndent: `enum: ENUM_VALUE`,
|
|
},
|
|
{
|
|
desc: "float64",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(1.0199999809265137, 64)
|
|
},
|
|
wantOut: `float64:1.0199999809265137`,
|
|
wantOutIndent: `float64: 1.0199999809265137`,
|
|
},
|
|
{
|
|
desc: "float64 max value",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(math.MaxFloat64, 64)
|
|
},
|
|
wantOut: `float64:1.7976931348623157e+308`,
|
|
wantOutIndent: `float64: 1.7976931348623157e+308`,
|
|
},
|
|
{
|
|
desc: "float64 min value",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(-math.MaxFloat64, 64)
|
|
},
|
|
wantOut: `float64:-1.7976931348623157e+308`,
|
|
wantOutIndent: `float64: -1.7976931348623157e+308`,
|
|
},
|
|
{
|
|
desc: "float64 nan",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(math.NaN(), 64)
|
|
},
|
|
wantOut: `float64:nan`,
|
|
wantOutIndent: `float64: nan`,
|
|
},
|
|
{
|
|
desc: "float64 inf",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(math.Inf(+1), 64)
|
|
},
|
|
wantOut: `float64:inf`,
|
|
wantOutIndent: `float64: inf`,
|
|
},
|
|
{
|
|
desc: "float64 -inf",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(math.Inf(-1), 64)
|
|
},
|
|
wantOut: `float64:-inf`,
|
|
wantOutIndent: `float64: -inf`,
|
|
},
|
|
{
|
|
desc: "float64 negative zero",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float64")
|
|
e.WriteFloat(math.Copysign(0, -1), 64)
|
|
},
|
|
wantOut: `float64:-0`,
|
|
wantOutIndent: `float64: -0`,
|
|
},
|
|
{
|
|
desc: "float32",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float")
|
|
e.WriteFloat(1.02, 32)
|
|
},
|
|
wantOut: `float:1.02`,
|
|
wantOutIndent: `float: 1.02`,
|
|
},
|
|
{
|
|
desc: "float32 max value",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float32")
|
|
e.WriteFloat(math.MaxFloat32, 32)
|
|
},
|
|
wantOut: `float32:3.4028235e+38`,
|
|
wantOutIndent: `float32: 3.4028235e+38`,
|
|
},
|
|
{
|
|
desc: "float32 nan",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float32")
|
|
e.WriteFloat(math.NaN(), 32)
|
|
},
|
|
wantOut: `float32:nan`,
|
|
wantOutIndent: `float32: nan`,
|
|
},
|
|
{
|
|
desc: "float32 inf",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float32")
|
|
e.WriteFloat(math.Inf(+1), 32)
|
|
},
|
|
wantOut: `float32:inf`,
|
|
wantOutIndent: `float32: inf`,
|
|
},
|
|
{
|
|
desc: "float32 -inf",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float32")
|
|
e.WriteFloat(math.Inf(-1), 32)
|
|
},
|
|
wantOut: `float32:-inf`,
|
|
wantOutIndent: `float32: -inf`,
|
|
},
|
|
{
|
|
desc: "float32 negative zero",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("float32")
|
|
e.WriteFloat(math.Copysign(0, -1), 32)
|
|
},
|
|
wantOut: `float32:-0`,
|
|
wantOutIndent: `float32: -0`,
|
|
},
|
|
{
|
|
desc: "int64 max value",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("int")
|
|
e.WriteInt(math.MaxInt64)
|
|
},
|
|
wantOut: `int:9223372036854775807`,
|
|
wantOutIndent: `int: 9223372036854775807`,
|
|
},
|
|
{
|
|
desc: "int64 min value",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("int")
|
|
e.WriteInt(math.MinInt64)
|
|
},
|
|
wantOut: `int:-9223372036854775808`,
|
|
wantOutIndent: `int: -9223372036854775808`,
|
|
},
|
|
{
|
|
desc: "uint",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("uint")
|
|
e.WriteUint(math.MaxUint64)
|
|
},
|
|
wantOut: `uint:18446744073709551615`,
|
|
wantOutIndent: `uint: 18446744073709551615`,
|
|
},
|
|
{
|
|
desc: "empty message field",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("m")
|
|
e.StartMessage()
|
|
e.EndMessage()
|
|
},
|
|
wantOut: `m:{}`,
|
|
wantOutIndent: `m: {}`,
|
|
},
|
|
{
|
|
desc: "multiple fields",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("bool")
|
|
e.WriteBool(true)
|
|
e.WriteName("str")
|
|
e.WriteString("hello")
|
|
e.WriteName("str")
|
|
e.WriteString("world")
|
|
e.WriteName("m")
|
|
e.StartMessage()
|
|
e.EndMessage()
|
|
e.WriteName("[int]")
|
|
e.WriteInt(49)
|
|
e.WriteName("float64")
|
|
e.WriteFloat(1.00023e4, 64)
|
|
e.WriteName("101")
|
|
e.WriteString("unknown")
|
|
},
|
|
wantOut: `bool:true str:"hello" str:"world" m:{} [int]:49 float64:10002.3 101:"unknown"`,
|
|
wantOutIndent: `bool: true
|
|
str: "hello"
|
|
str: "world"
|
|
m: {}
|
|
[int]: 49
|
|
float64: 10002.3
|
|
101: "unknown"`,
|
|
},
|
|
{
|
|
desc: "populated message fields",
|
|
write: func(e *text.Encoder) {
|
|
e.WriteName("m1")
|
|
e.StartMessage()
|
|
{
|
|
e.WriteName("str")
|
|
e.WriteString("hello")
|
|
}
|
|
e.EndMessage()
|
|
|
|
e.WriteName("bool")
|
|
e.WriteBool(true)
|
|
|
|
e.WriteName("m2")
|
|
e.StartMessage()
|
|
{
|
|
e.WriteName("str")
|
|
e.WriteString("world")
|
|
e.WriteName("m2-1")
|
|
e.StartMessage()
|
|
e.EndMessage()
|
|
e.WriteName("m2-2")
|
|
e.StartMessage()
|
|
{
|
|
e.WriteName("[int]")
|
|
e.WriteInt(49)
|
|
}
|
|
e.EndMessage()
|
|
e.WriteName("float64")
|
|
e.WriteFloat(1.00023e4, 64)
|
|
}
|
|
e.EndMessage()
|
|
|
|
e.WriteName("101")
|
|
e.WriteString("unknown")
|
|
},
|
|
wantOut: `m1:{str:"hello"} bool:true m2:{str:"world" m2-1:{} m2-2:{[int]:49} float64:10002.3} 101:"unknown"`,
|
|
wantOutIndent: `m1: {
|
|
str: "hello"
|
|
}
|
|
bool: true
|
|
m2: {
|
|
str: "world"
|
|
m2-1: {}
|
|
m2-2: {
|
|
[int]: 49
|
|
}
|
|
float64: 10002.3
|
|
}
|
|
101: "unknown"`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
runEncoderTest(t, tc, [2]byte{})
|
|
|
|
// Test using the angle brackets.
|
|
// Testcases should not contain characters '{' and '}'.
|
|
tc.wantOut = replaceDelims(tc.wantOut)
|
|
tc.wantOutIndent = replaceDelims(tc.wantOutIndent)
|
|
runEncoderTest(t, tc, [2]byte{'<', '>'})
|
|
})
|
|
}
|
|
}
|
|
|
|
type encoderTestCase struct {
|
|
desc string
|
|
write func(*text.Encoder)
|
|
wantOut string
|
|
wantOutIndent string
|
|
}
|
|
|
|
func runEncoderTest(t *testing.T, tc encoderTestCase, delims [2]byte) {
|
|
t.Helper()
|
|
|
|
if tc.wantOut != "" {
|
|
enc, err := text.NewEncoder("", delims, false)
|
|
if err != nil {
|
|
t.Fatalf("NewEncoder returned error: %v", err)
|
|
}
|
|
tc.write(enc)
|
|
got := string(enc.Bytes())
|
|
if got != tc.wantOut {
|
|
t.Errorf("(compact)\n<got>\n%v\n<want>\n%v\n", got, tc.wantOut)
|
|
}
|
|
}
|
|
if tc.wantOutIndent != "" {
|
|
enc, err := text.NewEncoder("\t", delims, false)
|
|
if err != nil {
|
|
t.Fatalf("NewEncoder returned error: %v", err)
|
|
}
|
|
tc.write(enc)
|
|
got, want := string(enc.Bytes()), tc.wantOutIndent
|
|
if got != want {
|
|
t.Errorf("(multi-line)\n<got>\n%v\n<want>\n%v\n<diff -want +got>\n%v\n",
|
|
got, want, cmp.Diff(want, got))
|
|
}
|
|
}
|
|
}
|
|
|
|
func replaceDelims(s string) string {
|
|
s = strings.Replace(s, "{", "<", -1)
|
|
return strings.Replace(s, "}", ">", -1)
|
|
}
|
|
|
|
// Test for UTF-8 and ASCII outputs.
|
|
func TestEncodeStrings(t *testing.T) {
|
|
tests := []struct {
|
|
in string
|
|
wantOut string
|
|
wantOutASCII string
|
|
}{
|
|
{
|
|
in: `"`,
|
|
wantOut: `"\""`,
|
|
},
|
|
{
|
|
in: `'`,
|
|
wantOut: `"'"`,
|
|
},
|
|
{
|
|
in: "hello\u1234world",
|
|
wantOut: "\"hello\u1234world\"",
|
|
wantOutASCII: `"hello\u1234world"`,
|
|
},
|
|
{
|
|
// String that has as few escaped characters as possible.
|
|
in: func() string {
|
|
var b []byte
|
|
for i := 0; i < utf8.RuneSelf; i++ {
|
|
switch i {
|
|
case 0, '\\', '\n', '\'': // these must be escaped, so ignore them
|
|
default:
|
|
b = append(b, byte(i))
|
|
}
|
|
}
|
|
return string(b)
|
|
}(),
|
|
wantOut: `"\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_` + "`abcdefghijklmnopqrstuvwxyz{|}~\x7f\"",
|
|
wantOutASCII: `"\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_` + "`abcdefghijklmnopqrstuvwxyz{|}~\x7f\"",
|
|
},
|
|
{
|
|
// Valid UTF-8 wire encoding of the RuneError rune.
|
|
in: string(utf8.RuneError),
|
|
wantOut: `"` + string(utf8.RuneError) + `"`,
|
|
wantOutASCII: `"\ufffd"`,
|
|
},
|
|
{
|
|
in: "\"'\\?\a\b\n\r\t\v\f\x01\nS\n\xab\x12\uab8f\U0010ffff",
|
|
wantOut: `"\"'\\?\x07\x08\n\r\t\x0b\x0c\x01\nS\n\xab\x12` + "\uab8f\U0010ffff" + `"`,
|
|
wantOutASCII: `"\"'\\?\x07\x08\n\r\t\x0b\x0c\x01\nS\n\xab\x12\uab8f\U0010ffff"`,
|
|
},
|
|
{
|
|
in: "\001x",
|
|
wantOut: `"\x01x"`,
|
|
wantOutASCII: `"\x01x"`,
|
|
},
|
|
{
|
|
in: "\012x",
|
|
wantOut: `"\nx"`,
|
|
wantOutASCII: `"\nx"`,
|
|
},
|
|
{
|
|
in: "\123x",
|
|
wantOut: `"Sx"`,
|
|
wantOutASCII: `"Sx"`,
|
|
},
|
|
{
|
|
in: "\1234x",
|
|
wantOut: `"S4x"`,
|
|
wantOutASCII: `"S4x"`,
|
|
},
|
|
{
|
|
in: "\001",
|
|
wantOut: `"\x01"`,
|
|
wantOutASCII: `"\x01"`,
|
|
},
|
|
{
|
|
in: "\012",
|
|
wantOut: `"\n"`,
|
|
wantOutASCII: `"\n"`,
|
|
},
|
|
{
|
|
in: "\123",
|
|
wantOut: `"S"`,
|
|
wantOutASCII: `"S"`,
|
|
},
|
|
{
|
|
in: "\1234",
|
|
wantOut: `"S4"`,
|
|
wantOutASCII: `"S4"`,
|
|
},
|
|
{
|
|
in: "\377",
|
|
wantOut: `"\xff"`,
|
|
wantOutASCII: `"\xff"`,
|
|
},
|
|
{
|
|
in: "\x0fx",
|
|
wantOut: `"\x0fx"`,
|
|
wantOutASCII: `"\x0fx"`,
|
|
},
|
|
{
|
|
in: "\xffx",
|
|
wantOut: `"\xffx"`,
|
|
wantOutASCII: `"\xffx"`,
|
|
},
|
|
{
|
|
in: "\xfffx",
|
|
wantOut: `"\xfffx"`,
|
|
wantOutASCII: `"\xfffx"`,
|
|
},
|
|
{
|
|
in: "\x0f",
|
|
wantOut: `"\x0f"`,
|
|
wantOutASCII: `"\x0f"`,
|
|
},
|
|
{
|
|
in: "\xff",
|
|
wantOut: `"\xff"`,
|
|
wantOutASCII: `"\xff"`,
|
|
},
|
|
{
|
|
in: "\xfff",
|
|
wantOut: `"\xfff"`,
|
|
wantOutASCII: `"\xfff"`,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
if tc.wantOut != "" {
|
|
runEncodeStringsTest(t, tc.in, tc.wantOut, false)
|
|
}
|
|
if tc.wantOutASCII != "" {
|
|
runEncodeStringsTest(t, tc.in, tc.wantOutASCII, true)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func runEncodeStringsTest(t *testing.T, in string, want string, outputASCII bool) {
|
|
t.Helper()
|
|
|
|
charType := "UTF-8"
|
|
if outputASCII {
|
|
charType = "ASCII"
|
|
}
|
|
|
|
enc, err := text.NewEncoder("", [2]byte{}, outputASCII)
|
|
if err != nil {
|
|
t.Fatalf("[%s] NewEncoder returned error: %v", charType, err)
|
|
}
|
|
enc.WriteString(in)
|
|
got := string(enc.Bytes())
|
|
if got != want {
|
|
t.Errorf("[%s] WriteString(%q)\n<got>\n%v\n<want>\n%v\n", charType, in, got, want)
|
|
}
|
|
}
|
|
|
|
func TestReset(t *testing.T) {
|
|
enc, err := text.NewEncoder("\t", [2]byte{}, false)
|
|
if err != nil {
|
|
t.Fatalf("NewEncoder returned error: %v", err)
|
|
}
|
|
|
|
enc.WriteName("foo")
|
|
pos := enc.Snapshot()
|
|
|
|
// Attempt to write a message value.
|
|
enc.StartMessage()
|
|
enc.WriteName("bar")
|
|
enc.WriteUint(10)
|
|
|
|
// Reset the value and decided to write a string value instead.
|
|
enc.Reset(pos)
|
|
enc.WriteString("0123456789")
|
|
|
|
got := string(enc.Bytes())
|
|
want := `foo: "0123456789"`
|
|
if got != want {
|
|
t.Errorf("Reset did not restore given position:\n<got>\n%v\n<want>\n%v\n", got, want)
|
|
}
|
|
}
|