Fix []byte type of implemeting Marshaler

This commit is contained in:
Masaaki Goshima 2020-08-20 17:58:28 +09:00
parent 8d18f5f3f0
commit d3d5df5bd4
2 changed files with 124 additions and 1 deletions

View File

@ -31,6 +31,20 @@ func (e *Encoder) compileHead(typ *rtype, withIndent bool) (*opcode, error) {
return e.compile(typ, root, withIndent) return e.compile(typ, root, withIndent)
} }
func (e *Encoder) implementsMarshaler(typ *rtype) bool {
switch {
case typ.Implements(marshalJSONType):
return true
case rtype_ptrTo(typ).Implements(marshalJSONType):
return true
case typ.Implements(marshalTextType):
return true
case rtype_ptrTo(typ).Implements(marshalTextType):
return true
}
return false
}
func (e *Encoder) compile(typ *rtype, root, withIndent bool) (*opcode, error) { func (e *Encoder) compile(typ *rtype, root, withIndent bool) (*opcode, error) {
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
@ -46,7 +60,8 @@ func (e *Encoder) compile(typ *rtype, root, withIndent bool) (*opcode, error) {
case reflect.Ptr: case reflect.Ptr:
return e.compilePtr(typ, root, withIndent) return e.compilePtr(typ, root, withIndent)
case reflect.Slice: case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 { elem := typ.Elem()
if !e.implementsMarshaler(elem) && elem.Kind() == reflect.Uint8 {
return e.compileBytes(typ) return e.compileBytes(typ)
} }
return e.compileSlice(typ, root, withIndent) return e.compileSlice(typ, root, withIndent)

View File

@ -1024,3 +1024,111 @@ func TestMarshalFloat(t *testing.T) {
test(0, 32) test(0, 32)
test(math.Copysign(0, -1), 32) test(math.Copysign(0, -1), 32)
} }
var encodeStringTests = []struct {
in string
out string
}{
{"\x00", `"\u0000"`},
{"\x01", `"\u0001"`},
{"\x02", `"\u0002"`},
{"\x03", `"\u0003"`},
{"\x04", `"\u0004"`},
{"\x05", `"\u0005"`},
{"\x06", `"\u0006"`},
{"\x07", `"\u0007"`},
{"\x08", `"\u0008"`},
{"\x09", `"\t"`},
{"\x0a", `"\n"`},
{"\x0b", `"\u000b"`},
{"\x0c", `"\u000c"`},
{"\x0d", `"\r"`},
{"\x0e", `"\u000e"`},
{"\x0f", `"\u000f"`},
{"\x10", `"\u0010"`},
{"\x11", `"\u0011"`},
{"\x12", `"\u0012"`},
{"\x13", `"\u0013"`},
{"\x14", `"\u0014"`},
{"\x15", `"\u0015"`},
{"\x16", `"\u0016"`},
{"\x17", `"\u0017"`},
{"\x18", `"\u0018"`},
{"\x19", `"\u0019"`},
{"\x1a", `"\u001a"`},
{"\x1b", `"\u001b"`},
{"\x1c", `"\u001c"`},
{"\x1d", `"\u001d"`},
{"\x1e", `"\u001e"`},
{"\x1f", `"\u001f"`},
}
func TestEncodeString(t *testing.T) {
for _, tt := range encodeStringTests {
b, err := json.Marshal(tt.in)
if err != nil {
t.Errorf("Marshal(%q): %v", tt.in, err)
continue
}
out := string(b)
if out != tt.out {
t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
}
}
}
type jsonbyte byte
func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }
type textbyte byte
func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }
type jsonint int
func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }
type textint int
func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }
func tenc(format string, a ...interface{}) ([]byte, error) {
var buf bytes.Buffer
fmt.Fprintf(&buf, format, a...)
return buf.Bytes(), nil
}
// Issue 13783
func TestEncodeBytekind(t *testing.T) {
testdata := []struct {
data interface{}
want string
}{
{byte(7), "7"},
{jsonbyte(7), `{"JB":7}`},
{textbyte(4), `"TB:4"`},
{jsonint(5), `{"JI":5}`},
{textint(1), `"TI:1"`},
{[]byte{0, 1}, `"AAE="`},
{[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},
{[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},
{[]textbyte{2, 3}, `["TB:2","TB:3"]`},
{[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},
{[]textint{9, 3}, `["TI:9","TI:3"]`},
{[]int{9, 3}, `[9,3]`},
}
for i, d := range testdata {
js, err := json.Marshal(d.data)
if err != nil {
t.Error(err)
continue
}
got, want := string(js), d.want
if got != want {
t.Errorf("%d: got %s, want %s", i, got, want)
}
}
}