2019-10-18 13:05:36 +09:00
|
|
|
package yaml_test
|
|
|
|
|
|
|
|
|
|
import (
|
2020-03-02 23:11:18 +09:00
|
|
|
"bytes"
|
2019-10-18 13:05:36 +09:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/goccy/go-yaml"
|
2020-03-02 23:11:18 +09:00
|
|
|
"github.com/goccy/go-yaml/ast"
|
2019-10-24 17:16:29 +09:00
|
|
|
"golang.org/x/xerrors"
|
2019-10-18 13:05:36 +09:00
|
|
|
)
|
|
|
|
|
|
2019-10-19 18:28:36 +09:00
|
|
|
func TestMarshal(t *testing.T) {
|
|
|
|
|
var v struct {
|
|
|
|
|
A int
|
|
|
|
|
B string
|
|
|
|
|
}
|
|
|
|
|
v.A = 1
|
|
|
|
|
v.B = "hello"
|
|
|
|
|
bytes, err := yaml.Marshal(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
|
}
|
|
|
|
|
if string(bytes) != "a: 1\nb: hello\n" {
|
|
|
|
|
t.Fatal("failed to marshal")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 13:05:36 +09:00
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
|
|
|
yml := `
|
|
|
|
|
%YAML 1.2
|
|
|
|
|
---
|
|
|
|
|
a: 1
|
|
|
|
|
b: c
|
|
|
|
|
`
|
|
|
|
|
var v struct {
|
|
|
|
|
A int
|
|
|
|
|
B string
|
|
|
|
|
}
|
|
|
|
|
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-24 17:16:29 +09:00
|
|
|
|
|
|
|
|
type marshalTest struct{}
|
|
|
|
|
|
2019-10-25 02:38:32 +09:00
|
|
|
func (t *marshalTest) MarshalYAML() ([]byte, error) {
|
|
|
|
|
return yaml.Marshal(yaml.MapSlice{
|
2019-10-24 17:16:29 +09:00
|
|
|
{
|
|
|
|
|
"a", 1,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"b", "hello",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"c", true,
|
|
|
|
|
},
|
2019-12-12 17:43:58 +09:00
|
|
|
{
|
|
|
|
|
"d", map[string]string{"x": "y"},
|
|
|
|
|
},
|
2019-10-25 02:38:32 +09:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type marshalTest2 struct{}
|
|
|
|
|
|
|
|
|
|
func (t *marshalTest2) MarshalYAML() (interface{}, error) {
|
|
|
|
|
return yaml.MapSlice{
|
|
|
|
|
{
|
|
|
|
|
"a", 2,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"b", "world",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"c", true,
|
|
|
|
|
},
|
2019-10-24 17:16:29 +09:00
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMarshalYAML(t *testing.T) {
|
|
|
|
|
var v struct {
|
|
|
|
|
A *marshalTest
|
2019-10-25 02:38:32 +09:00
|
|
|
B *marshalTest2
|
2019-10-24 17:16:29 +09:00
|
|
|
}
|
|
|
|
|
v.A = &marshalTest{}
|
2019-10-25 02:38:32 +09:00
|
|
|
v.B = &marshalTest2{}
|
2019-10-24 17:16:29 +09:00
|
|
|
bytes, err := yaml.Marshal(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to Marshal: %+v", err)
|
|
|
|
|
}
|
|
|
|
|
expect := `
|
|
|
|
|
a:
|
|
|
|
|
a: 1
|
|
|
|
|
b: hello
|
|
|
|
|
c: true
|
2019-12-12 17:43:58 +09:00
|
|
|
d:
|
|
|
|
|
x: y
|
2019-10-25 02:38:32 +09:00
|
|
|
b:
|
|
|
|
|
a: 2
|
|
|
|
|
b: world
|
|
|
|
|
c: true
|
2019-10-24 17:16:29 +09:00
|
|
|
`
|
|
|
|
|
actual := "\n" + string(bytes)
|
|
|
|
|
if expect != actual {
|
|
|
|
|
t.Fatalf("failed to MarshalYAML expect:[%s], actual:[%s]", expect, actual)
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
|
|
|
|
|
type unmarshalTest struct {
|
|
|
|
|
a int
|
|
|
|
|
b string
|
|
|
|
|
c bool
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (t *unmarshalTest) UnmarshalYAML(b []byte) error {
|
|
|
|
|
if t.a != 0 {
|
|
|
|
|
return xerrors.New("unexpected field value to a")
|
|
|
|
|
}
|
|
|
|
|
if t.b != "" {
|
|
|
|
|
return xerrors.New("unexpected field value to b")
|
|
|
|
|
}
|
|
|
|
|
if t.c {
|
|
|
|
|
return xerrors.New("unexpected field value to c")
|
|
|
|
|
}
|
|
|
|
|
var v struct {
|
|
|
|
|
A int
|
|
|
|
|
B string
|
|
|
|
|
C bool
|
|
|
|
|
}
|
|
|
|
|
if err := yaml.Unmarshal(b, &v); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t.a = v.A
|
|
|
|
|
t.b = v.B
|
|
|
|
|
t.c = v.C
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type unmarshalTest2 struct {
|
|
|
|
|
a int
|
|
|
|
|
b string
|
|
|
|
|
c bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (t *unmarshalTest2) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
2019-10-24 17:18:03 +09:00
|
|
|
var v struct {
|
|
|
|
|
A int
|
|
|
|
|
B string
|
|
|
|
|
C bool
|
|
|
|
|
}
|
|
|
|
|
if t.a != 0 {
|
|
|
|
|
return xerrors.New("unexpected field value to a")
|
|
|
|
|
}
|
|
|
|
|
if t.b != "" {
|
|
|
|
|
return xerrors.New("unexpected field value to b")
|
|
|
|
|
}
|
|
|
|
|
if t.c {
|
|
|
|
|
return xerrors.New("unexpected field value to c")
|
|
|
|
|
}
|
|
|
|
|
if err := unmarshal(&v); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t.a = v.A
|
|
|
|
|
t.b = v.B
|
|
|
|
|
t.c = v.C
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestUnmarshalYAML(t *testing.T) {
|
|
|
|
|
yml := `
|
|
|
|
|
a:
|
|
|
|
|
a: 1
|
|
|
|
|
b: hello
|
|
|
|
|
c: true
|
2019-10-24 23:54:17 +09:00
|
|
|
b:
|
|
|
|
|
a: 2
|
|
|
|
|
b: world
|
|
|
|
|
c: true
|
2019-10-24 17:18:03 +09:00
|
|
|
`
|
|
|
|
|
var v struct {
|
|
|
|
|
A *unmarshalTest
|
2019-10-24 23:54:17 +09:00
|
|
|
B *unmarshalTest2
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
|
|
|
|
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
|
|
|
|
t.Fatalf("failed to Unmarshal: %+v", err)
|
|
|
|
|
}
|
|
|
|
|
if v.A == nil {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if v.A.a != 1 {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if v.A.b != "hello" {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if !v.A.c {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
if v.B == nil {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if v.B.a != 2 {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if v.B.b != "world" {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
if !v.B.c {
|
|
|
|
|
t.Fatal("failed to UnmarshalYAML")
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
2020-03-02 23:11:18 +09:00
|
|
|
|
|
|
|
|
type ObjectMap map[string]*Object
|
|
|
|
|
type ObjectDecl struct {
|
|
|
|
|
Name string `yaml:"-"`
|
|
|
|
|
*Object `yaml:",inline,anchor"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m ObjectMap) MarshalYAML() (interface{}, error) {
|
|
|
|
|
newMap := map[string]*ObjectDecl{}
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
newMap[k] = &ObjectDecl{Name: k, Object: v}
|
|
|
|
|
}
|
|
|
|
|
return newMap, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type rootObject struct {
|
|
|
|
|
Single ObjectMap `yaml:"single"`
|
|
|
|
|
Collection map[string][]*Object `yaml:"collection"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Object struct {
|
|
|
|
|
*Object `yaml:",omitempty,inline,alias"`
|
|
|
|
|
MapValue map[string]interface{} `yaml:",omitempty,inline"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInlineAnchorAndAlias(t *testing.T) {
|
|
|
|
|
yml := `---
|
|
|
|
|
single:
|
|
|
|
|
default: &default
|
|
|
|
|
id: 1
|
|
|
|
|
name: john
|
|
|
|
|
user_1: &user_1
|
|
|
|
|
id: 1
|
|
|
|
|
name: ken
|
|
|
|
|
user_2: &user_2
|
|
|
|
|
<<: *default
|
|
|
|
|
id: 2
|
|
|
|
|
collection:
|
|
|
|
|
defaults:
|
|
|
|
|
- *default
|
|
|
|
|
- <<: *default
|
|
|
|
|
- <<: *default
|
|
|
|
|
id: 2
|
|
|
|
|
users:
|
|
|
|
|
- <<: *user_1
|
|
|
|
|
- <<: *user_2
|
|
|
|
|
- <<: *user_1
|
|
|
|
|
id: 3
|
|
|
|
|
- <<: *user_1
|
|
|
|
|
id: 4
|
|
|
|
|
- <<: *user_1
|
|
|
|
|
id: 5
|
|
|
|
|
`
|
|
|
|
|
var v rootObject
|
|
|
|
|
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
2020-06-22 23:44:26 +09:00
|
|
|
t.Fatal(err)
|
2020-03-02 23:11:18 +09:00
|
|
|
}
|
|
|
|
|
opt := yaml.MarshalAnchor(func(anchor *ast.AnchorNode, value interface{}) error {
|
|
|
|
|
if o, ok := value.(*ObjectDecl); ok {
|
2020-06-22 23:44:26 +09:00
|
|
|
return anchor.SetName(o.Name)
|
2020-03-02 23:11:18 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := yaml.NewEncoder(&buf, opt).Encode(v); err != nil {
|
|
|
|
|
t.Fatalf("%+v", err)
|
|
|
|
|
}
|
|
|
|
|
actual := "---\n" + buf.String()
|
|
|
|
|
if yml != actual {
|
|
|
|
|
t.Fatalf("failed to marshal: expected:[%s] actual:[%s]", yml, actual)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-21 16:20:46 +09:00
|
|
|
|
|
|
|
|
func TestMapSlice_Map(t *testing.T) {
|
|
|
|
|
yml := `
|
|
|
|
|
a: b
|
|
|
|
|
c: d
|
|
|
|
|
`
|
|
|
|
|
var v yaml.MapSlice
|
|
|
|
|
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
m := v.ToMap()
|
|
|
|
|
if len(m) != 2 {
|
|
|
|
|
t.Fatal("failed to convert MapSlice to map")
|
|
|
|
|
}
|
|
|
|
|
if m["a"] != "b" {
|
|
|
|
|
t.Fatal("failed to convert MapSlice to map")
|
|
|
|
|
}
|
|
|
|
|
if m["c"] != "d" {
|
|
|
|
|
t.Fatal("failed to convert MapSlice to map")
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-22 23:30:51 +09:00
|
|
|
|
|
|
|
|
func TestMarshalWithModifiedAnchorAlias(t *testing.T) {
|
|
|
|
|
yml := `
|
|
|
|
|
a: &a 1
|
|
|
|
|
b: *a
|
|
|
|
|
`
|
|
|
|
|
var v struct {
|
|
|
|
|
A *int `yaml:"a,anchor"`
|
|
|
|
|
B *int `yaml:"b,alias"`
|
|
|
|
|
}
|
|
|
|
|
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
node, err := yaml.ValueToNode(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
anchors := ast.Filter(ast.AnchorType, node)
|
|
|
|
|
if len(anchors) != 1 {
|
|
|
|
|
t.Fatal("failed to filter node")
|
|
|
|
|
}
|
|
|
|
|
anchor := anchors[0].(*ast.AnchorNode)
|
|
|
|
|
if err := anchor.SetName("b"); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
aliases := ast.Filter(ast.AliasType, node)
|
|
|
|
|
if len(anchors) != 1 {
|
|
|
|
|
t.Fatal("failed to filter node")
|
|
|
|
|
}
|
|
|
|
|
alias := aliases[0].(*ast.AliasNode)
|
|
|
|
|
if err := alias.SetName("b"); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expected := `
|
|
|
|
|
a: &b 1
|
|
|
|
|
b: *b`
|
|
|
|
|
|
|
|
|
|
actual := "\n" + node.String()
|
|
|
|
|
if expected != actual {
|
|
|
|
|
t.Fatalf("failed to marshal: expected:[%q] but got [%q]", expected, actual)
|
|
|
|
|
}
|
|
|
|
|
}
|