205 lines
5.5 KiB
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,
|
|
)
|
|
}
|