packer-cn/vendor/github.com/approvals/go-approval-tests/approvals.go

205 lines
5.5 KiB
Go

package approvaltests
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"encoding/xml"
"github.com/approvals/go-approval-tests/reporters"
"github.com/approvals/go-approval-tests/utils"
"reflect"
)
var (
defaultReporter = reporters.NewDiffReporter()
defaultFrontLoadedReporter = reporters.NewFrontLoadedReporter()
)
// Failable is an interface wrapper around testing.T
type Failable interface {
Fail()
}
// VerifyWithExtension Example:
// VerifyWithExtension(t, strings.NewReader("Hello"), ".txt")
func VerifyWithExtension(t Failable, reader io.Reader, extWithDot string) error {
namer, err := getApprovalName()
if err != nil {
return err
}
reporter := getReporter()
err = namer.compare(namer.getApprovalFile(extWithDot), namer.getReceivedFile(extWithDot), reader)
if err != nil {
reporter.Report(namer.getApprovalFile(extWithDot), namer.getReceivedFile(extWithDot))
t.Fail()
} else {
os.Remove(namer.getReceivedFile(extWithDot))
}
return err
}
// Verify Example:
// Verify(t, strings.NewReader("Hello"))
func Verify(t Failable, reader io.Reader) error {
return VerifyWithExtension(t, reader, ".txt")
}
// VerifyString Example:
// VerifyString(t, "Hello")
func VerifyString(t Failable, s string) error {
reader := strings.NewReader(s)
return Verify(t, reader)
}
// VerifyXMLStruct Example:
// VerifyXMLStruct(t, xml)
func VerifyXMLStruct(t Failable, obj interface{}) error {
xmlb, err := xml.MarshalIndent(obj, "", " ")
if err != nil {
tip := ""
if reflect.TypeOf(obj).Name() == "" {
tip = "when using anonymous types be sure to include\n XMLName xml.Name `xml:\"Your_Name_Here\"`\n"
}
message := fmt.Sprintf("error while pretty printing XML\n%verror:\n %v\nXML:\n %v\n", tip, err, obj)
return VerifyWithExtension(t, strings.NewReader(message), ".xml")
}
return VerifyWithExtension(t, bytes.NewReader(xmlb), ".xml")
}
// VerifyXMLBytes Example:
// VerifyXMLBytes(t, []byte("<Test/>"))
func VerifyXMLBytes(t Failable, bs []byte) error {
type node struct {
Attr []xml.Attr
XMLName xml.Name
Children []node `xml:",any"`
Text string `xml:",chardata"`
}
x := node{}
err := xml.Unmarshal(bs, &x)
if err != nil {
message := fmt.Sprintf("error while parsing XML\nerror:\n %s\nXML:\n %s\n", err, string(bs))
return VerifyWithExtension(t, strings.NewReader(message), ".xml")
}
return VerifyXMLStruct(t, x)
}
// VerifyJSONStruct Example:
// VerifyJSONStruct(t, json)
func VerifyJSONStruct(t Failable, obj interface{}) error {
jsonb, err := json.MarshalIndent(obj, "", " ")
if err != nil {
message := fmt.Sprintf("error while pretty printing JSON\nerror:\n %s\nJSON:\n %s\n", err, obj)
return VerifyWithExtension(t, strings.NewReader(message), ".json")
}
return VerifyWithExtension(t, bytes.NewReader(jsonb), ".json")
}
// VerifyJSONBytes Example:
// VerifyJSONBytes(t, []byte("{ \"Greeting\": \"Hello\" }"))
func VerifyJSONBytes(t Failable, bs []byte) error {
var obj map[string]interface{}
err := json.Unmarshal(bs, &obj)
if err != nil {
message := fmt.Sprintf("error while parsing JSON\nerror:\n %s\nJSON:\n %s\n", err, string(bs))
return VerifyWithExtension(t, strings.NewReader(message), ".json")
}
return VerifyJSONStruct(t, obj)
}
// VerifyMap Example:
// VerifyMap(t, map[string][string] { "dog": "bark" })
func VerifyMap(t Failable, m interface{}) error {
outputText := utils.PrintMap(m)
return VerifyString(t, outputText)
}
// VerifyArray Example:
// VerifyArray(t, []string{"dog", "cat"})
func VerifyArray(t Failable, array interface{}) error {
outputText := utils.PrintArray(array)
return VerifyString(t, outputText)
}
// VerifyAll Example:
// VerifyAll(t, "uppercase", []string("dog", "cat"}, func(x interface{}) string { return strings.ToUpper(x.(string)) })
func VerifyAll(t Failable, header string, collection interface{}, transform func(interface{}) string) error {
if len(header) != 0 {
header = fmt.Sprintf("%s\n\n\n", header)
}
outputText := header + strings.Join(utils.MapToString(collection, transform), "\n")
return VerifyString(t, outputText)
}
type reporterCloser struct {
reporter *reporters.Reporter
}
func (s *reporterCloser) Close() error {
defaultReporter = s.reporter
return nil
}
type frontLoadedReporterCloser struct {
reporter *reporters.Reporter
}
func (s *frontLoadedReporterCloser) Close() error {
defaultFrontLoadedReporter = s.reporter
return nil
}
// UseReporter configures which reporter to use on failure.
// Add at the test or method level to configure your reporter.
//
// The following examples shows how to use a reporter for all of your test cases
// in a package directory through go's setup feature.
//
//
// func TestMain(m *testing.M) {
// r := UseReporter(reporters.NewBeyondCompareReporter())
// defer r.Close()
//
// os.Exit(m.Run())
// }
//
func UseReporter(reporter reporters.Reporter) io.Closer {
closer := &reporterCloser{
reporter: defaultReporter,
}
defaultReporter = &reporter
return closer
}
// UseFrontLoadedReporter configures reporters ahead of all other reporters to
// handle situations like CI. These reporters usually prevent reporting in
// scenarios that are headless.
func UseFrontLoadedReporter(reporter reporters.Reporter) io.Closer {
closer := &frontLoadedReporterCloser{
reporter: defaultFrontLoadedReporter,
}
defaultFrontLoadedReporter = &reporter
return closer
}
func getReporter() reporters.Reporter {
return reporters.NewFirstWorkingReporter(
*defaultFrontLoadedReporter,
*defaultReporter,
)
}