123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- // 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 json_test
- import (
- "math"
- "strings"
- "testing"
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
- "google.golang.org/protobuf/internal/detrand"
- "google.golang.org/protobuf/internal/encoding/json"
- )
- // Disable detrand to enable direct comparisons on outputs.
- func init() { detrand.Disable() }
- // splitLines is a cmpopts.Option for comparing strings with line breaks.
- var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
- return strings.Split(s, "\n")
- })
- func TestEncoder(t *testing.T) {
- tests := []struct {
- desc string
- write func(*json.Encoder)
- wantOut string
- wantOutIndent string
- }{
- {
- desc: "null",
- write: func(e *json.Encoder) {
- e.WriteNull()
- },
- wantOut: `null`,
- },
- {
- desc: "true",
- write: func(e *json.Encoder) {
- e.WriteBool(true)
- },
- wantOut: `true`,
- },
- {
- desc: "false",
- write: func(e *json.Encoder) {
- e.WriteBool(false)
- },
- wantOut: `false`,
- },
- {
- desc: "string",
- write: func(e *json.Encoder) {
- e.WriteString("hello world")
- },
- wantOut: `"hello world"`,
- },
- {
- desc: "string contains escaped characters",
- write: func(e *json.Encoder) {
- e.WriteString("\u0000\"\\/\b\f\n\r\t")
- },
- wantOut: `"\u0000\"\\/\b\f\n\r\t"`,
- },
- {
- desc: "float64",
- write: func(e *json.Encoder) {
- e.WriteFloat(1.0199999809265137, 64)
- },
- wantOut: `1.0199999809265137`,
- },
- {
- desc: "float64 max value",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.MaxFloat64, 64)
- },
- wantOut: `1.7976931348623157e+308`,
- },
- {
- desc: "float64 min value",
- write: func(e *json.Encoder) {
- e.WriteFloat(-math.MaxFloat64, 64)
- },
- wantOut: `-1.7976931348623157e+308`,
- },
- {
- desc: "float64 NaN",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.NaN(), 64)
- },
- wantOut: `"NaN"`,
- },
- {
- desc: "float64 Infinity",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.Inf(+1), 64)
- },
- wantOut: `"Infinity"`,
- },
- {
- desc: "float64 -Infinity",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.Inf(-1), 64)
- },
- wantOut: `"-Infinity"`,
- },
- {
- desc: "float64 negative zero",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.Copysign(0, -1), 64)
- },
- wantOut: `-0`,
- },
- {
- desc: "float32",
- write: func(e *json.Encoder) {
- e.WriteFloat(1.02, 32)
- },
- wantOut: `1.02`,
- },
- {
- desc: "float32 max value",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.MaxFloat32, 32)
- },
- wantOut: `3.4028235e+38`,
- },
- {
- desc: "float32 min value",
- write: func(e *json.Encoder) {
- e.WriteFloat(-math.MaxFloat32, 32)
- },
- wantOut: `-3.4028235e+38`,
- },
- {
- desc: "float32 negative zero",
- write: func(e *json.Encoder) {
- e.WriteFloat(math.Copysign(0, -1), 32)
- },
- wantOut: `-0`,
- },
- {
- desc: "int",
- write: func(e *json.Encoder) {
- e.WriteInt(-math.MaxInt64)
- },
- wantOut: `-9223372036854775807`,
- },
- {
- desc: "uint",
- write: func(e *json.Encoder) {
- e.WriteUint(math.MaxUint64)
- },
- wantOut: `18446744073709551615`,
- },
- {
- desc: "empty object",
- write: func(e *json.Encoder) {
- e.StartObject()
- e.EndObject()
- },
- wantOut: `{}`,
- },
- {
- desc: "empty array",
- write: func(e *json.Encoder) {
- e.StartArray()
- e.EndArray()
- },
- wantOut: `[]`,
- },
- {
- desc: "object with one member",
- write: func(e *json.Encoder) {
- e.StartObject()
- e.WriteName("hello")
- e.WriteString("world")
- e.EndObject()
- },
- wantOut: `{"hello":"world"}`,
- wantOutIndent: `{
- "hello": "world"
- }`,
- },
- {
- desc: "array with one member",
- write: func(e *json.Encoder) {
- e.StartArray()
- e.WriteNull()
- e.EndArray()
- },
- wantOut: `[null]`,
- wantOutIndent: `[
- null
- ]`,
- },
- {
- desc: "simple object",
- write: func(e *json.Encoder) {
- e.StartObject()
- {
- e.WriteName("null")
- e.WriteNull()
- }
- {
- e.WriteName("bool")
- e.WriteBool(true)
- }
- {
- e.WriteName("string")
- e.WriteString("hello")
- }
- {
- e.WriteName("float")
- e.WriteFloat(6.28318, 64)
- }
- {
- e.WriteName("int")
- e.WriteInt(42)
- }
- {
- e.WriteName("uint")
- e.WriteUint(47)
- }
- e.EndObject()
- },
- wantOut: `{"null":null,"bool":true,"string":"hello","float":6.28318,"int":42,"uint":47}`,
- wantOutIndent: `{
- "null": null,
- "bool": true,
- "string": "hello",
- "float": 6.28318,
- "int": 42,
- "uint": 47
- }`,
- },
- {
- desc: "simple array",
- write: func(e *json.Encoder) {
- e.StartArray()
- {
- e.WriteString("hello")
- e.WriteFloat(6.28318, 32)
- e.WriteInt(42)
- e.WriteUint(47)
- e.WriteBool(true)
- e.WriteNull()
- }
- e.EndArray()
- },
- wantOut: `["hello",6.28318,42,47,true,null]`,
- wantOutIndent: `[
- "hello",
- 6.28318,
- 42,
- 47,
- true,
- null
- ]`,
- },
- {
- desc: "fancy object",
- write: func(e *json.Encoder) {
- e.StartObject()
- {
- e.WriteName("object0")
- e.StartObject()
- e.EndObject()
- }
- {
- e.WriteName("array0")
- e.StartArray()
- e.EndArray()
- }
- {
- e.WriteName("object1")
- e.StartObject()
- {
- e.WriteName("null")
- e.WriteNull()
- }
- {
- e.WriteName("object1-1")
- e.StartObject()
- {
- e.WriteName("bool")
- e.WriteBool(false)
- }
- {
- e.WriteName("float")
- e.WriteFloat(3.14159, 32)
- }
- e.EndObject()
- }
- e.EndObject()
- }
- {
- e.WriteName("array1")
- e.StartArray()
- {
- e.WriteNull()
- e.StartObject()
- e.EndObject()
- e.StartObject()
- {
- e.WriteName("hello")
- e.WriteString("world")
- }
- {
- e.WriteName("hola")
- e.WriteString("mundo")
- }
- e.EndObject()
- e.StartArray()
- {
- e.WriteUint(1)
- e.WriteUint(0)
- e.WriteUint(1)
- }
- e.EndArray()
- }
- e.EndArray()
- }
- e.EndObject()
- },
- wantOutIndent: `{
- "object0": {},
- "array0": [],
- "object1": {
- "null": null,
- "object1-1": {
- "bool": false,
- "float": 3.14159
- }
- },
- "array1": [
- null,
- {},
- {
- "hello": "world",
- "hola": "mundo"
- },
- [
- 1,
- 0,
- 1
- ]
- ]
- }`,
- }}
- for _, tc := range tests {
- t.Run(tc.desc, func(t *testing.T) {
- if tc.wantOut != "" {
- enc, err := json.NewEncoder(nil, "")
- if err != nil {
- t.Fatalf("NewEncoder() returned error: %v", err)
- }
- tc.write(enc)
- got := string(enc.Bytes())
- if got != tc.wantOut {
- t.Errorf("%s:\n<got>:\n%v\n<want>\n%v\n", tc.desc, got, tc.wantOut)
- }
- }
- if tc.wantOutIndent != "" {
- enc, err := json.NewEncoder(nil, "\t")
- 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("%s(indent):\n<got>:\n%v\n<want>\n%v\n<diff -want +got>\n%v\n",
- tc.desc, got, want, cmp.Diff(want, got, splitLines))
- }
- }
- })
- }
- }
- func TestWriteStringError(t *testing.T) {
- tests := []string{"abc\xff"}
- for _, in := range tests {
- t.Run(in, func(t *testing.T) {
- enc, err := json.NewEncoder(nil, "")
- if err != nil {
- t.Fatalf("NewEncoder() returned error: %v", err)
- }
- if err := enc.WriteString(in); err == nil {
- t.Errorf("WriteString(%v): got nil error, want error", in)
- }
- })
- }
- }
|