ugorji / go

idiomatic codec and rpc lib for msgpack, cbor, json, etc. msgpack.org[Go]
MIT License
1.83k stars 294 forks source link

Unexpected encoding with interface{} key using Canonical and MapKeyAsString. #390

Closed winder closed 1 year ago

winder commented 1 year ago

Problem statement

When MapKeyAsString and Canonical are true, integer map keys are not quoted.

Expected behavior

Setting MapKeyAsString should ensure all map keys are quoted.

Example

These examples show the unexpected behavior using github.com/ugorji/go/codec v1.2.9.

Snippet

    handle := new(codec.JsonHandle)
    handle.MapKeyAsString = true
    handle.Canonical = true

    var b []byte
    enc := codec.NewEncoderBytes(&b, handle)
    enc.MustEncode(map[interface{}]interface{}{0: "int key"})
    if strings.Contains(string(b), "0:") {
        fmt.Printf("   * ERROR: unquoted key in \"%s\"\n", b)
    }

Standalone program:

package main

import (
    "fmt"
    "strings"

    "github.com/ugorji/go/codec"
)

func test(name string, canonical bool, mapType interface{}) {
    fmt.Printf("* %s, canonical = %t\n", name, canonical)

    handle := new(codec.JsonHandle)
    handle.MapKeyAsString = true
    handle.Canonical = canonical

    var b []byte
    enc := codec.NewEncoderBytes(&b, handle)
    enc.MustEncode(mapType)
    if strings.Contains(string(b), "0:") {
        fmt.Printf("   * ERROR: unquoted key in \"%s\"\n", b)
    }
}

func main() {
    test("map[int]interface{}", true, map[int]interface{}{0: "int key"})
    test("map[int]interface{}", false, map[int]interface{}{0: "int key"})
    test("map[interface{}]interface{}", true, map[interface{}]interface{}{0: "interface{} key"})
    test("map[interface{}]interface{}", false, map[interface{}]interface{}{0: "interface{} key"})
}

Output:

* map[int]interface{}, canonical = true
* map[int]interface{}, canonical = false
* map[interface{}]interface{}, canonical = true
   * ERROR: unquoted key in "{0:"interface{} key"}"
* map[interface{}]interface{}, canonical = false