fuzzyworld

template / commit

Added more tests.

05f9e8ef1f0d26e2462ee66f2ab25734124f4ec5 · Pavel Safronov · 2022-10-06 13:23:27 -0700 · parents a4642553b09c

Added more tests.
 Makefile        |  9 +++++++--
 config.go       | 10 ++++------
 config_test.go  | 46 ++++++++++++++++++++++++++++++++-------------
 extras_test.go  |  9 +++++++++
 file.go         | 13 ++++---------
 main.go         | 11 +++++++++--
 name_pattern.go |  9 +++++----
 profile.go      | 39 +++++++++++++++++---------------------
 profile_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 utils.go        |  8 ++------
 utils_test.go   | 11 ++++-------
 11 files changed, 146 insertions(+), 77 deletions(-)

diff --git a/Makefile b/Makefile
index abda531..28a2431 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,9 @@
-SHELL := pwsh
+ifeq ($(OS),Windows_NT)
+    SHELL := pwsh.exe
+else
+    SHELL := pwsh
+endif
+
 .SHELLFLAGS := -Command
 
 BINARY_NAME := template
@@ -12,7 +17,7 @@ install: build
 	./scripts/clean-install.ps1
 
 test: build
-	@New-Item -ItemType Directory -Force -Path ./test | out-null
+	New-Item -ItemType Directory -Force -Path ./test | out-null
 	go test -v ./... -coverprofile="./test/coverage.out"
 
 test_coverage: test
diff --git a/config.go b/config.go
index c8a6526..dab0302 100644
--- a/config.go
+++ b/config.go
@@ -3,6 +3,7 @@ package main
 import (
 	"fmt"
 	"os"
+	"os/user"
 
 	"gopkg.in/yaml.v3"
 )
@@ -178,7 +179,7 @@ func validateConfig(config Config) error {
 		}
 		error := validateProfile(profile)
 		if error != nil {
-			return error
+			return fmt.Errorf("error validating profile %s: %s", profile.Name, error)
 		}
 	}
 	return nil
@@ -214,13 +215,10 @@ func saveConfig(path string, config Config) error {
 	return nil
 }
 
-func getOrCreateConfig(configFilePath string) (Config, error) {
+func getOrCreateConfig(configFilePath string, usr user.User) (Config, error) {
 	emptyConfig := Config{}
 
-	fullConfigPath, err := getFullPath(configFilePath)
-	if err != nil {
-		return emptyConfig, fmt.Errorf("failed to get full path for config file %v: %v", configFilePath, err)
-	}
+	fullConfigPath := getFullPath(configFilePath, usr)
 
 	// try and load config
 	config, err := loadConfig(fullConfigPath)
diff --git a/config_test.go b/config_test.go
index eca3067..59a30ff 100644
--- a/config_test.go
+++ b/config_test.go
@@ -3,17 +3,21 @@ package main
 import (
 	"errors"
 	"os"
+	"os/user"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
 func TestSaveLoadConfig(t *testing.T) {
+	usr, err := user.Current()
+	assert.Nil(t, err)
+
 	config := defaultConfig()
 	configPath := "./test/test-config.yaml"
 
 	// save config
-	err := saveConfig(configPath, config)
+	err = saveConfig(configPath, config)
 	assert.Nil(t, err, "Error saving config")
 
 	// load config
@@ -44,7 +48,7 @@ func TestSaveLoadConfig(t *testing.T) {
 	assert.True(t, errors.Is(err, os.ErrNotExist), "Expected config file to not exist, but it does")
 
 	// get and create config
-	loadedConfig, err = getOrCreateConfig(configPath)
+	loadedConfig, err = getOrCreateConfig(configPath, *usr)
 	assert.Nil(t, err, "Error loading config")
 
 	// test config
@@ -55,7 +59,7 @@ func TestSaveLoadConfig(t *testing.T) {
 	assert.Nil(t, err, "Expected config file to exist, but it does not")
 
 	// get and create config
-	loadedConfig, err = getOrCreateConfig(configPath)
+	loadedConfig, err = getOrCreateConfig(configPath, *usr)
 	assert.Nil(t, err, "Error loading config")
 
 	// test config
@@ -68,14 +72,15 @@ func TestSaveLoadConfig(t *testing.T) {
 }
 
 func TestGetOrCreateConfig(t *testing.T) {
+	usr, err := user.Current()
+	assert.Nil(t, err)
 	testFailure := func(configPath string) {
-		_, err := getOrCreateConfig(configPath)
+		_, err := getOrCreateConfig(configPath, *usr)
 		if err == nil {
 			t.Errorf("Expected to fail to get or create config, but succeeded")
 		}
 	}
 
-	testFailure("~~~")
 	testFailure("invalid/path/invalid-config.yaml")
 }
 
@@ -88,23 +93,38 @@ func TestValidateDefaultConfig(t *testing.T) {
 }
 
 func TestValidateConfig(t *testing.T) {
-	testFailure := func(config Config) {
+	testFailure := func(config Config, errorText string) {
 		err := validateConfig(config)
 		if err == nil {
 			t.Errorf("Expected to fail to validate config, but succeeded")
 		}
+		assert.Contains(t, err.Error(), errorText)
 	}
 
-	testFailure(Config{})
-	testFailure(Config{Profiles: []Profile{}})
+	testFailure(Config{}, "no profiles found")
+	testFailure(Config{Profiles: []Profile{}}, "no profiles found")
+	testFailure(Config{Profiles: []Profile{
+		{
+			Name:         "daily",
+			IsDefault:    true,
+			NamePatterns: []string{"daily"},
+			FileTemplate: "foo",
+		},
+	}}, "error validating profile")
 	testFailure(Config{Profiles: []Profile{
 		{
-			Name:      "daily",
-			IsDefault: true,
+			Name:         "daily",
+			IsDefault:    true,
+			NamePatterns: []string{"daily"},
+			Type:         FileType,
+			FileTemplate: "foo",
 		},
 		{
-			Name:      "daily2",
-			IsDefault: true,
+			Name:         "daily2",
+			IsDefault:    true,
+			NamePatterns: []string{"daily"},
+			Type:         FileType,
+			FileTemplate: "foo",
 		},
-	}})
+	}}, "multiple default profiles found")
 }
diff --git a/extras_test.go b/extras_test.go
index 9a72542..5719ab0 100644
--- a/extras_test.go
+++ b/extras_test.go
@@ -49,4 +49,13 @@ func TestExtras(t *testing.T) {
 		t.Error("Error loading extras: ", error)
 	}
 	assert.Equal(t, extras, loadedExtras)
+
+	// test path errors
+	_, error = loadExtras("non-existent-file.yaml")
+	assert.NotNil(t, error, "Expected to fail to load extras, but succeeded")
+
+	os.WriteFile(file.Name(), []byte("invalid yaml"), 0644)
+
+	_, error = loadExtras(fileName)
+	assert.NotNil(t, error, "Expected to fail to parse extras, but succeeded")
 }
diff --git a/file.go b/file.go
index f604e55..e364f77 100644
--- a/file.go
+++ b/file.go
@@ -3,6 +3,7 @@ package main
 import (
 	"fmt"
 	"os"
+	"os/user"
 	"path/filepath"
 	"strings"
 	"text/template"
@@ -29,19 +30,13 @@ func createFilePatternData(now time.Time, projectName string, name string, extra
 	}
 }
 
-func createTemplateFile(srcPath string, destPath string, projectName string, name string, extras map[string]string) error {
+func createTemplateFile(srcPath string, destPath string, projectName string, name string, extras map[string]string, usr user.User) error {
 	now := time.Now()
 	filePatternData := createFilePatternData(now, projectName, name, extras)
 
 	// standardize paths
-	srcPath, err := getFullPath(srcPath)
-	if err != nil {
-		return err
-	}
-	destPath, err = getFullPath(destPath)
-	if err != nil {
-		return err
-	}
+	srcPath = getFullPath(srcPath, usr)
+	destPath = getFullPath(destPath, usr)
 
 	// parse template
 	srcName := filepath.Base(srcPath) // srcName is required because we are sending files to ParseFiles
diff --git a/main.go b/main.go
index 028a555..c0ea6ab 100644
--- a/main.go
+++ b/main.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"log"
 	"os"
+	"os/user"
 	"strings"
 
 	"github.com/urfave/cli/v2" // imports as package "cli"
@@ -17,6 +18,7 @@ func main() {
 	var extrasFilePath string
 	var useDefaultConfig bool
 	var err error
+	var usr *user.User
 
 	app := &cli.App{
 		Name:                 "template",
@@ -65,12 +67,17 @@ func main() {
 		},
 		Action: func(context *cli.Context) error {
 
+			usr, err = user.Current()
+			if err != nil {
+				log.Fatal(err)
+			}
+
 			// get config
 			var config Config
 			if useDefaultConfig {
 				config = defaultConfig()
 			} else {
-				config, err = getOrCreateConfig(configFilePath)
+				config, err = getOrCreateConfig(configFilePath, *usr)
 				if err != nil {
 					return err
 				}
@@ -136,7 +143,7 @@ func main() {
 			}
 
 			// process profile
-			err = processProfile(profile, projectName, extras)
+			err = processProfile(profile, projectName, extras, *usr)
 			if err != nil {
 				return fmt.Errorf("error processing profile: %v", err)
 			}
diff --git a/name_pattern.go b/name_pattern.go
index c383b63..32fb4d3 100644
--- a/name_pattern.go
+++ b/name_pattern.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"errors"
+	"fmt"
 	"strings"
 	"text/template"
 	"time"
@@ -42,13 +43,13 @@ func createNewNameForProfile(now time.Time, projectName string, profile Profile,
 
 			template, err := template.Parse(namePattern)
 			if err != nil {
-				return "", err
+				return "", fmt.Errorf("error parsing name pattern %d: %w", index, err)
 			}
 
 			sb := new(strings.Builder)
 			err = template.Execute(sb, patternData)
 			if err != nil {
-				return "", err
+				return "", fmt.Errorf("error executing name pattern %d: %w", index, err)
 			}
 
 			newName := sb.String()
@@ -68,11 +69,11 @@ func createNewNameForProfile(now time.Time, projectName string, profile Profile,
 
 			// if getVersion was used, but this isn't the last pattern, report an error
 			if useIndex && !isLastPattern {
-				return "", errors.New("Cannot use function getVersion in a pattern that is not the last pattern")
+				return "", errors.New("cannot use function getVersion in a pattern that is not the last pattern")
 			}
 
 			startingVersion++
 		}
 	}
-	return "", errors.New("Couldn't find a new name")
+	return "", errors.New("couldn't find a new name")
 }
diff --git a/profile.go b/profile.go
index fd19ac1..888ee70 100644
--- a/profile.go
+++ b/profile.go
@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -59,24 +60,18 @@ func findProfile(config Config, profileName string) (Profile, error) {
 				return p, nil
 			}
 		}
-	} else {
-		// find profile by name
-		for _, p := range config.Profiles {
-			if p.Name == profileName {
-				return p, nil
-			}
+		return Profile{}, errors.New("no default profile found")
+	}
+	// find profile by name
+	for _, p := range config.Profiles {
+		if p.Name == profileName {
+			return p, nil
 		}
-		return Profile{}, fmt.Errorf("unable to find profile '%v'", profileName)
 	}
-	return Profile{}, errors.New("couldn't find profile")
+	return Profile{}, fmt.Errorf("unable to find profile '%v'", profileName)
 }
 
-func processProfile(profile Profile, projectName string, extras map[string]string) error {
-	// validate profile
-	if profile.NamePatterns == nil || len(profile.NamePatterns) == 0 {
-		return errors.New("no name patterns specified")
-	}
-
+func processProfile(profile Profile, projectName string, extras map[string]string, usr user.User) error {
 	// decide if the profile should run on this OS
 	profileOs := profile.OS
 	isWindows := runtime.GOOS == "windows"
@@ -95,10 +90,7 @@ func processProfile(profile Profile, projectName string, extras map[string]strin
 	}
 	if profile.Path != "" {
 		// change cwd to the profile's path, if one is specified
-		path, err := getFullPath(profile.Path)
-		if err != nil {
-			return fmt.Errorf("unable to get full path for '%v': %v", profile.Path, err)
-		}
+		path := getFullPath(profile.Path, usr)
 		err = os.Chdir(path)
 		if err != nil {
 			return fmt.Errorf("unable to change directory to %v: %v", path, err)
@@ -153,7 +145,7 @@ func processProfile(profile Profile, projectName string, extras map[string]strin
 		useTemplate := profile.FileTemplate != ""
 		if useTemplateFile {
 			fmt.Printf("Creating file '%v' from template: %v\n", fullPath, profile.FileTemplatePath)
-			err := createTemplateFile(profile.FileTemplatePath, fullPath, projectName, newName, extras)
+			err := createTemplateFile(profile.FileTemplatePath, fullPath, projectName, newName, extras, usr)
 			if err != nil {
 				return fmt.Errorf("error creating template file: %v", err)
 			}
@@ -203,15 +195,18 @@ func validateProfile(profile Profile) error {
 	if profile.NamePatterns == nil || len(profile.NamePatterns) == 0 {
 		return fmt.Errorf("no name patterns found for profile %s", profile.Name)
 	}
-	if profile.Path != "" && strings.Contains(profile.Path, "\\") {
-		return fmt.Errorf("invalid path for profile %s: %s", profile.Name, profile.Path)
-	}
 	if profile.Type == "" || (profile.Type != FileType && profile.Type != FolderType && profile.Type != ScriptType) {
 		return fmt.Errorf("invalid profile type %s for profile %s", profile.Type, profile.Name)
 	}
 	if profile.Type != FileType && profile.FileTemplatePath != "" {
 		return fmt.Errorf("file template path is not supported for profile %s, which has Type=%s", profile.Name, profile.Type)
 	}
+	if profile.Type != FileType && profile.FileTemplate != "" {
+		return fmt.Errorf("file template is not supported for profile %s, which has Type=%s", profile.Name, profile.Type)
+	}
+	if profile.Type == FileType && profile.FileTemplatePath != "" && profile.FileTemplate != "" {
+		return fmt.Errorf("both file template path and file template are specified for profile %s", profile.Name)
+	}
 	if profile.Type == ScriptType && profile.NamePatterns != nil && len(profile.NamePatterns) > 1 {
 		return fmt.Errorf("multiple name patterns are not supported for profile %s, which has Type=%s", profile.Name, profile.Type)
 	}
diff --git a/profile_test.go b/profile_test.go
index 2eb60aa..f2c747f 100644
--- a/profile_test.go
+++ b/profile_test.go
@@ -23,6 +23,18 @@ func TestValidateProfile(t *testing.T) {
 		Name:         "daily",
 		NamePatterns: []string{"{{.Date}}"},
 	})
+	testSuccess(Profile{
+		Type:         FileType,
+		Name:         "daily",
+		NamePatterns: []string{"{{.Date}}"},
+		FileTemplate: "foo",
+	})
+	testSuccess(Profile{
+		Type:             FileType,
+		Name:             "daily",
+		NamePatterns:     []string{"{{.Date}}"},
+		FileTemplatePath: "foo",
+	})
 
 	// empty name
 	testFailure(Profile{
@@ -51,12 +63,42 @@ func TestValidateProfile(t *testing.T) {
 		Name:         "daily",
 		NamePatterns: []string{},
 	})
-	// testFailure(Profile{
-	// 	Type:         FileType,
-	// 	Name:         "daily",
-	// 	NamePatterns: []string{"test"},
-	// 	FileTemplatePath: "",
-	// })
+	// file template and file template path are set
+	testFailure(Profile{
+		Type:             FileType,
+		Name:             "daily",
+		NamePatterns:     []string{"test"},
+		FileTemplatePath: "foo",
+		FileTemplate:     "bar",
+	})
+	// file template set with wrong type
+	testFailure(Profile{
+		Type:         FolderType,
+		Name:         "daily",
+		NamePatterns: []string{"test"},
+		FileTemplate: "bar",
+	})
+	// file template path set with wrong type
+	testFailure(Profile{
+		Type:             FolderType,
+		Name:             "daily",
+		NamePatterns:     []string{"test"},
+		FileTemplatePath: "bar",
+	})
+	// script type with multiple name patterns
+	testFailure(Profile{
+		Type:         ScriptType,
+		Name:         "daily",
+		NamePatterns: []string{"test", "test2"},
+	})
+	// postscripts with no shell
+	testFailure(Profile{
+		Type:         ScriptType,
+		Name:         "daily",
+		NamePatterns: []string{"test"},
+		PostScripts:  []string{"test"},
+		ScriptShell:  "",
+	})
 
 	for _, profile := range defaultConfig().Profiles {
 		testSuccess(profile)
@@ -96,4 +138,8 @@ func TestFindProfile(t *testing.T) {
 	testSuccess("notes", "notes")
 
 	testFailure("non-existent")
+
+	config.Profiles[1].IsDefault = false
+	testFailure("")
+	testFailure("non-default")
 }
diff --git a/utils.go b/utils.go
index 4cda077..7a794bb 100644
--- a/utils.go
+++ b/utils.go
@@ -6,11 +6,7 @@ import (
 	"strings"
 )
 
-func getFullPath(path string) (string, error) {
-	usr, error := user.Current()
-	if error != nil {
-		return "", error
-	}
+func getFullPath(path string, usr user.User) string {
 	dir := usr.HomeDir
 	var newPath string
 	if path == "~" {
@@ -20,5 +16,5 @@ func getFullPath(path string) (string, error) {
 	} else {
 		newPath = path
 	}
-	return newPath, nil
+	return newPath
 }
diff --git a/utils_test.go b/utils_test.go
index 1cd946f..851bdca 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -8,11 +8,11 @@ import (
 )
 
 func TestGetFullPath(t *testing.T) {
+	usr, err := user.Current()
+	assert.Nil(t, err)
+
 	testSuccess := func(path string, expected string) {
-		fullPath, err := getFullPath(path)
-		if err != nil {
-			t.Errorf("Expected to get full path for '%v', but failed: %v", path, err)
-		}
+		fullPath := getFullPath(path, *usr)
 		if fullPath != expected {
 			t.Errorf("Expected to get full path '%v' for '%v', but got '%v'", expected, path, fullPath)
 		}
@@ -29,9 +29,6 @@ func TestGetFullPath(t *testing.T) {
 	testSuccess("C:\\test\\", "C:\\test\\")
 	testSuccess("C:\\test\\..", "C:\\test\\..") // WRONG
 
-	usr, err := user.Current()
-	assert.NoError(t, err, "Failed to get current user")
-
 	testSuccess("~/", usr.HomeDir)
 	testSuccess("~", usr.HomeDir)
 }