mirror of
https://github.com/jimeh/go-golden.git
synced 2026-02-19 11:16:47 +00:00
308 lines
9.2 KiB
Go
308 lines
9.2 KiB
Go
package golden
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"io"
|
|
"testing"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var globalAssert = NewAssert()
|
|
|
|
// AssertJSONMarshaling asserts that the given "v" value JSON marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "v" when unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and unmarshaled.
|
|
func AssertJSONMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.JSONMarshaling(t, v)
|
|
}
|
|
|
|
// AssertJSONMarshalingP asserts that the given "v" value JSON marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "want" when unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
func AssertJSONMarshalingP(t *testing.T, v, want interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.JSONMarshalingP(t, v, want)
|
|
}
|
|
|
|
// AssertXMLMarshaling asserts that the given "v" value XML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "v" when unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and unmarshaled.
|
|
func AssertXMLMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.XMLMarshaling(t, v)
|
|
}
|
|
|
|
// AssertXMLMarshalingP asserts that the given "v" value XML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "want" when unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
func AssertXMLMarshalingP(t *testing.T, v, want interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.XMLMarshalingP(t, v, want)
|
|
}
|
|
|
|
// AssertYAMLMarshaling asserts that the given "v" value YAML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "v" when unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and unmarshaled.
|
|
func AssertYAMLMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.YAMLMarshaling(t, v)
|
|
}
|
|
|
|
// AssertYAMLMarshalingP asserts that the given "v" value YAML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that the
|
|
// marshaled result produces a value that is equal to "want" when unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
func AssertYAMLMarshalingP(t *testing.T, v, want interface{}) {
|
|
t.Helper()
|
|
|
|
globalAssert.YAMLMarshalingP(t, v, want)
|
|
}
|
|
|
|
// Assert exposes a series of JSON, YAML, and XML marshaling assertion helpers.
|
|
type Assert interface {
|
|
// JSONMarshaling asserts that the given "v" value JSON marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "v" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and
|
|
// unmarshaled.
|
|
JSONMarshaling(t *testing.T, v interface{})
|
|
|
|
// JSONMarshalingP asserts that the given "v" value JSON marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "want" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
JSONMarshalingP(t *testing.T, v interface{}, want interface{})
|
|
|
|
// XMLMarshaling asserts that the given "v" value XML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "v" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and
|
|
// unmarshaled.
|
|
XMLMarshaling(t *testing.T, v interface{})
|
|
|
|
// XMLMarshalingP asserts that the given "v" value XML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "want" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
XMLMarshalingP(t *testing.T, v interface{}, want interface{})
|
|
|
|
// YAMLMarshaling asserts that the given "v" value YAML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "v" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that do NOT change when they are marshaled and
|
|
// unmarshaled.
|
|
YAMLMarshaling(t *testing.T, v interface{})
|
|
|
|
// YAMLMarshalingP asserts that the given "v" value YAML marshals to an
|
|
// expected value fetched from a golden file on disk, and then verifies that
|
|
// the marshaled result produces a value that is equal to "want" when
|
|
// unmarshaled.
|
|
//
|
|
// Used for objects that change when they are marshaled and unmarshaled.
|
|
YAMLMarshalingP(t *testing.T, v interface{}, want interface{})
|
|
}
|
|
|
|
type AssertOption interface {
|
|
apply(*asserter)
|
|
}
|
|
|
|
type assertOptionFunc func(*asserter)
|
|
|
|
func (fn assertOptionFunc) apply(c *asserter) {
|
|
fn(c)
|
|
}
|
|
|
|
// WithGolden allows setting a custom *Golden instance when calling NewAssert().
|
|
func WithGolden(golden *Golden) AssertOption {
|
|
return assertOptionFunc(func(a *asserter) {
|
|
a.golden = golden
|
|
})
|
|
}
|
|
|
|
// WithNormalizedLineBreaks allows turning off line-break normalization which
|
|
// replaces Windows' CRLF (\r\n) and Mac Classic CR (\r) line breaks with Unix's
|
|
// LF (\n) line breaks.
|
|
func WithNormalizedLineBreaks(value bool) AssertOption {
|
|
return assertOptionFunc(func(a *asserter) {
|
|
a.normalizeLineBreaks = value
|
|
})
|
|
}
|
|
|
|
// NewAssert returns a new Assert which exposes a number of marshaling assertion
|
|
// helpers for JSON, YAML and XML.
|
|
//
|
|
// The default encoders all specify indentation of two spaces, essentially
|
|
// enforcing pretty formatting for JSON and XML.
|
|
//
|
|
// The default decoders for JSON and YAML prohibit unknown fields which are not
|
|
// present on the provided struct.
|
|
func NewAssert(options ...AssertOption) Assert {
|
|
a := &asserter{
|
|
golden: globalGolden,
|
|
normalizeLineBreaks: true,
|
|
}
|
|
|
|
for _, opt := range options {
|
|
opt.apply(a)
|
|
}
|
|
|
|
a.JSONAsserter = NewMarshalAsserter(
|
|
a.golden, "JSON",
|
|
newJSONEncoder, newJSONDecoder,
|
|
a.normalizeLineBreaks,
|
|
)
|
|
a.XMLAsserter = NewMarshalAsserter(
|
|
a.golden, "XML",
|
|
newXMLEncoder, newXMLDecoder,
|
|
a.normalizeLineBreaks,
|
|
)
|
|
a.YAMLAsserter = NewMarshalAsserter(
|
|
a.golden, "YAML",
|
|
newYAMLEncoder, newYAMLDecoder,
|
|
a.normalizeLineBreaks,
|
|
)
|
|
|
|
return a
|
|
}
|
|
|
|
// asserter implements the Assert interface.
|
|
type asserter struct {
|
|
golden *Golden
|
|
normalizeLineBreaks bool
|
|
|
|
JSONAsserter *MarshalAsserter
|
|
XMLAsserter *MarshalAsserter
|
|
YAMLAsserter *MarshalAsserter
|
|
}
|
|
|
|
func (s *asserter) JSONMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
s.JSONAsserter.Marshaling(t, v)
|
|
}
|
|
|
|
func (s *asserter) JSONMarshalingP(
|
|
t *testing.T,
|
|
v interface{},
|
|
want interface{},
|
|
) {
|
|
t.Helper()
|
|
|
|
s.JSONAsserter.MarshalingP(t, v, want)
|
|
}
|
|
|
|
func (s *asserter) XMLMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
s.XMLAsserter.Marshaling(t, v)
|
|
}
|
|
|
|
func (s *asserter) XMLMarshalingP(t *testing.T, v, want interface{}) {
|
|
t.Helper()
|
|
|
|
s.XMLAsserter.MarshalingP(t, v, want)
|
|
}
|
|
|
|
func (s *asserter) YAMLMarshaling(t *testing.T, v interface{}) {
|
|
t.Helper()
|
|
|
|
s.YAMLAsserter.Marshaling(t, v)
|
|
}
|
|
|
|
func (s *asserter) YAMLMarshalingP(t *testing.T, v, want interface{}) {
|
|
t.Helper()
|
|
|
|
s.YAMLAsserter.MarshalingP(t, v, want)
|
|
}
|
|
|
|
// newJSONEncoder is the default JSONEncoderFunc used by Assert. It returns a
|
|
// *json.Encoder which is set to indent with two spaces.
|
|
func newJSONEncoder(w io.Writer) MarshalEncoder {
|
|
enc := json.NewEncoder(w)
|
|
enc.SetIndent("", " ")
|
|
|
|
return enc
|
|
}
|
|
|
|
// newJSONDecoder is the default JSONDecoderFunc used by Assert. It returns a
|
|
// *json.Decoder which disallows unknown fields.
|
|
func newJSONDecoder(r io.Reader) MarshalDecoder {
|
|
dec := json.NewDecoder(r)
|
|
dec.DisallowUnknownFields()
|
|
|
|
return dec
|
|
}
|
|
|
|
// newXMLEncoder is the default XMLEncoderFunc used by Assert. It returns a
|
|
// *xml.Encoder which is set to indent with two spaces.
|
|
func newXMLEncoder(w io.Writer) MarshalEncoder {
|
|
enc := xml.NewEncoder(w)
|
|
enc.Indent("", " ")
|
|
|
|
return enc
|
|
}
|
|
|
|
// newXMLDecoder is the default XMLDecoderFunc used by Assert.
|
|
func newXMLDecoder(r io.Reader) MarshalDecoder {
|
|
return xml.NewDecoder(r)
|
|
}
|
|
|
|
// newYAMLEncoder is the default YAMLEncoderFunc used by Assert. It returns a
|
|
// *yaml.Encoder which is set to indent with two spaces.
|
|
func newYAMLEncoder(w io.Writer) MarshalEncoder {
|
|
enc := yaml.NewEncoder(w)
|
|
enc.SetIndent(2)
|
|
|
|
return enc
|
|
}
|
|
|
|
// newYAMLDecoder is the default YAMLDecoderFunc used by Assert. It returns a
|
|
// *yaml.Decoder which disallows unknown fields.
|
|
func newYAMLDecoder(r io.Reader) MarshalDecoder {
|
|
dec := yaml.NewDecoder(r)
|
|
dec.KnownFields(true)
|
|
|
|
return dec
|
|
}
|
|
|
|
// normalizeLineBreaks replaces Windows CRLF (\r\n) and Classic MacOS CR (\r)
|
|
// line-breaks with Unix LF (\n) line breaks.
|
|
func normalizeLineBreaks(data []byte) []byte {
|
|
// Replace Windows CRLF (\r\n) with Unix LF (\n)
|
|
result := bytes.ReplaceAll(data, []byte{13, 10}, []byte{10})
|
|
// Replace Classic MacOS CR (\r) with Unix LF (\n)
|
|
result = bytes.ReplaceAll(result, []byte{13}, []byte{10})
|
|
|
|
return result
|
|
}
|