mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-22 04:08:49 +02:00
265 lines
5.5 KiB
Go
265 lines
5.5 KiB
Go
|
package yaml
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
func TestYAMLMarshalError(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
type yamlMarshalError struct {
|
||
|
BoolValue bool `yaml:"bool_value"`
|
||
|
FuncValue func() `yaml:"func_value"`
|
||
|
}
|
||
|
|
||
|
v := yamlMarshalError{
|
||
|
BoolValue: true,
|
||
|
FuncValue: func() {},
|
||
|
}
|
||
|
|
||
|
require.Panics(t, func() {
|
||
|
_, _ = Marshal(v)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestYAML(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
type (
|
||
|
yamlKey struct {
|
||
|
BoolValue bool `yaml:"bool_value"`
|
||
|
NumberValue float64 `yaml:"number_value"`
|
||
|
StringValue string `yaml:"string_value"`
|
||
|
}
|
||
|
yamlObject struct {
|
||
|
Array []string `yaml:"array"`
|
||
|
Key yamlKey `yaml:"key"`
|
||
|
}
|
||
|
yamlReceiver struct {
|
||
|
Object yamlObject `yaml:"object"`
|
||
|
}
|
||
|
|
||
|
interfaceOrObject struct {
|
||
|
obj yamlReceiver
|
||
|
iface interface{}
|
||
|
}
|
||
|
)
|
||
|
|
||
|
for _, toPin := range []struct {
|
||
|
Title string
|
||
|
InputYAML []byte
|
||
|
ExpectedYAML []byte // optional: when marshaled YAML is expected to differ from raw input (e.g. on bool flags)
|
||
|
Expected interfaceOrObject // maybe either untyped interface{} or yamlObject struct with struct tags
|
||
|
ExpectError bool
|
||
|
WantsStrict bool // apply Strict mode
|
||
|
}{
|
||
|
{
|
||
|
Title: "happy path, untyped",
|
||
|
InputYAML: testYAMLObject(),
|
||
|
Expected: interfaceOrObject{
|
||
|
iface: map[string]interface{}{
|
||
|
"object": map[string]interface{}{
|
||
|
"key": map[string]interface{}{
|
||
|
"string_value": "This is a doc.\nOn multiple lines.\n",
|
||
|
"bool_value": "y",
|
||
|
"number_value": 10.23,
|
||
|
},
|
||
|
"array": []interface{}{"x", "y"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Title: "happy path strict, untyped",
|
||
|
InputYAML: testYAMLObject(),
|
||
|
WantsStrict: true,
|
||
|
Expected: interfaceOrObject{
|
||
|
iface: map[string]interface{}{
|
||
|
"object": map[string]interface{}{
|
||
|
"key": map[string]interface{}{
|
||
|
"string_value": "This is a doc.\nOn multiple lines.\n",
|
||
|
"bool_value": "y",
|
||
|
"number_value": 10.23,
|
||
|
},
|
||
|
"array": []interface{}{"x", "y"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Title: "happy path strict, explicit target",
|
||
|
InputYAML: testYAMLObject(),
|
||
|
ExpectedYAML: testYAMLObjectBool(),
|
||
|
WantsStrict: true,
|
||
|
Expected: interfaceOrObject{
|
||
|
iface: nil,
|
||
|
obj: yamlReceiver{
|
||
|
Object: yamlObject{
|
||
|
Key: yamlKey{
|
||
|
StringValue: "This is a doc.\nOn multiple lines.\n",
|
||
|
BoolValue: true,
|
||
|
NumberValue: 10.23,
|
||
|
},
|
||
|
Array: []string{"x", "y"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Title: "happy path non-strict, explicit target",
|
||
|
InputYAML: testYAMLObjectNonStrict(),
|
||
|
ExpectedYAML: testYAMLObjectBool(),
|
||
|
WantsStrict: false,
|
||
|
Expected: interfaceOrObject{
|
||
|
iface: nil,
|
||
|
obj: yamlReceiver{
|
||
|
Object: yamlObject{
|
||
|
Key: yamlKey{
|
||
|
StringValue: "This is a doc.\nOn multiple lines.\n",
|
||
|
BoolValue: true,
|
||
|
NumberValue: 10.23,
|
||
|
},
|
||
|
Array: []string{"x", "y"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Title: "happy path strict, explicit target: unknown field failure",
|
||
|
InputYAML: testYAMLObjectNonStrict(),
|
||
|
ExpectedYAML: testYAMLObjectBool(),
|
||
|
WantsStrict: true,
|
||
|
ExpectError: true,
|
||
|
Expected: interfaceOrObject{
|
||
|
iface: nil,
|
||
|
obj: yamlReceiver{
|
||
|
Object: yamlObject{
|
||
|
Key: yamlKey{
|
||
|
StringValue: "This is a doc.\nOn multiple lines.\n",
|
||
|
BoolValue: true,
|
||
|
NumberValue: 10.23,
|
||
|
},
|
||
|
Array: []string{"x", "y"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
} {
|
||
|
testCase := toPin
|
||
|
|
||
|
t.Run(testCase.Title, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
var (
|
||
|
err error
|
||
|
b, expectedOutput []byte
|
||
|
)
|
||
|
iface := testCase.Expected.iface
|
||
|
obj := testCase.Expected.obj
|
||
|
|
||
|
expectedInput := toPlainYaml(testCase.InputYAML)
|
||
|
|
||
|
if testCase.WantsStrict {
|
||
|
if iface != nil {
|
||
|
err = UnmarshalStrict(expectedInput, &iface)
|
||
|
} else {
|
||
|
err = UnmarshalStrict(expectedInput, &obj)
|
||
|
}
|
||
|
} else {
|
||
|
if iface != nil {
|
||
|
err = Unmarshal(expectedInput, &iface)
|
||
|
} else {
|
||
|
err = Unmarshal(expectedInput, &obj)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if testCase.ExpectError {
|
||
|
require.Error(t, err)
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
if iface != nil {
|
||
|
require.EqualValues(t, testCase.Expected.iface, iface)
|
||
|
|
||
|
b, err = Marshal(iface)
|
||
|
require.NoError(t, err)
|
||
|
} else {
|
||
|
require.EqualValues(t, testCase.Expected.obj, obj)
|
||
|
|
||
|
b, err = Marshal(obj)
|
||
|
require.NoError(t, err)
|
||
|
}
|
||
|
|
||
|
if testCase.ExpectedYAML == nil {
|
||
|
expectedOutput = expectedInput
|
||
|
} else {
|
||
|
expectedOutput = toPlainYaml(testCase.ExpectedYAML)
|
||
|
}
|
||
|
|
||
|
require.EqualValues(t, expectedOutput, b)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func toPlainYaml(in []byte) []byte {
|
||
|
// ensure we got legit yaml for go strings that may have been reindented using tabs, or leading new CR in source.
|
||
|
return bytes.ReplaceAll(
|
||
|
bytes.TrimLeft(in, "\n\r"),
|
||
|
[]byte("\t"), bytes.Repeat([]byte(" "), 4),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func testYAMLObject() []byte {
|
||
|
return []byte(`
|
||
|
object:
|
||
|
array:
|
||
|
- x
|
||
|
- "y"
|
||
|
key:
|
||
|
bool_value: "y"
|
||
|
number_value: 10.23
|
||
|
string_value: |
|
||
|
This is a doc.
|
||
|
On multiple lines.
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
func testYAMLObjectBool() []byte {
|
||
|
// same object, but the "y" YAML for bool has been marshaled as "true"
|
||
|
return []byte(`
|
||
|
object:
|
||
|
array:
|
||
|
- x
|
||
|
- "y"
|
||
|
key:
|
||
|
bool_value: true
|
||
|
number_value: 10.23
|
||
|
string_value: |
|
||
|
This is a doc.
|
||
|
On multiple lines.
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
func testYAMLObjectNonStrict() []byte {
|
||
|
// same object, but with an extra unknown value
|
||
|
return []byte(`
|
||
|
object:
|
||
|
array:
|
||
|
- x
|
||
|
- "y"
|
||
|
key:
|
||
|
bool_value: true
|
||
|
number_value: 10.23
|
||
|
string_value: |
|
||
|
This is a doc.
|
||
|
On multiple lines.
|
||
|
unknown: 'wrong'
|
||
|
`)
|
||
|
}
|