encoding: remove reflect on yaml and xml (#1005)
parent
0f011ad688
commit
49064e7232
@ -0,0 +1,92 @@ |
|||||||
|
package encoding |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/xml" |
||||||
|
"fmt" |
||||||
|
"runtime/debug" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
type codec struct{} |
||||||
|
|
||||||
|
func (c codec) Marshal(v interface{}) ([]byte, error) { |
||||||
|
panic("implement me") |
||||||
|
} |
||||||
|
|
||||||
|
func (c codec) Unmarshal(data []byte, v interface{}) error { |
||||||
|
panic("implement me") |
||||||
|
} |
||||||
|
|
||||||
|
func (c codec) Name() string { |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
// codec2 is a Codec implementation with xml.
|
||||||
|
type codec2 struct{} |
||||||
|
|
||||||
|
func (codec2) Marshal(v interface{}) ([]byte, error) { |
||||||
|
return xml.Marshal(v) |
||||||
|
} |
||||||
|
|
||||||
|
func (codec2) Unmarshal(data []byte, v interface{}) error { |
||||||
|
return xml.Unmarshal(data, v) |
||||||
|
} |
||||||
|
|
||||||
|
func (codec2) Name() string { |
||||||
|
return "xml" |
||||||
|
} |
||||||
|
|
||||||
|
func TestRegisterCodec(t *testing.T) { |
||||||
|
f := func() { RegisterCodec(nil) } |
||||||
|
funcDidPanic, panicValue, _ := didPanic(f) |
||||||
|
if !funcDidPanic { |
||||||
|
t.Fatalf(fmt.Sprintf("func should panic\n\tPanic value:\t%#v", panicValue)) |
||||||
|
} |
||||||
|
if panicValue != "cannot register a nil Codec" { |
||||||
|
t.Fatalf("panic error got %s want cannot register a nil Codec", panicValue) |
||||||
|
} |
||||||
|
f = func() { |
||||||
|
RegisterCodec(codec{}) |
||||||
|
} |
||||||
|
funcDidPanic, panicValue, _ = didPanic(f) |
||||||
|
if !funcDidPanic { |
||||||
|
t.Fatalf(fmt.Sprintf("func should panic\n\tPanic value:\t%#v", panicValue)) |
||||||
|
} |
||||||
|
if panicValue != "cannot register Codec with empty string result for Name()" { |
||||||
|
t.Fatalf("panic error got %s want cannot register Codec with empty string result for Name()", panicValue) |
||||||
|
} |
||||||
|
codec := codec2{} |
||||||
|
RegisterCodec(codec) |
||||||
|
got := GetCodec("xml") |
||||||
|
if got != codec { |
||||||
|
t.Fatalf("RegisterCodec(%v) want %v got %v", codec, codec, got) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
|
||||||
|
// methods, and represents a simple func that takes no arguments, and returns nothing.
|
||||||
|
type PanicTestFunc func() |
||||||
|
|
||||||
|
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
|
||||||
|
func didPanic(f PanicTestFunc) (bool, interface{}, string) { |
||||||
|
|
||||||
|
didPanic := false |
||||||
|
var message interface{} |
||||||
|
var stack string |
||||||
|
func() { |
||||||
|
|
||||||
|
defer func() { |
||||||
|
if message = recover(); message != nil { |
||||||
|
didPanic = true |
||||||
|
stack = string(debug.Stack()) |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
// call the target function
|
||||||
|
f() |
||||||
|
|
||||||
|
}() |
||||||
|
|
||||||
|
return didPanic, message, stack |
||||||
|
|
||||||
|
} |
@ -0,0 +1,117 @@ |
|||||||
|
package xml |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"strings" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
type Plain struct { |
||||||
|
V interface{} |
||||||
|
} |
||||||
|
|
||||||
|
type NestedOrder struct { |
||||||
|
XMLName struct{} `xml:"result"` |
||||||
|
Field1 string `xml:"parent>c"` |
||||||
|
Field2 string `xml:"parent>b"` |
||||||
|
Field3 string `xml:"parent>a"` |
||||||
|
} |
||||||
|
|
||||||
|
func TestCodec_Marshal(t *testing.T) { |
||||||
|
tests := []struct { |
||||||
|
Value interface{} |
||||||
|
ExpectXML string |
||||||
|
}{ |
||||||
|
// Test value types
|
||||||
|
{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`}, |
||||||
|
{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`}, |
||||||
|
{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, |
||||||
|
{ |
||||||
|
Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"}, |
||||||
|
ExpectXML: `<result>` + |
||||||
|
`<parent>` + |
||||||
|
`<c>C</c>` + |
||||||
|
`<b>B</b>` + |
||||||
|
`<a>A</a>` + |
||||||
|
`</parent>` + |
||||||
|
`</result>`, |
||||||
|
}, |
||||||
|
} |
||||||
|
for _, tt := range tests { |
||||||
|
data, err := (codec{}).Marshal(tt.Value) |
||||||
|
if err != nil { |
||||||
|
t.Errorf("marshal(%#v): %s", tt.Value, err) |
||||||
|
} |
||||||
|
if got, want := string(data), tt.ExpectXML; got != want { |
||||||
|
if strings.Contains(want, "\n") { |
||||||
|
t.Errorf("marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", tt.Value, got, want) |
||||||
|
} else { |
||||||
|
t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", tt.Value, got, want) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestCodec_Unmarshal(t *testing.T) { |
||||||
|
tests := []struct { |
||||||
|
want interface{} |
||||||
|
InputXML string |
||||||
|
}{ |
||||||
|
{ |
||||||
|
want: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"}, |
||||||
|
InputXML: `<result>` + |
||||||
|
`<parent>` + |
||||||
|
`<c>C</c>` + |
||||||
|
`<b>B</b>` + |
||||||
|
`<a>A</a>` + |
||||||
|
`</parent>` + |
||||||
|
`</result>`}, |
||||||
|
} |
||||||
|
|
||||||
|
for _, tt := range tests { |
||||||
|
vt := reflect.TypeOf(tt.want) |
||||||
|
dest := reflect.New(vt.Elem()).Interface() |
||||||
|
data := []byte(tt.InputXML) |
||||||
|
codec := codec{} |
||||||
|
err := codec.Unmarshal(data, dest) |
||||||
|
if err != nil { |
||||||
|
t.Errorf("unmarshal(%#v, %#v): %s", tt.InputXML, dest, err) |
||||||
|
} |
||||||
|
if got, want := dest, tt.want; !reflect.DeepEqual(got, want) { |
||||||
|
t.Errorf("unmarshal(%q):\nhave %#v\nwant %#v", tt.InputXML, got, want) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestCodec_NilUnmarshal(t *testing.T) { |
||||||
|
|
||||||
|
tests := []struct { |
||||||
|
want interface{} |
||||||
|
InputXML string |
||||||
|
}{ |
||||||
|
{ |
||||||
|
want: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"}, |
||||||
|
InputXML: `<result>` + |
||||||
|
`<parent>` + |
||||||
|
`<c>C</c>` + |
||||||
|
`<b>B</b>` + |
||||||
|
`<a>A</a>` + |
||||||
|
`</parent>` + |
||||||
|
`</result>`}, |
||||||
|
} |
||||||
|
|
||||||
|
for _, tt := range tests { |
||||||
|
s := struct { |
||||||
|
A string `xml:"a"` |
||||||
|
B *NestedOrder |
||||||
|
}{A: "a"} |
||||||
|
data := []byte(tt.InputXML) |
||||||
|
err := (codec{}).Unmarshal(data, &s.B) |
||||||
|
if err != nil { |
||||||
|
t.Errorf("unmarshal(%#v, %#v): %s", tt.InputXML, s.B, err) |
||||||
|
} |
||||||
|
if got, want := s.B, tt.want; !reflect.DeepEqual(got, want) { |
||||||
|
t.Errorf("unmarshal(%q):\nhave %#v\nwant %#v", tt.InputXML, got, want) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package yaml |
||||||
|
|
||||||
|
import ( |
||||||
|
"math" |
||||||
|
"reflect" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestCodec_Unmarshal(t *testing.T) { |
||||||
|
|
||||||
|
tests := []struct { |
||||||
|
data string |
||||||
|
value interface{} |
||||||
|
}{ |
||||||
|
{ |
||||||
|
"", |
||||||
|
(*struct{})(nil), |
||||||
|
}, |
||||||
|
{ |
||||||
|
"{}", &struct{}{}, |
||||||
|
}, { |
||||||
|
"v: hi", |
||||||
|
map[string]string{"v": "hi"}, |
||||||
|
}, { |
||||||
|
"v: hi", map[string]interface{}{"v": "hi"}, |
||||||
|
}, { |
||||||
|
"v: true", |
||||||
|
map[string]string{"v": "true"}, |
||||||
|
}, { |
||||||
|
"v: true", |
||||||
|
map[string]interface{}{"v": true}, |
||||||
|
}, { |
||||||
|
"v: 10", |
||||||
|
map[string]interface{}{"v": 10}, |
||||||
|
}, { |
||||||
|
"v: 0b10", |
||||||
|
map[string]interface{}{"v": 2}, |
||||||
|
}, { |
||||||
|
"v: 0xA", |
||||||
|
map[string]interface{}{"v": 10}, |
||||||
|
}, { |
||||||
|
"v: 4294967296", |
||||||
|
map[string]int64{"v": 4294967296}, |
||||||
|
}, { |
||||||
|
"v: 0.1", |
||||||
|
map[string]interface{}{"v": 0.1}, |
||||||
|
}, { |
||||||
|
"v: .1", |
||||||
|
map[string]interface{}{"v": 0.1}, |
||||||
|
}, { |
||||||
|
"v: .Inf", |
||||||
|
map[string]interface{}{"v": math.Inf(+1)}, |
||||||
|
}, { |
||||||
|
"v: -.Inf", |
||||||
|
map[string]interface{}{"v": math.Inf(-1)}, |
||||||
|
}, { |
||||||
|
"v: -10", |
||||||
|
map[string]interface{}{"v": -10}, |
||||||
|
}, { |
||||||
|
"v: -.1", |
||||||
|
map[string]interface{}{"v": -0.1}, |
||||||
|
}, |
||||||
|
} |
||||||
|
for _, tt := range tests { |
||||||
|
v := reflect.ValueOf(tt.value).Type() |
||||||
|
value := reflect.New(v) |
||||||
|
err := (codec{}).Unmarshal([]byte(tt.data), value.Interface()) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("(codec{}).Unmarshal should not return err") |
||||||
|
} |
||||||
|
} |
||||||
|
spec := struct { |
||||||
|
A string |
||||||
|
B map[string]interface{} |
||||||
|
}{A: "a"} |
||||||
|
err := (codec{}).Unmarshal([]byte("v: hi"), &spec.B) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("(codec{}).Unmarshal should not return err") |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func TestCodec_Marshal(t *testing.T) { |
||||||
|
value := map[string]string{"v": "hi"} |
||||||
|
got, err := (codec{}).Marshal(value) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("should not return err") |
||||||
|
} |
||||||
|
if string(got) != "v: hi\n" { |
||||||
|
t.Fatalf("want \"v: hi\n\" return \"%s\"", string(got)) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue