github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/encoding/json/encode_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package json 6 7 import ( 8 "bytes" 9 "math" 10 "reflect" 11 "testing" 12 "unicode" 13 ) 14 15 type Optionals struct { 16 Sr string `json:"sr"` 17 So string `json:"so,omitempty"` 18 Sw string `json:"-"` 19 20 Ir int `json:"omitempty"` // actually named omitempty, not an option 21 Io int `json:"io,omitempty"` 22 23 Slr []string `json:"slr,random"` 24 Slo []string `json:"slo,omitempty"` 25 26 Mr map[string]interface{} `json:"mr"` 27 Mo map[string]interface{} `json:",omitempty"` 28 } 29 30 var optionalsExpected = `{ 31 "sr": "", 32 "omitempty": 0, 33 "slr": null, 34 "mr": {} 35 }` 36 37 func TestOmitEmpty(t *testing.T) { 38 var o Optionals 39 o.Sw = "something" 40 o.Mr = map[string]interface{}{} 41 o.Mo = map[string]interface{}{} 42 43 got, err := MarshalIndent(&o, "", " ") 44 if err != nil { 45 t.Fatal(err) 46 } 47 if got := string(got); got != optionalsExpected { 48 t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) 49 } 50 } 51 52 type StringTag struct { 53 BoolStr bool `json:",string"` 54 IntStr int64 `json:",string"` 55 StrStr string `json:",string"` 56 } 57 58 var stringTagExpected = `{ 59 "BoolStr": "true", 60 "IntStr": "42", 61 "StrStr": "\"xzbit\"" 62 }` 63 64 func TestStringTag(t *testing.T) { 65 var s StringTag 66 s.BoolStr = true 67 s.IntStr = 42 68 s.StrStr = "xzbit" 69 got, err := MarshalIndent(&s, "", " ") 70 if err != nil { 71 t.Fatal(err) 72 } 73 if got := string(got); got != stringTagExpected { 74 t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected) 75 } 76 77 // Verify that it round-trips. 78 var s2 StringTag 79 err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2) 80 if err != nil { 81 t.Fatalf("Decode: %v", err) 82 } 83 if !reflect.DeepEqual(s, s2) { 84 t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2) 85 } 86 } 87 88 // byte slices are special even if they're renamed types. 89 type renamedByte byte 90 type renamedByteSlice []byte 91 type renamedRenamedByteSlice []renamedByte 92 93 func TestEncodeRenamedByteSlice(t *testing.T) { 94 s := renamedByteSlice("abc") 95 result, err := Marshal(s) 96 if err != nil { 97 t.Fatal(err) 98 } 99 expect := `"YWJj"` 100 if string(result) != expect { 101 t.Errorf(" got %s want %s", result, expect) 102 } 103 r := renamedRenamedByteSlice("abc") 104 result, err = Marshal(r) 105 if err != nil { 106 t.Fatal(err) 107 } 108 if string(result) != expect { 109 t.Errorf(" got %s want %s", result, expect) 110 } 111 } 112 113 var unsupportedValues = []interface{}{ 114 math.NaN(), 115 math.Inf(-1), 116 math.Inf(1), 117 } 118 119 func TestUnsupportedValues(t *testing.T) { 120 for _, v := range unsupportedValues { 121 if _, err := Marshal(v); err != nil { 122 if _, ok := err.(*UnsupportedValueError); !ok { 123 t.Errorf("for %v, got %T want UnsupportedValueError", v, err) 124 } 125 } else { 126 t.Errorf("for %v, expected error", v) 127 } 128 } 129 } 130 131 // Ref has Marshaler and Unmarshaler methods with pointer receiver. 132 type Ref int 133 134 func (*Ref) MarshalJSON() ([]byte, error) { 135 return []byte(`"ref"`), nil 136 } 137 138 func (r *Ref) UnmarshalJSON([]byte) error { 139 *r = 12 140 return nil 141 } 142 143 // Val has Marshaler methods with value receiver. 144 type Val int 145 146 func (Val) MarshalJSON() ([]byte, error) { 147 return []byte(`"val"`), nil 148 } 149 150 // RefText has Marshaler and Unmarshaler methods with pointer receiver. 151 type RefText int 152 153 func (*RefText) MarshalText() ([]byte, error) { 154 return []byte(`"ref"`), nil 155 } 156 157 func (r *RefText) UnmarshalText([]byte) error { 158 *r = 13 159 return nil 160 } 161 162 // ValText has Marshaler methods with value receiver. 163 type ValText int 164 165 func (ValText) MarshalText() ([]byte, error) { 166 return []byte(`"val"`), nil 167 } 168 169 func TestRefValMarshal(t *testing.T) { 170 var s = struct { 171 R0 Ref 172 R1 *Ref 173 R2 RefText 174 R3 *RefText 175 V0 Val 176 V1 *Val 177 V2 ValText 178 V3 *ValText 179 }{ 180 R0: 12, 181 R1: new(Ref), 182 R2: 14, 183 R3: new(RefText), 184 V0: 13, 185 V1: new(Val), 186 V2: 15, 187 V3: new(ValText), 188 } 189 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}` 190 b, err := Marshal(&s) 191 if err != nil { 192 t.Fatalf("Marshal: %v", err) 193 } 194 if got := string(b); got != want { 195 t.Errorf("got %q, want %q", got, want) 196 } 197 } 198 199 // C implements Marshaler and returns unescaped JSON. 200 type C int 201 202 func (C) MarshalJSON() ([]byte, error) { 203 return []byte(`"<&>"`), nil 204 } 205 206 // CText implements Marshaler and returns unescaped text. 207 type CText int 208 209 func (CText) MarshalText() ([]byte, error) { 210 return []byte(`"<&>"`), nil 211 } 212 213 func TestMarshalerEscaping(t *testing.T) { 214 var c C 215 want := `"\u003c\u0026\u003e"` 216 b, err := Marshal(c) 217 if err != nil { 218 t.Fatalf("Marshal(c): %v", err) 219 } 220 if got := string(b); got != want { 221 t.Errorf("Marshal(c) = %#q, want %#q", got, want) 222 } 223 224 var ct CText 225 want = `"\"\u003c\u0026\u003e\""` 226 b, err = Marshal(ct) 227 if err != nil { 228 t.Fatalf("Marshal(ct): %v", err) 229 } 230 if got := string(b); got != want { 231 t.Errorf("Marshal(ct) = %#q, want %#q", got, want) 232 } 233 } 234 235 type IntType int 236 237 type MyStruct struct { 238 IntType 239 } 240 241 func TestAnonymousNonstruct(t *testing.T) { 242 var i IntType = 11 243 a := MyStruct{i} 244 const want = `{"IntType":11}` 245 246 b, err := Marshal(a) 247 if err != nil { 248 t.Fatalf("Marshal: %v", err) 249 } 250 if got := string(b); got != want { 251 t.Errorf("got %q, want %q", got, want) 252 } 253 } 254 255 type BugA struct { 256 S string 257 } 258 259 type BugB struct { 260 BugA 261 S string 262 } 263 264 type BugC struct { 265 S string 266 } 267 268 // Legal Go: We never use the repeated embedded field (S). 269 type BugX struct { 270 A int 271 BugA 272 BugB 273 } 274 275 // Issue 5245. 276 func TestEmbeddedBug(t *testing.T) { 277 v := BugB{ 278 BugA{"A"}, 279 "B", 280 } 281 b, err := Marshal(v) 282 if err != nil { 283 t.Fatal("Marshal:", err) 284 } 285 want := `{"S":"B"}` 286 got := string(b) 287 if got != want { 288 t.Fatalf("Marshal: got %s want %s", got, want) 289 } 290 // Now check that the duplicate field, S, does not appear. 291 x := BugX{ 292 A: 23, 293 } 294 b, err = Marshal(x) 295 if err != nil { 296 t.Fatal("Marshal:", err) 297 } 298 want = `{"A":23}` 299 got = string(b) 300 if got != want { 301 t.Fatalf("Marshal: got %s want %s", got, want) 302 } 303 } 304 305 type BugD struct { // Same as BugA after tagging. 306 XXX string `json:"S"` 307 } 308 309 // BugD's tagged S field should dominate BugA's. 310 type BugY struct { 311 BugA 312 BugD 313 } 314 315 // Test that a field with a tag dominates untagged fields. 316 func TestTaggedFieldDominates(t *testing.T) { 317 v := BugY{ 318 BugA{"BugA"}, 319 BugD{"BugD"}, 320 } 321 b, err := Marshal(v) 322 if err != nil { 323 t.Fatal("Marshal:", err) 324 } 325 want := `{"S":"BugD"}` 326 got := string(b) 327 if got != want { 328 t.Fatalf("Marshal: got %s want %s", got, want) 329 } 330 } 331 332 // There are no tags here, so S should not appear. 333 type BugZ struct { 334 BugA 335 BugC 336 BugY // Contains a tagged S field through BugD; should not dominate. 337 } 338 339 func TestDuplicatedFieldDisappears(t *testing.T) { 340 v := BugZ{ 341 BugA{"BugA"}, 342 BugC{"BugC"}, 343 BugY{ 344 BugA{"nested BugA"}, 345 BugD{"nested BugD"}, 346 }, 347 } 348 b, err := Marshal(v) 349 if err != nil { 350 t.Fatal("Marshal:", err) 351 } 352 want := `{}` 353 got := string(b) 354 if got != want { 355 t.Fatalf("Marshal: got %s want %s", got, want) 356 } 357 } 358 359 func TestStringBytes(t *testing.T) { 360 // Test that encodeState.stringBytes and encodeState.string use the same encoding. 361 es := &encodeState{} 362 var r []rune 363 for i := '\u0000'; i <= unicode.MaxRune; i++ { 364 r = append(r, i) 365 } 366 s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too 367 _, err := es.string(s) 368 if err != nil { 369 t.Fatal(err) 370 } 371 372 esBytes := &encodeState{} 373 _, err = esBytes.stringBytes([]byte(s)) 374 if err != nil { 375 t.Fatal(err) 376 } 377 378 enc := es.Buffer.String() 379 encBytes := esBytes.Buffer.String() 380 if enc != encBytes { 381 i := 0 382 for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] { 383 i++ 384 } 385 enc = enc[i:] 386 encBytes = encBytes[i:] 387 i = 0 388 for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] { 389 i++ 390 } 391 enc = enc[:len(enc)-i] 392 encBytes = encBytes[:len(encBytes)-i] 393 394 if len(enc) > 20 { 395 enc = enc[:20] + "..." 396 } 397 if len(encBytes) > 20 { 398 encBytes = encBytes[:20] + "..." 399 } 400 401 t.Errorf("encodings differ at %#q vs %#q", enc, encBytes) 402 } 403 }