From cf0a1d9d22a09990a1c890934e4cb8593d859f9c Mon Sep 17 00:00:00 2001 From: Alex ATorres Date: Tue, 2 Apr 2024 05:02:29 +0200 Subject: [PATCH] feat: Add test for ProcessTemplFile function Added a test function for ProcessTemplFile in processor_test.go to cover various scenarios such as file existence, directory creation, template parsing, destination file creation, template execution, and error handling. --- go.mod | 2 +- pkg/gh/release.go | 8 +-- pkg/tmplutils/processor.go | 42 ++++++++++++++ pkg/tmplutils/processor_test.go | 100 ++++++++++++++++++++++++++++++++ pkg/utils/git.go | 2 +- 5 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 pkg/tmplutils/processor.go create mode 100644 pkg/tmplutils/processor_test.go diff --git a/go.mod b/go.mod index 05f7060..afba021 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/gruntwork-io/terratest v0.46.11 github.com/hashicorp/terraform-json v0.13.0 github.com/stretchr/testify v1.8.4 + golang.org/x/oauth2 v0.8.0 ) require ( @@ -88,7 +89,6 @@ require ( go.opencensus.io v0.24.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/pkg/gh/release.go b/pkg/gh/release.go index 292ac75..fe64473 100644 --- a/pkg/gh/release.go +++ b/pkg/gh/release.go @@ -36,16 +36,16 @@ func FetchReleases(repoURL string, onlyLatest bool) ([]*github.RepositoryRelease return []*github.RepositoryRelease{release}, nil } - releases, _, err := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("error fetching releases: %w", err) + releases, _, releaseErr := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{}) + if releaseErr != nil { + return nil, fmt.Errorf("error fetching releases: %w", releaseErr) } return releases, nil } // GetOwnerAndRepoFromURL extracts the owner and repo name from a GitHub URL -func GetOwnerAndRepoFromURL(repoURL string) (string, string, error) { +func GetOwnerAndRepoFromURL(repoURL string) (owner, repo string, err error) { u, err := url.Parse(repoURL) if err != nil { return "", "", fmt.Errorf("error parsing URL: %w", err) diff --git a/pkg/tmplutils/processor.go b/pkg/tmplutils/processor.go new file mode 100644 index 0000000..f8e1cc2 --- /dev/null +++ b/pkg/tmplutils/processor.go @@ -0,0 +1,42 @@ +package tmplutils + +import ( + "fmt" + "html/template" + "os" + "path/filepath" +) + +// ProcessTemplFile processes a template file with the provided data and writes the output to the destination file. +// It returns an error if any of the operations fail. +// The function map is used to define custom functions that can be called from the template. +func ProcessTemplFile(templatePath, destPath string, funcMap template.FuncMap, data interface{}) error { + content, err := os.ReadFile(templatePath) + if err != nil { + return fmt.Errorf("failed to read template file: %w", err) + } + + if err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil { + return fmt.Errorf("failed to create parent directory for %s: %w", destPath, err) + } + + tmpl, tmplErr := template.New(filepath.Base(templatePath)).Funcs(funcMap).Parse(string(content)) + if tmplErr != nil { + return fmt.Errorf("failed to parse template: %w", tmplErr) + } + + // Write to destination with processed content + file, fileErr := os.Create(destPath) + if fileErr != nil { + return fmt.Errorf("failed to create destination file: %w", fileErr) + } + + defer file.Close() + + // Execute the template with provided data + if err := tmpl.Execute(file, data); err != nil { + return fmt.Errorf("failed to execute template with provided data: %w", err) + } + + return nil +} diff --git a/pkg/tmplutils/processor_test.go b/pkg/tmplutils/processor_test.go new file mode 100644 index 0000000..b28c550 --- /dev/null +++ b/pkg/tmplutils/processor_test.go @@ -0,0 +1,100 @@ +package tmplutils + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "text/template" + + "github.com/stretchr/testify/assert" +) + +func TestProcessTemplFile(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Define test cases + testCases := []struct { + name string + templatePath string + destPath string + funcMap template.FuncMap + data interface{} + expectError bool + }{ + { + name: "Template file does not exist", + templatePath: "nonexistent", + destPath: filepath.Join(tempDir, "dest"), + expectError: true, + }, + { + name: "Cannot create destination directory", + templatePath: filepath.Join(tempDir, "template"), + destPath: "/invalid/path/dest", + expectError: true, + }, + { + name: "Cannot parse template", + templatePath: filepath.Join(tempDir, "invalid_template"), + destPath: filepath.Join(tempDir, "dest"), + expectError: true, + }, + { + name: "Cannot create destination file", + templatePath: filepath.Join(tempDir, "template"), + destPath: "/invalid/path/dest", + expectError: true, + }, + { + name: "Template execution fails", + templatePath: filepath.Join(tempDir, "template"), + destPath: filepath.Join(tempDir, "dest"), + funcMap: template.FuncMap{"fail": func() (string, error) { return "", fmt.Errorf("fail") }}, + data: map[string]interface{}{"Value": "fail"}, + expectError: true, + }, + { + name: "Everything is correct", + templatePath: filepath.Join(tempDir, "template"), + destPath: filepath.Join(tempDir, "dest"), + expectError: false, + }, + } + + // Run test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create template file if it should exist + if tc.templatePath != "nonexistent" { + var content []byte + if tc.templatePath == filepath.Join(tempDir, "invalid_template") { + content = []byte("{{") + } else if tc.name == "Template execution fails" { + content = []byte("{{fail}}") // Call the "fail" function in the template + } else { + content = []byte("{{.Value}}") + } + err := os.WriteFile(tc.templatePath, content, 0644) + if err != nil { + t.Fatalf("Failed to create template file: %v", err) + } + } + + // Call ProcessTemplFile + err := ProcessTemplFile(tc.templatePath, tc.destPath, tc.funcMap, tc.data) + + // Check if error is expected + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/pkg/utils/git.go b/pkg/utils/git.go index 75b3d6e..db1b014 100644 --- a/pkg/utils/git.go +++ b/pkg/utils/git.go @@ -8,7 +8,7 @@ import ( // IsAGitRepository checks if the given directory or any of its parent directories up to `levels` is a git repository. // It returns the git root directory, the subdirectory passed relative to the git root, and any error encountered. -func IsAGitRepository(repoRoot string, levels int) (gitRoot string, subDir string, err error) { +func IsAGitRepository(repoRoot string, levels int) (gitRoot, subDir string, err error) { if repoRoot == "" { return "", "", fmt.Errorf("directory path cannot be empty") }