| // Copyright 2009 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 | |
| import ( | |
| "bytes" | |
| "reflect" | |
| "strconv" | |
| "testing" | |
| ) | |
| type myStruct struct { | |
| T bool | |
| F bool | |
| S string | |
| I8 int8 | |
| I16 int16 | |
| I32 int32 | |
| I64 int64 | |
| U8 uint8 | |
| U16 uint16 | |
| U32 uint32 | |
| U64 uint64 | |
| I int | |
| U uint | |
| Fl float | |
| Fl32 float32 | |
| Fl64 float64 | |
| A []string | |
| My *myStruct | |
| Map map[string][]int | |
| MapStruct map[string]myStruct | |
| MapPtrStruct map[string]*myStruct | |
| } | |
| const encoded = `{"t":true,"f":false,"s":"abc","i8":1,"i16":2,"i32":3,"i64":4,` + | |
| ` "u8":5,"u16":6,"u32":7,"u64":8,` + | |
| ` "i":-9,"u":10,"bogusfield":"should be ignored",` + | |
| ` "fl":11.5,"fl32":12.25,"fl64":13.75,` + | |
| ` "a":["x","y","z"],"my":{"s":"subguy"},` + | |
| `"map":{"k1":[1,2,3],"k2":[],"k3":[3,4]},` + | |
| `"mapstruct":{"m1":{"u8":8}},` + | |
| `"mapptrstruct":{"m1":{"u8":8}}}` | |
| var decodedMap = map[string][]int{ | |
| "k1": []int{1, 2, 3}, | |
| "k2": []int{}, | |
| "k3": []int{3, 4}, | |
| } | |
| var decodedMapStruct = map[string]myStruct{ | |
| "m1": myStruct{U8: 8}, | |
| } | |
| var decodedMapPtrStruct = map[string]*myStruct{ | |
| "m1": &myStruct{U8: 8}, | |
| } | |
| func check(t *testing.T, ok bool, name string, v interface{}) { | |
| if !ok { | |
| t.Errorf("%s = %v (BAD)", name, v) | |
| } else { | |
| t.Logf("%s = %v (good)", name, v) | |
| } | |
| } | |
| const whiteSpaceEncoded = " \t{\n\"s\"\r:\"string\"\v}" | |
| func TestUnmarshalWhitespace(t *testing.T) { | |
| var m myStruct | |
| ok, errtok := Unmarshal(whiteSpaceEncoded, &m) | |
| if !ok { | |
| t.Fatalf("Unmarshal failed near %s", errtok) | |
| } | |
| check(t, m.S == "string", "string", m.S) | |
| } | |
| func TestUnmarshal(t *testing.T) { | |
| var m myStruct | |
| m.F = true | |
| ok, errtok := Unmarshal(encoded, &m) | |
| if !ok { | |
| t.Fatalf("Unmarshal failed near %s", errtok) | |
| } | |
| check(t, m.T == true, "t", m.T) | |
| check(t, m.F == false, "f", m.F) | |
| check(t, m.S == "abc", "s", m.S) | |
| check(t, m.I8 == 1, "i8", m.I8) | |
| check(t, m.I16 == 2, "i16", m.I16) | |
| check(t, m.I32 == 3, "i32", m.I32) | |
| check(t, m.I64 == 4, "i64", m.I64) | |
| check(t, m.U8 == 5, "u8", m.U8) | |
| check(t, m.U16 == 6, "u16", m.U16) | |
| check(t, m.U32 == 7, "u32", m.U32) | |
| check(t, m.U64 == 8, "u64", m.U64) | |
| check(t, m.I == -9, "i", m.I) | |
| check(t, m.U == 10, "u", m.U) | |
| check(t, m.Fl == 11.5, "fl", m.Fl) | |
| check(t, m.Fl32 == 12.25, "fl32", m.Fl32) | |
| check(t, m.Fl64 == 13.75, "fl64", m.Fl64) | |
| check(t, m.A != nil, "a", m.A) | |
| if m.A != nil { | |
| check(t, m.A[0] == "x", "a[0]", m.A[0]) | |
| check(t, m.A[1] == "y", "a[1]", m.A[1]) | |
| check(t, m.A[2] == "z", "a[2]", m.A[2]) | |
| } | |
| check(t, m.My != nil, "my", m.My) | |
| if m.My != nil { | |
| check(t, m.My.S == "subguy", "my.s", m.My.S) | |
| } | |
| check(t, reflect.DeepEqual(m.Map, decodedMap), "map", m.Map) | |
| check(t, reflect.DeepEqual(m.MapStruct, decodedMapStruct), "mapstruct", m.MapStruct) | |
| check(t, reflect.DeepEqual(m.MapPtrStruct, decodedMapPtrStruct), "mapptrstruct", m.MapPtrStruct) | |
| } | |
| type Issue147Text struct { | |
| Text string | |
| } | |
| type Issue147 struct { | |
| Test []Issue147Text | |
| } | |
| const issue147Input = `{"test": [{"text":"0"},{"text":"1"},{"text":"2"}, | |
| {"text":"3"},{"text":"4"},{"text":"5"}, | |
| {"text":"6"},{"text":"7"},{"text":"8"}, | |
| {"text":"9"},{"text":"10"},{"text":"11"}, | |
| {"text":"12"},{"text":"13"},{"text":"14"}, | |
| {"text":"15"},{"text":"16"},{"text":"17"}, | |
| {"text":"18"},{"text":"19"},{"text":"20"}, | |
| {"text":"21"},{"text":"22"},{"text":"23"}, | |
| {"text":"24"},{"text":"25"},{"text":"26"}, | |
| {"text":"27"},{"text":"28"},{"text":"29"}]}` | |
| func TestIssue147(t *testing.T) { | |
| var timeline Issue147 | |
| Unmarshal(issue147Input, &timeline) | |
| if len(timeline.Test) != 30 { | |
| t.Errorf("wrong length: got %d want 30", len(timeline.Test)) | |
| } | |
| for i, e := range timeline.Test { | |
| if e.Text != strconv.Itoa(i) { | |
| t.Errorf("index: %d got: %s want: %d", i, e.Text, i) | |
| } | |
| } | |
| } | |
| type Issue114 struct { | |
| Text string | |
| } | |
| const issue114Input = `[{"text" : "0"}, {"text" : "1"}, {"text" : "2"}, {"text" : "3"}]` | |
| func TestIssue114(t *testing.T) { | |
| var items []Issue114 | |
| Unmarshal(issue114Input, &items) | |
| if len(items) != 4 { | |
| t.Errorf("wrong length: got %d want 4", len(items)) | |
| } | |
| for i, e := range items { | |
| if e.Text != strconv.Itoa(i) { | |
| t.Errorf("index: %d got: %s want: %d", i, e.Text, i) | |
| } | |
| } | |
| } | |
| type marshalTest struct { | |
| val interface{} | |
| out string | |
| } | |
| type MTE string | |
| type OneField struct { | |
| a int | |
| } | |
| type ScalarWithString int | |
| const ( | |
| AA ScalarWithString = iota | |
| BB | |
| CC | |
| ) | |
| var scalarStrings = []string{"AA", "BB", "CC"} | |
| func (x ScalarWithString) String() string { return scalarStrings[x] } | |
| var marshalTests = []marshalTest{ | |
| // basic string | |
| marshalTest{nil, "null"}, | |
| marshalTest{true, "true"}, | |
| marshalTest{false, "false"}, | |
| marshalTest{123, "123"}, | |
| marshalTest{0.1, "0.1"}, | |
| marshalTest{1e-10, "1e-10"}, | |
| marshalTest{"teststring", `"teststring"`}, | |
| marshalTest{[4]int{1, 2, 3, 4}, "[1,2,3,4]"}, | |
| marshalTest{[]int{1, 2, 3, 4}, "[1,2,3,4]"}, | |
| marshalTest{[]interface{}{nil}, "[null]"}, | |
| marshalTest{[][]int{[]int{1, 2}, []int{3, 4}}, "[[1,2],[3,4]]"}, | |
| marshalTest{map[string]string{"one": "one"}, `{"one":"one"}`}, | |
| marshalTest{map[string]int{"one": 1}, `{"one":1}`}, | |
| marshalTest{map[string]interface{}{"null": nil}, `{"null":null}`}, | |
| marshalTest{struct{}{}, "{}"}, | |
| marshalTest{struct{ a int }{1}, `{"a":1}`}, | |
| marshalTest{struct{ a interface{} }{nil}, `{"a":null}`}, | |
| marshalTest{struct { | |
| a int | |
| b string | |
| }{1, "hello"}, | |
| `{"a":1,"b":"hello"}`, | |
| }, | |
| marshalTest{map[string][]int{"3": []int{1, 2, 3}}, `{"3":[1,2,3]}`}, | |
| marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`}, | |
| marshalTest{map[string]interface{}{"hi": 3}, `{"hi":3}`}, | |
| marshalTest{&OneField{3}, `{"a":3}`}, | |
| marshalTest{"\x05\x06", `"\u0005\u0006"`}, | |
| marshalTest{uintptr(50000), "50000"}, | |
| marshalTest{uint64(50000), "50000"}, | |
| marshalTest{uint32(50000), "50000"}, | |
| marshalTest{uint16(50000), "50000"}, | |
| marshalTest{uint8(50), "50"}, | |
| marshalTest{int64(50000), "50000"}, | |
| marshalTest{int32(50000), "50000"}, | |
| marshalTest{int16(10000), "10000"}, | |
| marshalTest{int8(50), "50"}, | |
| marshalTest{BB, "1"}, | |
| } | |
| func TestMarshal(t *testing.T) { | |
| for _, tt := range marshalTests { | |
| var buf bytes.Buffer | |
| err := Marshal(&buf, tt.val) | |
| if err != nil { | |
| t.Fatalf("Marshal(%T): %s", tt.val, err) | |
| } | |
| s := buf.String() | |
| if s != tt.out { | |
| t.Errorf("Marshal(%T) = %q, want %q\n", tt.val, s, tt.out) | |
| } | |
| } | |
| } | |
| type marshalIndentTest struct { | |
| val interface{} | |
| indent string | |
| out string | |
| } | |
| const marshalIndentTest1 = `[ | |
| 1, | |
| 2, | |
| 3, | |
| 4 | |
| ] | |
| ` | |
| const marshalIndentTest2 = `[ | |
| [ | |
| 1, | |
| 2 | |
| ], | |
| [ | |
| 3, | |
| 4 | |
| ] | |
| ] | |
| ` | |
| const marshalIndentTest3 = `[ | |
| [ | |
| 1, | |
| 2 | |
| ], | |
| [ | |
| 3, | |
| 4 | |
| ] | |
| ] | |
| ` | |
| const marshalIndentTest4 = `[ | |
| [ | |
| 1, | |
| 2 | |
| ], | |
| [ | |
| 3, | |
| 4 | |
| ] | |
| ] | |
| ` | |
| const marshalIndentTest5 = `{ | |
| "a":1, | |
| "b":"hello" | |
| } | |
| ` | |
| const marshalIndentTest6 = `{ | |
| "3":[ | |
| 1, | |
| 2, | |
| 3 | |
| ] | |
| } | |
| ` | |
| var marshalIndentTests = []marshalIndentTest{ | |
| marshalIndentTest{[]int{1, 2, 3, 4}, " ", marshalIndentTest1}, | |
| marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, "", marshalIndentTest2}, | |
| marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, " ", marshalIndentTest3}, | |
| marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, " ", marshalIndentTest4}, | |
| marshalIndentTest{struct { | |
| a int | |
| b string | |
| }{1, "hello"}, | |
| " ", | |
| marshalIndentTest5, | |
| }, | |
| marshalIndentTest{map[string][]int{"3": []int{1, 2, 3}}, " ", marshalIndentTest6}, | |
| } | |
| func TestMarshalIndent(t *testing.T) { | |
| for _, tt := range marshalIndentTests { | |
| var buf bytes.Buffer | |
| err := MarshalIndent(&buf, tt.val, tt.indent) | |
| if err != nil { | |
| t.Fatalf("MarshalIndent(%v): %s", tt.val, err) | |
| } | |
| s := buf.String() | |
| if s != tt.out { | |
| t.Errorf("MarshalIndent(%v) = %q, want %q\n", tt.val, s, tt.out) | |
| } | |
| } | |
| } | |
| type marshalErrorTest struct { | |
| val interface{} | |
| error string | |
| } | |
| type ChanVal struct { | |
| C chan int | |
| } | |
| var marshalErrorTests = []marshalErrorTest{ | |
| marshalErrorTest{map[chan int]string{make(chan int): "one"}, "json cannot encode value of type map[chan int] string"}, | |
| marshalErrorTest{make(chan int, 100), "json cannot encode value of type chan int"}, | |
| marshalErrorTest{new(ChanVal), "json cannot encode value of type chan int"}, | |
| } | |
| func TestMarshalError(t *testing.T) { | |
| for _, tt := range marshalErrorTests { | |
| var buf bytes.Buffer | |
| err := Marshal(&buf, tt.val) | |
| if err == nil { | |
| t.Fatalf("Marshal(%T): no error, want error %s", tt.val, tt.error) | |
| } | |
| if err.String() != tt.error { | |
| t.Fatalf("Marshal(%T) = error %s, want error %s", tt.val, err, tt.error) | |
| } | |
| } | |
| } |