2019-10-19 18:28:36 +09:00
|
|
|
package yaml_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-10-23 21:00:00 +09:00
|
|
|
"fmt"
|
2019-10-19 18:28:36 +09:00
|
|
|
"math"
|
2019-10-26 18:39:15 +09:00
|
|
|
"strconv"
|
2019-10-19 18:28:36 +09:00
|
|
|
"testing"
|
2019-11-07 21:14:36 +09:00
|
|
|
"time"
|
2019-10-19 18:28:36 +09:00
|
|
|
|
|
|
|
"github.com/goccy/go-yaml"
|
2020-01-09 13:33:10 +09:00
|
|
|
"github.com/goccy/go-yaml/ast"
|
2019-10-19 18:28:36 +09:00
|
|
|
)
|
|
|
|
|
2020-02-22 11:43:45 +09:00
|
|
|
var zero = 0
|
|
|
|
var emptyStr = ""
|
|
|
|
|
2019-10-19 18:28:36 +09:00
|
|
|
func TestEncoder(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
source string
|
|
|
|
value interface{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"null\n",
|
|
|
|
(*struct{})(nil),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: hi\n",
|
|
|
|
map[string]string{"v": "hi"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: \"true\"\n",
|
|
|
|
map[string]string{"v": "true"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: \"false\"\n",
|
|
|
|
map[string]string{"v": "false"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: true\n",
|
|
|
|
map[string]interface{}{"v": true},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: false\n",
|
|
|
|
map[string]bool{"v": false},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 10\n",
|
|
|
|
map[string]int{"v": 10},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: -10\n",
|
|
|
|
map[string]int{"v": -10},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 4294967296\n",
|
|
|
|
map[string]int{"v": 4294967296},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 0.1\n",
|
|
|
|
map[string]interface{}{"v": 0.1},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 0.99\n",
|
|
|
|
map[string]float32{"v": 0.99},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: -0.1\n",
|
|
|
|
map[string]float64{"v": -0.1},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 1.0\n",
|
|
|
|
map[string]float64{"v": 1.0},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: .inf\n",
|
|
|
|
map[string]interface{}{"v": math.Inf(0)},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: -.inf\n",
|
|
|
|
map[string]interface{}{"v": math.Inf(-1)},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: .nan\n",
|
|
|
|
map[string]interface{}{"v": math.NaN()},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: null\n",
|
|
|
|
map[string]interface{}{"v": nil},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: \"\"\n",
|
|
|
|
map[string]string{"v": ""},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v:\n- A\n- B\n",
|
2019-10-21 01:28:48 +09:00
|
|
|
map[string][]string{"v": {"A", "B"}},
|
2019-10-19 18:28:36 +09:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: -\n",
|
|
|
|
map[string]string{"a": "-"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"123\n",
|
|
|
|
123,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hello: world\n",
|
|
|
|
map[string]string{"hello": "world"},
|
|
|
|
},
|
2020-02-16 16:10:19 +09:00
|
|
|
{
|
|
|
|
"hello: |\n hello\n world\n",
|
|
|
|
map[string]string{"hello": "hello\nworld\n"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hello: |-\n hello\n world\n",
|
|
|
|
map[string]string{"hello": "hello\nworld"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hello: |+\n hello\n world\n\n",
|
|
|
|
map[string]string{"hello": "hello\nworld\n\n"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hello:\n hello: |\n hello\n world\n",
|
|
|
|
map[string]map[string]string{"hello": {"hello": "hello\nworld\n"}},
|
|
|
|
},
|
2020-02-17 21:14:54 +09:00
|
|
|
{
|
|
|
|
"hello: |\r hello\r world\n",
|
|
|
|
map[string]string{"hello": "hello\rworld\r"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hello: |\r\n hello\r\n world\n",
|
|
|
|
map[string]string{"hello": "hello\r\nworld\r\n"},
|
|
|
|
},
|
2019-10-19 18:28:36 +09:00
|
|
|
{
|
|
|
|
"v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
|
|
|
|
map[string]interface{}{
|
|
|
|
"v": []interface{}{
|
|
|
|
"A",
|
|
|
|
1,
|
|
|
|
map[string][]int{
|
2019-10-21 01:28:48 +09:00
|
|
|
"B": {2, 3},
|
2019-10-19 18:28:36 +09:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a:\n b: c\n",
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": map[string]string{
|
|
|
|
"b": "c",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"t2: 2018-01-09T10:40:47Z\nt4: 2098-01-09T10:40:47Z\n",
|
|
|
|
map[string]string{
|
|
|
|
"t2": "2018-01-09T10:40:47Z",
|
|
|
|
"t4": "2098-01-09T10:40:47Z",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a:\n b: c\n d: e\n",
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": map[string]string{
|
|
|
|
"b": "c",
|
|
|
|
"d": "e",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 3s\n",
|
|
|
|
map[string]string{
|
|
|
|
"a": "3s",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: <foo>\n",
|
|
|
|
map[string]string{"a": "<foo>"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: \"1:1\"\n",
|
|
|
|
map[string]string{"a": "1:1"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 1.2.3.4\n",
|
|
|
|
map[string]string{"a": "1.2.3.4"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: \"b: c\"\n",
|
|
|
|
map[string]string{"a": "b: c"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: \"Hello #comment\"\n",
|
|
|
|
map[string]string{"a": "Hello #comment"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 100.5\n",
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": 100.5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: \"\\\\0\"\n",
|
|
|
|
map[string]string{"a": "\\0"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 1\nb: 2\nc: 3\nd: 4\nsub:\n e: 5\n",
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": 1,
|
|
|
|
"b": 2,
|
|
|
|
"c": 3,
|
|
|
|
"d": 4,
|
|
|
|
"sub": map[string]int{
|
|
|
|
"e": 5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-02-14 17:28:54 +09:00
|
|
|
{
|
|
|
|
"a: 1\nb: []\n",
|
|
|
|
struct {
|
|
|
|
A int
|
|
|
|
B []string
|
|
|
|
}{
|
|
|
|
1, ([]string)(nil),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 1\nb: []\n",
|
|
|
|
struct {
|
|
|
|
A int
|
|
|
|
B []string
|
|
|
|
}{
|
|
|
|
1, []string{},
|
|
|
|
},
|
|
|
|
},
|
2020-03-07 09:50:32 +09:00
|
|
|
{
|
|
|
|
"a: {}\n",
|
|
|
|
struct {
|
|
|
|
A map[string]interface{}
|
|
|
|
}{
|
|
|
|
map[string]interface{}{},
|
|
|
|
},
|
|
|
|
},
|
2019-10-19 18:28:36 +09:00
|
|
|
{
|
|
|
|
"a: b\nc: d\n",
|
|
|
|
struct {
|
|
|
|
A string
|
|
|
|
C string `yaml:"c"`
|
|
|
|
}{
|
|
|
|
"b", "d",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 1\n",
|
|
|
|
struct {
|
|
|
|
A int
|
|
|
|
B int `yaml:"-"`
|
|
|
|
}{
|
|
|
|
1, 0,
|
|
|
|
},
|
|
|
|
},
|
2020-02-22 11:43:45 +09:00
|
|
|
{
|
|
|
|
"a: \"\"\n",
|
|
|
|
struct {
|
|
|
|
A string
|
|
|
|
}{
|
|
|
|
"",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: null\n",
|
|
|
|
struct {
|
|
|
|
A *string
|
|
|
|
}{
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: \"\"\n",
|
|
|
|
struct {
|
|
|
|
A *string
|
|
|
|
}{
|
|
|
|
&emptyStr,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: null\n",
|
|
|
|
struct {
|
|
|
|
A *int
|
|
|
|
}{
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 0\n",
|
|
|
|
struct {
|
|
|
|
A *int
|
|
|
|
}{
|
|
|
|
&zero,
|
|
|
|
},
|
|
|
|
},
|
2019-10-31 13:08:11 +09:00
|
|
|
|
|
|
|
// Conditional flag
|
|
|
|
{
|
|
|
|
"a: 1\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A int `yaml:"a,omitempty"`
|
|
|
|
B int `yaml:"b,omitempty"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{1, 0},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"{}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A int `yaml:"a,omitempty"`
|
|
|
|
B int `yaml:"b,omitempty"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{0, 0},
|
|
|
|
},
|
|
|
|
|
2020-03-09 21:58:05 +09:00
|
|
|
{
|
|
|
|
"a:\n y: \"\"\n",
|
|
|
|
struct {
|
|
|
|
A *struct {
|
|
|
|
X string `yaml:"x,omitempty"`
|
|
|
|
Y string
|
|
|
|
}
|
|
|
|
}{&struct {
|
|
|
|
X string `yaml:"x,omitempty"`
|
|
|
|
Y string
|
|
|
|
}{}},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"a: {}\n",
|
|
|
|
struct {
|
|
|
|
A *struct {
|
|
|
|
X string `yaml:"x,omitempty"`
|
|
|
|
Y string `yaml:"y,omitempty"`
|
|
|
|
}
|
|
|
|
}{&struct {
|
|
|
|
X string `yaml:"x,omitempty"`
|
|
|
|
Y string `yaml:"y,omitempty"`
|
|
|
|
}{}},
|
|
|
|
},
|
|
|
|
|
2019-10-31 13:08:11 +09:00
|
|
|
{
|
|
|
|
"a: {x: 1}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A *struct{ X, y int } `yaml:"a,omitempty,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{&struct{ X, y int }{1, 2}},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"{}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A *struct{ X, y int } `yaml:"a,omitempty,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{nil},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"a: {x: 0}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A *struct{ X, y int } `yaml:"a,omitempty,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{&struct{ X, y int }{}},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"a: {x: 1}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A struct{ X, y int } `yaml:"a,omitempty,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{struct{ X, y int }{1, 2}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"{}\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A struct{ X, y int } `yaml:"a,omitempty,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{struct{ X, y int }{0, 1}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: 1.0\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A float64 `yaml:"a,omitempty"`
|
|
|
|
B float64 `yaml:"b,omitempty"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{1, 0},
|
|
|
|
},
|
2020-02-14 17:28:54 +09:00
|
|
|
{
|
|
|
|
"a: 1\n",
|
|
|
|
struct {
|
|
|
|
A int
|
|
|
|
B []string `yaml:"b,omitempty"`
|
|
|
|
}{
|
|
|
|
1, []string{},
|
|
|
|
},
|
|
|
|
},
|
2019-10-31 13:08:11 +09:00
|
|
|
|
|
|
|
// Flow flag
|
|
|
|
{
|
|
|
|
"a: [1, 2]\n",
|
|
|
|
struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A []int `yaml:"a,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{[]int{1, 2}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: {b: c, d: e}\n",
|
|
|
|
&struct {
|
2019-11-13 12:14:49 +09:00
|
|
|
A map[string]string `yaml:"a,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{map[string]string{"b": "c", "d": "e"}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"a: {b: c, d: e}\n",
|
|
|
|
struct {
|
|
|
|
A struct {
|
|
|
|
B, D string
|
2019-11-13 12:14:49 +09:00
|
|
|
} `yaml:"a,flow"`
|
2019-10-31 13:08:11 +09:00
|
|
|
}{struct{ B, D string }{"c", "e"}},
|
|
|
|
},
|
2019-11-07 17:18:17 +09:00
|
|
|
|
|
|
|
// Multi bytes
|
|
|
|
{
|
2019-11-07 18:01:45 +09:00
|
|
|
"v: あいうえお\nv2: かきくけこ\n",
|
|
|
|
map[string]string{"v": "あいうえお", "v2": "かきくけこ"},
|
2019-11-07 17:18:17 +09:00
|
|
|
},
|
2019-11-07 21:14:36 +09:00
|
|
|
|
|
|
|
// time value
|
|
|
|
{
|
|
|
|
"v: 0001-01-01T00:00:00Z\n",
|
|
|
|
map[string]time.Time{"v": time.Time{}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: 0001-01-01T00:00:00Z\n",
|
|
|
|
map[string]*time.Time{"v": &time.Time{}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"v: null\n",
|
|
|
|
map[string]*time.Time{"v": nil},
|
|
|
|
},
|
2019-10-19 18:28:36 +09:00
|
|
|
}
|
|
|
|
for _, test := range tests {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
if err := enc.Encode(test.value); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
if test.source != buf.String() {
|
|
|
|
t.Fatalf("expect = [%s], actual = [%s]", test.source, buf.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-19 22:01:36 +09:00
|
|
|
|
2019-12-12 17:38:01 +09:00
|
|
|
func TestEncodeStructIncludeMap(t *testing.T) {
|
|
|
|
type U struct {
|
|
|
|
M map[string]string
|
|
|
|
}
|
|
|
|
type T struct {
|
|
|
|
A U
|
|
|
|
}
|
|
|
|
bytes, err := yaml.Marshal(T{
|
|
|
|
A: U{
|
|
|
|
M: map[string]string{"x": "y"},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := "a:\n m:\n x: y\n"
|
|
|
|
actual := string(bytes)
|
|
|
|
if actual != expect {
|
|
|
|
t.Fatalf("unexpected output. expect:[%s] actual:[%s]", expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 22:01:36 +09:00
|
|
|
func TestEncodeWithAnchorAndAlias(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
type T struct {
|
|
|
|
A int
|
|
|
|
B string
|
|
|
|
}
|
|
|
|
var v struct {
|
|
|
|
A *T `yaml:"a,anchor=c"`
|
|
|
|
B *T `yaml:"b,alias=c"`
|
|
|
|
}
|
|
|
|
v.A = &T{A: 1, B: "hello"}
|
|
|
|
v.B = v.A
|
|
|
|
if err := enc.Encode(v); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := "a: &c\n a: 1\n b: hello\nb: *c\n"
|
|
|
|
if expect != buf.String() {
|
|
|
|
t.Fatalf("expect = [%s], actual = [%s]", expect, buf.String())
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:05:03 +09:00
|
|
|
|
|
|
|
func TestEncodeWithAutoAlias(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
type T struct {
|
|
|
|
I int
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
var v struct {
|
|
|
|
A *T `yaml:"a,anchor=a"`
|
|
|
|
B *T `yaml:"b,anchor=b"`
|
|
|
|
C *T `yaml:"c,alias"`
|
|
|
|
D *T `yaml:"d,alias"`
|
|
|
|
}
|
|
|
|
v.A = &T{I: 1, S: "hello"}
|
|
|
|
v.B = &T{I: 2, S: "world"}
|
|
|
|
v.C = v.A
|
|
|
|
v.D = v.B
|
|
|
|
if err := enc.Encode(v); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `a: &a
|
|
|
|
i: 1
|
|
|
|
s: hello
|
|
|
|
b: &b
|
|
|
|
i: 2
|
|
|
|
s: world
|
|
|
|
c: *a
|
|
|
|
d: *b
|
|
|
|
`
|
|
|
|
if expect != buf.String() {
|
|
|
|
t.Fatalf("expect = [%s], actual = [%s]", expect, buf.String())
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 13:31:29 +09:00
|
|
|
|
|
|
|
func TestEncodeWithImplicitAnchorAndAlias(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
type T struct {
|
|
|
|
I int
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
var v struct {
|
|
|
|
A *T `yaml:"a,anchor"`
|
|
|
|
B *T `yaml:"b,anchor"`
|
|
|
|
C *T `yaml:"c,alias"`
|
|
|
|
D *T `yaml:"d,alias"`
|
|
|
|
}
|
|
|
|
v.A = &T{I: 1, S: "hello"}
|
|
|
|
v.B = &T{I: 2, S: "world"}
|
|
|
|
v.C = v.A
|
|
|
|
v.D = v.B
|
|
|
|
if err := enc.Encode(v); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `a: &a
|
|
|
|
i: 1
|
|
|
|
s: hello
|
|
|
|
b: &b
|
|
|
|
i: 2
|
|
|
|
s: world
|
|
|
|
c: *a
|
|
|
|
d: *b
|
|
|
|
`
|
|
|
|
if expect != buf.String() {
|
|
|
|
t.Fatalf("expect = [%s], actual = [%s]", expect, buf.String())
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 21:47:06 +09:00
|
|
|
|
|
|
|
func TestEncodeWithMerge(t *testing.T) {
|
|
|
|
type Person struct {
|
|
|
|
*Person `yaml:",omitempty,inline,alias"`
|
|
|
|
Name string `yaml:",omitempty"`
|
|
|
|
Age int `yaml:",omitempty"`
|
|
|
|
}
|
|
|
|
defaultPerson := &Person{
|
|
|
|
Name: "John Smith",
|
|
|
|
Age: 20,
|
|
|
|
}
|
|
|
|
people := []*Person{
|
|
|
|
{
|
|
|
|
Person: defaultPerson,
|
|
|
|
Name: "Ken",
|
|
|
|
Age: 10,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Person: defaultPerson,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
var doc struct {
|
|
|
|
Default *Person `yaml:"default,anchor"`
|
|
|
|
People []*Person `yaml:"people"`
|
|
|
|
}
|
|
|
|
doc.Default = defaultPerson
|
|
|
|
doc.People = people
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
if err := enc.Encode(doc); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `default: &default
|
|
|
|
name: John Smith
|
|
|
|
age: 20
|
|
|
|
people:
|
|
|
|
- <<: *default
|
|
|
|
name: Ken
|
|
|
|
age: 10
|
|
|
|
- <<: *default
|
|
|
|
`
|
|
|
|
if expect != buf.String() {
|
|
|
|
t.Fatalf("expect = [%s], actual = [%s]", expect, buf.String())
|
|
|
|
}
|
|
|
|
}
|
2019-10-23 21:00:00 +09:00
|
|
|
|
2019-10-28 22:13:03 +09:00
|
|
|
func TestEncoder_Inline(t *testing.T) {
|
2019-10-28 21:37:12 +09:00
|
|
|
type base struct {
|
|
|
|
A int
|
|
|
|
B string
|
|
|
|
}
|
2019-10-28 22:13:03 +09:00
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
if err := enc.Encode(struct {
|
2019-10-28 21:37:12 +09:00
|
|
|
*base `yaml:",inline"`
|
|
|
|
C bool
|
|
|
|
}{
|
|
|
|
base: &base{
|
|
|
|
A: 1,
|
|
|
|
B: "hello",
|
|
|
|
},
|
|
|
|
C: true,
|
2019-10-28 22:13:03 +09:00
|
|
|
}); err != nil {
|
2019-10-28 21:37:12 +09:00
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `
|
|
|
|
a: 1
|
|
|
|
b: hello
|
|
|
|
c: true
|
|
|
|
`
|
2019-10-28 22:13:03 +09:00
|
|
|
actual := "\n" + buf.String()
|
2019-10-28 21:37:12 +09:00
|
|
|
if expect != actual {
|
|
|
|
t.Fatalf("inline marshal error: expect=[%s] actual=[%s]", expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 22:25:00 +09:00
|
|
|
func TestEncoder_InlineAndConflictKey(t *testing.T) {
|
|
|
|
type base struct {
|
|
|
|
A int
|
|
|
|
B string
|
|
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf)
|
|
|
|
if err := enc.Encode(struct {
|
|
|
|
*base `yaml:",inline"`
|
|
|
|
A int // conflict
|
|
|
|
C bool
|
|
|
|
}{
|
|
|
|
base: &base{
|
|
|
|
A: 1,
|
|
|
|
B: "hello",
|
|
|
|
},
|
|
|
|
A: 0, // default value
|
|
|
|
C: true,
|
|
|
|
}); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `
|
|
|
|
b: hello
|
|
|
|
a: 0
|
|
|
|
c: true
|
|
|
|
`
|
|
|
|
actual := "\n" + buf.String()
|
|
|
|
if expect != actual {
|
|
|
|
t.Fatalf("inline marshal error: expect=[%s] actual=[%s]", expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 13:29:43 +09:00
|
|
|
func TestEncoder_Flow(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf, yaml.Flow(true))
|
|
|
|
var v struct {
|
|
|
|
A int
|
|
|
|
B string
|
|
|
|
C struct {
|
|
|
|
D int
|
|
|
|
E string
|
|
|
|
}
|
|
|
|
F []int
|
|
|
|
}
|
|
|
|
v.A = 1
|
|
|
|
v.B = "hello"
|
|
|
|
v.C.D = 3
|
|
|
|
v.C.E = "world"
|
|
|
|
v.F = []int{1, 2}
|
|
|
|
if err := enc.Encode(v); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `
|
|
|
|
{a: 1, b: hello, c: {d: 3, e: world}, f: [1, 2]}
|
|
|
|
`
|
|
|
|
actual := "\n" + buf.String()
|
|
|
|
if expect != actual {
|
|
|
|
t.Fatalf("flow style marshal error: expect=[%s] actual=[%s]", expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-02 19:56:02 +09:00
|
|
|
func TestEncoder_JSON(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := yaml.NewEncoder(&buf, yaml.JSON())
|
|
|
|
type st struct {
|
|
|
|
I int8
|
|
|
|
S string
|
|
|
|
F float32
|
|
|
|
}
|
|
|
|
if err := enc.Encode(struct {
|
|
|
|
I int
|
|
|
|
U uint
|
|
|
|
S string
|
|
|
|
F float64
|
|
|
|
Struct *st
|
|
|
|
Slice []int
|
|
|
|
Map map[string]interface{}
|
|
|
|
Time time.Time
|
|
|
|
}{
|
|
|
|
I: -10,
|
|
|
|
U: 10,
|
|
|
|
S: "hello",
|
|
|
|
F: 3.14,
|
|
|
|
Struct: &st{
|
|
|
|
I: 2,
|
|
|
|
S: "world",
|
|
|
|
F: 1.23,
|
|
|
|
},
|
|
|
|
Slice: []int{1, 2, 3, 4, 5},
|
|
|
|
Map: map[string]interface{}{
|
|
|
|
"a": 1,
|
|
|
|
"b": 1.23,
|
|
|
|
"c": "json",
|
|
|
|
},
|
|
|
|
Time: time.Time{},
|
|
|
|
}); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `
|
|
|
|
{"i": -10, "u": 10, "s": "hello", "f": 3.14, "struct": {"i": 2, "s": "world", "f": 1.23}, "slice": [1, 2, 3, 4, 5], "map": {"a": 1, "b": 1.23, "c": "json"}, "time": "0001-01-01T00:00:00Z"}
|
|
|
|
`
|
|
|
|
actual := "\n" + buf.String()
|
|
|
|
if expect != actual {
|
|
|
|
t.Fatalf("JSON style marshal error: expect=[%s] actual=[%s]", expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 13:33:10 +09:00
|
|
|
func TestEncoder_MarshalAnchor(t *testing.T) {
|
|
|
|
type Host struct {
|
|
|
|
Hostname string
|
|
|
|
Username string
|
|
|
|
Password string
|
|
|
|
}
|
|
|
|
type HostDecl struct {
|
|
|
|
Host *Host `yaml:",anchor"`
|
|
|
|
}
|
|
|
|
type Queue struct {
|
|
|
|
Name string `yaml:","`
|
|
|
|
*Host `yaml:",alias"`
|
|
|
|
}
|
|
|
|
var doc struct {
|
|
|
|
Hosts []*HostDecl `yaml:"hosts"`
|
|
|
|
Queues []*Queue `yaml:"queues"`
|
|
|
|
}
|
|
|
|
host1 := &Host{
|
|
|
|
Hostname: "host1.example.com",
|
|
|
|
Username: "userA",
|
|
|
|
Password: "pass1",
|
|
|
|
}
|
|
|
|
host2 := &Host{
|
|
|
|
Hostname: "host2.example.com",
|
|
|
|
Username: "userB",
|
|
|
|
Password: "pass2",
|
|
|
|
}
|
|
|
|
doc.Hosts = []*HostDecl{
|
|
|
|
{
|
|
|
|
Host: host1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Host: host2,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
doc.Queues = []*Queue{
|
|
|
|
{
|
|
|
|
Name: "queue",
|
|
|
|
Host: host1,
|
|
|
|
}, {
|
|
|
|
Name: "queue2",
|
|
|
|
Host: host2,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
hostIdx := 1
|
|
|
|
opt := yaml.MarshalAnchor(func(anchor *ast.AnchorNode, value interface{}) error {
|
|
|
|
if _, ok := value.(*Host); ok {
|
|
|
|
nameNode := anchor.Name.(*ast.StringNode)
|
|
|
|
nameNode.Value = fmt.Sprintf("host%d", hostIdx)
|
|
|
|
hostIdx++
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if err := yaml.NewEncoder(&buf, opt).Encode(doc); err != nil {
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
}
|
|
|
|
expect := `
|
|
|
|
hosts:
|
|
|
|
- host: &host1
|
|
|
|
hostname: host1.example.com
|
|
|
|
username: userA
|
|
|
|
password: pass1
|
|
|
|
- host: &host2
|
|
|
|
hostname: host2.example.com
|
|
|
|
username: userB
|
|
|
|
password: pass2
|
|
|
|
queues:
|
|
|
|
- name: queue
|
|
|
|
host: *host1
|
|
|
|
- name: queue2
|
|
|
|
host: *host2
|
|
|
|
`
|
|
|
|
if "\n"+buf.String() != expect {
|
|
|
|
t.Fatalf("unexpected output. %s", buf.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-23 21:00:00 +09:00
|
|
|
func Example_Marshal_ExplicitAnchorAlias() {
|
|
|
|
type T struct {
|
|
|
|
A int
|
|
|
|
B string
|
|
|
|
}
|
|
|
|
var v struct {
|
|
|
|
C *T `yaml:"c,anchor=x"`
|
|
|
|
D *T `yaml:"d,alias=x"`
|
|
|
|
}
|
|
|
|
v.C = &T{A: 1, B: "hello"}
|
|
|
|
v.D = v.C
|
|
|
|
bytes, err := yaml.Marshal(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Println(string(bytes))
|
|
|
|
// OUTPUT:
|
|
|
|
//c: &x
|
|
|
|
// a: 1
|
|
|
|
// b: hello
|
|
|
|
//d: *x
|
|
|
|
}
|
|
|
|
|
|
|
|
func Example_Marshal_ImplicitAnchorAlias() {
|
|
|
|
type T struct {
|
|
|
|
I int
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
var v struct {
|
|
|
|
A *T `yaml:"a,anchor"`
|
|
|
|
B *T `yaml:"b,anchor"`
|
|
|
|
C *T `yaml:"c,alias"`
|
|
|
|
D *T `yaml:"d,alias"`
|
|
|
|
}
|
|
|
|
v.A = &T{I: 1, S: "hello"}
|
|
|
|
v.B = &T{I: 2, S: "world"}
|
|
|
|
v.C = v.A // C has same pointer address to A
|
|
|
|
v.D = v.B // D has same pointer address to B
|
|
|
|
bytes, err := yaml.Marshal(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Println(string(bytes))
|
|
|
|
// OUTPUT:
|
2019-10-23 21:05:41 +09:00
|
|
|
// a: &a
|
|
|
|
// i: 1
|
|
|
|
// s: hello
|
|
|
|
// b: &b
|
|
|
|
// i: 2
|
|
|
|
// s: world
|
|
|
|
// c: *a
|
|
|
|
// d: *b
|
2019-10-23 21:00:00 +09:00
|
|
|
}
|
2019-10-26 18:39:15 +09:00
|
|
|
|
|
|
|
type tMarshal []string
|
|
|
|
|
|
|
|
func (t *tMarshal) MarshalYAML() ([]byte, error) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("tags:\n")
|
|
|
|
for i, v := range *t {
|
|
|
|
if i == 0 {
|
|
|
|
fmt.Fprintf(&buf, "- %s\n", v)
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(&buf, " %s\n", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
|
|
|
func Test_Marshaler(t *testing.T) {
|
|
|
|
const expected = `- hello-world
|
|
|
|
`
|
|
|
|
|
|
|
|
// sanity check
|
|
|
|
var l []string
|
|
|
|
if err := yaml.Unmarshal([]byte(expected), &l); err != nil {
|
|
|
|
t.Fatalf("failed to parse string: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
buf, err := yaml.Marshal(tMarshal{"hello-world"})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to marshal: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(buf) != expected {
|
|
|
|
t.Fatalf("expected '%s', got '%s'", expected, buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Logf("%s", buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
type SlowMarshaler struct {
|
|
|
|
A string
|
|
|
|
B int
|
|
|
|
}
|
|
|
|
type FastMarshaler struct {
|
|
|
|
A string
|
|
|
|
B int
|
|
|
|
}
|
2020-01-12 02:50:51 +09:00
|
|
|
type TextMarshaler int64
|
|
|
|
type TextMarshalerContainer struct {
|
|
|
|
Field TextMarshaler `yaml:"field"`
|
2020-02-16 16:10:19 +09:00
|
|
|
}
|
|
|
|
|
2019-10-26 18:39:15 +09:00
|
|
|
func (v SlowMarshaler) MarshalYAML() ([]byte, error) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("tags:\n")
|
|
|
|
buf.WriteString("- slow-marshaler\n")
|
|
|
|
buf.WriteString("a: " + v.A + "\n")
|
|
|
|
buf.WriteString("b: " + strconv.FormatInt(int64(v.B), 10) + "\n")
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v FastMarshaler) MarshalYAML() (interface{}, error) {
|
|
|
|
return yaml.MapSlice{
|
|
|
|
{"tags", []string{"fast-marshaler"}},
|
|
|
|
{"a", v.A},
|
|
|
|
{"b", v.B},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-01-12 02:50:51 +09:00
|
|
|
func (t TextMarshaler) MarshalText() ([]byte, error) {
|
|
|
|
return []byte(strconv.FormatInt(int64(t), 8)), nil
|
|
|
|
}
|
|
|
|
|
2019-10-26 18:39:15 +09:00
|
|
|
func Example_MarshalYAML() {
|
|
|
|
var slow SlowMarshaler
|
|
|
|
slow.A = "Hello slow poke"
|
|
|
|
slow.B = 100
|
|
|
|
buf, err := yaml.Marshal(slow)
|
|
|
|
if err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(string(buf))
|
|
|
|
|
|
|
|
var fast FastMarshaler
|
|
|
|
fast.A = "Hello speed demon"
|
|
|
|
fast.B = 100
|
|
|
|
buf, err = yaml.Marshal(fast)
|
|
|
|
if err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
|
2020-01-12 02:50:51 +09:00
|
|
|
fmt.Println(string(buf))
|
|
|
|
|
|
|
|
text := TextMarshalerContainer{
|
|
|
|
Field: 11,
|
|
|
|
}
|
|
|
|
buf, err = yaml.Marshal(text)
|
|
|
|
if err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
|
2019-10-26 18:39:15 +09:00
|
|
|
fmt.Println(string(buf))
|
|
|
|
// OUTPUT:
|
|
|
|
// tags:
|
|
|
|
// - slow-marshaler
|
|
|
|
// a: Hello slow poke
|
|
|
|
// b: 100
|
|
|
|
//
|
|
|
|
// tags:
|
|
|
|
// - fast-marshaler
|
|
|
|
// a: Hello speed demon
|
|
|
|
// b: 100
|
2020-01-12 02:50:51 +09:00
|
|
|
//
|
|
|
|
// field: 13
|
2019-10-26 18:39:15 +09:00
|
|
|
}
|