github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/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 Fr float64 `json:"fr"` 30 Fo float64 `json:"fo,omitempty"` 31 32 Br bool `json:"br"` 33 Bo bool `json:"bo,omitempty"` 34 35 Ur uint `json:"ur"` 36 Uo uint `json:"uo,omitempty"` 37 38 Str struct{} `json:"str"` 39 Sto struct{} `json:"sto,omitempty"` 40 } 41 42 var optionalsExpected = `{ 43 "sr": "", 44 "omitempty": 0, 45 "slr": null, 46 "mr": {}, 47 "fr": 0, 48 "br": false, 49 "ur": 0, 50 "str": {}, 51 "sto": {} 52 }` 53 54 func TestOmitEmpty(t *testing.T) { 55 var o Optionals 56 o.Sw = "something" 57 o.Mr = map[string]interface{}{} 58 o.Mo = map[string]interface{}{} 59 60 got, err := MarshalIndent(&o, "", " ") 61 if err != nil { 62 t.Fatal(err) 63 } 64 if got := string(got); got != optionalsExpected { 65 t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) 66 } 67 } 68 69 type StringTag struct { 70 BoolStr bool `json:",string"` 71 IntStr int64 `json:",string"` 72 StrStr string `json:",string"` 73 } 74 75 var stringTagExpected = `{ 76 "BoolStr": "true", 77 "IntStr": "42", 78 "StrStr": "\"xzbit\"" 79 }` 80 81 func TestStringTag(t *testing.T) { 82 var s StringTag 83 s.BoolStr = true 84 s.IntStr = 42 85 s.StrStr = "xzbit" 86 got, err := MarshalIndent(&s, "", " ") 87 if err != nil { 88 t.Fatal(err) 89 } 90 if got := string(got); got != stringTagExpected { 91 t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected) 92 } 93 94 // Verify that it round-trips. 95 var s2 StringTag 96 err = NewDecoder(bytes.NewReader(got)).Decode(&s2) 97 if err != nil { 98 t.Fatalf("Decode: %v", err) 99 } 100 if !reflect.DeepEqual(s, s2) { 101 t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2) 102 } 103 } 104 105 // byte slices are special even if they're renamed types. 106 type renamedByte byte 107 type renamedByteSlice []byte 108 type renamedRenamedByteSlice []renamedByte 109 110 func TestEncodeRenamedByteSlice(t *testing.T) { 111 s := renamedByteSlice("abc") 112 result, err := Marshal(s) 113 if err != nil { 114 t.Fatal(err) 115 } 116 expect := `"YWJj"` 117 if string(result) != expect { 118 t.Errorf(" got %s want %s", result, expect) 119 } 120 r := renamedRenamedByteSlice("abc") 121 result, err = Marshal(r) 122 if err != nil { 123 t.Fatal(err) 124 } 125 if string(result) != expect { 126 t.Errorf(" got %s want %s", result, expect) 127 } 128 } 129 130 var unsupportedValues = []interface{}{ 131 math.NaN(), 132 math.Inf(-1), 133 math.Inf(1), 134 } 135 136 func TestUnsupportedValues(t *testing.T) { 137 for _, v := range unsupportedValues { 138 if _, err := Marshal(v); err != nil { 139 if _, ok := err.(*UnsupportedValueError); !ok { 140 t.Errorf("for %v, got %T want UnsupportedValueError", v, err) 141 } 142 } else { 143 t.Errorf("for %v, expected error", v) 144 } 145 } 146 } 147 148 // Ref has Marshaler and Unmarshaler methods with pointer receiver. 149 type Ref int 150 151 func (*Ref) MarshalJSON() ([]byte, error) { 152 return []byte(`"ref"`), nil 153 } 154 155 func (r *Ref) UnmarshalJSON([]byte) error { 156 *r = 12 157 return nil 158 } 159 160 // Val has Marshaler methods with value receiver. 161 type Val int 162 163 func (Val) MarshalJSON() ([]byte, error) { 164 return []byte(`"val"`), nil 165 } 166 167 // RefText has Marshaler and Unmarshaler methods with pointer receiver. 168 type RefText int 169 170 func (*RefText) MarshalText() ([]byte, error) { 171 return []byte(`"ref"`), nil 172 } 173 174 func (r *RefText) UnmarshalText([]byte) error { 175 *r = 13 176 return nil 177 } 178 179 // ValText has Marshaler methods with value receiver. 180 type ValText int 181 182 func (ValText) MarshalText() ([]byte, error) { 183 return []byte(`"val"`), nil 184 } 185 186 func TestRefValMarshal(t *testing.T) { 187 var s = struct { 188 R0 Ref 189 R1 *Ref 190 R2 RefText 191 R3 *RefText 192 V0 Val 193 V1 *Val 194 V2 ValText 195 V3 *ValText 196 }{ 197 R0: 12, 198 R1: new(Ref), 199 R2: 14, 200 R3: new(RefText), 201 V0: 13, 202 V1: new(Val), 203 V2: 15, 204 V3: new(ValText), 205 } 206 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}` 207 b, err := Marshal(&s) 208 if err != nil { 209 t.Fatalf("Marshal: %v", err) 210 } 211 if got := string(b); got != want { 212 t.Errorf("got %q, want %q", got, want) 213 } 214 } 215 216 // C implements Marshaler and returns unescaped JSON. 217 type C int 218 219 func (C) MarshalJSON() ([]byte, error) { 220 return []byte(`"<&>"`), nil 221 } 222 223 // CText implements Marshaler and returns unescaped text. 224 type CText int 225 226 func (CText) MarshalText() ([]byte, error) { 227 return []byte(`"<&>"`), nil 228 } 229 230 func TestMarshalerEscaping(t *testing.T) { 231 var c C 232 want := `"\u003c\u0026\u003e"` 233 b, err := Marshal(c) 234 if err != nil { 235 t.Fatalf("Marshal(c): %v", err) 236 } 237 if got := string(b); got != want { 238 t.Errorf("Marshal(c) = %#q, want %#q", got, want) 239 } 240 241 var ct CText 242 want = `"\"\u003c\u0026\u003e\""` 243 b, err = Marshal(ct) 244 if err != nil { 245 t.Fatalf("Marshal(ct): %v", err) 246 } 247 if got := string(b); got != want { 248 t.Errorf("Marshal(ct) = %#q, want %#q", got, want) 249 } 250 } 251 252 type IntType int 253 254 type MyStruct struct { 255 IntType 256 } 257 258 func TestAnonymousNonstruct(t *testing.T) { 259 var i IntType = 11 260 a := MyStruct{i} 261 const want = `{"IntType":11}` 262 263 b, err := Marshal(a) 264 if err != nil { 265 t.Fatalf("Marshal: %v", err) 266 } 267 if got := string(b); got != want { 268 t.Errorf("got %q, want %q", got, want) 269 } 270 } 271 272 type BugA struct { 273 S string 274 } 275 276 type BugB struct { 277 BugA 278 S string 279 } 280 281 type BugC struct { 282 S string 283 } 284 285 // Legal Go: We never use the repeated embedded field (S). 286 type BugX struct { 287 A int 288 BugA 289 BugB 290 } 291 292 // Issue 5245. 293 func TestEmbeddedBug(t *testing.T) { 294 v := BugB{ 295 BugA{"A"}, 296 "B", 297 } 298 b, err := Marshal(v) 299 if err != nil { 300 t.Fatal("Marshal:", err) 301 } 302 want := `{"S":"B"}` 303 got := string(b) 304 if got != want { 305 t.Fatalf("Marshal: got %s want %s", got, want) 306 } 307 // Now check that the duplicate field, S, does not appear. 308 x := BugX{ 309 A: 23, 310 } 311 b, err = Marshal(x) 312 if err != nil { 313 t.Fatal("Marshal:", err) 314 } 315 want = `{"A":23}` 316 got = string(b) 317 if got != want { 318 t.Fatalf("Marshal: got %s want %s", got, want) 319 } 320 } 321 322 type BugD struct { // Same as BugA after tagging. 323 XXX string `json:"S"` 324 } 325 326 // BugD's tagged S field should dominate BugA's. 327 type BugY struct { 328 BugA 329 BugD 330 } 331 332 // Test that a field with a tag dominates untagged fields. 333 func TestTaggedFieldDominates(t *testing.T) { 334 v := BugY{ 335 BugA{"BugA"}, 336 BugD{"BugD"}, 337 } 338 b, err := Marshal(v) 339 if err != nil { 340 t.Fatal("Marshal:", err) 341 } 342 want := `{"S":"BugD"}` 343 got := string(b) 344 if got != want { 345 t.Fatalf("Marshal: got %s want %s", got, want) 346 } 347 } 348 349 // There are no tags here, so S should not appear. 350 type BugZ struct { 351 BugA 352 BugC 353 BugY // Contains a tagged S field through BugD; should not dominate. 354 } 355 356 func TestDuplicatedFieldDisappears(t *testing.T) { 357 v := BugZ{ 358 BugA{"BugA"}, 359 BugC{"BugC"}, 360 BugY{ 361 BugA{"nested BugA"}, 362 BugD{"nested BugD"}, 363 }, 364 } 365 b, err := Marshal(v) 366 if err != nil { 367 t.Fatal("Marshal:", err) 368 } 369 want := `{}` 370 got := string(b) 371 if got != want { 372 t.Fatalf("Marshal: got %s want %s", got, want) 373 } 374 } 375 376 func TestStringBytes(t *testing.T) { 377 // Test that encodeState.stringBytes and encodeState.string use the same encoding. 378 es := &encodeState{} 379 var r []rune 380 for i := '\u0000'; i <= unicode.MaxRune; i++ { 381 r = append(r, i) 382 } 383 s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too 384 es.string(s) 385 386 esBytes := &encodeState{} 387 esBytes.stringBytes([]byte(s)) 388 389 enc := es.Buffer.String() 390 encBytes := esBytes.Buffer.String() 391 if enc != encBytes { 392 i := 0 393 for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] { 394 i++ 395 } 396 enc = enc[i:] 397 encBytes = encBytes[i:] 398 i = 0 399 for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] { 400 i++ 401 } 402 enc = enc[:len(enc)-i] 403 encBytes = encBytes[:len(encBytes)-i] 404 405 if len(enc) > 20 { 406 enc = enc[:20] + "..." 407 } 408 if len(encBytes) > 20 { 409 encBytes = encBytes[:20] + "..." 410 } 411 412 t.Errorf("encodings differ at %#q vs %#q", enc, encBytes) 413 } 414 } 415 416 func TestIssue6458(t *testing.T) { 417 type Foo struct { 418 M RawMessage 419 } 420 x := Foo{RawMessage(`"foo"`)} 421 422 b, err := Marshal(&x) 423 if err != nil { 424 t.Fatal(err) 425 } 426 if want := `{"M":"foo"}`; string(b) != want { 427 t.Errorf("Marshal(&x) = %#q; want %#q", b, want) 428 } 429 430 b, err = Marshal(x) 431 if err != nil { 432 t.Fatal(err) 433 } 434 435 if want := `{"M":"ImZvbyI="}`; string(b) != want { 436 t.Errorf("Marshal(x) = %#q; want %#q", b, want) 437 } 438 } 439 440 func TestIssue10281(t *testing.T) { 441 type Foo struct { 442 N Number 443 } 444 x := Foo{Number(`invalid`)} 445 446 b, err := Marshal(&x) 447 if err == nil { 448 t.Errorf("Marshal(&x) = %#q; want error", b) 449 } 450 } 451 452 func TestHTMLEscape(t *testing.T) { 453 var b, want bytes.Buffer 454 m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}` 455 want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`)) 456 HTMLEscape(&b, []byte(m)) 457 if !bytes.Equal(b.Bytes(), want.Bytes()) { 458 t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes()) 459 } 460 } 461 462 // golang.org/issue/8582 463 func TestEncodePointerString(t *testing.T) { 464 type stringPointer struct { 465 N *int64 `json:"n,string"` 466 } 467 var n int64 = 42 468 b, err := Marshal(stringPointer{N: &n}) 469 if err != nil { 470 t.Fatalf("Marshal: %v", err) 471 } 472 if got, want := string(b), `{"n":"42"}`; got != want { 473 t.Errorf("Marshal = %s, want %s", got, want) 474 } 475 var back stringPointer 476 err = Unmarshal(b, &back) 477 if err != nil { 478 t.Fatalf("Unmarshal: %v", err) 479 } 480 if back.N == nil { 481 t.Fatalf("Unmarshalled nil N field") 482 } 483 if *back.N != 42 { 484 t.Fatalf("*N = %d; want 42", *back.N) 485 } 486 } 487 488 var encodeStringTests = []struct { 489 in string 490 out string 491 }{ 492 {"\x00", `"\u0000"`}, 493 {"\x01", `"\u0001"`}, 494 {"\x02", `"\u0002"`}, 495 {"\x03", `"\u0003"`}, 496 {"\x04", `"\u0004"`}, 497 {"\x05", `"\u0005"`}, 498 {"\x06", `"\u0006"`}, 499 {"\x07", `"\u0007"`}, 500 {"\x08", `"\u0008"`}, 501 {"\x09", `"\t"`}, 502 {"\x0a", `"\n"`}, 503 {"\x0b", `"\u000b"`}, 504 {"\x0c", `"\u000c"`}, 505 {"\x0d", `"\r"`}, 506 {"\x0e", `"\u000e"`}, 507 {"\x0f", `"\u000f"`}, 508 {"\x10", `"\u0010"`}, 509 {"\x11", `"\u0011"`}, 510 {"\x12", `"\u0012"`}, 511 {"\x13", `"\u0013"`}, 512 {"\x14", `"\u0014"`}, 513 {"\x15", `"\u0015"`}, 514 {"\x16", `"\u0016"`}, 515 {"\x17", `"\u0017"`}, 516 {"\x18", `"\u0018"`}, 517 {"\x19", `"\u0019"`}, 518 {"\x1a", `"\u001a"`}, 519 {"\x1b", `"\u001b"`}, 520 {"\x1c", `"\u001c"`}, 521 {"\x1d", `"\u001d"`}, 522 {"\x1e", `"\u001e"`}, 523 {"\x1f", `"\u001f"`}, 524 } 525 526 func TestEncodeString(t *testing.T) { 527 for _, tt := range encodeStringTests { 528 b, err := Marshal(tt.in) 529 if err != nil { 530 t.Errorf("Marshal(%q): %v", tt.in, err) 531 continue 532 } 533 out := string(b) 534 if out != tt.out { 535 t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out) 536 } 537 } 538 }