-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from sebdah/feature/improve-structure-tests
feature/improve-structure-tests
- Loading branch information
Showing
6 changed files
with
579 additions
and
525 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package goldie | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"encoding/xml" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"testing" | ||
"text/template" | ||
) | ||
|
||
// Assert compares the actual data received with the expected data in the | ||
// golden files. If the update flag is set, it will also update the golden | ||
// file. | ||
// | ||
// `name` refers to the name of the test and it should typically be unique | ||
// within the package. Also it should be a valid file name (so keeping to | ||
// `a-z0-9\-\_` is a good idea). | ||
func (g *Goldie) Assert(t *testing.T, name string, actualData []byte) { | ||
t.Helper() | ||
if *update { | ||
err := g.Update(t, name, actualData) | ||
if err != nil { | ||
t.Error(err) | ||
t.FailNow() | ||
} | ||
} | ||
|
||
err := g.compare(t, name, actualData) | ||
if err != nil { | ||
{ | ||
var e *errFixtureNotFound | ||
if errors.As(err, &e) { | ||
t.Error(err) | ||
t.FailNow() | ||
return | ||
} | ||
} | ||
|
||
{ | ||
var e *errFixtureMismatch | ||
if errors.As(err, &e) { | ||
t.Error(err) | ||
return | ||
} | ||
} | ||
|
||
t.Error(err) | ||
} | ||
} | ||
|
||
// AssertJson compares the actual json data received with expected data in the | ||
// golden files. If the update flag is set, it will also update the golden | ||
// file. | ||
// | ||
// `name` refers to the name of the test and it should typically be unique | ||
// within the package. Also it should be a valid file name (so keeping to | ||
// `a-z0-9\-\_` is a good idea). | ||
func (g *Goldie) AssertJson(t *testing.T, name string, actualJsonData interface{}) { | ||
t.Helper() | ||
js, err := json.MarshalIndent(actualJsonData, "", " ") | ||
|
||
if err != nil { | ||
t.Error(err) | ||
t.FailNow() | ||
} | ||
|
||
g.Assert(t, name, normalizeLF(js)) | ||
} | ||
|
||
// AssertXml compares the actual xml data received with expected data in the | ||
// golden files. If the update flag is set, it will also update the golden | ||
// file. | ||
// | ||
// `name` refers to the name of the test and it should typically be unique | ||
// within the package. Also it should be a valid file name (so keeping to | ||
// `a-z0-9\-\_` is a good idea). | ||
func (g *Goldie) AssertXml(t *testing.T, name string, actualXmlData interface{}) { | ||
t.Helper() | ||
x, err := xml.MarshalIndent(actualXmlData, "", " ") | ||
|
||
if err != nil { | ||
t.Error(err) | ||
t.FailNow() | ||
} | ||
|
||
g.Assert(t, name, normalizeLF(x)) | ||
} | ||
|
||
// normalizeLF normalizes line feed character set across os (es) | ||
// \r\n (windows) & \r (mac) into \n (unix) | ||
func normalizeLF(d []byte) []byte { | ||
// if empty / nil return as is | ||
if len(d) == 0 { | ||
return d | ||
} | ||
// replace CR LF \r\n (windows) with LF \n (unix) | ||
d = bytes.Replace(d, []byte{13, 10}, []byte{10}, -1) | ||
// replace CF \r (mac) with LF \n (unix) | ||
d = bytes.Replace(d, []byte{13}, []byte{10}, -1) | ||
return d | ||
} | ||
|
||
// Assert compares the actual data received with the expected data in the | ||
// golden files after executing it as a template with data parameter. If the | ||
// update flag is set, it will also update the golden file. `name` refers to | ||
// the name of the test and it should typically be unique within the package. | ||
// Also it should be a valid file name (so keeping to `a-z0-9\-\_` is a good | ||
// idea). | ||
func (g *Goldie) AssertWithTemplate(t *testing.T, name string, data interface{}, actualData []byte) { | ||
t.Helper() | ||
if *update { | ||
err := g.Update(t, name, actualData) | ||
if err != nil { | ||
t.Error(err) | ||
t.FailNow() | ||
} | ||
} | ||
|
||
err := g.compareTemplate(t, name, data, actualData) | ||
if err != nil { | ||
{ | ||
var e *errFixtureNotFound | ||
if errors.As(err, &e) { | ||
t.Error(err) | ||
t.FailNow() | ||
return | ||
} | ||
} | ||
|
||
{ | ||
var e *errFixtureMismatch | ||
if errors.As(err, &e) { | ||
t.Error(err) | ||
return | ||
} | ||
} | ||
|
||
t.Error(err) | ||
} | ||
} | ||
|
||
// compare is reading the golden fixture file and compare the stored data with | ||
// the actual data. | ||
func (g *Goldie) compare(t *testing.T, name string, actualData []byte) error { | ||
expectedData, err := ioutil.ReadFile(g.GoldenFileName(t, name)) | ||
|
||
if err != nil { | ||
if os.IsNotExist(err) { | ||
return newErrFixtureNotFound() | ||
} | ||
|
||
return fmt.Errorf("expected %s to be nil", err.Error()) | ||
} | ||
|
||
if !bytes.Equal(actualData, expectedData) { | ||
msg := "Result did not match the golden fixture. Diff is below:\n\n" | ||
actual := string(actualData) | ||
expected := string(expectedData) | ||
|
||
if g.diffFn != nil { | ||
msg += g.diffFn(actual, expected) | ||
} else { | ||
msg += Diff(g.diffEngine, actual, expected) | ||
} | ||
|
||
return newErrFixtureMismatch(msg) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// compareTemplate is reading the golden fixture file and compare the stored | ||
// data with the actual data. | ||
func (g *Goldie) compareTemplate(t *testing.T, name string, data interface{}, actualData []byte) error { | ||
expectedDataTmpl, err := ioutil.ReadFile(g.GoldenFileName(t, name)) | ||
|
||
if err != nil { | ||
if os.IsNotExist(err) { | ||
return newErrFixtureNotFound() | ||
} | ||
|
||
return fmt.Errorf("expected %s to be nil", err.Error()) | ||
} | ||
|
||
missingKey := "error" | ||
if g.ignoreTemplateErrors { | ||
missingKey = "default" | ||
} | ||
|
||
tmpl, err := template.New("test").Option("missingkey=" + missingKey).Parse(string(expectedDataTmpl)) | ||
if err != nil { | ||
return fmt.Errorf("expected %s to be nil", err.Error()) | ||
} | ||
|
||
var expectedData bytes.Buffer | ||
err = tmpl.Execute(&expectedData, data) | ||
if err != nil { | ||
return newErrMissingKey(fmt.Sprintf("Template error: %s", err.Error())) | ||
} | ||
|
||
if !bytes.Equal(actualData, expectedData.Bytes()) { | ||
msg := "Result did not match the golden fixture. Diff is below:\n\n" | ||
actual := string(actualData) | ||
expected := expectedData.String() | ||
|
||
if g.diffFn != nil { | ||
msg += g.diffFn(actual, expected) | ||
} else { | ||
msg += Diff(g.diffEngine, actual, expected) | ||
} | ||
|
||
return newErrFixtureMismatch(msg) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package goldie | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCompare(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
actualData []byte | ||
expectedData []byte | ||
update bool | ||
err error | ||
}{ | ||
{ | ||
name: "example", | ||
actualData: []byte("abc"), | ||
expectedData: []byte("abc"), | ||
update: true, | ||
err: nil, | ||
}, | ||
{ | ||
name: "example", | ||
actualData: []byte("abc"), | ||
expectedData: []byte("abc"), | ||
update: false, | ||
err: &errFixtureNotFound{}, | ||
}, | ||
{ | ||
name: "example", | ||
actualData: []byte("bc"), | ||
expectedData: []byte("abc"), | ||
update: true, | ||
err: &errFixtureMismatch{}, | ||
}, | ||
{ | ||
name: "nil", | ||
actualData: nil, | ||
expectedData: nil, | ||
update: true, | ||
err: nil, | ||
}, | ||
} | ||
|
||
g := New(t) | ||
|
||
for _, test := range tests { | ||
if test.update { | ||
err := g.Update(t, test.name, test.expectedData) | ||
assert.Nil(t, err) | ||
} | ||
|
||
err := g.compare(t, test.name, test.actualData) | ||
assert.IsType(t, test.err, err) | ||
|
||
g.GoldenFileName(t, test.name) | ||
err = os.RemoveAll(filepath.Dir(g.GoldenFileName(t, test.name))) | ||
assert.Nil(t, err) | ||
} | ||
} | ||
|
||
func TestCompareTemplate(t *testing.T) { | ||
data := struct { | ||
Name string | ||
}{ | ||
Name: "example", | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
actualData []byte | ||
expectedData []byte | ||
data interface{} | ||
update bool | ||
err error | ||
}{ | ||
{ | ||
name: "example", | ||
actualData: []byte("abc example"), | ||
expectedData: []byte("abc {{ .Name }}"), | ||
data: data, | ||
update: true, | ||
err: nil, | ||
}, | ||
{ | ||
name: "example", | ||
actualData: []byte("abc example"), | ||
expectedData: []byte("abc {{ .Name }}"), | ||
data: nil, | ||
update: false, | ||
err: &errFixtureNotFound{}, | ||
}, | ||
{ | ||
name: "example", | ||
actualData: []byte("bc example"), | ||
expectedData: []byte("abc {{ .Name }}"), | ||
data: data, | ||
update: true, | ||
err: &errFixtureMismatch{}, | ||
}, | ||
{ | ||
name: "example", | ||
actualData: []byte("bc example"), | ||
expectedData: []byte("abc {{ .Name }}"), | ||
data: nil, | ||
update: true, | ||
err: &errMissingKey{}, | ||
}} | ||
|
||
g := New(t) | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
if test.update { | ||
err := g.Update(t, test.name, test.expectedData) | ||
assert.Nil(t, err) | ||
} | ||
|
||
err := g.compareTemplate(t, test.name, test.data, test.actualData) | ||
assert.IsType(t, test.err, err) | ||
|
||
err = os.RemoveAll(g.fixtureDir) | ||
assert.Nil(t, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestNormalizeLF(t *testing.T) { | ||
tests := map[string]struct { | ||
input []byte | ||
expectedD []byte | ||
}{ | ||
"windows style": {[]byte("Hello\r\nWorld"), []byte("Hello\nWorld")}, | ||
"mac style": {[]byte("Hello\rWorld"), []byte("Hello\nWorld")}, | ||
"unix style": {[]byte("Hello\nWorld"), []byte("Hello\nWorld")}, | ||
"empty slice": {[]byte(""), []byte{}}, | ||
"nil input": {nil, nil}, | ||
} | ||
|
||
for name, test := range tests { | ||
t.Run(name, func(t *testing.T) { | ||
assert.Equal(t, test.expectedD, normalizeLF(test.input)) | ||
}) | ||
} | ||
} |
Oops, something went wrong.