yaml/encode_test.go

424 строки
7.4 KiB
Go
Исходник Обычный вид История

2014-03-05 22:48:33 +04:00
package yaml_test
2011-01-10 21:03:42 +03:00
import (
2012-09-20 13:00:32 +04:00
"fmt"
2014-04-06 17:56:05 +04:00
. "gopkg.in/check.v1"
2014-09-23 01:31:54 +04:00
"gopkg.in/yaml.v2"
2011-04-14 01:20:44 +04:00
"math"
2012-09-20 13:27:14 +04:00
"strconv"
2012-09-20 13:00:32 +04:00
"strings"
2014-04-06 17:56:05 +04:00
"time"
2011-01-10 21:03:42 +03:00
)
var marshalIntTest = 123
2011-01-20 15:06:04 +03:00
var marshalTests = []struct {
2011-04-14 01:20:44 +04:00
value interface{}
data string
2011-01-20 15:06:04 +03:00
}{
{
&struct{}{},
"{}\n",
}, {
map[string]string{"v": "hi"},
"v: hi\n",
}, {
map[string]interface{}{"v": "hi"},
"v: hi\n",
}, {
map[string]string{"v": "true"},
"v: \"true\"\n",
}, {
map[string]string{"v": "false"},
"v: \"false\"\n",
}, {
map[string]interface{}{"v": true},
"v: true\n",
}, {
map[string]interface{}{"v": false},
"v: false\n",
}, {
map[string]interface{}{"v": 10},
"v: 10\n",
}, {
map[string]interface{}{"v": -10},
"v: -10\n",
}, {
map[string]uint{"v": 42},
"v: 42\n",
}, {
map[string]interface{}{"v": int64(4294967296)},
"v: 4294967296\n",
}, {
map[string]int64{"v": int64(4294967296)},
"v: 4294967296\n",
}, {
map[string]uint64{"v": 4294967296},
"v: 4294967296\n",
}, {
map[string]interface{}{"v": "10"},
"v: \"10\"\n",
}, {
map[string]interface{}{"v": 0.1},
"v: 0.1\n",
}, {
map[string]interface{}{"v": float64(0.1)},
"v: 0.1\n",
}, {
map[string]interface{}{"v": -0.1},
"v: -0.1\n",
}, {
map[string]interface{}{"v": math.Inf(+1)},
"v: .inf\n",
}, {
map[string]interface{}{"v": math.Inf(-1)},
"v: -.inf\n",
}, {
map[string]interface{}{"v": math.NaN()},
"v: .nan\n",
}, {
map[string]interface{}{"v": nil},
"v: null\n",
}, {
map[string]interface{}{"v": ""},
"v: \"\"\n",
}, {
map[string][]string{"v": []string{"A", "B"}},
"v:\n- A\n- B\n",
2013-04-29 19:13:04 +04:00
}, {
map[string][]string{"v": []string{"A", "B\nC"}},
"v:\n- A\n- |-\n B\n C\n",
}, {
map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
"v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
}, {
map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
"a:\n b: c\n",
2013-11-14 06:37:57 +04:00
}, {
2013-11-14 06:37:06 +04:00
map[string]interface{}{"a": "-"},
2013-11-14 06:37:57 +04:00
"a: '-'\n",
},
2011-04-14 01:20:44 +04:00
// Simple values.
{
&marshalIntTest,
"123\n",
},
2011-04-14 01:20:44 +04:00
// Structures
{
&struct{ Hello string }{"world"},
"hello: world\n",
}, {
&struct {
A struct {
B string
}
}{struct{ B string }{"c"}},
"a:\n b: c\n",
}, {
&struct {
A *struct {
B string
}
}{&struct{ B string }{"c"}},
"a:\n b: c\n",
}, {
&struct {
A *struct {
B string
}
}{},
"a: null\n",
}, {
&struct{ A int }{1},
"a: 1\n",
}, {
&struct{ A []int }{[]int{1, 2}},
"a:\n- 1\n- 2\n",
}, {
&struct {
B int "a"
}{1},
"a: 1\n",
}, {
&struct{ A bool }{true},
"a: true\n",
},
2011-04-14 01:20:44 +04:00
// Conditional flag
{
&struct {
A int "a,omitempty"
B int "b,omitempty"
}{1, 0},
"a: 1\n",
}, {
&struct {
A int "a,omitempty"
B int "b,omitempty"
}{0, 0},
"{}\n",
}, {
&struct {
A *struct{ X int } "a,omitempty"
B int "b,omitempty"
}{nil, 0},
"{}\n",
},
2011-04-14 01:20:44 +04:00
// Flow flag
{
&struct {
A []int "a,flow"
}{[]int{1, 2}},
"a: [1, 2]\n",
}, {
2011-04-14 01:20:44 +04:00
&struct {
A map[string]string "a,flow"
}{map[string]string{"b": "c", "d": "e"}},
"a: {b: c, d: e}\n",
}, {
2011-04-14 01:20:44 +04:00
&struct {
A struct {
B, D string
} "a,flow"
}{struct{ B, D string }{"c", "e"}},
"a: {b: c, d: e}\n",
},
// Unexported field
{
&struct {
u int
A int
}{0, 1},
"a: 1\n",
},
2013-04-17 22:55:21 +04:00
// Ignored field
{
2013-04-17 22:55:21 +04:00
&struct {
A int
B int "-"
}{1, 2},
"a: 1\n",
},
// Struct inlining
{
&struct {
A int
C inlineB `yaml:",inline"`
}{1, inlineB{2, inlineC{3}}},
"a: 1\nb: 2\nc: 3\n",
},
2014-04-06 17:56:05 +04:00
// Duration
{
map[string]time.Duration{"a": 3 * time.Second},
"a: 3s\n",
},
// Issue #24: bug in map merging logic.
{
map[string]string{"a": "<foo>"},
"a: <foo>\n",
},
// Issue #34: marshal unsupported base 60 floats quoted for compatibility
// with old YAML 1.1 parsers.
{
map[string]string{"a": "1:1"},
"a: \"1:1\"\n",
},
// Binary data.
{
map[string]string{"a": "\x00"},
"a: \"\\0\"\n",
}, {
map[string]string{"a": "\x80\x81\x82"},
"a: !!binary gIGC\n",
}, {
map[string]string{"a": strings.Repeat("\x90", 54)},
"a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
},
2014-09-19 17:22:26 +04:00
// Ordered maps.
{
&yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
"b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
},
// Encode unicode as utf-8 rather than in escaped form.
{
map[string]string{"a": "你好"},
"a: 你好\n",
},
2011-01-10 21:03:42 +03:00
}
func (s *S) TestMarshal(c *C) {
2011-04-14 01:20:44 +04:00
for _, item := range marshalTests {
2014-03-05 22:48:33 +04:00
data, err := yaml.Marshal(item.value)
2011-04-14 01:20:44 +04:00
c.Assert(err, IsNil)
c.Assert(string(data), Equals, item.data)
}
2011-01-10 21:03:42 +03:00
}
var marshalErrorTests = []struct {
value interface{}
error string
panic string
}{{
value: &struct {
B int
inlineB ",inline"
}{1, inlineB{2, inlineC{3}}},
panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
}}
func (s *S) TestMarshalErrors(c *C) {
for _, item := range marshalErrorTests {
if item.panic != "" {
c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
} else {
_, err := yaml.Marshal(item.value)
c.Assert(err, ErrorMatches, item.error)
}
}
}
2011-01-10 21:03:42 +03:00
func (s *S) TestMarshalTypeCache(c *C) {
var data []byte
var err error
func() {
type T struct{ A int }
2014-03-05 22:48:33 +04:00
data, err = yaml.Marshal(&T{})
c.Assert(err, IsNil)
}()
func() {
type T struct{ B int }
2014-03-05 22:48:33 +04:00
data, err = yaml.Marshal(&T{})
c.Assert(err, IsNil)
}()
c.Assert(string(data), Equals, "b: 0\n")
}
2014-09-20 03:29:07 +04:00
var marshalerTests = []struct {
data string
value interface{}
}{
{"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
{"_:\n- 1\n- A\n", []interface{}{1, "A"}},
{"_: 10\n", 10},
{"_: null\n", nil},
{"_: BAR!\n", "BAR!"},
}
2014-09-20 03:29:07 +04:00
type marshalerType struct {
2011-04-14 01:20:44 +04:00
value interface{}
2011-01-10 21:03:42 +03:00
}
2014-09-20 03:29:07 +04:00
func (o marshalerType) MarshalYAML() (interface{}, error) {
return o.value, nil
2011-01-10 21:03:42 +03:00
}
2014-09-20 03:29:07 +04:00
type marshalerValue struct {
Field marshalerType "_"
2011-01-10 21:03:42 +03:00
}
2014-09-20 03:29:07 +04:00
func (s *S) TestMarshaler(c *C) {
for _, item := range marshalerTests {
obj := &marshalerValue{}
2011-04-14 01:20:44 +04:00
obj.Field.value = item.value
2014-03-05 22:48:33 +04:00
data, err := yaml.Marshal(obj)
2011-04-14 01:20:44 +04:00
c.Assert(err, IsNil)
c.Assert(string(data), Equals, string(item.data))
}
2011-01-10 21:03:42 +03:00
}
2014-09-20 03:29:07 +04:00
func (s *S) TestMarshalerWholeDocument(c *C) {
obj := &marshalerType{}
2011-04-14 01:20:44 +04:00
obj.value = map[string]string{"hello": "world!"}
2014-03-05 22:48:33 +04:00
data, err := yaml.Marshal(obj)
2011-04-14 01:20:44 +04:00
c.Assert(err, IsNil)
c.Assert(string(data), Equals, "hello: world!\n")
2011-01-10 21:03:42 +03:00
}
2012-09-20 13:00:32 +04:00
type failingMarshaler struct{}
func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
return nil, failingErr
}
func (s *S) TestMarshalerError(c *C) {
_, err := yaml.Marshal(&failingMarshaler{})
c.Assert(err, Equals, failingErr)
}
2012-09-20 13:00:32 +04:00
func (s *S) TestSortedOutput(c *C) {
order := []interface{}{
2012-09-20 13:27:14 +04:00
false,
true,
2012-09-20 13:00:32 +04:00
1,
2012-09-20 13:27:14 +04:00
uint(1),
2012-09-20 13:00:32 +04:00
1.0,
1.1,
1.2,
2,
2012-09-20 13:27:14 +04:00
uint(2),
2012-09-20 13:00:32 +04:00
2.0,
2.1,
"",
2012-09-20 13:27:14 +04:00
".1",
".2",
".a",
"1",
"2",
2012-09-20 13:00:32 +04:00
"a!10",
"a/2",
"a/10",
"a~10",
"ab/1",
"b/1",
"b/01",
"b/2",
"b/02",
"b/3",
"b/03",
"b1",
"b01",
"b3",
"c2.10",
"c10.2",
"d1",
"d12",
"d12a",
}
m := make(map[interface{}]int)
for _, k := range order {
m[k] = 1
}
2014-03-05 22:48:33 +04:00
data, err := yaml.Marshal(m)
2012-09-20 13:00:32 +04:00
c.Assert(err, IsNil)
out := "\n" + string(data)
last := 0
for i, k := range order {
repr := fmt.Sprint(k)
if s, ok := k.(string); ok {
if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
2012-09-20 13:27:14 +04:00
repr = `"` + repr + `"`
}
}
2012-09-20 13:00:32 +04:00
index := strings.Index(out, "\n"+repr+":")
if index == -1 {
c.Fatalf("%#v is not in the output: %#v", k, out)
}
if index < last {
c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
}
last = index
}
}