diff options
| author | Caleb Spare <cespare@gmail.com> | 2016-04-13 16:51:25 -0700 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2016-05-10 03:53:12 +0000 |
| commit | f05c3aa24d815cd3869153750c9875e35fc48a6e (patch) | |
| tree | 224d3057425643cb6ced8fe29a8d26ddc1ca8722 /src/encoding/json/decode_test.go | |
| parent | 9af83462c6f432b77a846a24b4d8efae9bdf0567 (diff) | |
| download | go-f05c3aa24d815cd3869153750c9875e35fc48a6e.tar.xz | |
encoding/json: support maps with integer keys
This change makes encoding and decoding support integer types in map
keys, converting to/from JSON string keys.
JSON object keys are still sorted lexically, even though the keys may be
integer strings.
For backwards-compatibility, the existing Text(Un)Marshaler support for
map keys (added in CL 20356) does not take precedence over the default
encoding for string types. There is no such concern for integer types,
so integer map key encoding is only used as a fallback if the map key
type is not a Text(Un)Marshaler.
Fixes #12529.
Change-Id: I7e68c34f9cd19704b1d233a9862da15fabf0908a
Reviewed-on: https://go-review.googlesource.com/22060
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/encoding/json/decode_test.go')
| -rw-r--r-- | src/encoding/json/decode_test.go | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 30e46ca44f..7c388c0c27 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -10,8 +10,10 @@ import ( "errors" "fmt" "image" + "math" "net" "reflect" + "strconv" "strings" "testing" "time" @@ -53,6 +55,8 @@ type tx struct { x int } +type u8 uint8 + // A type that can unmarshal itself. type unmarshaler struct { @@ -92,6 +96,29 @@ type ustructText struct { M unmarshalerText } +// u8marshal is an integer type that can marshal/unmarshal itself. +type u8marshal uint8 + +func (u8 u8marshal) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("u%d", u8)), nil +} + +var errMissingU8Prefix = errors.New("missing 'u' prefix") + +func (u8 *u8marshal) UnmarshalText(b []byte) error { + if !bytes.HasPrefix(b, []byte{'u'}) { + return errMissingU8Prefix + } + n, err := strconv.Atoi(string(b[1:])) + if err != nil { + return err + } + *u8 = u8marshal(n) + return nil +} + +var _ encoding.TextUnmarshaler = (*u8marshal)(nil) + var ( um0, um1 unmarshaler // target2 of unmarshaling ump = &um1 @@ -320,7 +347,69 @@ var unmarshalTests = []unmarshalTest{ {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, - // Map keys can be encoding.TextUnmarshalers + // integer-keyed map test + { + in: `{"-1":"a","0":"b","1":"c"}`, + ptr: new(map[int]string), + out: map[int]string{-1: "a", 0: "b", 1: "c"}, + }, + { + in: `{"0":"a","10":"c","9":"b"}`, + ptr: new(map[u8]string), + out: map[u8]string{0: "a", 9: "b", 10: "c"}, + }, + { + in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, + ptr: new(map[int64]string), + out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, + }, + { + in: `{"18446744073709551615":"max"}`, + ptr: new(map[uint64]string), + out: map[uint64]string{math.MaxUint64: "max"}, + }, + { + in: `{"0":false,"10":true}`, + ptr: new(map[uintptr]bool), + out: map[uintptr]bool{0: false, 10: true}, + }, + + // Check that MarshalText and UnmarshalText take precedence + // over default integer handling in map keys. + { + in: `{"u2":4}`, + ptr: new(map[u8marshal]int), + out: map[u8marshal]int{2: 4}, + }, + { + in: `{"2":4}`, + ptr: new(map[u8marshal]int), + err: errMissingU8Prefix, + }, + + // integer-keyed map errors + { + in: `{"abc":"abc"}`, + ptr: new(map[int]string), + err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2}, + }, + { + in: `{"256":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2}, + }, + { + in: `{"128":"abc"}`, + ptr: new(map[int8]string), + err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2}, + }, + { + in: `{"-1":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2}, + }, + + // Map keys can be encoding.TextUnmarshalers. {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, // If multiple values for the same key exists, only the most recent value is used. {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, |
