@@ -7,14 +7,26 @@ import (
77 "io"
88 "net/http"
99 "os"
10+ "path/filepath"
1011 "strconv"
1112 "strings"
1213
1314 "github.com/stretchr/testify/assert"
14- "github.com/stretchr/testify/require"
1515)
1616
17- var overwrite , _ = strconv .ParseBool (os .Getenv ("OVERWRITE_GOLDEN_FILES" ))
17+ var DefaultHandler = & FileHandler {
18+ FileName : TestNameToFilePath ,
19+ ShouldRecreate : ParseRecreateFromEnv ,
20+ Equal : EqualWithDiff ,
21+ ProcessContent : nil ,
22+ }
23+
24+ type FileHandler struct {
25+ FileName func (T ) string
26+ ShouldRecreate func (T ) bool
27+ ProcessContent func (T , string ) string
28+ Equal func (t T , expected , actual string , msgAndArgs ... interface {}) (ok bool )
29+ }
1830
1931type T interface {
2032 Logf (format string , args ... any )
@@ -24,6 +36,7 @@ type T interface {
2436 Helper ()
2537}
2638
39+ // Client is an interface that allows using http.Client or any other client that implements the Do method.
2740type Client interface {
2841 Do (req * http.Request ) (* http.Response , error )
2942}
@@ -58,35 +71,56 @@ type Client interface {
5871// }
5972// }
6073func Request (t T , client Client , req * http.Request , expectedStatusCode int ) (* http.Response , bool ) {
61- t .Helper ()
74+ return DefaultHandler .Request (t , client , req , expectedStatusCode )
75+ }
76+
77+ // Assert checks the golden file content against the given data.
78+ func Assert (t T , data string ) bool {
79+ return DefaultHandler .Assert (t , data )
80+ }
81+
82+ func (h * FileHandler ) Request (t T , client Client , req * http.Request , expectedStatusCode int ) (* http.Response , bool ) {
6283 resp , err := client .Do (req )
63- require .NoError (t , err , "client.Do failed" )
84+ NoError (t , err , "client.Do failed" )
85+
86+ ok := true
87+ if resp .StatusCode != expectedStatusCode {
88+ ok = false
89+ t .Errorf ("expected status code %d, got %d" , expectedStatusCode , resp .StatusCode )
90+ }
6491
65- ok := assert .Equal (t , expectedStatusCode , resp .StatusCode , "unexpected status code" )
6692 body , err := io .ReadAll (resp .Body )
67- ok = assert .NoError (t , err , "reading response body failed" ) && ok
93+ NoError (t , err , "reading response body failed" )
94+
6895 resp .Body = io .NopCloser (bytes .NewReader (body ))
69- return resp , Equal (t , string (body )) && ok
96+ return resp , h . Assert (t , string (body )) && ok
7097}
7198
72- // Equal asserts that the golden file content is equal to the data in string format.
73- func Equal (t T , data string ) bool {
99+ func (h * FileHandler ) Assert (t T , data string ) bool {
74100 t .Helper ()
75- return assert .Equal (t , File (t , data ), string (data ))
101+ if h .ProcessContent != nil {
102+ data = h .ProcessContent (t , data )
103+ }
104+ return h .Equal (t , h .loadAndSaveFile (t , data ), data )
76105}
77106
78- // File returns the golden file content for the test.
79- // If OVERWRITE_GOLDEN_FILES env is set to true, the golden file will be created with the content of the data.
80- // OVERWRITE_GOLDEN_FILES is read only once at the start of the test and it's value is not updated.
81- // Depending of the test structure the golden file and it's directories arew created in
82- // ./testdata/{testFuncName}/{subTestName}.golden or ./testdata/{testFuncName}/{testFuncName}.golden.
83- func File (t T , data string ) string {
84- t .Helper ()
85- return file (t , data , overwrite )
107+ func (h * FileHandler ) loadAndSaveFile (t T , data string ) string {
108+ fileName := h .FileName (t )
109+ if h .ShouldRecreate (t ) {
110+ t .Logf ("recreating golden file: %s" , fileName )
111+ NoError (t , os .MkdirAll (filepath .Dir (fileName ), 0o755 ), "failed to create testdata directory for golden file" )
112+ NoError (t , os .WriteFile (fileName , []byte (data ), 0o600 ), "failed to write golden file" )
113+ }
114+
115+ b , err := os .ReadFile (fileName )
116+ NoError (t , err , "failed to read golden file" )
117+ return string (b )
86118}
87119
88- func file (t T , data string , recreate bool ) string {
89- t .Helper ()
120+ // TestNameToFilePath creates file name and path for the golden file using t.Name() with following rules:
121+ // Top level: ./testdata/{testFuncName}/{testFuncName}.golden
122+ // Subtest: ./testdata/{testFuncName}/{subTestName}.golden
123+ func TestNameToFilePath (t T ) string {
90124 split := strings .SplitN (t .Name (), "/" , 2 )
91125 mainTestName := t .Name ()
92126 testName := t .Name ()
@@ -95,15 +129,29 @@ func file(t T, data string, recreate bool) string {
95129 testName = strings .ReplaceAll (split [1 ], "/" , "_" )
96130 }
97131
98- folderName := fmt .Sprintf ("./testdata/%s" , mainTestName )
99- fileName := strings .ReplaceAll (fmt .Sprintf ("%s/%s.golden" , folderName , testName ), " " , "_" )
100- if recreate {
101- t .Logf ("recreating golden file: %s" , fileName )
102- require .NoError (t , os .MkdirAll (folderName , 0o755 ), "failed to create testdata directory for golden file" )
103- require .NoError (t , os .WriteFile (fileName , []byte (data ), 0o600 ), "failed to write golden file" )
132+ return strings .ReplaceAll (filepath .Join ("./testdata/" , mainTestName , testName + ".golden" ), " " , "_" )
133+ }
134+
135+ // ParseRecreateFromEnv checks if the environment variable GOLDEN_FILES_RECREATE is set to true.
136+ func ParseRecreateFromEnv (t T ) bool {
137+ str := os .Getenv ("GOLDEN_FILES_RECREATE" )
138+ if str == "" {
139+ return false
104140 }
105141
106- b , err := os .ReadFile (fileName )
107- require .NoError (t , err , "failed to read golden file" )
108- return string (b )
142+ overwrite , err := strconv .ParseBool (str )
143+ NoError (t , err , fmt .Sprintf ("failed to parse GOLDEN_FILES_RECREATE env variable: '%s' to bool" , str ))
144+ return overwrite
145+ }
146+
147+ func NoError (t T , err error , msg string ) {
148+ t .Helper ()
149+ if err != nil {
150+ t .Errorf ("%s: %s" , msg , err )
151+ t .FailNow ()
152+ }
153+ }
154+
155+ func EqualWithDiff (t T , expected , actual string , msgAndArgs ... interface {}) (ok bool ) {
156+ return assert .Equal (t , expected , actual , msgAndArgs ... )
109157}
0 commit comments