diff --git a/go.mod b/go.mod index 1ef7a8c..8260020 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/speakeasy-api/sdk-gen-config -go 1.21.5 - -toolchain go1.22.0 +go 1.23 require ( github.com/AlekSi/pointer v1.2.0 @@ -10,6 +8,7 @@ require ( github.com/google/uuid v1.5.0 github.com/mitchellh/mapstructure v1.5.0 github.com/stretchr/testify v1.9.0 + github.com/wk8/go-ordered-map/v2 v2.1.8 gopkg.in/yaml.v3 v3.0.1 ) @@ -26,9 +25,11 @@ require ( github.com/sergi/go-diff v1.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.6.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) + +// Can be removed once https://github.com/wk8/go-ordered-map/pull/41 is merged and the dependency updated in libopenapi +replace github.com/wk8/go-ordered-map/v2 => github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283 diff --git a/go.sum b/go.sum index f032215..66780ae 100644 --- a/go.sum +++ b/go.sum @@ -85,6 +85,8 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283 h1:QPZc0Mne/K4/R0giVVay0YODjMwP/BMSpYnQm5kWBgE= +github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -92,8 +94,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/io_test.go b/io_test.go index 1e6605c..3a3fd7d 100644 --- a/io_test.go +++ b/io_test.go @@ -6,9 +6,9 @@ import ( "path/filepath" "testing" + "github.com/speakeasy-api/sdk-gen-config/testutils" "github.com/speakeasy-api/sdk-gen-config/workspace" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const testDir = "gen/test" @@ -82,7 +82,7 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "pre-v100-gen.yaml"), + genYaml: testutils.ReadTestFile(t, "pre-v100-gen.yaml"), }, want: &Config{ Config: &Configuration{ @@ -132,7 +132,7 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v100-gen.yaml"), + genYaml: testutils.ReadTestFile(t, "v100-gen.yaml"), configSubDir: ".speakeasy", }, want: &Config{ @@ -187,8 +187,8 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v200-gen.yaml"), - lockFile: readTestFile(t, "v200-gen.lock"), + genYaml: testutils.ReadTestFile(t, "v200-gen.yaml"), + lockFile: testutils.ReadTestFile(t, "v200-gen.lock"), configSubDir: ".speakeasy", }, want: &Config{ @@ -243,7 +243,7 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v200-gen.yaml"), + genYaml: testutils.ReadTestFile(t, "v200-gen.yaml"), configSubDir: ".speakeasy", }, want: &Config{ @@ -293,7 +293,7 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v200-gen.yaml"), + genYaml: testutils.ReadTestFile(t, "v200-gen.yaml"), configSubDir: ".gen", }, want: &Config{ @@ -343,8 +343,8 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: filepath.Dir(testDir), targetDir: testDir, - genYaml: readTestFile(t, "v200-gen.yaml"), - lockFile: readTestFile(t, "v200-gen.lock"), + genYaml: testutils.ReadTestFile(t, "v200-gen.yaml"), + lockFile: testutils.ReadTestFile(t, "v200-gen.lock"), }, want: &Config{ Config: &Configuration{ @@ -398,7 +398,7 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go", "typescript"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v100-gen.yaml"), + genYaml: testutils.ReadTestFile(t, "v100-gen.yaml"), }, want: &Config{ Config: &Configuration{ @@ -457,8 +457,8 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go", "typescript"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v200-gen.yaml"), - lockFile: readTestFile(t, "v200-gen.lock"), + genYaml: testutils.ReadTestFile(t, "v200-gen.yaml"), + lockFile: testutils.ReadTestFile(t, "v200-gen.lock"), configSubDir: ".speakeasy", }, want: &Config{ @@ -518,8 +518,8 @@ func TestLoad_Success(t *testing.T) { langs: []string{"go"}, configDir: testDir, targetDir: testDir, - genYaml: readTestFile(t, "v200-generation-mockserver-disabled.yaml"), - lockFile: readTestFile(t, "v200-gen.lock"), + genYaml: testutils.ReadTestFile(t, "v200-generation-mockserver-disabled.yaml"), + lockFile: testutils.ReadTestFile(t, "v200-gen.lock"), configSubDir: ".speakeasy", }, want: &Config{ @@ -585,11 +585,8 @@ func TestLoad_Success(t *testing.T) { lockFileDir = filepath.Join(targetDir, ".speakeasy") } - err := createTempFile(configDir, "gen.yaml", tt.args.genYaml) - require.NoError(t, err) - - err = createTempFile(lockFileDir, "gen.lock", tt.args.lockFile) - require.NoError(t, err) + testutils.CreateTempFile(t, configDir, "gen.yaml", tt.args.genYaml) + testutils.CreateTempFile(t, lockFileDir, "gen.lock", tt.args.lockFile) defer os.RemoveAll(configDir) defer os.RemoveAll(targetDir) @@ -620,13 +617,11 @@ func TestLoad_BackwardsCompatibility_Success(t *testing.T) { // Create new config file in .speakeasy dir speakeasyDir := filepath.Join(os.TempDir(), testDir, workspace.SpeakeasyFolder) - err := createTempFile(speakeasyDir, "gen.yaml", readTestFile(t, "v200-gen.yaml")) - require.NoError(t, err) + testutils.CreateTempFile(t, speakeasyDir, "gen.yaml", testutils.ReadTestFile(t, "v200-gen.yaml")) // Create old config file in root dir rootDir := filepath.Join(os.TempDir(), testDir) - err = createTempFile(rootDir, "gen.yaml", readTestFile(t, "v100-gen.yaml")) - require.NoError(t, err) + testutils.CreateTempFile(t, rootDir, "gen.yaml", testutils.ReadTestFile(t, "v100-gen.yaml")) defer os.RemoveAll(speakeasyDir) defer os.RemoveAll(rootDir) @@ -722,7 +717,7 @@ func TestSaveConfig(t *testing.T) { speakeasyPath := filepath.Join(tempDir, ".speakeasy") configPath := filepath.Join(speakeasyPath, "gen.yaml") - err := os.Mkdir(speakeasyPath, 0755) + err := os.Mkdir(speakeasyPath, 0o755) assert.NoError(t, err) err = SaveConfig(tempDir, testCase.cfg, testCase.opts...) @@ -738,7 +733,7 @@ func TestSaveConfig(t *testing.T) { assert.NoError(t, err) assert.Equal(t, false, fileInfo.IsDir()) - assert.Equal(t, fs.FileMode(0644), fileInfo.Mode()) + assert.Equal(t, fs.FileMode(0o644), fileInfo.Mode()) contents, err := os.ReadFile(configPath) assert.NoError(t, err) @@ -782,7 +777,7 @@ management: {} speakeasyPath := filepath.Join(tempDir, ".speakeasy") configPath := filepath.Join(speakeasyPath, "gen.lock") - err := os.Mkdir(speakeasyPath, 0755) + err := os.Mkdir(speakeasyPath, 0o755) assert.NoError(t, err) err = SaveLockFile(tempDir, testCase.lf, testCase.opts...) @@ -798,7 +793,7 @@ management: {} assert.NoError(t, err) assert.Equal(t, false, fileInfo.IsDir()) - assert.Equal(t, fs.FileMode(0644), fileInfo.Mode()) + assert.Equal(t, fs.FileMode(0o644), fileInfo.Mode()) contents, err := os.ReadFile(configPath) assert.NoError(t, err) @@ -806,28 +801,3 @@ management: {} }) } } - -func createTempFile(dir string, fileName, contents string) error { - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return err - } - - if contents != "" { - tmpFile := filepath.Join(dir, fileName) - if err := os.WriteFile(tmpFile, []byte(contents), os.ModePerm); err != nil { - return err - } - } - - return nil -} - -func readTestFile(t *testing.T, file string) string { - t.Helper() - data, err := os.ReadFile(filepath.Join("testdata", file)) - if err != nil { - t.Fatal(err) - } - - return string(data) -} diff --git a/tests/tests.go b/tests/tests.go index 28eada9..443ab3a 100644 --- a/tests/tests.go +++ b/tests/tests.go @@ -17,19 +17,19 @@ const ( ) type Tests struct { - Version string `yaml:"testsVersion"` - Tests map[string][]Test `yaml:"tests"` + Version string `yaml:"testsVersion"` + Tests *orderedmap.OrderedMap[string, []Test] `yaml:"tests"` } type Test struct { - Name string `yaml:"name"` - Description string `yaml:"description,omitempty"` - Targets []string `yaml:"targets,omitempty"` - Server string `yaml:"server,omitempty"` - Security yaml.Node `yaml:"security,omitempty"` - Parameters *Parameters `yaml:"parameters,omitempty"` - RequestBody *orderedmap.OrderedMap[string, yaml.Node] `yaml:"requestBody,omitempty"` - Responses *orderedmap.OrderedMap[string, *orderedmap.OrderedMap[string, yaml.Node]] `yaml:"responses,omitempty"` + Name string `yaml:"name"` + Description string `yaml:"description,omitempty"` + Targets []string `yaml:"targets,omitempty"` + Server string `yaml:"server,omitempty"` + Security yaml.Node `yaml:"security,omitempty"` + Parameters *Parameters `yaml:"parameters,omitempty"` + RequestBody *orderedmap.OrderedMap[string, yaml.Node] `yaml:"requestBody,omitempty"` + Responses *orderedmap.OrderedMap[string, yaml.Node] `yaml:"responses,omitempty"` // Internal use only InternalID string `yaml:"internalId,omitempty"` @@ -72,7 +72,7 @@ func (t Tests) Validate() error { return fmt.Errorf("unsupported tests version: %s", t.Version) } - for operationID, tests := range t.Tests { + for operationID, tests := range t.Tests.FromOldest() { if operationID == "" { return fmt.Errorf("empty operationId found") } @@ -88,15 +88,32 @@ func (t Tests) Validate() error { return fmt.Errorf("test %s has more than one request body", name) } + if test.Responses.Len() == 0 { + return fmt.Errorf("test %s should defined at least one response", name) + } + if test.Responses.Len() > 1 { return fmt.Errorf("test %s has more than one response code", name) } if test.Responses != nil { - for pair := test.Responses.Oldest(); pair != nil; pair = pair.Next() { - responseBody := pair.Value - if responseBody.Len() > 1 { - return fmt.Errorf("test %s has more than one response body", name) + for _, responseBody := range test.Responses.FromOldest() { + switch responseBody.Kind { + case yaml.ScalarNode: + if responseBody.Tag != "!!bool" { + return fmt.Errorf("test %s has invalid response body", name) + } + case yaml.MappingNode: + var contentTypes *orderedmap.OrderedMap[string, yaml.Node] + if err := responseBody.Decode(&contentTypes); err != nil { + return fmt.Errorf("failed to decode response body: %w", err) + } + + if contentTypes.Len() > 1 { + return fmt.Errorf("test %s has more than one response body", name) + } + default: + return fmt.Errorf("test %s has invalid response body", name) } } } @@ -105,3 +122,25 @@ func (t Tests) Validate() error { return nil } + +func (t Test) GetResponse(statusCode string) (*orderedmap.OrderedMap[string, yaml.Node], bool, error) { + if t.Responses == nil { + return nil, false, nil + } + resNode, ok := t.Responses.Get(statusCode) + if !ok { + return nil, false, nil + } + + var res *orderedmap.OrderedMap[string, yaml.Node] + if err := resNode.Decode(&res); err == nil { + return res, false, nil + } + + var assertStatusCode bool + if err := resNode.Decode(&assertStatusCode); err != nil { + return nil, false, fmt.Errorf("failed to decode response body: %w", err) + } + + return nil, assertStatusCode, nil +} diff --git a/tests/tests_test.go b/tests/tests_test.go new file mode 100644 index 0000000..85f867e --- /dev/null +++ b/tests/tests_test.go @@ -0,0 +1,378 @@ +package tests_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/speakeasy-api/sdk-gen-config/tests" + "github.com/speakeasy-api/sdk-gen-config/testutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + orderedmap "github.com/wk8/go-ordered-map/v2" + "gopkg.in/yaml.v3" +) + +func TestLoad_Success(t *testing.T) { + type args struct { + contents string + } + testss := []struct { + name string + args args + want *tests.Tests + }{ + { + name: "loads tests file", + args: args{ + contents: `testsVersion: 0.0.1 +tests: + test: + - name: test + description: test + targets: + - typescript + server: http://localhost:8080 + security: + - api_key: [] + parameters: + path: + id: test + query: + limit: 100 + requestBody: + application/json: {"id": "test", "name": "test"} + responses: + "200": + application/json: + id: test + name: test +`, + }, + want: &tests.Tests{ + Version: "0.0.1", + Tests: orderedmap.New[string, []tests.Test](orderedmap.WithInitialData( + orderedmap.Pair[string, []tests.Test]{ + Key: "test", + Value: []tests.Test{ + { + Name: "test", + Description: "test", + Targets: []string{"typescript"}, + Server: "http://localhost:8080", + Security: yaml.Node{ + Kind: yaml.SequenceNode, + Tag: "!!seq", + Line: 10, + Column: 9, + Content: []*yaml.Node{ + { + Kind: yaml.MappingNode, + Tag: "!!map", + Line: 10, + Column: 11, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "api_key", + Tag: "!!str", + Line: 10, + Column: 11, + }, + { + Kind: yaml.SequenceNode, + Tag: "!!seq", + Style: yaml.FlowStyle, + Line: 10, + Column: 20, + }, + }, + }, + }, + }, + Parameters: &tests.Parameters{ + Path: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "id", + Value: yaml.Node{ + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Line: 13, + Column: 15, + }, + }, + )), + Query: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "limit", + Value: yaml.Node{ + Kind: yaml.ScalarNode, + Value: "100", + Tag: "!!int", + Line: 15, + Column: 18, + }, + }, + )), + }, + RequestBody: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "application/json", + Value: yaml.Node{ + Kind: yaml.MappingNode, + Tag: "!!map", + Line: 17, + Column: 29, + Style: yaml.FlowStyle, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "id", + Tag: "!!str", + Style: yaml.DoubleQuotedStyle, + Line: 17, + Column: 30, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Style: yaml.DoubleQuotedStyle, + Line: 17, + Column: 36, + }, + { + Kind: yaml.ScalarNode, + Value: "name", + Tag: "!!str", + Style: yaml.DoubleQuotedStyle, + Line: 17, + Column: 44, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Style: yaml.DoubleQuotedStyle, + Line: 17, + Column: 52, + }, + }, + }, + }, + )), + Responses: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "200", + Value: yaml.Node{ + Kind: yaml.MappingNode, + Tag: "!!map", + Line: 20, + Column: 11, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "application/json", + Tag: "!!str", + Line: 20, + Column: 11, + }, + { + Kind: yaml.MappingNode, + Tag: "!!map", + Line: 21, + Column: 13, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "id", + Tag: "!!str", + Line: 21, + Column: 13, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Line: 21, + Column: 17, + }, + { + Kind: yaml.ScalarNode, + Value: "name", + Tag: "!!str", + Line: 22, + Column: 13, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Line: 22, + Column: 19, + }, + }, + }, + }, + }, + }, + )), + }, + }, + }, + )), + }, + }, + { + name: "loads test file with simple test", + args: args{ + contents: `testsVersion: 0.0.1 +tests: + test: + - name: test + responses: + "200": true +`, + }, + want: &tests.Tests{ + Version: "0.0.1", + Tests: orderedmap.New[string, []tests.Test](orderedmap.WithInitialData( + orderedmap.Pair[string, []tests.Test]{ + Key: "test", + Value: []tests.Test{ + { + Name: "test", + Responses: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "200", + Value: yaml.Node{ + Kind: yaml.ScalarNode, + Value: "true", + Tag: "!!bool", + Line: 6, + Column: 16, + }, + }, + )), + }, + }, + }, + )), + }, + }, + } + for _, tt := range testss { + t.Run(tt.name, func(t *testing.T) { + testsDir := filepath.Join(os.TempDir(), "tests/.speakeasy") + testutils.CreateTempFile(t, testsDir, "tests.yaml", tt.args.contents) + defer os.RemoveAll(testsDir) + + loadedTests, _, err := tests.Load(testsDir) + require.NoError(t, err) + + assert.Equal(t, tt.want, loadedTests) + }) + } +} + +func TestTest_GetResponse_Success(t *testing.T) { + type args struct { + contents string + } + testss := []struct { + name string + args args + wantResBody *orderedmap.OrderedMap[string, yaml.Node] + wantAssertStatusCode bool + }{ + { + name: "get response body", + args: args{ + contents: `testsVersion: 0.0.1 +tests: + test: + - name: test + responses: + "200": + application/json: + id: test + name: test +`, + }, + wantResBody: orderedmap.New[string, yaml.Node](orderedmap.WithInitialData( + orderedmap.Pair[string, yaml.Node]{ + Key: "application/json", + Value: yaml.Node{ + Kind: yaml.MappingNode, + Tag: "!!map", + Line: 8, + Column: 13, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "id", + Tag: "!!str", + Line: 8, + Column: 13, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Line: 8, + Column: 17, + }, + { + Kind: yaml.ScalarNode, + Value: "name", + Tag: "!!str", + Line: 9, + Column: 13, + }, + { + Kind: yaml.ScalarNode, + Value: "test", + Tag: "!!str", + Line: 9, + Column: 19, + }, + }, + }, + }, + )), + }, + { + name: "get assert status code", + args: args{ + contents: `testsVersion: 0.0.1 +tests: + test: + - name: test + responses: + "200": true +`, + }, + wantAssertStatusCode: true, + }, + } + for _, tt := range testss { + t.Run(tt.name, func(t *testing.T) { + testsDir := filepath.Join(os.TempDir(), "tests/.speakeasy") + testutils.CreateTempFile(t, testsDir, "tests.yaml", tt.args.contents) + defer os.RemoveAll(testsDir) + + loadedTests, _, err := tests.Load(testsDir) + require.NoError(t, err) + + test, ok := loadedTests.Tests.Get("test") + require.True(t, ok) + + resBody, assertStatusCode, err := test[0].GetResponse("200") + require.NoError(t, err) + + assert.Equal(t, tt.wantResBody, resBody) + assert.Equal(t, tt.wantAssertStatusCode, assertStatusCode) + }) + } +} diff --git a/testutils/testutils.go b/testutils/testutils.go new file mode 100644 index 0000000..c6c0340 --- /dev/null +++ b/testutils/testutils.go @@ -0,0 +1,33 @@ +package testutils + +import ( + "os" + "path/filepath" + "testing" +) + +func CreateTempFile(t *testing.T, dir string, fileName, contents string) { + t.Helper() + + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + t.Fatal(err) + } + + if contents != "" { + tmpFile := filepath.Join(dir, fileName) + if err := os.WriteFile(tmpFile, []byte(contents), os.ModePerm); err != nil { + t.Fatal(err) + } + } +} + +func ReadTestFile(t *testing.T, file string) string { + t.Helper() + + data, err := os.ReadFile(filepath.Join("testdata", file)) + if err != nil { + t.Fatal(err) + } + + return string(data) +}