Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1 | // Copyright 2010 The Go Authors. All rights reserved. |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 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 ( |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 8 | "bytes" |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 9 | "encoding" |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 10 | "errors" |
Brad Fitzpatrick | f89b574 | 2011-12-15 10:02:47 -0800 | [diff] [blame] | 11 | "fmt" |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 12 | "image" |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 13 | "math" |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 14 | "math/big" |
Russ Cox | 671bddf | 2015-07-14 19:31:44 -0400 | [diff] [blame] | 15 | "net" |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 16 | "reflect" |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 17 | "strconv" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 18 | "strings" |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 19 | "testing" |
Russ Cox | d340a89 | 2013-02-14 14:46:15 -0500 | [diff] [blame] | 20 | "time" |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 21 | ) |
| 22 | |
Russ Cox | 4e5bc6a | 2010-05-11 14:38:55 -0700 | [diff] [blame] | 23 | type T struct { |
| 24 | X string |
| 25 | Y int |
David Symonds | 3be088e | 2011-09-15 08:09:43 +1000 | [diff] [blame] | 26 | Z int `json:"-"` |
Russ Cox | 4e5bc6a | 2010-05-11 14:38:55 -0700 | [diff] [blame] | 27 | } |
| 28 | |
David Symonds | c3c8e35 | 2012-05-01 11:37:44 +1000 | [diff] [blame] | 29 | type U struct { |
| 30 | Alphabet string `json:"alpha"` |
| 31 | } |
| 32 | |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 33 | type V struct { |
| 34 | F1 interface{} |
| 35 | F2 int32 |
| 36 | F3 Number |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 37 | F4 *VOuter |
| 38 | } |
| 39 | |
| 40 | type VOuter struct { |
| 41 | V V |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 42 | } |
| 43 | |
Rob Pike | 357e37d | 2013-04-09 15:00:21 -0700 | [diff] [blame] | 44 | // ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 45 | // without UseNumber |
| 46 | var ifaceNumAsFloat64 = map[string]interface{}{ |
| 47 | "k1": float64(1), |
| 48 | "k2": "s", |
| 49 | "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)}, |
| 50 | "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, |
| 51 | } |
| 52 | |
| 53 | var ifaceNumAsNumber = map[string]interface{}{ |
| 54 | "k1": Number("1"), |
| 55 | "k2": "s", |
| 56 | "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")}, |
| 57 | "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")}, |
| 58 | } |
| 59 | |
Russ Cox | a400b0e | 2010-09-28 14:40:23 -0400 | [diff] [blame] | 60 | type tx struct { |
| 61 | x int |
| 62 | } |
| 63 | |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 64 | type u8 uint8 |
| 65 | |
Rob Pike | e9c901d | 2010-11-08 15:33:00 -0800 | [diff] [blame] | 66 | // A type that can unmarshal itself. |
| 67 | |
| 68 | type unmarshaler struct { |
| 69 | T bool |
| 70 | } |
| 71 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 72 | func (u *unmarshaler) UnmarshalJSON(b []byte) error { |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 73 | *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. |
Rob Pike | e9c901d | 2010-11-08 15:33:00 -0800 | [diff] [blame] | 74 | return nil |
| 75 | } |
| 76 | |
Russ Cox | 83c7346 | 2011-08-10 09:26:51 -0400 | [diff] [blame] | 77 | type ustruct struct { |
| 78 | M unmarshaler |
| 79 | } |
| 80 | |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 81 | type unmarshalerText struct { |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 82 | A, B string |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | // needed for re-marshaling tests |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 86 | func (u unmarshalerText) MarshalText() ([]byte, error) { |
| 87 | return []byte(u.A + ":" + u.B), nil |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | func (u *unmarshalerText) UnmarshalText(b []byte) error { |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 91 | pos := bytes.Index(b, []byte(":")) |
| 92 | if pos == -1 { |
| 93 | return errors.New("missing separator") |
| 94 | } |
| 95 | u.A, u.B = string(b[:pos]), string(b[pos+1:]) |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 96 | return nil |
| 97 | } |
| 98 | |
| 99 | var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) |
| 100 | |
| 101 | type ustructText struct { |
| 102 | M unmarshalerText |
| 103 | } |
| 104 | |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 105 | // u8marshal is an integer type that can marshal/unmarshal itself. |
| 106 | type u8marshal uint8 |
| 107 | |
| 108 | func (u8 u8marshal) MarshalText() ([]byte, error) { |
| 109 | return []byte(fmt.Sprintf("u%d", u8)), nil |
| 110 | } |
| 111 | |
| 112 | var errMissingU8Prefix = errors.New("missing 'u' prefix") |
| 113 | |
| 114 | func (u8 *u8marshal) UnmarshalText(b []byte) error { |
| 115 | if !bytes.HasPrefix(b, []byte{'u'}) { |
| 116 | return errMissingU8Prefix |
| 117 | } |
| 118 | n, err := strconv.Atoi(string(b[1:])) |
| 119 | if err != nil { |
| 120 | return err |
| 121 | } |
| 122 | *u8 = u8marshal(n) |
| 123 | return nil |
| 124 | } |
| 125 | |
| 126 | var _ encoding.TextUnmarshaler = (*u8marshal)(nil) |
| 127 | |
Rob Pike | e9c901d | 2010-11-08 15:33:00 -0800 | [diff] [blame] | 128 | var ( |
| 129 | um0, um1 unmarshaler // target2 of unmarshaling |
| 130 | ump = &um1 |
| 131 | umtrue = unmarshaler{true} |
Robert Griesemer | 61650b2 | 2011-09-06 16:04:55 -0700 | [diff] [blame] | 132 | umslice = []unmarshaler{{true}} |
Russ Cox | 83c7346 | 2011-08-10 09:26:51 -0400 | [diff] [blame] | 133 | umslicep = new([]unmarshaler) |
| 134 | umstruct = ustruct{unmarshaler{true}} |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 135 | |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 136 | um0T, um1T unmarshalerText // target2 of unmarshaling |
| 137 | umpType = &um1T |
| 138 | umtrueXY = unmarshalerText{"x", "y"} |
| 139 | umsliceXY = []unmarshalerText{{"x", "y"}} |
| 140 | umslicepType = new([]unmarshalerText) |
| 141 | umstructType = new(ustructText) |
| 142 | umstructXY = ustructText{unmarshalerText{"x", "y"}} |
| 143 | |
| 144 | ummapType = map[unmarshalerText]bool{} |
| 145 | ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true} |
Rob Pike | e9c901d | 2010-11-08 15:33:00 -0800 | [diff] [blame] | 146 | ) |
| 147 | |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 148 | // Test data structures for anonymous fields. |
| 149 | |
| 150 | type Point struct { |
| 151 | Z int |
| 152 | } |
| 153 | |
| 154 | type Top struct { |
| 155 | Level0 int |
| 156 | Embed0 |
| 157 | *Embed0a |
| 158 | *Embed0b `json:"e,omitempty"` // treated as named |
| 159 | Embed0c `json:"-"` // ignored |
| 160 | Loop |
| 161 | Embed0p // has Point with X, Y, used |
| 162 | Embed0q // has Point with Z, used |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 163 | embed // contains exported field |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | type Embed0 struct { |
| 167 | Level1a int // overridden by Embed0a's Level1a with json tag |
| 168 | Level1b int // used because Embed0a's Level1b is renamed |
| 169 | Level1c int // used because Embed0a's Level1c is ignored |
| 170 | Level1d int // annihilated by Embed0a's Level1d |
| 171 | Level1e int `json:"x"` // annihilated by Embed0a.Level1e |
| 172 | } |
| 173 | |
| 174 | type Embed0a struct { |
| 175 | Level1a int `json:"Level1a,omitempty"` |
| 176 | Level1b int `json:"LEVEL1B,omitempty"` |
| 177 | Level1c int `json:"-"` |
| 178 | Level1d int // annihilated by Embed0's Level1d |
| 179 | Level1f int `json:"x"` // annihilated by Embed0's Level1e |
| 180 | } |
| 181 | |
| 182 | type Embed0b Embed0 |
| 183 | |
| 184 | type Embed0c Embed0 |
| 185 | |
| 186 | type Embed0p struct { |
| 187 | image.Point |
| 188 | } |
| 189 | |
| 190 | type Embed0q struct { |
| 191 | Point |
| 192 | } |
| 193 | |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 194 | type embed struct { |
| 195 | Q int |
| 196 | } |
| 197 | |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 198 | type Loop struct { |
| 199 | Loop1 int `json:",omitempty"` |
| 200 | Loop2 int `json:",omitempty"` |
| 201 | *Loop |
| 202 | } |
| 203 | |
| 204 | // From reflect test: |
| 205 | // The X in S6 and S7 annihilate, but they also block the X in S8.S9. |
| 206 | type S5 struct { |
| 207 | S6 |
| 208 | S7 |
| 209 | S8 |
| 210 | } |
| 211 | |
| 212 | type S6 struct { |
| 213 | X int |
| 214 | } |
| 215 | |
| 216 | type S7 S6 |
| 217 | |
| 218 | type S8 struct { |
| 219 | S9 |
| 220 | } |
| 221 | |
| 222 | type S9 struct { |
| 223 | X int |
| 224 | Y int |
| 225 | } |
| 226 | |
| 227 | // From reflect test: |
| 228 | // The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. |
| 229 | type S10 struct { |
| 230 | S11 |
| 231 | S12 |
| 232 | S13 |
| 233 | } |
| 234 | |
| 235 | type S11 struct { |
| 236 | S6 |
| 237 | } |
| 238 | |
| 239 | type S12 struct { |
| 240 | S6 |
| 241 | } |
| 242 | |
| 243 | type S13 struct { |
| 244 | S8 |
| 245 | } |
| 246 | |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 247 | type Ambig struct { |
| 248 | // Given "hello", the first match should win. |
| 249 | First int `json:"HELLO"` |
| 250 | Second int `json:"Hello"` |
| 251 | } |
| 252 | |
Russ Cox | 5d2c3a6 | 2013-09-09 19:11:05 -0400 | [diff] [blame] | 253 | type XYZ struct { |
| 254 | X interface{} |
| 255 | Y interface{} |
| 256 | Z interface{} |
| 257 | } |
| 258 | |
Russ Cox | 749b391 | 2015-07-14 21:32:47 -0400 | [diff] [blame] | 259 | func sliceAddr(x []int) *[]int { return &x } |
| 260 | func mapAddr(x map[string]int) *map[string]int { return &x } |
| 261 | |
Russ Cox | 1261023 | 2016-05-23 12:21:57 -0400 | [diff] [blame] | 262 | type byteWithMarshalJSON byte |
| 263 | |
| 264 | func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { |
| 265 | return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil |
| 266 | } |
| 267 | |
| 268 | func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { |
| 269 | if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { |
| 270 | return fmt.Errorf("bad quoted string") |
| 271 | } |
| 272 | i, err := strconv.ParseInt(string(data[2:4]), 16, 8) |
| 273 | if err != nil { |
| 274 | return fmt.Errorf("bad hex") |
| 275 | } |
| 276 | *b = byteWithMarshalJSON(i) |
| 277 | return nil |
| 278 | } |
| 279 | |
| 280 | type byteWithPtrMarshalJSON byte |
| 281 | |
| 282 | func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { |
| 283 | return byteWithMarshalJSON(*b).MarshalJSON() |
| 284 | } |
| 285 | |
| 286 | func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { |
| 287 | return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) |
| 288 | } |
| 289 | |
| 290 | type byteWithMarshalText byte |
| 291 | |
| 292 | func (b byteWithMarshalText) MarshalText() ([]byte, error) { |
| 293 | return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil |
| 294 | } |
| 295 | |
| 296 | func (b *byteWithMarshalText) UnmarshalText(data []byte) error { |
| 297 | if len(data) != 3 || data[0] != 'Z' { |
| 298 | return fmt.Errorf("bad quoted string") |
| 299 | } |
| 300 | i, err := strconv.ParseInt(string(data[1:3]), 16, 8) |
| 301 | if err != nil { |
| 302 | return fmt.Errorf("bad hex") |
| 303 | } |
| 304 | *b = byteWithMarshalText(i) |
| 305 | return nil |
| 306 | } |
| 307 | |
| 308 | type byteWithPtrMarshalText byte |
| 309 | |
| 310 | func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { |
| 311 | return byteWithMarshalText(*b).MarshalText() |
| 312 | } |
| 313 | |
| 314 | func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { |
| 315 | return (*byteWithMarshalText)(b).UnmarshalText(data) |
| 316 | } |
| 317 | |
| 318 | type intWithMarshalJSON int |
| 319 | |
| 320 | func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { |
| 321 | return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil |
| 322 | } |
| 323 | |
| 324 | func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { |
| 325 | if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { |
| 326 | return fmt.Errorf("bad quoted string") |
| 327 | } |
| 328 | i, err := strconv.ParseInt(string(data[2:4]), 16, 8) |
| 329 | if err != nil { |
| 330 | return fmt.Errorf("bad hex") |
| 331 | } |
| 332 | *b = intWithMarshalJSON(i) |
| 333 | return nil |
| 334 | } |
| 335 | |
| 336 | type intWithPtrMarshalJSON int |
| 337 | |
| 338 | func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { |
| 339 | return intWithMarshalJSON(*b).MarshalJSON() |
| 340 | } |
| 341 | |
| 342 | func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { |
| 343 | return (*intWithMarshalJSON)(b).UnmarshalJSON(data) |
| 344 | } |
| 345 | |
| 346 | type intWithMarshalText int |
| 347 | |
| 348 | func (b intWithMarshalText) MarshalText() ([]byte, error) { |
| 349 | return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil |
| 350 | } |
| 351 | |
| 352 | func (b *intWithMarshalText) UnmarshalText(data []byte) error { |
| 353 | if len(data) != 3 || data[0] != 'Z' { |
| 354 | return fmt.Errorf("bad quoted string") |
| 355 | } |
| 356 | i, err := strconv.ParseInt(string(data[1:3]), 16, 8) |
| 357 | if err != nil { |
| 358 | return fmt.Errorf("bad hex") |
| 359 | } |
| 360 | *b = intWithMarshalText(i) |
| 361 | return nil |
| 362 | } |
| 363 | |
| 364 | type intWithPtrMarshalText int |
| 365 | |
| 366 | func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { |
| 367 | return intWithMarshalText(*b).MarshalText() |
| 368 | } |
| 369 | |
| 370 | func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { |
| 371 | return (*intWithMarshalText)(b).UnmarshalText(data) |
| 372 | } |
| 373 | |
| 374 | type unmarshalTest struct { |
| 375 | in string |
| 376 | ptr interface{} |
| 377 | out interface{} |
| 378 | err error |
| 379 | useNumber bool |
| 380 | golden bool |
| 381 | } |
| 382 | |
Russ Cox | 0da30d5 | 2016-10-12 15:55:02 -0400 | [diff] [blame] | 383 | type B struct { |
| 384 | B bool `json:",string"` |
| 385 | } |
| 386 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 387 | var unmarshalTests = []unmarshalTest{ |
| 388 | // basic types |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 389 | {in: `true`, ptr: new(bool), out: true}, |
| 390 | {in: `1`, ptr: new(int), out: 1}, |
| 391 | {in: `1.2`, ptr: new(float64), out: 1.2}, |
| 392 | {in: `-5`, ptr: new(int16), out: int16(-5)}, |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 393 | {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, |
| 394 | {in: `2`, ptr: new(Number), out: Number("2")}, |
| 395 | {in: `2`, ptr: new(interface{}), out: float64(2.0)}, |
| 396 | {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true}, |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 397 | {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, |
| 398 | {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, |
| 399 | {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, |
| 400 | {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, |
| 401 | {in: "null", ptr: new(interface{}), out: nil}, |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 402 | {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}}, |
Rick Arnold | 6e3f3af | 2013-01-22 17:49:07 -0500 | [diff] [blame] | 403 | {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 404 | {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, |
| 405 | {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, |
| 406 | {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, |
| 407 | {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 408 | |
Rick Arnold | 60abc6b | 2013-01-10 17:58:45 -0800 | [diff] [blame] | 409 | // raw values with whitespace |
| 410 | {in: "\n true ", ptr: new(bool), out: true}, |
| 411 | {in: "\t 1 ", ptr: new(int), out: 1}, |
| 412 | {in: "\r 1.2 ", ptr: new(float64), out: 1.2}, |
| 413 | {in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, |
| 414 | {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, |
| 415 | |
David Symonds | 3be088e | 2011-09-15 08:09:43 +1000 | [diff] [blame] | 416 | // Z has a "-" tag. |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 417 | {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, |
David Symonds | 3be088e | 2011-09-15 08:09:43 +1000 | [diff] [blame] | 418 | |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 419 | {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, |
| 420 | {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, |
| 421 | {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, |
David Symonds | c3c8e35 | 2012-05-01 11:37:44 +1000 | [diff] [blame] | 422 | |
Anthony Martin | 2db4c3d | 2010-08-03 17:05:00 -0700 | [diff] [blame] | 423 | // syntax errors |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 424 | {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, |
| 425 | {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 426 | {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, |
Rémy Oudompheng | 4a4c39e | 2011-12-19 15:32:06 -0500 | [diff] [blame] | 427 | |
Rick Arnold | 60abc6b | 2013-01-10 17:58:45 -0800 | [diff] [blame] | 428 | // raw value errors |
| 429 | {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, |
| 430 | {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}}, |
| 431 | {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, |
| 432 | {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}}, |
| 433 | {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, |
| 434 | {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}}, |
| 435 | {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, |
| 436 | {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, |
| 437 | |
Rémy Oudompheng | 4a4c39e | 2011-12-19 15:32:06 -0500 | [diff] [blame] | 438 | // array tests |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 439 | {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, |
| 440 | {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, |
| 441 | {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, |
Anthony Martin | 2db4c3d | 2010-08-03 17:05:00 -0700 | [diff] [blame] | 442 | |
Andrey Mirtchovski | e579395 | 2013-01-30 09:10:32 -0800 | [diff] [blame] | 443 | // empty array to interface test |
| 444 | {in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, |
| 445 | {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, |
| 446 | {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, |
| 447 | {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, |
| 448 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 449 | // composite tests |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 450 | {in: allValueIndent, ptr: new(All), out: allValue}, |
| 451 | {in: allValueCompact, ptr: new(All), out: allValue}, |
| 452 | {in: allValueIndent, ptr: new(*All), out: &allValue}, |
| 453 | {in: allValueCompact, ptr: new(*All), out: &allValue}, |
| 454 | {in: pallValueIndent, ptr: new(All), out: pallValue}, |
| 455 | {in: pallValueCompact, ptr: new(All), out: pallValue}, |
| 456 | {in: pallValueIndent, ptr: new(*All), out: &pallValue}, |
| 457 | {in: pallValueCompact, ptr: new(*All), out: &pallValue}, |
Rob Pike | e9c901d | 2010-11-08 15:33:00 -0800 | [diff] [blame] | 458 | |
| 459 | // unmarshal interface test |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 460 | {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called |
| 461 | {in: `{"T":false}`, ptr: &ump, out: &umtrue}, |
| 462 | {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, |
| 463 | {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 464 | {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct}, |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 465 | |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 466 | // UnmarshalText interface test |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 467 | {in: `"x:y"`, ptr: &um0T, out: umtrueXY}, |
| 468 | {in: `"x:y"`, ptr: &umpType, out: &umtrueXY}, |
| 469 | {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY}, |
| 470 | {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, |
| 471 | {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, |
| 472 | |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 473 | // integer-keyed map test |
| 474 | { |
| 475 | in: `{"-1":"a","0":"b","1":"c"}`, |
| 476 | ptr: new(map[int]string), |
| 477 | out: map[int]string{-1: "a", 0: "b", 1: "c"}, |
| 478 | }, |
| 479 | { |
| 480 | in: `{"0":"a","10":"c","9":"b"}`, |
| 481 | ptr: new(map[u8]string), |
| 482 | out: map[u8]string{0: "a", 9: "b", 10: "c"}, |
| 483 | }, |
| 484 | { |
| 485 | in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, |
| 486 | ptr: new(map[int64]string), |
| 487 | out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, |
| 488 | }, |
| 489 | { |
| 490 | in: `{"18446744073709551615":"max"}`, |
| 491 | ptr: new(map[uint64]string), |
| 492 | out: map[uint64]string{math.MaxUint64: "max"}, |
| 493 | }, |
| 494 | { |
| 495 | in: `{"0":false,"10":true}`, |
| 496 | ptr: new(map[uintptr]bool), |
| 497 | out: map[uintptr]bool{0: false, 10: true}, |
| 498 | }, |
| 499 | |
| 500 | // Check that MarshalText and UnmarshalText take precedence |
| 501 | // over default integer handling in map keys. |
| 502 | { |
| 503 | in: `{"u2":4}`, |
| 504 | ptr: new(map[u8marshal]int), |
| 505 | out: map[u8marshal]int{2: 4}, |
| 506 | }, |
| 507 | { |
| 508 | in: `{"2":4}`, |
| 509 | ptr: new(map[u8marshal]int), |
| 510 | err: errMissingU8Prefix, |
| 511 | }, |
| 512 | |
| 513 | // integer-keyed map errors |
| 514 | { |
| 515 | in: `{"abc":"abc"}`, |
| 516 | ptr: new(map[int]string), |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 517 | err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2}, |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 518 | }, |
| 519 | { |
| 520 | in: `{"256":"abc"}`, |
| 521 | ptr: new(map[uint8]string), |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 522 | err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2}, |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 523 | }, |
| 524 | { |
| 525 | in: `{"128":"abc"}`, |
| 526 | ptr: new(map[int8]string), |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 527 | err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2}, |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 528 | }, |
| 529 | { |
| 530 | in: `{"-1":"abc"}`, |
| 531 | ptr: new(map[uint8]string), |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 532 | err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2}, |
Caleb Spare | f05c3aa | 2016-04-13 16:51:25 -0700 | [diff] [blame] | 533 | }, |
| 534 | |
| 535 | // Map keys can be encoding.TextUnmarshalers. |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 536 | {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, |
| 537 | // If multiple values for the same key exists, only the most recent value is used. |
| 538 | {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 539 | |
Russ Cox | 749b391 | 2015-07-14 21:32:47 -0400 | [diff] [blame] | 540 | // Overwriting of data. |
| 541 | // This is different from package xml, but it's what we've always done. |
| 542 | // Now documented and tested. |
| 543 | {in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}}, |
| 544 | {in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, |
| 545 | |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 546 | { |
| 547 | in: `{ |
| 548 | "Level0": 1, |
| 549 | "Level1b": 2, |
| 550 | "Level1c": 3, |
| 551 | "x": 4, |
| 552 | "Level1a": 5, |
| 553 | "LEVEL1B": 6, |
| 554 | "e": { |
| 555 | "Level1a": 8, |
| 556 | "Level1b": 9, |
| 557 | "Level1c": 10, |
| 558 | "Level1d": 11, |
| 559 | "x": 12 |
| 560 | }, |
| 561 | "Loop1": 13, |
| 562 | "Loop2": 14, |
| 563 | "X": 15, |
| 564 | "Y": 16, |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 565 | "Z": 17, |
| 566 | "Q": 18 |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 567 | }`, |
| 568 | ptr: new(Top), |
| 569 | out: Top{ |
| 570 | Level0: 1, |
| 571 | Embed0: Embed0{ |
| 572 | Level1b: 2, |
| 573 | Level1c: 3, |
| 574 | }, |
| 575 | Embed0a: &Embed0a{ |
| 576 | Level1a: 5, |
| 577 | Level1b: 6, |
| 578 | }, |
| 579 | Embed0b: &Embed0b{ |
| 580 | Level1a: 8, |
| 581 | Level1b: 9, |
| 582 | Level1c: 10, |
| 583 | Level1d: 11, |
| 584 | Level1e: 12, |
| 585 | }, |
| 586 | Loop: Loop{ |
| 587 | Loop1: 13, |
| 588 | Loop2: 14, |
| 589 | }, |
| 590 | Embed0p: Embed0p{ |
| 591 | Point: image.Point{X: 15, Y: 16}, |
| 592 | }, |
| 593 | Embed0q: Embed0q{ |
| 594 | Point: Point{Z: 17}, |
| 595 | }, |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 596 | embed: embed{ |
| 597 | Q: 18, |
| 598 | }, |
Russ Cox | f97bfb9 | 2012-09-10 23:31:40 -0400 | [diff] [blame] | 599 | }, |
| 600 | }, |
| 601 | { |
| 602 | in: `{"hello": 1}`, |
| 603 | ptr: new(Ambig), |
| 604 | out: Ambig{First: 1}, |
| 605 | }, |
| 606 | |
| 607 | { |
| 608 | in: `{"X": 1,"Y":2}`, |
| 609 | ptr: new(S5), |
| 610 | out: S5{S8: S8{S9: S9{Y: 2}}}, |
| 611 | }, |
| 612 | { |
| 613 | in: `{"X": 1,"Y":2}`, |
| 614 | ptr: new(S10), |
| 615 | out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, |
| 616 | }, |
Russ Cox | 30359a5 | 2013-02-14 14:56:01 -0500 | [diff] [blame] | 617 | |
| 618 | // invalid UTF-8 is coerced to valid UTF-8. |
| 619 | { |
| 620 | in: "\"hello\xffworld\"", |
| 621 | ptr: new(string), |
| 622 | out: "hello\ufffdworld", |
| 623 | }, |
| 624 | { |
| 625 | in: "\"hello\xc2\xc2world\"", |
| 626 | ptr: new(string), |
| 627 | out: "hello\ufffd\ufffdworld", |
| 628 | }, |
| 629 | { |
| 630 | in: "\"hello\xc2\xffworld\"", |
| 631 | ptr: new(string), |
| 632 | out: "hello\ufffd\ufffdworld", |
| 633 | }, |
| 634 | { |
| 635 | in: "\"hello\\ud800world\"", |
| 636 | ptr: new(string), |
| 637 | out: "hello\ufffdworld", |
| 638 | }, |
| 639 | { |
| 640 | in: "\"hello\\ud800\\ud800world\"", |
| 641 | ptr: new(string), |
| 642 | out: "hello\ufffd\ufffdworld", |
| 643 | }, |
| 644 | { |
| 645 | in: "\"hello\\ud800\\ud800world\"", |
| 646 | ptr: new(string), |
| 647 | out: "hello\ufffd\ufffdworld", |
| 648 | }, |
| 649 | { |
| 650 | in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", |
| 651 | ptr: new(string), |
| 652 | out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", |
| 653 | }, |
Robert Griesemer | 7e8218a | 2014-10-01 16:24:17 -0700 | [diff] [blame] | 654 | |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 655 | // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. |
Robert Griesemer | 7e8218a | 2014-10-01 16:24:17 -0700 | [diff] [blame] | 656 | { |
| 657 | in: `{"2009-11-10T23:00:00Z": "hello world"}`, |
| 658 | ptr: &map[time.Time]string{}, |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 659 | out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, |
| 660 | }, |
| 661 | |
| 662 | // issue 8305 |
| 663 | { |
| 664 | in: `{"2009-11-10T23:00:00Z": "hello world"}`, |
| 665 | ptr: &map[Point]string{}, |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 666 | err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1}, |
Augusto Roman | ffbd31e | 2016-03-08 12:41:35 -0800 | [diff] [blame] | 667 | }, |
| 668 | { |
| 669 | in: `{"asdf": "hello world"}`, |
| 670 | ptr: &map[unmarshaler]string{}, |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 671 | err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1}, |
Robert Griesemer | 7e8218a | 2014-10-01 16:24:17 -0700 | [diff] [blame] | 672 | }, |
Russ Cox | 1261023 | 2016-05-23 12:21:57 -0400 | [diff] [blame] | 673 | |
| 674 | // related to issue 13783. |
| 675 | // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, |
| 676 | // similar to marshaling a slice of typed int. |
| 677 | // These tests check that, assuming the byte type also has valid decoding methods, |
| 678 | // either the old base64 string encoding or the new per-element encoding can be |
| 679 | // successfully unmarshaled. The custom unmarshalers were accessible in earlier |
| 680 | // versions of Go, even though the custom marshaler was not. |
| 681 | { |
| 682 | in: `"AQID"`, |
| 683 | ptr: new([]byteWithMarshalJSON), |
| 684 | out: []byteWithMarshalJSON{1, 2, 3}, |
| 685 | }, |
| 686 | { |
| 687 | in: `["Z01","Z02","Z03"]`, |
| 688 | ptr: new([]byteWithMarshalJSON), |
| 689 | out: []byteWithMarshalJSON{1, 2, 3}, |
| 690 | golden: true, |
| 691 | }, |
| 692 | { |
| 693 | in: `"AQID"`, |
| 694 | ptr: new([]byteWithMarshalText), |
| 695 | out: []byteWithMarshalText{1, 2, 3}, |
| 696 | }, |
| 697 | { |
| 698 | in: `["Z01","Z02","Z03"]`, |
| 699 | ptr: new([]byteWithMarshalText), |
| 700 | out: []byteWithMarshalText{1, 2, 3}, |
| 701 | golden: true, |
| 702 | }, |
| 703 | { |
| 704 | in: `"AQID"`, |
| 705 | ptr: new([]byteWithPtrMarshalJSON), |
| 706 | out: []byteWithPtrMarshalJSON{1, 2, 3}, |
| 707 | }, |
| 708 | { |
| 709 | in: `["Z01","Z02","Z03"]`, |
| 710 | ptr: new([]byteWithPtrMarshalJSON), |
| 711 | out: []byteWithPtrMarshalJSON{1, 2, 3}, |
| 712 | golden: true, |
| 713 | }, |
| 714 | { |
| 715 | in: `"AQID"`, |
| 716 | ptr: new([]byteWithPtrMarshalText), |
| 717 | out: []byteWithPtrMarshalText{1, 2, 3}, |
| 718 | }, |
| 719 | { |
| 720 | in: `["Z01","Z02","Z03"]`, |
| 721 | ptr: new([]byteWithPtrMarshalText), |
| 722 | out: []byteWithPtrMarshalText{1, 2, 3}, |
| 723 | golden: true, |
| 724 | }, |
| 725 | |
| 726 | // ints work with the marshaler but not the base64 []byte case |
| 727 | { |
| 728 | in: `["Z01","Z02","Z03"]`, |
| 729 | ptr: new([]intWithMarshalJSON), |
| 730 | out: []intWithMarshalJSON{1, 2, 3}, |
| 731 | golden: true, |
| 732 | }, |
| 733 | { |
| 734 | in: `["Z01","Z02","Z03"]`, |
| 735 | ptr: new([]intWithMarshalText), |
| 736 | out: []intWithMarshalText{1, 2, 3}, |
| 737 | golden: true, |
| 738 | }, |
| 739 | { |
| 740 | in: `["Z01","Z02","Z03"]`, |
| 741 | ptr: new([]intWithPtrMarshalJSON), |
| 742 | out: []intWithPtrMarshalJSON{1, 2, 3}, |
| 743 | golden: true, |
| 744 | }, |
| 745 | { |
| 746 | in: `["Z01","Z02","Z03"]`, |
| 747 | ptr: new([]intWithPtrMarshalText), |
| 748 | out: []intWithPtrMarshalText{1, 2, 3}, |
| 749 | golden: true, |
| 750 | }, |
Russ Cox | 92b3e36 | 2016-10-05 11:26:04 -0400 | [diff] [blame] | 751 | |
| 752 | {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true}, |
| 753 | {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true}, |
| 754 | {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true}, |
| 755 | {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true}, |
| 756 | {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true}, |
| 757 | {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true}, |
| 758 | {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true}, |
| 759 | {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true}, |
| 760 | {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true}, |
| 761 | {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true}, |
| 762 | {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false}, |
Jirka Daněk | b9fd510 | 2016-01-18 16:26:05 +0100 | [diff] [blame] | 763 | |
| 764 | { |
| 765 | in: `{"V": {"F2": "hello"}}`, |
| 766 | ptr: new(VOuter), |
| 767 | err: &UnmarshalTypeError{ |
| 768 | Value: "string", |
| 769 | Struct: "V", |
| 770 | Field: "F2", |
| 771 | Type: reflect.TypeOf(int32(0)), |
| 772 | Offset: 20, |
| 773 | }, |
| 774 | }, |
| 775 | { |
| 776 | in: `{"V": {"F4": {}, "F2": "hello"}}`, |
| 777 | ptr: new(VOuter), |
| 778 | err: &UnmarshalTypeError{ |
| 779 | Value: "string", |
| 780 | Struct: "V", |
| 781 | Field: "F2", |
| 782 | Type: reflect.TypeOf(int32(0)), |
| 783 | Offset: 30, |
| 784 | }, |
| 785 | }, |
Russ Cox | 0da30d5 | 2016-10-12 15:55:02 -0400 | [diff] [blame] | 786 | |
| 787 | // issue 15146. |
| 788 | // invalid inputs in wrongStringTests below. |
| 789 | {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true}, |
| 790 | {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true}, |
| 791 | {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)}, |
| 792 | {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)}, |
| 793 | {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, |
| 794 | {in: `{"B": "null"}`, ptr: new(B), out: B{false}}, |
| 795 | {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 796 | } |
| 797 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 798 | func TestMarshal(t *testing.T) { |
| 799 | b, err := Marshal(allValue) |
| 800 | if err != nil { |
| 801 | t.Fatalf("Marshal allValue: %v", err) |
| 802 | } |
| 803 | if string(b) != allValueCompact { |
| 804 | t.Errorf("Marshal allValueCompact") |
| 805 | diff(t, b, []byte(allValueCompact)) |
| 806 | return |
| 807 | } |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 808 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 809 | b, err = Marshal(pallValue) |
| 810 | if err != nil { |
| 811 | t.Fatalf("Marshal pallValue: %v", err) |
| 812 | } |
| 813 | if string(b) != pallValueCompact { |
| 814 | t.Errorf("Marshal pallValueCompact") |
| 815 | diff(t, b, []byte(pallValueCompact)) |
| 816 | return |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 817 | } |
| 818 | } |
| 819 | |
Russ Cox | 4274d07 | 2013-07-12 20:40:50 -0400 | [diff] [blame] | 820 | var badUTF8 = []struct { |
| 821 | in, out string |
| 822 | }{ |
| 823 | {"hello\xffworld", `"hello\ufffdworld"`}, |
| 824 | {"", `""`}, |
| 825 | {"\xff", `"\ufffd"`}, |
| 826 | {"\xff\xff", `"\ufffd\ufffd"`}, |
| 827 | {"a\xffb", `"a\ufffdb"`}, |
| 828 | {"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`}, |
| 829 | } |
| 830 | |
Russ Cox | 287e45e | 2010-12-13 15:51:11 -0500 | [diff] [blame] | 831 | func TestMarshalBadUTF8(t *testing.T) { |
Russ Cox | 4274d07 | 2013-07-12 20:40:50 -0400 | [diff] [blame] | 832 | for _, tt := range badUTF8 { |
| 833 | b, err := Marshal(tt.in) |
| 834 | if string(b) != tt.out || err != nil { |
| 835 | t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out) |
| 836 | } |
Russ Cox | 287e45e | 2010-12-13 15:51:11 -0500 | [diff] [blame] | 837 | } |
| 838 | } |
| 839 | |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 840 | func TestMarshalNumberZeroVal(t *testing.T) { |
| 841 | var n Number |
| 842 | out, err := Marshal(n) |
| 843 | if err != nil { |
| 844 | t.Fatal(err) |
| 845 | } |
| 846 | outStr := string(out) |
| 847 | if outStr != "0" { |
| 848 | t.Fatalf("Invalid zero val for Number: %q", outStr) |
| 849 | } |
| 850 | } |
| 851 | |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 852 | func TestMarshalEmbeds(t *testing.T) { |
| 853 | top := &Top{ |
| 854 | Level0: 1, |
| 855 | Embed0: Embed0{ |
| 856 | Level1b: 2, |
| 857 | Level1c: 3, |
| 858 | }, |
| 859 | Embed0a: &Embed0a{ |
| 860 | Level1a: 5, |
| 861 | Level1b: 6, |
| 862 | }, |
| 863 | Embed0b: &Embed0b{ |
| 864 | Level1a: 8, |
| 865 | Level1b: 9, |
| 866 | Level1c: 10, |
| 867 | Level1d: 11, |
| 868 | Level1e: 12, |
| 869 | }, |
| 870 | Loop: Loop{ |
| 871 | Loop1: 13, |
| 872 | Loop2: 14, |
| 873 | }, |
| 874 | Embed0p: Embed0p{ |
| 875 | Point: image.Point{X: 15, Y: 16}, |
| 876 | }, |
| 877 | Embed0q: Embed0q{ |
| 878 | Point: Point{Z: 17}, |
| 879 | }, |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 880 | embed: embed{ |
| 881 | Q: 18, |
| 882 | }, |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 883 | } |
| 884 | b, err := Marshal(top) |
| 885 | if err != nil { |
| 886 | t.Fatal(err) |
| 887 | } |
Marcel van Lohuizen | a30dd9c | 2015-08-28 10:17:05 +0200 | [diff] [blame] | 888 | want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}" |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 889 | if string(b) != want { |
| 890 | t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want) |
| 891 | } |
| 892 | } |
| 893 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 894 | func TestUnmarshal(t *testing.T) { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 895 | for i, tt := range unmarshalTests { |
Brad Fitzpatrick | 9b8d4e0 | 2011-04-15 08:14:34 -0700 | [diff] [blame] | 896 | var scan scanner |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 897 | in := []byte(tt.in) |
| 898 | if err := checkValid(in, &scan); err != nil { |
Anthony Martin | 2db4c3d | 2010-08-03 17:05:00 -0700 | [diff] [blame] | 899 | if !reflect.DeepEqual(err, tt.err) { |
Brad Fitzpatrick | 9b8d4e0 | 2011-04-15 08:14:34 -0700 | [diff] [blame] | 900 | t.Errorf("#%d: checkValid: %#v", i, err) |
Anthony Martin | 2db4c3d | 2010-08-03 17:05:00 -0700 | [diff] [blame] | 901 | continue |
| 902 | } |
| 903 | } |
| 904 | if tt.ptr == nil { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 905 | continue |
| 906 | } |
Robert Griesemer | 7e8218a | 2014-10-01 16:24:17 -0700 | [diff] [blame] | 907 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 908 | // v = new(right-type) |
Russ Cox | 07abf1c | 2011-04-25 13:39:36 -0400 | [diff] [blame] | 909 | v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 910 | dec := NewDecoder(bytes.NewReader(in)) |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 911 | if tt.useNumber { |
| 912 | dec.UseNumber() |
| 913 | } |
| 914 | if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { |
Robert Griesemer | 7e8218a | 2014-10-01 16:24:17 -0700 | [diff] [blame] | 915 | t.Errorf("#%d: %v, want %v", i, err, tt.err) |
| 916 | continue |
| 917 | } else if err != nil { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 918 | continue |
| 919 | } |
| 920 | if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { |
| 921 | t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) |
| 922 | data, _ := Marshal(v.Elem().Interface()) |
| 923 | println(string(data)) |
| 924 | data, _ = Marshal(tt.out) |
| 925 | println(string(data)) |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 926 | continue |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 927 | } |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 928 | |
Russ Cox | 1261023 | 2016-05-23 12:21:57 -0400 | [diff] [blame] | 929 | // Check round trip also decodes correctly. |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 930 | if tt.err == nil { |
| 931 | enc, err := Marshal(v.Interface()) |
| 932 | if err != nil { |
| 933 | t.Errorf("#%d: error re-marshaling: %v", i, err) |
| 934 | continue |
| 935 | } |
Russ Cox | 1261023 | 2016-05-23 12:21:57 -0400 | [diff] [blame] | 936 | if tt.golden && !bytes.Equal(enc, in) { |
| 937 | t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) |
| 938 | } |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 939 | vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 940 | dec = NewDecoder(bytes.NewReader(enc)) |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 941 | if tt.useNumber { |
| 942 | dec.UseNumber() |
| 943 | } |
| 944 | if err := dec.Decode(vv.Interface()); err != nil { |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 945 | t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 946 | continue |
| 947 | } |
| 948 | if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { |
| 949 | t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) |
Brad Fitzpatrick | 89b5c6c | 2013-08-09 09:46:47 -0700 | [diff] [blame] | 950 | t.Errorf(" In: %q", strings.Map(noSpace, string(in))) |
| 951 | t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) |
Russ Cox | d61707f | 2012-05-29 18:02:40 -0400 | [diff] [blame] | 952 | continue |
| 953 | } |
| 954 | } |
Sergey 'SnakE' Gromov | 9d50b46 | 2009-11-30 13:55:09 -0800 | [diff] [blame] | 955 | } |
| 956 | } |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 957 | |
| 958 | func TestUnmarshalMarshal(t *testing.T) { |
Rob Pike | 7f9acb5 | 2011-03-26 11:25:22 -0700 | [diff] [blame] | 959 | initBig() |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 960 | var v interface{} |
| 961 | if err := Unmarshal(jsonBig, &v); err != nil { |
| 962 | t.Fatalf("Unmarshal: %v", err) |
| 963 | } |
| 964 | b, err := Marshal(v) |
| 965 | if err != nil { |
| 966 | t.Fatalf("Marshal: %v", err) |
| 967 | } |
Matthew Dempsky | 46811d2 | 2013-01-07 10:03:49 +1100 | [diff] [blame] | 968 | if !bytes.Equal(jsonBig, b) { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 969 | t.Errorf("Marshal jsonBig") |
| 970 | diff(t, b, jsonBig) |
| 971 | return |
| 972 | } |
| 973 | } |
| 974 | |
Jonathan Gold | b7bb1e3 | 2012-06-25 17:36:09 -0400 | [diff] [blame] | 975 | var numberTests = []struct { |
| 976 | in string |
| 977 | i int64 |
| 978 | intErr string |
| 979 | f float64 |
| 980 | floatErr string |
| 981 | }{ |
| 982 | {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, |
| 983 | {in: "-12", i: -12, f: -12.0}, |
| 984 | {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, |
| 985 | } |
| 986 | |
| 987 | // Independent of Decode, basic coverage of the accessors in Number |
| 988 | func TestNumberAccessors(t *testing.T) { |
| 989 | for _, tt := range numberTests { |
| 990 | n := Number(tt.in) |
| 991 | if s := n.String(); s != tt.in { |
| 992 | t.Errorf("Number(%q).String() is %q", tt.in, s) |
| 993 | } |
| 994 | if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { |
| 995 | t.Errorf("Number(%q).Int64() is %d", tt.in, i) |
| 996 | } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { |
| 997 | t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err) |
| 998 | } |
| 999 | if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { |
| 1000 | t.Errorf("Number(%q).Float64() is %g", tt.in, f) |
| 1001 | } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { |
| 1002 | t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err) |
| 1003 | } |
| 1004 | } |
| 1005 | } |
| 1006 | |
Roger Peppe | 83da7d1 | 2011-02-23 11:32:29 -0500 | [diff] [blame] | 1007 | func TestLargeByteSlice(t *testing.T) { |
| 1008 | s0 := make([]byte, 2000) |
| 1009 | for i := range s0 { |
| 1010 | s0[i] = byte(i) |
| 1011 | } |
| 1012 | b, err := Marshal(s0) |
| 1013 | if err != nil { |
| 1014 | t.Fatalf("Marshal: %v", err) |
| 1015 | } |
| 1016 | var s1 []byte |
| 1017 | if err := Unmarshal(b, &s1); err != nil { |
| 1018 | t.Fatalf("Unmarshal: %v", err) |
| 1019 | } |
Matthew Dempsky | 46811d2 | 2013-01-07 10:03:49 +1100 | [diff] [blame] | 1020 | if !bytes.Equal(s0, s1) { |
Roger Peppe | 83da7d1 | 2011-02-23 11:32:29 -0500 | [diff] [blame] | 1021 | t.Errorf("Marshal large byte slice") |
| 1022 | diff(t, s0, s1) |
| 1023 | } |
| 1024 | } |
| 1025 | |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1026 | type Xint struct { |
| 1027 | X int |
| 1028 | } |
| 1029 | |
| 1030 | func TestUnmarshalInterface(t *testing.T) { |
| 1031 | var xint Xint |
| 1032 | var i interface{} = &xint |
| 1033 | if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { |
| 1034 | t.Fatalf("Unmarshal: %v", err) |
| 1035 | } |
| 1036 | if xint.X != 1 { |
| 1037 | t.Fatalf("Did not write to xint") |
| 1038 | } |
| 1039 | } |
| 1040 | |
| 1041 | func TestUnmarshalPtrPtr(t *testing.T) { |
| 1042 | var xint Xint |
| 1043 | pxint := &xint |
| 1044 | if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { |
| 1045 | t.Fatalf("Unmarshal: %v", err) |
| 1046 | } |
| 1047 | if xint.X != 1 { |
| 1048 | t.Fatalf("Did not write to xint") |
| 1049 | } |
| 1050 | } |
| 1051 | |
David Symonds | cbad580 | 2011-07-14 13:30:08 +1000 | [diff] [blame] | 1052 | func TestEscape(t *testing.T) { |
David Symonds | d754647 | 2013-07-12 14:35:55 +1000 | [diff] [blame] | 1053 | const input = `"foobar"<html>` + " [\u2028 \u2029]" |
| 1054 | const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"` |
David Symonds | cbad580 | 2011-07-14 13:30:08 +1000 | [diff] [blame] | 1055 | b, err := Marshal(input) |
| 1056 | if err != nil { |
| 1057 | t.Fatalf("Marshal error: %v", err) |
| 1058 | } |
| 1059 | if s := string(b); s != expected { |
David Symonds | d754647 | 2013-07-12 14:35:55 +1000 | [diff] [blame] | 1060 | t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected) |
David Symonds | cbad580 | 2011-07-14 13:30:08 +1000 | [diff] [blame] | 1061 | } |
| 1062 | } |
| 1063 | |
Brad Fitzpatrick | f89b574 | 2011-12-15 10:02:47 -0800 | [diff] [blame] | 1064 | // WrongString is a struct that's misusing the ,string modifier. |
| 1065 | type WrongString struct { |
| 1066 | Message string `json:"result,string"` |
| 1067 | } |
| 1068 | |
| 1069 | type wrongStringTest struct { |
| 1070 | in, err string |
| 1071 | } |
| 1072 | |
Brad Fitzpatrick | f89b574 | 2011-12-15 10:02:47 -0800 | [diff] [blame] | 1073 | var wrongStringTests = []wrongStringTest{ |
Brad Fitzpatrick | b37de73 | 2012-01-12 14:40:29 -0800 | [diff] [blame] | 1074 | {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, |
| 1075 | {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, |
| 1076 | {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, |
Emil Hessman | 2c987e1 | 2014-12-27 20:52:17 +0100 | [diff] [blame] | 1077 | {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, |
Brad Fitzpatrick | f89b574 | 2011-12-15 10:02:47 -0800 | [diff] [blame] | 1078 | } |
| 1079 | |
| 1080 | // If people misuse the ,string modifier, the error message should be |
| 1081 | // helpful, telling the user that they're doing it wrong. |
| 1082 | func TestErrorMessageFromMisusedString(t *testing.T) { |
| 1083 | for n, tt := range wrongStringTests { |
| 1084 | r := strings.NewReader(tt.in) |
| 1085 | var s WrongString |
| 1086 | err := NewDecoder(r).Decode(&s) |
| 1087 | got := fmt.Sprintf("%v", err) |
| 1088 | if got != tt.err { |
| 1089 | t.Errorf("%d. got err = %q, want %q", n, got, tt.err) |
| 1090 | } |
| 1091 | } |
| 1092 | } |
| 1093 | |
Russ Cox | b50a847 | 2011-10-25 22:23:54 -0700 | [diff] [blame] | 1094 | func noSpace(c rune) rune { |
Marvin Stenger | fcf8143 | 2015-09-21 00:45:21 +0200 | [diff] [blame] | 1095 | if isSpace(byte(c)) { //only used for ascii |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1096 | return -1 |
| 1097 | } |
| 1098 | return c |
| 1099 | } |
| 1100 | |
| 1101 | type All struct { |
| 1102 | Bool bool |
| 1103 | Int int |
| 1104 | Int8 int8 |
| 1105 | Int16 int16 |
| 1106 | Int32 int32 |
| 1107 | Int64 int64 |
| 1108 | Uint uint |
| 1109 | Uint8 uint8 |
| 1110 | Uint16 uint16 |
| 1111 | Uint32 uint32 |
| 1112 | Uint64 uint64 |
| 1113 | Uintptr uintptr |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1114 | Float32 float32 |
| 1115 | Float64 float64 |
| 1116 | |
Brad Fitzpatrick | 396cd36 | 2011-08-26 12:27:33 +0400 | [diff] [blame] | 1117 | Foo string `json:"bar"` |
| 1118 | Foo2 string `json:"bar2,dummyopt"` |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1119 | |
Brad Fitzpatrick | 596bf61 | 2011-08-29 12:46:32 -0700 | [diff] [blame] | 1120 | IntStr int64 `json:",string"` |
| 1121 | |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1122 | PBool *bool |
| 1123 | PInt *int |
| 1124 | PInt8 *int8 |
| 1125 | PInt16 *int16 |
| 1126 | PInt32 *int32 |
| 1127 | PInt64 *int64 |
| 1128 | PUint *uint |
| 1129 | PUint8 *uint8 |
| 1130 | PUint16 *uint16 |
| 1131 | PUint32 *uint32 |
| 1132 | PUint64 *uint64 |
| 1133 | PUintptr *uintptr |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1134 | PFloat32 *float32 |
| 1135 | PFloat64 *float64 |
| 1136 | |
| 1137 | String string |
| 1138 | PString *string |
| 1139 | |
| 1140 | Map map[string]Small |
| 1141 | MapP map[string]*Small |
| 1142 | PMap *map[string]Small |
| 1143 | PMapP *map[string]*Small |
| 1144 | |
| 1145 | EmptyMap map[string]Small |
| 1146 | NilMap map[string]Small |
| 1147 | |
| 1148 | Slice []Small |
| 1149 | SliceP []*Small |
| 1150 | PSlice *[]Small |
| 1151 | PSliceP *[]*Small |
| 1152 | |
| 1153 | EmptySlice []Small |
| 1154 | NilSlice []Small |
| 1155 | |
| 1156 | StringSlice []string |
| 1157 | ByteSlice []byte |
| 1158 | |
| 1159 | Small Small |
| 1160 | PSmall *Small |
| 1161 | PPSmall **Small |
| 1162 | |
| 1163 | Interface interface{} |
| 1164 | PInterface *interface{} |
Andrew Gerrand | 09d4bcf | 2011-01-12 11:59:33 +1100 | [diff] [blame] | 1165 | |
| 1166 | unexported int |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1167 | } |
| 1168 | |
| 1169 | type Small struct { |
| 1170 | Tag string |
| 1171 | } |
| 1172 | |
| 1173 | var allValue = All{ |
| 1174 | Bool: true, |
| 1175 | Int: 2, |
| 1176 | Int8: 3, |
| 1177 | Int16: 4, |
| 1178 | Int32: 5, |
| 1179 | Int64: 6, |
| 1180 | Uint: 7, |
| 1181 | Uint8: 8, |
| 1182 | Uint16: 9, |
| 1183 | Uint32: 10, |
| 1184 | Uint64: 11, |
| 1185 | Uintptr: 12, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1186 | Float32: 14.1, |
| 1187 | Float64: 15.1, |
| 1188 | Foo: "foo", |
Brad Fitzpatrick | 396cd36 | 2011-08-26 12:27:33 +0400 | [diff] [blame] | 1189 | Foo2: "foo2", |
Brad Fitzpatrick | 596bf61 | 2011-08-29 12:46:32 -0700 | [diff] [blame] | 1190 | IntStr: 42, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1191 | String: "16", |
| 1192 | Map: map[string]Small{ |
Robert Griesemer | 3478891 | 2010-10-22 10:06:33 -0700 | [diff] [blame] | 1193 | "17": {Tag: "tag17"}, |
| 1194 | "18": {Tag: "tag18"}, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1195 | }, |
| 1196 | MapP: map[string]*Small{ |
Russ Cox | dcf1d7b | 2011-12-02 14:14:25 -0500 | [diff] [blame] | 1197 | "19": {Tag: "tag19"}, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1198 | "20": nil, |
| 1199 | }, |
| 1200 | EmptyMap: map[string]Small{}, |
Robert Griesemer | 3478891 | 2010-10-22 10:06:33 -0700 | [diff] [blame] | 1201 | Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, |
Russ Cox | dcf1d7b | 2011-12-02 14:14:25 -0500 | [diff] [blame] | 1202 | SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1203 | EmptySlice: []Small{}, |
| 1204 | StringSlice: []string{"str24", "str25", "str26"}, |
| 1205 | ByteSlice: []byte{27, 28, 29}, |
| 1206 | Small: Small{Tag: "tag30"}, |
| 1207 | PSmall: &Small{Tag: "tag31"}, |
Russ Cox | f2b5a07 | 2011-01-19 23:09:00 -0500 | [diff] [blame] | 1208 | Interface: 5.2, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1209 | } |
| 1210 | |
| 1211 | var pallValue = All{ |
| 1212 | PBool: &allValue.Bool, |
| 1213 | PInt: &allValue.Int, |
| 1214 | PInt8: &allValue.Int8, |
| 1215 | PInt16: &allValue.Int16, |
| 1216 | PInt32: &allValue.Int32, |
| 1217 | PInt64: &allValue.Int64, |
| 1218 | PUint: &allValue.Uint, |
| 1219 | PUint8: &allValue.Uint8, |
| 1220 | PUint16: &allValue.Uint16, |
| 1221 | PUint32: &allValue.Uint32, |
| 1222 | PUint64: &allValue.Uint64, |
| 1223 | PUintptr: &allValue.Uintptr, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1224 | PFloat32: &allValue.Float32, |
| 1225 | PFloat64: &allValue.Float64, |
| 1226 | PString: &allValue.String, |
| 1227 | PMap: &allValue.Map, |
| 1228 | PMapP: &allValue.MapP, |
| 1229 | PSlice: &allValue.Slice, |
| 1230 | PSliceP: &allValue.SliceP, |
| 1231 | PPSmall: &allValue.PSmall, |
| 1232 | PInterface: &allValue.Interface, |
| 1233 | } |
| 1234 | |
| 1235 | var allValueIndent = `{ |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1236 | "Bool": true, |
| 1237 | "Int": 2, |
| 1238 | "Int8": 3, |
| 1239 | "Int16": 4, |
| 1240 | "Int32": 5, |
| 1241 | "Int64": 6, |
| 1242 | "Uint": 7, |
| 1243 | "Uint8": 8, |
| 1244 | "Uint16": 9, |
| 1245 | "Uint32": 10, |
| 1246 | "Uint64": 11, |
| 1247 | "Uintptr": 12, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1248 | "Float32": 14.1, |
| 1249 | "Float64": 15.1, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1250 | "bar": "foo", |
Brad Fitzpatrick | 396cd36 | 2011-08-26 12:27:33 +0400 | [diff] [blame] | 1251 | "bar2": "foo2", |
Brad Fitzpatrick | 596bf61 | 2011-08-29 12:46:32 -0700 | [diff] [blame] | 1252 | "IntStr": "42", |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1253 | "PBool": null, |
| 1254 | "PInt": null, |
| 1255 | "PInt8": null, |
| 1256 | "PInt16": null, |
| 1257 | "PInt32": null, |
| 1258 | "PInt64": null, |
| 1259 | "PUint": null, |
| 1260 | "PUint8": null, |
| 1261 | "PUint16": null, |
| 1262 | "PUint32": null, |
| 1263 | "PUint64": null, |
| 1264 | "PUintptr": null, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1265 | "PFloat32": null, |
| 1266 | "PFloat64": null, |
| 1267 | "String": "16", |
| 1268 | "PString": null, |
| 1269 | "Map": { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1270 | "17": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1271 | "Tag": "tag17" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1272 | }, |
| 1273 | "18": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1274 | "Tag": "tag18" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1275 | } |
| 1276 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1277 | "MapP": { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1278 | "19": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1279 | "Tag": "tag19" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1280 | }, |
| 1281 | "20": null |
| 1282 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1283 | "PMap": null, |
| 1284 | "PMapP": null, |
| 1285 | "EmptyMap": {}, |
| 1286 | "NilMap": null, |
| 1287 | "Slice": [ |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1288 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1289 | "Tag": "tag20" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1290 | }, |
| 1291 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1292 | "Tag": "tag21" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1293 | } |
| 1294 | ], |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1295 | "SliceP": [ |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1296 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1297 | "Tag": "tag22" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1298 | }, |
| 1299 | null, |
| 1300 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1301 | "Tag": "tag23" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1302 | } |
| 1303 | ], |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1304 | "PSlice": null, |
| 1305 | "PSliceP": null, |
| 1306 | "EmptySlice": [], |
Alexander Reece | 48c75c5 | 2011-10-31 13:59:23 -0400 | [diff] [blame] | 1307 | "NilSlice": null, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1308 | "StringSlice": [ |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1309 | "str24", |
| 1310 | "str25", |
| 1311 | "str26" |
| 1312 | ], |
Roger Peppe | 83da7d1 | 2011-02-23 11:32:29 -0500 | [diff] [blame] | 1313 | "ByteSlice": "Gxwd", |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1314 | "Small": { |
| 1315 | "Tag": "tag30" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1316 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1317 | "PSmall": { |
| 1318 | "Tag": "tag31" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1319 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1320 | "PPSmall": null, |
| 1321 | "Interface": 5.2, |
| 1322 | "PInterface": null |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1323 | }` |
| 1324 | |
| 1325 | var allValueCompact = strings.Map(noSpace, allValueIndent) |
| 1326 | |
| 1327 | var pallValueIndent = `{ |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1328 | "Bool": false, |
| 1329 | "Int": 0, |
| 1330 | "Int8": 0, |
| 1331 | "Int16": 0, |
| 1332 | "Int32": 0, |
| 1333 | "Int64": 0, |
| 1334 | "Uint": 0, |
| 1335 | "Uint8": 0, |
| 1336 | "Uint16": 0, |
| 1337 | "Uint32": 0, |
| 1338 | "Uint64": 0, |
| 1339 | "Uintptr": 0, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1340 | "Float32": 0, |
| 1341 | "Float64": 0, |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1342 | "bar": "", |
Brad Fitzpatrick | 396cd36 | 2011-08-26 12:27:33 +0400 | [diff] [blame] | 1343 | "bar2": "", |
Brad Fitzpatrick | 596bf61 | 2011-08-29 12:46:32 -0700 | [diff] [blame] | 1344 | "IntStr": "0", |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1345 | "PBool": true, |
| 1346 | "PInt": 2, |
| 1347 | "PInt8": 3, |
| 1348 | "PInt16": 4, |
| 1349 | "PInt32": 5, |
| 1350 | "PInt64": 6, |
| 1351 | "PUint": 7, |
| 1352 | "PUint8": 8, |
| 1353 | "PUint16": 9, |
| 1354 | "PUint32": 10, |
| 1355 | "PUint64": 11, |
| 1356 | "PUintptr": 12, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1357 | "PFloat32": 14.1, |
| 1358 | "PFloat64": 15.1, |
| 1359 | "String": "", |
| 1360 | "PString": "16", |
| 1361 | "Map": null, |
| 1362 | "MapP": null, |
| 1363 | "PMap": { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1364 | "17": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1365 | "Tag": "tag17" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1366 | }, |
| 1367 | "18": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1368 | "Tag": "tag18" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1369 | } |
| 1370 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1371 | "PMapP": { |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1372 | "19": { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1373 | "Tag": "tag19" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1374 | }, |
| 1375 | "20": null |
| 1376 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1377 | "EmptyMap": null, |
| 1378 | "NilMap": null, |
Alexander Reece | 48c75c5 | 2011-10-31 13:59:23 -0400 | [diff] [blame] | 1379 | "Slice": null, |
| 1380 | "SliceP": null, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1381 | "PSlice": [ |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1382 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1383 | "Tag": "tag20" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1384 | }, |
| 1385 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1386 | "Tag": "tag21" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1387 | } |
| 1388 | ], |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1389 | "PSliceP": [ |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1390 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1391 | "Tag": "tag22" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1392 | }, |
| 1393 | null, |
| 1394 | { |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1395 | "Tag": "tag23" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1396 | } |
| 1397 | ], |
Alexander Reece | 48c75c5 | 2011-10-31 13:59:23 -0400 | [diff] [blame] | 1398 | "EmptySlice": null, |
| 1399 | "NilSlice": null, |
| 1400 | "StringSlice": null, |
| 1401 | "ByteSlice": null, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1402 | "Small": { |
| 1403 | "Tag": "" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1404 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1405 | "PSmall": null, |
| 1406 | "PPSmall": { |
| 1407 | "Tag": "tag31" |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1408 | }, |
Russ Cox | bec40ba | 2010-04-27 10:24:00 -0700 | [diff] [blame] | 1409 | "Interface": null, |
| 1410 | "PInterface": 5.2 |
Russ Cox | dba9d62 | 2010-04-21 16:40:53 -0700 | [diff] [blame] | 1411 | }` |
| 1412 | |
| 1413 | var pallValueCompact = strings.Map(noSpace, pallValueIndent) |
David Symonds | bf89d58 | 2012-02-03 11:15:06 +1100 | [diff] [blame] | 1414 | |
| 1415 | func TestRefUnmarshal(t *testing.T) { |
| 1416 | type S struct { |
| 1417 | // Ref is defined in encode_test.go. |
| 1418 | R0 Ref |
| 1419 | R1 *Ref |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 1420 | R2 RefText |
| 1421 | R3 *RefText |
David Symonds | bf89d58 | 2012-02-03 11:15:06 +1100 | [diff] [blame] | 1422 | } |
| 1423 | want := S{ |
| 1424 | R0: 12, |
| 1425 | R1: new(Ref), |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 1426 | R2: 13, |
| 1427 | R3: new(RefText), |
David Symonds | bf89d58 | 2012-02-03 11:15:06 +1100 | [diff] [blame] | 1428 | } |
| 1429 | *want.R1 = 12 |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 1430 | *want.R3 = 13 |
David Symonds | bf89d58 | 2012-02-03 11:15:06 +1100 | [diff] [blame] | 1431 | |
| 1432 | var got S |
Russ Cox | 7e88674 | 2013-08-14 14:56:07 -0400 | [diff] [blame] | 1433 | if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { |
David Symonds | bf89d58 | 2012-02-03 11:15:06 +1100 | [diff] [blame] | 1434 | t.Fatalf("Unmarshal: %v", err) |
| 1435 | } |
| 1436 | if !reflect.DeepEqual(got, want) { |
| 1437 | t.Errorf("got %+v, want %+v", got, want) |
| 1438 | } |
| 1439 | } |
Russ Cox | 990f9f4 | 2012-02-19 00:27:05 -0500 | [diff] [blame] | 1440 | |
Michael Chaten | 3fab2a9 | 2012-05-03 17:35:44 -0400 | [diff] [blame] | 1441 | // Test that the empty string doesn't panic decoding when ,string is specified |
| 1442 | // Issue 3450 |
| 1443 | func TestEmptyString(t *testing.T) { |
| 1444 | type T2 struct { |
| 1445 | Number1 int `json:",string"` |
| 1446 | Number2 int `json:",string"` |
| 1447 | } |
| 1448 | data := `{"Number1":"1", "Number2":""}` |
| 1449 | dec := NewDecoder(strings.NewReader(data)) |
| 1450 | var t2 T2 |
| 1451 | err := dec.Decode(&t2) |
| 1452 | if err == nil { |
| 1453 | t.Fatal("Decode: did not return error") |
| 1454 | } |
| 1455 | if t2.Number1 != 1 { |
| 1456 | t.Fatal("Decode: did not set Number1") |
| 1457 | } |
| 1458 | } |
Russ Cox | 09b736a | 2012-06-07 01:48:55 -0400 | [diff] [blame] | 1459 | |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1460 | // Test that a null for ,string is not replaced with the previous quoted string (issue 7046). |
| 1461 | // It should also not be an error (issue 2540, issue 8587). |
Emil Hessman | 880442f | 2014-01-03 10:13:28 -0800 | [diff] [blame] | 1462 | func TestNullString(t *testing.T) { |
| 1463 | type T struct { |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1464 | A int `json:",string"` |
| 1465 | B int `json:",string"` |
| 1466 | C *int `json:",string"` |
Emil Hessman | 880442f | 2014-01-03 10:13:28 -0800 | [diff] [blame] | 1467 | } |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1468 | data := []byte(`{"A": "1", "B": null, "C": null}`) |
Emil Hessman | 880442f | 2014-01-03 10:13:28 -0800 | [diff] [blame] | 1469 | var s T |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1470 | s.B = 1 |
| 1471 | s.C = new(int) |
| 1472 | *s.C = 2 |
Emil Hessman | 880442f | 2014-01-03 10:13:28 -0800 | [diff] [blame] | 1473 | err := Unmarshal(data, &s) |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1474 | if err != nil { |
Emil Hessman | 2c987e1 | 2014-12-27 20:52:17 +0100 | [diff] [blame] | 1475 | t.Fatalf("Unmarshal: %v", err) |
Russ Cox | 7b2b8ed | 2014-10-07 11:07:04 -0400 | [diff] [blame] | 1476 | } |
| 1477 | if s.B != 1 || s.C != nil { |
| 1478 | t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) |
Emil Hessman | 880442f | 2014-01-03 10:13:28 -0800 | [diff] [blame] | 1479 | } |
| 1480 | } |
| 1481 | |
Russ Cox | 09b736a | 2012-06-07 01:48:55 -0400 | [diff] [blame] | 1482 | func intp(x int) *int { |
| 1483 | p := new(int) |
| 1484 | *p = x |
| 1485 | return p |
| 1486 | } |
| 1487 | |
| 1488 | func intpp(x *int) **int { |
| 1489 | pp := new(*int) |
| 1490 | *pp = x |
| 1491 | return pp |
| 1492 | } |
| 1493 | |
| 1494 | var interfaceSetTests = []struct { |
| 1495 | pre interface{} |
| 1496 | json string |
| 1497 | post interface{} |
| 1498 | }{ |
| 1499 | {"foo", `"bar"`, "bar"}, |
| 1500 | {"foo", `2`, 2.0}, |
| 1501 | {"foo", `true`, true}, |
| 1502 | {"foo", `null`, nil}, |
| 1503 | |
| 1504 | {nil, `null`, nil}, |
| 1505 | {new(int), `null`, nil}, |
| 1506 | {(*int)(nil), `null`, nil}, |
| 1507 | {new(*int), `null`, new(*int)}, |
| 1508 | {(**int)(nil), `null`, nil}, |
| 1509 | {intp(1), `null`, nil}, |
| 1510 | {intpp(nil), `null`, intpp(nil)}, |
| 1511 | {intpp(intp(1)), `null`, intpp(nil)}, |
| 1512 | } |
| 1513 | |
| 1514 | func TestInterfaceSet(t *testing.T) { |
| 1515 | for _, tt := range interfaceSetTests { |
| 1516 | b := struct{ X interface{} }{tt.pre} |
| 1517 | blob := `{"X":` + tt.json + `}` |
| 1518 | if err := Unmarshal([]byte(blob), &b); err != nil { |
| 1519 | t.Errorf("Unmarshal %#q: %v", blob, err) |
| 1520 | continue |
| 1521 | } |
| 1522 | if !reflect.DeepEqual(b.X, tt.post) { |
| 1523 | t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post) |
| 1524 | } |
| 1525 | } |
| 1526 | } |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1527 | |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 1528 | type NullTest struct { |
| 1529 | Bool bool |
| 1530 | Int int |
| 1531 | Int8 int8 |
| 1532 | Int16 int16 |
| 1533 | Int32 int32 |
| 1534 | Int64 int64 |
| 1535 | Uint uint |
| 1536 | Uint8 uint8 |
| 1537 | Uint16 uint16 |
| 1538 | Uint32 uint32 |
| 1539 | Uint64 uint64 |
| 1540 | Float32 float32 |
| 1541 | Float64 float64 |
| 1542 | String string |
| 1543 | PBool *bool |
| 1544 | Map map[string]string |
| 1545 | Slice []string |
| 1546 | Interface interface{} |
| 1547 | |
| 1548 | PRaw *RawMessage |
| 1549 | PTime *time.Time |
| 1550 | PBigInt *big.Int |
| 1551 | PText *MustNotUnmarshalText |
| 1552 | PBuffer *bytes.Buffer // has methods, just not relevant ones |
| 1553 | PStruct *struct{} |
| 1554 | |
| 1555 | Raw RawMessage |
| 1556 | Time time.Time |
| 1557 | BigInt big.Int |
| 1558 | Text MustNotUnmarshalText |
| 1559 | Buffer bytes.Buffer |
| 1560 | Struct struct{} |
| 1561 | } |
| 1562 | |
| 1563 | type NullTestStrings struct { |
| 1564 | Bool bool `json:",string"` |
| 1565 | Int int `json:",string"` |
| 1566 | Int8 int8 `json:",string"` |
| 1567 | Int16 int16 `json:",string"` |
| 1568 | Int32 int32 `json:",string"` |
| 1569 | Int64 int64 `json:",string"` |
| 1570 | Uint uint `json:",string"` |
| 1571 | Uint8 uint8 `json:",string"` |
| 1572 | Uint16 uint16 `json:",string"` |
| 1573 | Uint32 uint32 `json:",string"` |
| 1574 | Uint64 uint64 `json:",string"` |
| 1575 | Float32 float32 `json:",string"` |
| 1576 | Float64 float64 `json:",string"` |
| 1577 | String string `json:",string"` |
| 1578 | PBool *bool `json:",string"` |
| 1579 | Map map[string]string `json:",string"` |
| 1580 | Slice []string `json:",string"` |
| 1581 | Interface interface{} `json:",string"` |
| 1582 | |
| 1583 | PRaw *RawMessage `json:",string"` |
| 1584 | PTime *time.Time `json:",string"` |
| 1585 | PBigInt *big.Int `json:",string"` |
| 1586 | PText *MustNotUnmarshalText `json:",string"` |
| 1587 | PBuffer *bytes.Buffer `json:",string"` |
| 1588 | PStruct *struct{} `json:",string"` |
| 1589 | |
| 1590 | Raw RawMessage `json:",string"` |
| 1591 | Time time.Time `json:",string"` |
| 1592 | BigInt big.Int `json:",string"` |
| 1593 | Text MustNotUnmarshalText `json:",string"` |
| 1594 | Buffer bytes.Buffer `json:",string"` |
| 1595 | Struct struct{} `json:",string"` |
| 1596 | } |
| 1597 | |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1598 | // JSON null values should be ignored for primitives and string values instead of resulting in an error. |
| 1599 | // Issue 2540 |
| 1600 | func TestUnmarshalNulls(t *testing.T) { |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 1601 | // Unmarshal docs: |
| 1602 | // The JSON null value unmarshals into an interface, map, pointer, or slice |
| 1603 | // by setting that Go value to nil. Because null is often used in JSON to mean |
| 1604 | // ``not present,'' unmarshaling a JSON null into any other Go type has no effect |
| 1605 | // on the value and produces no error. |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1606 | |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 1607 | jsonData := []byte(`{ |
| 1608 | "Bool" : null, |
| 1609 | "Int" : null, |
| 1610 | "Int8" : null, |
| 1611 | "Int16" : null, |
| 1612 | "Int32" : null, |
| 1613 | "Int64" : null, |
| 1614 | "Uint" : null, |
| 1615 | "Uint8" : null, |
| 1616 | "Uint16" : null, |
| 1617 | "Uint32" : null, |
| 1618 | "Uint64" : null, |
| 1619 | "Float32" : null, |
| 1620 | "Float64" : null, |
| 1621 | "String" : null, |
| 1622 | "PBool": null, |
| 1623 | "Map": null, |
| 1624 | "Slice": null, |
| 1625 | "Interface": null, |
| 1626 | "PRaw": null, |
| 1627 | "PTime": null, |
| 1628 | "PBigInt": null, |
| 1629 | "PText": null, |
| 1630 | "PBuffer": null, |
| 1631 | "PStruct": null, |
| 1632 | "Raw": null, |
| 1633 | "Time": null, |
| 1634 | "BigInt": null, |
| 1635 | "Text": null, |
| 1636 | "Buffer": null, |
| 1637 | "Struct": null |
| 1638 | }`) |
| 1639 | nulls := NullTest{ |
| 1640 | Bool: true, |
| 1641 | Int: 2, |
| 1642 | Int8: 3, |
| 1643 | Int16: 4, |
| 1644 | Int32: 5, |
| 1645 | Int64: 6, |
| 1646 | Uint: 7, |
| 1647 | Uint8: 8, |
| 1648 | Uint16: 9, |
| 1649 | Uint32: 10, |
| 1650 | Uint64: 11, |
| 1651 | Float32: 12.1, |
| 1652 | Float64: 13.1, |
| 1653 | String: "14", |
| 1654 | PBool: new(bool), |
| 1655 | Map: map[string]string{}, |
| 1656 | Slice: []string{}, |
| 1657 | Interface: new(MustNotUnmarshalJSON), |
| 1658 | PRaw: new(RawMessage), |
| 1659 | PTime: new(time.Time), |
| 1660 | PBigInt: new(big.Int), |
| 1661 | PText: new(MustNotUnmarshalText), |
| 1662 | PStruct: new(struct{}), |
| 1663 | PBuffer: new(bytes.Buffer), |
| 1664 | Raw: RawMessage("123"), |
| 1665 | Time: time.Unix(123456789, 0), |
| 1666 | BigInt: *big.NewInt(123), |
| 1667 | } |
| 1668 | |
| 1669 | before := nulls.Time.String() |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1670 | |
| 1671 | err := Unmarshal(jsonData, &nulls) |
| 1672 | if err != nil { |
| 1673 | t.Errorf("Unmarshal of null values failed: %v", err) |
| 1674 | } |
| 1675 | if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || |
| 1676 | nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || |
| 1677 | nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1678 | t.Errorf("Unmarshal of null values affected primitives") |
| 1679 | } |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 1680 | |
| 1681 | if nulls.PBool != nil { |
| 1682 | t.Errorf("Unmarshal of null did not clear nulls.PBool") |
| 1683 | } |
| 1684 | if nulls.Map != nil { |
| 1685 | t.Errorf("Unmarshal of null did not clear nulls.Map") |
| 1686 | } |
| 1687 | if nulls.Slice != nil { |
| 1688 | t.Errorf("Unmarshal of null did not clear nulls.Slice") |
| 1689 | } |
| 1690 | if nulls.Interface != nil { |
| 1691 | t.Errorf("Unmarshal of null did not clear nulls.Interface") |
| 1692 | } |
| 1693 | if nulls.PRaw != nil { |
| 1694 | t.Errorf("Unmarshal of null did not clear nulls.PRaw") |
| 1695 | } |
| 1696 | if nulls.PTime != nil { |
| 1697 | t.Errorf("Unmarshal of null did not clear nulls.PTime") |
| 1698 | } |
| 1699 | if nulls.PBigInt != nil { |
| 1700 | t.Errorf("Unmarshal of null did not clear nulls.PBigInt") |
| 1701 | } |
| 1702 | if nulls.PText != nil { |
| 1703 | t.Errorf("Unmarshal of null did not clear nulls.PText") |
| 1704 | } |
| 1705 | if nulls.PBuffer != nil { |
| 1706 | t.Errorf("Unmarshal of null did not clear nulls.PBuffer") |
| 1707 | } |
| 1708 | if nulls.PStruct != nil { |
| 1709 | t.Errorf("Unmarshal of null did not clear nulls.PStruct") |
| 1710 | } |
| 1711 | |
| 1712 | if string(nulls.Raw) != "null" { |
| 1713 | t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw)) |
| 1714 | } |
| 1715 | if nulls.Time.String() != before { |
| 1716 | t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String()) |
| 1717 | } |
| 1718 | if nulls.BigInt.String() != "123" { |
| 1719 | t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String()) |
| 1720 | } |
| 1721 | } |
| 1722 | |
| 1723 | type MustNotUnmarshalJSON struct{} |
| 1724 | |
| 1725 | func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error { |
| 1726 | return errors.New("MustNotUnmarshalJSON was used") |
| 1727 | } |
| 1728 | |
| 1729 | type MustNotUnmarshalText struct{} |
| 1730 | |
| 1731 | func (x MustNotUnmarshalText) UnmarshalText(text []byte) error { |
| 1732 | return errors.New("MustNotUnmarshalText was used") |
Rick Arnold | c90739e | 2012-11-12 15:35:11 -0500 | [diff] [blame] | 1733 | } |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1734 | |
| 1735 | func TestStringKind(t *testing.T) { |
| 1736 | type stringKind string |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1737 | |
| 1738 | var m1, m2 map[stringKind]int |
| 1739 | m1 = map[stringKind]int{ |
| 1740 | "foo": 42, |
| 1741 | } |
| 1742 | |
| 1743 | data, err := Marshal(m1) |
| 1744 | if err != nil { |
Andrew Gerrand | 143f3fd | 2015-09-01 17:51:39 +1000 | [diff] [blame] | 1745 | t.Errorf("Unexpected error marshaling: %v", err) |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1746 | } |
| 1747 | |
| 1748 | err = Unmarshal(data, &m2) |
| 1749 | if err != nil { |
Andrew Gerrand | 143f3fd | 2015-09-01 17:51:39 +1000 | [diff] [blame] | 1750 | t.Errorf("Unexpected error unmarshaling: %v", err) |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1751 | } |
| 1752 | |
| 1753 | if !reflect.DeepEqual(m1, m2) { |
| 1754 | t.Error("Items should be equal after encoding and then decoding") |
| 1755 | } |
Håvard Haugen | 4302fd0 | 2015-04-26 23:52:42 +0200 | [diff] [blame] | 1756 | } |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1757 | |
Håvard Haugen | 4302fd0 | 2015-04-26 23:52:42 +0200 | [diff] [blame] | 1758 | // Custom types with []byte as underlying type could not be marshalled |
| 1759 | // and then unmarshalled. |
| 1760 | // Issue 8962. |
| 1761 | func TestByteKind(t *testing.T) { |
| 1762 | type byteKind []byte |
| 1763 | |
| 1764 | a := byteKind("hello") |
| 1765 | |
| 1766 | data, err := Marshal(a) |
| 1767 | if err != nil { |
| 1768 | t.Error(err) |
| 1769 | } |
| 1770 | var b byteKind |
| 1771 | err = Unmarshal(data, &b) |
| 1772 | if err != nil { |
| 1773 | t.Fatal(err) |
| 1774 | } |
| 1775 | if !reflect.DeepEqual(a, b) { |
| 1776 | t.Errorf("expected %v == %v", a, b) |
| 1777 | } |
Ryan Slade | a460012 | 2012-12-30 15:40:42 +1100 | [diff] [blame] | 1778 | } |
Rémy Oudompheng | 406ca3c | 2013-01-14 08:44:16 +0100 | [diff] [blame] | 1779 | |
Håvard Haugen | c60707b | 2015-10-25 22:42:41 +0100 | [diff] [blame] | 1780 | // The fix for issue 8962 introduced a regression. |
| 1781 | // Issue 12921. |
| 1782 | func TestSliceOfCustomByte(t *testing.T) { |
| 1783 | type Uint8 uint8 |
| 1784 | |
| 1785 | a := []Uint8("hello") |
| 1786 | |
| 1787 | data, err := Marshal(a) |
| 1788 | if err != nil { |
| 1789 | t.Fatal(err) |
| 1790 | } |
| 1791 | var b []Uint8 |
| 1792 | err = Unmarshal(data, &b) |
| 1793 | if err != nil { |
| 1794 | t.Fatal(err) |
| 1795 | } |
| 1796 | if !reflect.DeepEqual(a, b) { |
Dominik Honnef | 77f4b77 | 2016-03-22 06:37:16 +0100 | [diff] [blame] | 1797 | t.Fatalf("expected %v == %v", a, b) |
Håvard Haugen | c60707b | 2015-10-25 22:42:41 +0100 | [diff] [blame] | 1798 | } |
| 1799 | } |
| 1800 | |
Rémy Oudompheng | 406ca3c | 2013-01-14 08:44:16 +0100 | [diff] [blame] | 1801 | var decodeTypeErrorTests = []struct { |
| 1802 | dest interface{} |
| 1803 | src string |
| 1804 | }{ |
| 1805 | {new(string), `{"user": "name"}`}, // issue 4628. |
| 1806 | {new(error), `{}`}, // issue 4222 |
| 1807 | {new(error), `[]`}, |
| 1808 | {new(error), `""`}, |
| 1809 | {new(error), `123`}, |
| 1810 | {new(error), `true`}, |
| 1811 | } |
| 1812 | |
| 1813 | func TestUnmarshalTypeError(t *testing.T) { |
| 1814 | for _, item := range decodeTypeErrorTests { |
| 1815 | err := Unmarshal([]byte(item.src), item.dest) |
| 1816 | if _, ok := err.(*UnmarshalTypeError); !ok { |
Russ Cox | ad37081 | 2013-01-29 13:34:18 -0800 | [diff] [blame] | 1817 | t.Errorf("expected type error for Unmarshal(%q, type %T): got %T", |
Rémy Oudompheng | 406ca3c | 2013-01-14 08:44:16 +0100 | [diff] [blame] | 1818 | item.src, item.dest, err) |
| 1819 | } |
| 1820 | } |
| 1821 | } |
Rick Arnold | 6e3f3af | 2013-01-22 17:49:07 -0500 | [diff] [blame] | 1822 | |
Russ Cox | ad37081 | 2013-01-29 13:34:18 -0800 | [diff] [blame] | 1823 | var unmarshalSyntaxTests = []string{ |
| 1824 | "tru", |
| 1825 | "fals", |
| 1826 | "nul", |
| 1827 | "123e", |
| 1828 | `"hello`, |
| 1829 | `[1,2,3`, |
| 1830 | `{"key":1`, |
| 1831 | `{"key":1,`, |
| 1832 | } |
| 1833 | |
| 1834 | func TestUnmarshalSyntax(t *testing.T) { |
| 1835 | var x interface{} |
| 1836 | for _, src := range unmarshalSyntaxTests { |
| 1837 | err := Unmarshal([]byte(src), &x) |
| 1838 | if _, ok := err.(*SyntaxError); !ok { |
| 1839 | t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err) |
| 1840 | } |
| 1841 | } |
| 1842 | } |
| 1843 | |
Rick Arnold | 6e3f3af | 2013-01-22 17:49:07 -0500 | [diff] [blame] | 1844 | // Test handling of unexported fields that should be ignored. |
| 1845 | // Issue 4660 |
| 1846 | type unexportedFields struct { |
| 1847 | Name string |
| 1848 | m map[string]interface{} `json:"-"` |
| 1849 | m2 map[string]interface{} `json:"abcd"` |
| 1850 | } |
| 1851 | |
| 1852 | func TestUnmarshalUnexported(t *testing.T) { |
| 1853 | input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}` |
| 1854 | want := &unexportedFields{Name: "Bob"} |
| 1855 | |
| 1856 | out := &unexportedFields{} |
| 1857 | err := Unmarshal([]byte(input), out) |
| 1858 | if err != nil { |
| 1859 | t.Errorf("got error %v, expected nil", err) |
| 1860 | } |
| 1861 | if !reflect.DeepEqual(out, want) { |
| 1862 | t.Errorf("got %q, want %q", out, want) |
| 1863 | } |
| 1864 | } |
Russ Cox | d340a89 | 2013-02-14 14:46:15 -0500 | [diff] [blame] | 1865 | |
| 1866 | // Time3339 is a time.Time which encodes to and from JSON |
| 1867 | // as an RFC 3339 time in UTC. |
| 1868 | type Time3339 time.Time |
| 1869 | |
| 1870 | func (t *Time3339) UnmarshalJSON(b []byte) error { |
| 1871 | if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { |
Rob Pike | 707ab13 | 2013-02-25 12:43:03 -0800 | [diff] [blame] | 1872 | return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) |
Russ Cox | d340a89 | 2013-02-14 14:46:15 -0500 | [diff] [blame] | 1873 | } |
| 1874 | tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) |
| 1875 | if err != nil { |
| 1876 | return err |
| 1877 | } |
| 1878 | *t = Time3339(tm) |
| 1879 | return nil |
| 1880 | } |
| 1881 | |
Russ Cox | 80e6d63 | 2015-07-30 14:05:04 +0000 | [diff] [blame] | 1882 | func TestUnmarshalJSONLiteralError(t *testing.T) { |
Russ Cox | d340a89 | 2013-02-14 14:46:15 -0500 | [diff] [blame] | 1883 | var t3 Time3339 |
| 1884 | err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3) |
| 1885 | if err == nil { |
| 1886 | t.Fatalf("expected error; got time %v", time.Time(t3)) |
| 1887 | } |
| 1888 | if !strings.Contains(err.Error(), "range") { |
| 1889 | t.Errorf("got err = %v; want out of range error", err) |
| 1890 | } |
| 1891 | } |
Rick Arnold | cb8aebf | 2013-03-13 14:53:03 -0400 | [diff] [blame] | 1892 | |
| 1893 | // Test that extra object elements in an array do not result in a |
| 1894 | // "data changing underfoot" error. |
| 1895 | // Issue 3717 |
| 1896 | func TestSkipArrayObjects(t *testing.T) { |
| 1897 | json := `[{}]` |
| 1898 | var dest [0]interface{} |
| 1899 | |
| 1900 | err := Unmarshal([]byte(json), &dest) |
| 1901 | if err != nil { |
| 1902 | t.Errorf("got error %q, want nil", err) |
| 1903 | } |
| 1904 | } |
Russ Cox | 5d2c3a6 | 2013-09-09 19:11:05 -0400 | [diff] [blame] | 1905 | |
| 1906 | // Test semantics of pre-filled struct fields and pre-filled map fields. |
| 1907 | // Issue 4900. |
| 1908 | func TestPrefilled(t *testing.T) { |
| 1909 | ptrToMap := func(m map[string]interface{}) *map[string]interface{} { return &m } |
| 1910 | |
| 1911 | // Values here change, cannot reuse table across runs. |
| 1912 | var prefillTests = []struct { |
| 1913 | in string |
| 1914 | ptr interface{} |
| 1915 | out interface{} |
| 1916 | }{ |
| 1917 | { |
| 1918 | in: `{"X": 1, "Y": 2}`, |
| 1919 | ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, |
| 1920 | out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, |
| 1921 | }, |
| 1922 | { |
| 1923 | in: `{"X": 1, "Y": 2}`, |
| 1924 | ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}), |
| 1925 | out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}), |
| 1926 | }, |
| 1927 | } |
| 1928 | |
| 1929 | for _, tt := range prefillTests { |
| 1930 | ptrstr := fmt.Sprintf("%v", tt.ptr) |
| 1931 | err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here |
| 1932 | if err != nil { |
| 1933 | t.Errorf("Unmarshal: %v", err) |
| 1934 | } |
| 1935 | if !reflect.DeepEqual(tt.ptr, tt.out) { |
| 1936 | t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out) |
| 1937 | } |
| 1938 | } |
| 1939 | } |
Dave Cheney | 6673012 | 2014-01-02 09:49:55 +1100 | [diff] [blame] | 1940 | |
| 1941 | var invalidUnmarshalTests = []struct { |
| 1942 | v interface{} |
| 1943 | want string |
| 1944 | }{ |
| 1945 | {nil, "json: Unmarshal(nil)"}, |
| 1946 | {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, |
| 1947 | {(*int)(nil), "json: Unmarshal(nil *int)"}, |
| 1948 | } |
| 1949 | |
| 1950 | func TestInvalidUnmarshal(t *testing.T) { |
| 1951 | buf := []byte(`{"a":"1"}`) |
| 1952 | for _, tt := range invalidUnmarshalTests { |
| 1953 | err := Unmarshal(buf, tt.v) |
| 1954 | if err == nil { |
| 1955 | t.Errorf("Unmarshal expecting error, got nil") |
| 1956 | continue |
| 1957 | } |
| 1958 | if got := err.Error(); got != tt.want { |
| 1959 | t.Errorf("Unmarshal = %q; want %q", got, tt.want) |
| 1960 | } |
| 1961 | } |
| 1962 | } |
Larz Conwell | 1a4e177 | 2015-05-16 23:01:39 -0400 | [diff] [blame] | 1963 | |
Russ Cox | 671bddf | 2015-07-14 19:31:44 -0400 | [diff] [blame] | 1964 | var invalidUnmarshalTextTests = []struct { |
| 1965 | v interface{} |
| 1966 | want string |
| 1967 | }{ |
| 1968 | {nil, "json: Unmarshal(nil)"}, |
| 1969 | {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, |
| 1970 | {(*int)(nil), "json: Unmarshal(nil *int)"}, |
Russ Cox | f444b48 | 2016-10-12 16:54:02 -0400 | [diff] [blame] | 1971 | {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"}, |
Russ Cox | 671bddf | 2015-07-14 19:31:44 -0400 | [diff] [blame] | 1972 | } |
| 1973 | |
| 1974 | func TestInvalidUnmarshalText(t *testing.T) { |
| 1975 | buf := []byte(`123`) |
| 1976 | for _, tt := range invalidUnmarshalTextTests { |
| 1977 | err := Unmarshal(buf, tt.v) |
| 1978 | if err == nil { |
| 1979 | t.Errorf("Unmarshal expecting error, got nil") |
| 1980 | continue |
| 1981 | } |
| 1982 | if got := err.Error(); got != tt.want { |
| 1983 | t.Errorf("Unmarshal = %q; want %q", got, tt.want) |
| 1984 | } |
| 1985 | } |
| 1986 | } |
| 1987 | |
Larz Conwell | 1a4e177 | 2015-05-16 23:01:39 -0400 | [diff] [blame] | 1988 | // Test that string option is ignored for invalid types. |
| 1989 | // Issue 9812. |
| 1990 | func TestInvalidStringOption(t *testing.T) { |
| 1991 | num := 0 |
| 1992 | item := struct { |
| 1993 | T time.Time `json:",string"` |
| 1994 | M map[string]string `json:",string"` |
| 1995 | S []string `json:",string"` |
| 1996 | A [1]string `json:",string"` |
| 1997 | I interface{} `json:",string"` |
| 1998 | P *int `json:",string"` |
| 1999 | }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} |
| 2000 | |
| 2001 | data, err := Marshal(item) |
| 2002 | if err != nil { |
| 2003 | t.Fatalf("Marshal: %v", err) |
| 2004 | } |
| 2005 | |
| 2006 | err = Unmarshal(data, &item) |
| 2007 | if err != nil { |
| 2008 | t.Fatalf("Unmarshal: %v", err) |
| 2009 | } |
| 2010 | } |