|
- // Copyright 2015 Google Inc. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- package gensupport
-
- import (
- "encoding/json"
- "reflect"
- "testing"
-
- "google.golang.org/api/googleapi"
- )
-
- type schema struct {
- // Basic types
- B bool `json:"b,omitempty"`
- F float64 `json:"f,omitempty"`
- I int64 `json:"i,omitempty"`
- Istr int64 `json:"istr,omitempty,string"`
- Str string `json:"str,omitempty"`
-
- // Pointers to basic types
- PB *bool `json:"pb,omitempty"`
- PF *float64 `json:"pf,omitempty"`
- PI *int64 `json:"pi,omitempty"`
- PIStr *int64 `json:"pistr,omitempty,string"`
- PStr *string `json:"pstr,omitempty"`
-
- // Other types
- Int64s googleapi.Int64s `json:"i64s,omitempty"`
- S []int `json:"s,omitempty"`
- M map[string]string `json:"m,omitempty"`
- Any interface{} `json:"any,omitempty"`
- Child *child `json:"child,omitempty"`
- MapToAnyArray map[string][]interface{} `json:"maptoanyarray,omitempty"`
-
- ForceSendFields []string `json:"-"`
- NullFields []string `json:"-"`
- }
-
- type child struct {
- B bool `json:"childbool,omitempty"`
- }
-
- type testCase struct {
- s schema
- want string
- }
-
- func TestBasics(t *testing.T) {
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
- },
- want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`,
- },
- {
- s: schema{
- NullFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
- },
- want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":null,"pf":null,"pi":null,"pistr":null,"pstr":null}`,
- },
- {
- s: schema{
- B: true,
- F: 1.2,
- I: 1,
- Istr: 2,
- Str: "a",
- PB: googleapi.Bool(true),
- PF: googleapi.Float64(1.2),
- PI: googleapi.Int64(int64(1)),
- PIStr: googleapi.Int64(int64(2)),
- PStr: googleapi.String("a"),
- },
- want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`,
- },
- {
- s: schema{
- B: false,
- F: 0.0,
- I: 0,
- Istr: 0,
- Str: "",
- PB: googleapi.Bool(false),
- PF: googleapi.Float64(0.0),
- PI: googleapi.Int64(int64(0)),
- PIStr: googleapi.Int64(int64(0)),
- PStr: googleapi.String(""),
- },
- want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
- },
- {
- s: schema{
- B: false,
- F: 0.0,
- I: 0,
- Istr: 0,
- Str: "",
- PB: googleapi.Bool(false),
- PF: googleapi.Float64(0.0),
- PI: googleapi.Int64(int64(0)),
- PIStr: googleapi.Int64(int64(0)),
- PStr: googleapi.String(""),
- ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
- },
- want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
- },
- {
- s: schema{
- B: false,
- F: 0.0,
- I: 0,
- Istr: 0,
- Str: "",
- PB: googleapi.Bool(false),
- PF: googleapi.Float64(0.0),
- PI: googleapi.Int64(int64(0)),
- PIStr: googleapi.Int64(int64(0)),
- PStr: googleapi.String(""),
- NullFields: []string{"B", "F", "I", "Istr", "Str"},
- },
- want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- func TestSliceFields(t *testing.T) {
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{S: []int{}, Int64s: googleapi.Int64s{}},
- want: `{}`,
- },
- {
- s: schema{S: []int{1}, Int64s: googleapi.Int64s{1}},
- want: `{"s":[1],"i64s":["1"]}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"S", "Int64s"},
- },
- want: `{"s":[],"i64s":[]}`,
- },
- {
- s: schema{
- S: []int{},
- Int64s: googleapi.Int64s{},
- ForceSendFields: []string{"S", "Int64s"},
- },
- want: `{"s":[],"i64s":[]}`,
- },
- {
- s: schema{
- S: []int{1},
- Int64s: googleapi.Int64s{1},
- ForceSendFields: []string{"S", "Int64s"},
- },
- want: `{"s":[1],"i64s":["1"]}`,
- },
- {
- s: schema{
- NullFields: []string{"S", "Int64s"},
- },
- want: `{"s":null,"i64s":null}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- func TestMapField(t *testing.T) {
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{M: make(map[string]string)},
- want: `{}`,
- },
- {
- s: schema{M: map[string]string{"a": "b"}},
- want: `{"m":{"a":"b"}}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"M"},
- },
- want: `{"m":{}}`,
- },
- {
- s: schema{
- NullFields: []string{"M"},
- },
- want: `{"m":null}`,
- },
- {
- s: schema{
- M: make(map[string]string),
- ForceSendFields: []string{"M"},
- },
- want: `{"m":{}}`,
- },
- {
- s: schema{
- M: make(map[string]string),
- NullFields: []string{"M"},
- },
- want: `{"m":null}`,
- },
- {
- s: schema{
- M: map[string]string{"a": "b"},
- ForceSendFields: []string{"M"},
- },
- want: `{"m":{"a":"b"}}`,
- },
- {
- s: schema{
- M: map[string]string{"a": "b"},
- NullFields: []string{"M.a", "M."},
- },
- want: `{"m": {"a": null, "":null}}`,
- },
- {
- s: schema{
- M: map[string]string{"a": "b"},
- NullFields: []string{"M.c"},
- },
- want: `{"m": {"a": "b", "c": null}}`,
- },
- {
- s: schema{
- NullFields: []string{"M.a"},
- ForceSendFields: []string{"M"},
- },
- want: `{"m": {"a": null}}`,
- },
- {
- s: schema{
- NullFields: []string{"M.a"},
- },
- want: `{}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- func TestMapToAnyArray(t *testing.T) {
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{MapToAnyArray: make(map[string][]interface{})},
- want: `{}`,
- },
- {
- s: schema{
- MapToAnyArray: map[string][]interface{}{
- "a": []interface{}{2, "b"},
- },
- },
- want: `{"maptoanyarray":{"a":[2, "b"]}}`,
- },
- {
- s: schema{
- MapToAnyArray: map[string][]interface{}{
- "a": nil,
- },
- },
- want: `{"maptoanyarray":{"a": null}}`,
- },
- {
- s: schema{
- MapToAnyArray: map[string][]interface{}{
- "a": []interface{}{nil},
- },
- },
- want: `{"maptoanyarray":{"a":[null]}}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"MapToAnyArray"},
- },
- want: `{"maptoanyarray":{}}`,
- },
- {
- s: schema{
- NullFields: []string{"MapToAnyArray"},
- },
- want: `{"maptoanyarray":null}`,
- },
- {
- s: schema{
- MapToAnyArray: make(map[string][]interface{}),
- ForceSendFields: []string{"MapToAnyArray"},
- },
- want: `{"maptoanyarray":{}}`,
- },
- {
- s: schema{
- MapToAnyArray: map[string][]interface{}{
- "a": []interface{}{2, "b"},
- },
- ForceSendFields: []string{"MapToAnyArray"},
- },
- want: `{"maptoanyarray":{"a":[2, "b"]}}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- type anyType struct {
- Field int
- }
-
- func (a anyType) MarshalJSON() ([]byte, error) {
- return []byte(`"anyType value"`), nil
- }
-
- func TestAnyField(t *testing.T) {
- // ForceSendFields has no effect on nil interfaces and interfaces that contain nil pointers.
- var nilAny *anyType
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{Any: nilAny},
- want: `{"any": null}`,
- },
- {
- s: schema{Any: &anyType{}},
- want: `{"any":"anyType value"}`,
- },
- {
- s: schema{Any: anyType{}},
- want: `{"any":"anyType value"}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"Any"},
- },
- want: `{}`,
- },
- {
- s: schema{
- NullFields: []string{"Any"},
- },
- want: `{"any":null}`,
- },
- {
- s: schema{
- Any: nilAny,
- ForceSendFields: []string{"Any"},
- },
- want: `{"any": null}`,
- },
- {
- s: schema{
- Any: &anyType{},
- ForceSendFields: []string{"Any"},
- },
- want: `{"any":"anyType value"}`,
- },
- {
- s: schema{
- Any: anyType{},
- ForceSendFields: []string{"Any"},
- },
- want: `{"any":"anyType value"}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- func TestSubschema(t *testing.T) {
- // Subschemas are always stored as pointers, so ForceSendFields has no effect on them.
- for _, tc := range []testCase{
- {
- s: schema{},
- want: `{}`,
- },
- {
- s: schema{
- ForceSendFields: []string{"Child"},
- },
- want: `{}`,
- },
- {
- s: schema{
- NullFields: []string{"Child"},
- },
- want: `{"child":null}`,
- },
- {
- s: schema{Child: &child{}},
- want: `{"child":{}}`,
- },
- {
- s: schema{
- Child: &child{},
- ForceSendFields: []string{"Child"},
- },
- want: `{"child":{}}`,
- },
- {
- s: schema{Child: &child{B: true}},
- want: `{"child":{"childbool":true}}`,
- },
-
- {
- s: schema{
- Child: &child{B: true},
- ForceSendFields: []string{"Child"},
- },
- want: `{"child":{"childbool":true}}`,
- },
- } {
- checkMarshalJSON(t, tc)
- }
- }
-
- // checkMarshalJSON verifies that calling schemaToMap on tc.s yields a result which is equivalent to tc.want.
- func checkMarshalJSON(t *testing.T, tc testCase) {
- doCheckMarshalJSON(t, tc.s, tc.s.ForceSendFields, tc.s.NullFields, tc.want)
- if len(tc.s.ForceSendFields) == 0 && len(tc.s.NullFields) == 0 {
- // verify that the code path used when ForceSendFields and NullFields
- // are non-empty produces the same output as the fast path that is used
- // when they are empty.
- doCheckMarshalJSON(t, tc.s, []string{"dummy"}, []string{"dummy"}, tc.want)
- }
- }
-
- func doCheckMarshalJSON(t *testing.T, s schema, forceSendFields, nullFields []string, wantJSON string) {
- encoded, err := MarshalJSON(s, forceSendFields, nullFields)
- if err != nil {
- t.Fatalf("encoding json:\n got err: %v", err)
- }
-
- // The expected and obtained JSON can differ in field ordering, so unmarshal before comparing.
- var got interface{}
- var want interface{}
- err = json.Unmarshal(encoded, &got)
- if err != nil {
- t.Fatalf("decoding json:\n got err: %v", err)
- }
- err = json.Unmarshal([]byte(wantJSON), &want)
- if err != nil {
- t.Fatalf("decoding json:\n got err: %v", err)
- }
- if !reflect.DeepEqual(got, want) {
- t.Errorf("schemaToMap:\ngot :%v\nwant: %v", got, want)
- }
- }
-
- func TestParseJSONTag(t *testing.T) {
- for _, tc := range []struct {
- tag string
- want jsonTag
- }{
- {
- tag: "-",
- want: jsonTag{ignore: true},
- }, {
- tag: "name,omitempty",
- want: jsonTag{apiName: "name"},
- }, {
- tag: "name,omitempty,string",
- want: jsonTag{apiName: "name", stringFormat: true},
- },
- } {
- got, err := parseJSONTag(tc.tag)
- if err != nil {
- t.Fatalf("parsing json:\n got err: %v\ntag: %q", err, tc.tag)
- }
- if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("parseJSONTage:\ngot :%v\nwant:%v", got, tc.want)
- }
- }
- }
- func TestParseMalformedJSONTag(t *testing.T) {
- for _, tag := range []string{
- "",
- "name",
- "name,",
- "name,blah",
- "name,blah,string",
- ",omitempty",
- ",omitempty,string",
- "name,omitempty,string,blah",
- } {
- _, err := parseJSONTag(tag)
- if err == nil {
- t.Fatalf("parsing json: expected err, got nil for tag: %v", tag)
- }
- }
- }
|