mirror of https://github.com/linkerd/linkerd2.git
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
package testutil
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/go-test/deep"
|
|
"github.com/sergi/go-diff/diffmatchpatch"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
// TestDataDiffer holds configuration for generating test diff
|
|
type TestDataDiffer struct {
|
|
PrettyDiff bool
|
|
UpdateFixtures bool
|
|
RejectPath string
|
|
}
|
|
|
|
// DiffTestYAML compares a YAML structure to a fixture on the filestystem.
|
|
func (td *TestDataDiffer) DiffTestYAML(path string, actualYAML string) error {
|
|
actual, err := unmarshalYAML([]byte(actualYAML))
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to unmarshal generated YAML: %w", err)
|
|
}
|
|
expected, err := unmarshalYAML([]byte(ReadTestdata(path)))
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to unmarshal generated YAML from %s: %w", path, err)
|
|
}
|
|
diff := deep.Equal(expected, actual)
|
|
if diff == nil {
|
|
return nil
|
|
}
|
|
|
|
td.storeActual(path, []byte(actualYAML))
|
|
|
|
e := fmt.Sprintf("YAML mismatches %s:", path)
|
|
for _, d := range diff {
|
|
e += fmt.Sprintf("\n %s", d)
|
|
}
|
|
return errors.New(e)
|
|
}
|
|
|
|
// DiffTestdata generates the diff for actual w.r.the file in path
|
|
func (td *TestDataDiffer) DiffTestdata(t *testing.T, path, actual string) {
|
|
expected := ReadTestdata(path)
|
|
if actual == expected {
|
|
return
|
|
}
|
|
dmp := diffmatchpatch.New()
|
|
diffs := dmp.DiffMain(expected, actual, true)
|
|
diffs = dmp.DiffCleanupSemantic(diffs)
|
|
var diff string
|
|
if td.PrettyDiff {
|
|
diff = dmp.DiffPrettyText(diffs)
|
|
} else {
|
|
diff = dmp.PatchToText(dmp.PatchMake(diffs))
|
|
}
|
|
t.Errorf("mismatch: %s\n%s", path, diff)
|
|
|
|
td.storeActual(path, []byte(actual))
|
|
}
|
|
|
|
func (td *TestDataDiffer) storeActual(path string, actual []byte) {
|
|
if td.UpdateFixtures {
|
|
writeTestdata(path, actual)
|
|
}
|
|
|
|
if td.RejectPath != "" {
|
|
writeRejects(path, actual, td.RejectPath)
|
|
}
|
|
}
|
|
|
|
// ReadTestdata reads a file and returns the contents of that file as a string.
|
|
func ReadTestdata(fileName string) string {
|
|
file, err := os.Open(filepath.Join("testdata", fileName))
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Failed to open expected output file: %v", err))
|
|
}
|
|
|
|
fixture, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Failed to read expected output file: %v", err))
|
|
}
|
|
|
|
return string(fixture)
|
|
}
|
|
|
|
func unmarshalYAML(data []byte) ([]interface{}, error) {
|
|
objs := make([]interface{}, 0)
|
|
rd := bytes.NewReader(data)
|
|
decoder := yaml.NewDecoder(rd)
|
|
for {
|
|
var obj interface{}
|
|
if err := decoder.Decode(&obj); err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
return objs, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
objs = append(objs, obj)
|
|
}
|
|
}
|
|
|
|
func writeTestdata(fileName string, data []byte) {
|
|
p := filepath.Join("testdata", fileName)
|
|
if err := ioutil.WriteFile(p, data, 0600); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func writeRejects(origFileName string, data []byte, rejectPath string) {
|
|
p := filepath.Join(rejectPath, origFileName+".rej")
|
|
if err := ioutil.WriteFile(p, data, 0600); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|