Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade ghodss/yaml to use go-yaml v3 #62

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/ghodss/yaml
module github.com/ghodss/yaml/v2

require gopkg.in/yaml.v2 v2.2.2
go 1.11

require gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
15 changes: 1 addition & 14 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"reflect"
"strconv"

"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

// Marshals the object into JSON then converts JSON to YAML and returns the
Expand Down Expand Up @@ -46,13 +46,6 @@ func Unmarshal(y []byte, o interface{}, opts ...JSONOpt) error {
return unmarshal(yaml.Unmarshal, y, o, opts)
}

// UnmarshalStrict is like Unmarshal except that any mapping keys that are
// duplicates will result in an error.
// To also be strict about unknown fields, add the DisallowUnknownFields option.
func UnmarshalStrict(y []byte, o interface{}, opts ...JSONOpt) error {
return unmarshal(yaml.UnmarshalStrict, y, o, opts)
}

func unmarshal(f func(in []byte, out interface{}) (err error), y []byte, o interface{}, opts []JSONOpt) error {
vo := reflect.ValueOf(o)
j, err := yamlToJSON(y, &vo, f)
Expand Down Expand Up @@ -117,12 +110,6 @@ func YAMLToJSON(y []byte) ([]byte, error) {
return yamlToJSON(y, nil, yaml.Unmarshal)
}

// YAMLToJSONStrict is like YAMLToJSON but enables strict YAML decoding,
// returning an error on any duplicate field names.
func YAMLToJSONStrict(y []byte) ([]byte, error) {
return yamlToJSON(y, nil, yaml.UnmarshalStrict)
}

func yamlToJSON(y []byte, jsonTarget *reflect.Value, yamlUnmarshal func([]byte, interface{}) error) ([]byte, error) {
// Convert the YAML to an object.
var yamlObj interface{}
Expand Down
18 changes: 9 additions & 9 deletions yaml_go110_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,26 @@ func TestUnmarshalWithTags(t *testing.T) {
// duplicate fields in the YAML input.
func TestUnmarshalStrictWithJSONOpts(t *testing.T) {
for _, tc := range []struct {
yaml []byte
opts []JSONOpt
want UnmarshalString
wantErr string
yaml []byte
opts []JSONOpt
want UnmarshalPrimitives
wantErr string
}{
{
// By default, unknown field is ignored.
yaml: []byte("a: 1\nunknownField: 2"),
want: UnmarshalString{A: "1"},
yaml: []byte("bool: true\nunknownField: 2"),
want: UnmarshalPrimitives{Bool: true},
},
{
// Unknown field produces an error with `DisallowUnknownFields` option.
yaml: []byte("a: 1\nunknownField: 2"),
yaml: []byte("bool: true\nunknownField: 2"),
opts: []JSONOpt{DisallowUnknownFields},
wantErr: `unknown field "unknownField"`,
},
} {
po := prettyFunctionName(tc.opts)
s := UnmarshalString{}
err := UnmarshalStrict(tc.yaml, &s, tc.opts...)
s := UnmarshalPrimitives{}
err := Unmarshal(tc.yaml, &s, tc.opts...)
if tc.wantErr != "" && err == nil {
t.Errorf("UnmarshalStrict(%#q, &s, %v) = nil; want error", string(tc.yaml), po)
continue
Expand Down
166 changes: 56 additions & 110 deletions yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,61 +34,62 @@ func TestMarshal(t *testing.T) {
}
}

type UnmarshalString struct {
A string
True string
type UnmarshalPrimitives struct {
Number int
String string
Bool bool
}

type UnmarshalStringMap struct {
A map[string]string
Dict map[string]string
}

type UnmarshalNestedString struct {
A NestedString
NestedString NestedString
}

type NestedString struct {
A string
String string
}

type UnmarshalSlice struct {
A []NestedSlice
Slice []NestedStrings
}

type NestedSlice struct {
B string
C *string
type NestedStrings struct {
String string
StringPtr *string
}

func TestUnmarshal(t *testing.T) {
y := []byte("a: 1")
s1 := UnmarshalString{}
e1 := UnmarshalString{A: "1"}
y := []byte("string: \"1\"")
s1 := UnmarshalPrimitives{}
e1 := UnmarshalPrimitives{String: "1"}
unmarshalEqual(t, y, &s1, &e1)

y = []byte("a: true")
s1 = UnmarshalString{}
e1 = UnmarshalString{A: "true"}
y = []byte("bool: true")
s1 = UnmarshalPrimitives{}
e1 = UnmarshalPrimitives{Bool: true}
unmarshalEqual(t, y, &s1, &e1)

y = []byte("true: 1")
s1 = UnmarshalString{}
e1 = UnmarshalString{True: "1"}
y = []byte("bool: true")
s1 = UnmarshalPrimitives{}
e1 = UnmarshalPrimitives{Bool: true}
unmarshalEqual(t, y, &s1, &e1)

y = []byte("a:\n a: 1")
y = []byte("nestedString:\n string: hello")
s2 := UnmarshalNestedString{}
e2 := UnmarshalNestedString{NestedString{"1"}}
e2 := UnmarshalNestedString{NestedString{"hello"}}
unmarshalEqual(t, y, &s2, &e2)

y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n")
y = []byte("slice:\n - string: abc\n stringPtr: def\n - string: \"123\"\n stringPtr: \"456\"\n")
s3 := UnmarshalSlice{}
e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}}
e3 := UnmarshalSlice{[]NestedStrings{{"abc", strPtr("def")}, {"123", strPtr("456")}}}
unmarshalEqual(t, y, &s3, &e3)

y = []byte("a:\n b: 1")
y = []byte("dict:\n b: balloon")
s4 := UnmarshalStringMap{}
e4 := UnmarshalStringMap{map[string]string{"b": "1"}}
e4 := UnmarshalStringMap{map[string]string{"b": "balloon"}}
unmarshalEqual(t, y, &s4, &e4)

y = []byte(`
Expand All @@ -102,58 +103,12 @@ b:
}
s5 := map[string]*NamedThing{}
e5 := map[string]*NamedThing{
"a": &NamedThing{Name: "TestA"},
"b": &NamedThing{Name: "TestB"},
"a": {Name: "TestA"},
"b": {Name: "TestB"},
}
unmarshalEqual(t, y, &s5, &e5)
}

// TestUnmarshalNonStrict tests that we parse ambiguous YAML without error.
func TestUnmarshalNonStrict(t *testing.T) {
for _, tc := range []struct {
yaml []byte
want UnmarshalString
}{
{
yaml: []byte("a: 1"),
want: UnmarshalString{A: "1"},
},
{
// Unknown field get ignored.
yaml: []byte("a: 1\nunknownField: 2"),
want: UnmarshalString{A: "1"},
},
{
// Unknown fields get ignored.
yaml: []byte("unknownOne: 2\na: 1\nunknownTwo: 2"),
want: UnmarshalString{A: "1"},
},
{
// Last declaration of `a` wins.
yaml: []byte("a: 1\na: 2"),
want: UnmarshalString{A: "2"},
},
{
// Even ignore first declaration of `a` with wrong type.
yaml: []byte("a: [1,2,3]\na: value-of-a"),
want: UnmarshalString{A: "value-of-a"},
},
{
// Last value of `a` and first and only mention of `true` are parsed.
yaml: []byte("true: string-value-of-yes\na: 1\na: [1,2,3]\na: value-of-a"),
want: UnmarshalString{A: "value-of-a", True: "string-value-of-yes"},
},
{
// In YAML, `YES` is a Boolean true.
yaml: []byte("true: YES"),
want: UnmarshalString{True: "true"},
},
} {
s := UnmarshalString{}
unmarshalEqual(t, tc.yaml, &s, &tc.want)
}
}

// prettyFunctionName converts a slice of JSONOpt function pointers to a human
// readable string representation.
func prettyFunctionName(opts []JSONOpt) []string {
Expand All @@ -177,50 +132,45 @@ func unmarshalEqual(t *testing.T, y []byte, s, e interface{}, opts ...JSONOpt) {
}
}

// TestUnmarshalStrict tests that we return an error on ambiguous YAML.
func TestUnmarshalStrict(t *testing.T) {
// TestUnmarshalErrors tests that we return an error on ambiguous YAML.
func TestUnmarshalErrors(t *testing.T) {
for _, tc := range []struct {
yaml []byte
want UnmarshalString
wantErr string
yaml []byte
want UnmarshalPrimitives
wantErr string
}{
{
yaml: []byte("a: 1"),
want: UnmarshalString{A: "1"},
yaml: []byte("number: 1"),
want: UnmarshalPrimitives{Number: 1},
},
{
// Order does not matter.
yaml: []byte("true: 1\na: 2"),
want: UnmarshalString{A: "2", True: "1"},
yaml: []byte("bool: true\nnumber: 2"),
want: UnmarshalPrimitives{Number: 2, Bool: true},
},
{
// By default, unknown field is ignored.
yaml: []byte("a: 1\nunknownField: 2"),
want: UnmarshalString{A: "1"},
yaml: []byte("string: foo\nunknownField: 2"),
want: UnmarshalPrimitives{String: "foo"},
},
{
// Declaring `a` twice produces an error.
yaml: []byte("a: 1\na: 2"),
wantErr: `key "a" already set in map`,
},
{
// Not ignoring first declaration of A with wrong type.
yaml: []byte("a: [1,2,3]\na: value-of-a"),
wantErr: `key "a" already set in map`,
yaml: []byte("number: 1\nnumber: 2"),
wantErr: `mapping key "number" already defined at line 1`,
},
{
// Declaring field `true` twice.
yaml: []byte("true: string-value-of-yes\ntrue: 1"),
wantErr: `key true already set in map`,
// Not ignoring first declaration of String with wrong type.
yaml: []byte("a: [1,2,3]\na: value-of-a"),
wantErr: `mapping key "a" already defined at line 1`,
},
{
// In YAML, `YES` is a Boolean true.
yaml: []byte("true: YES"),
want: UnmarshalString{True: "true"},
// Declaring field `bool` twice.
yaml: []byte("bool: true\nbool: false"),
wantErr: `mapping key "bool" already defined at line 1`,
},
} {
s := UnmarshalString{}
err := UnmarshalStrict(tc.yaml, &s)
s := UnmarshalPrimitives{}
err := Unmarshal(tc.yaml, &s)
if tc.wantErr != "" && err == nil {
t.Errorf("UnmarshalStrict(%#q, &s) = nil; want error", string(tc.yaml))
continue
Expand All @@ -239,7 +189,7 @@ func TestUnmarshalStrict(t *testing.T) {

// Even if there was an error, we continue the test: We expect that all
// errors occur during YAML unmarshalling. Such errors leaves `s` unmodified
// and the following check will compare default values of `UnmarshalString`.
// and the following check will compare default values of `UnmarshalPrimitives`.

if !reflect.DeepEqual(s, tc.want) {
t.Errorf("UnmarshalStrict(%#q, &s) = %+#v; want %+#v", string(tc.yaml), s, tc.want)
Expand Down Expand Up @@ -319,17 +269,17 @@ func TestYAMLToJSON(t *testing.T) {
}, {
"- t: a\n" +
"- t:\n" +
" b: 1\n" +
" c: 2\n",
" b: 1\n" +
" c: 2\n",
`[{"t":"a"},{"t":{"b":1,"c":2}}]`,
nil,
}, {
`[{t: a}, {t: {b: 1, c: 2}}]`,
`[{"t":"a"},{"t":{"b":1,"c":2}}]`,
strPtr("- t: a\n" +
"- t:\n" +
" b: 1\n" +
" c: 2\n"),
" b: 1\n" +
" c: 2\n"),
}, {
"- t: \n",
`[{"t":null}]`,
Expand Down Expand Up @@ -407,23 +357,19 @@ func runCases(t *testing.T, runType RunType, cases []Case) {
invMsg, string(output), reverse, string(input))
}
}

}

// To be able to easily fill in the *Case.reverse string above.
func strPtr(s string) *string {
return &s
}

func TestYAMLToJSONStrict(t *testing.T) {
func TestYAMLToJSONDuplicateFields(t *testing.T) {
const data = `
foo: bar
foo: baz
`
if _, err := YAMLToJSON([]byte(data)); err != nil {
t.Error("expected YAMLtoJSON to pass on duplicate field names")
}
if _, err := YAMLToJSONStrict([]byte(data)); err == nil {
if _, err := YAMLToJSON([]byte(data)); err == nil {
t.Error("expected YAMLtoJSONStrict to fail on duplicate field names")
}
}