Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add unit tests to variables pkg #2519

Merged
merged 13 commits into from
May 23, 2024
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,5 @@ cve-report: ## Create a CVE report for the current project (must `brew install g
@test -d ./build || mkdir ./build
go run main.go tools sbom scan . -o json --exclude './site' --exclude './examples' | grype -o template -t hack/grype.tmpl > build/zarf-known-cves.csv

lint-go: ## Run golang-ci-lint to lint the go code (must `brew install golang-ci-lint` first)
lint-go: ## Run golang-ci-lint to lint the go code (must `brew install golangci-lint` first)
golangci-lint run
150 changes: 150 additions & 0 deletions src/pkg/variables/templates_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors

package variables

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

var start = `
This is a test file for templating.

###PREFIX_VAR_REPLACE_ME###
###PREFIX_CONST_REPLACE_ME###
###PREFIX_APP_REPLACE_ME###
###PREFIX_NON_EXIST###
`
var simple = `
This is a test file for templating.

VAR_REPLACED
CONST_REPLACED
APP_REPLACED
###PREFIX_NON_EXIST###
`
var multiline = `
This is a test file for templating.

VAR_REPLACED
VAR_SECOND
CONST_REPLACED
CONST_SECOND
APP_REPLACED
APP_SECOND
###PREFIX_NON_EXIST###
`
var autoIndent = `
This is a test file for templating.

VAR_REPLACED
VAR_SECOND
CONST_REPLACED
CONST_SECOND
APP_REPLACED
APP_SECOND
###PREFIX_NON_EXIST###
`
var file = `
This is a test file for templating.

The contents of this file become the template value
CONSTs Don't Support File
The contents of this file become the template value
###PREFIX_NON_EXIST###
`

func TestReplaceTextTemplate(t *testing.T) {
type test struct {
vc VariableConfig
path string
wantErr bool
wantContents string
}

tests := []test{
{
vc: VariableConfig{setVariableMap: SetVariableMap{}, applicationTemplates: map[string]*TextTemplate{}},
path: "non-existent.test",
wantErr: true,
wantContents: start,
},
{
vc: VariableConfig{
templatePrefix: "PREFIX",
setVariableMap: SetVariableMap{
"REPLACE_ME": {Value: "VAR_REPLACED"},
},
constants: []Constant{{Name: "REPLACE_ME", Value: "CONST_REPLACED"}},
applicationTemplates: map[string]*TextTemplate{
"###PREFIX_APP_REPLACE_ME###": {Value: "APP_REPLACED"},
},
},
wantContents: simple,
},
{
vc: VariableConfig{
templatePrefix: "PREFIX",
setVariableMap: SetVariableMap{
"REPLACE_ME": {Value: "VAR_REPLACED\nVAR_SECOND"},
},
constants: []Constant{{Name: "REPLACE_ME", Value: "CONST_REPLACED\nCONST_SECOND"}},
applicationTemplates: map[string]*TextTemplate{
"###PREFIX_APP_REPLACE_ME###": {Value: "APP_REPLACED\nAPP_SECOND"},
},
},
wantContents: multiline,
},
{
vc: VariableConfig{
templatePrefix: "PREFIX",
setVariableMap: SetVariableMap{
"REPLACE_ME": {Value: "VAR_REPLACED\nVAR_SECOND", Variable: Variable{AutoIndent: true}},
},
constants: []Constant{{Name: "REPLACE_ME", Value: "CONST_REPLACED\nCONST_SECOND", AutoIndent: true}},
applicationTemplates: map[string]*TextTemplate{
"###PREFIX_APP_REPLACE_ME###": {Value: "APP_REPLACED\nAPP_SECOND", AutoIndent: true},
},
},
wantContents: autoIndent,
},
{
vc: VariableConfig{
templatePrefix: "PREFIX",
setVariableMap: SetVariableMap{
"REPLACE_ME": {Value: "testdata/file.txt", Variable: Variable{Type: FileVariableType}},
},
constants: []Constant{{Name: "REPLACE_ME", Value: "CONSTs Don't Support File"}},
applicationTemplates: map[string]*TextTemplate{
"###PREFIX_APP_REPLACE_ME###": {Value: "testdata/file.txt", Type: FileVariableType},
},
},
wantContents: file,
},
}

for _, tc := range tests {
if tc.path == "" {
tmpDir := t.TempDir()
tc.path = filepath.Join(tmpDir, "templates.test")

f, _ := os.Create(tc.path)
defer f.Close()

f.WriteString(start)
}

gotErr := tc.vc.ReplaceTextTemplate(tc.path)
if tc.wantErr {
require.Error(t, gotErr)
} else {
require.NoError(t, gotErr)
gotContents, _ := os.ReadFile(tc.path)
require.Equal(t, tc.wantContents, string(gotContents))
}
}
}
1 change: 1 addition & 0 deletions src/pkg/variables/testdata/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The contents of this file become the template value
15 changes: 12 additions & 3 deletions src/pkg/variables/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,18 @@ func (vc *VariableConfig) SetVariable(name, value string, sensitive bool, autoIn

// CheckVariablePattern checks to see if a current variable is set to a value that matches its pattern
func (vc *VariableConfig) CheckVariablePattern(name, pattern string) error {
if regexp.MustCompile(pattern).MatchString(vc.setVariableMap[name].Value) {
return nil
if variable, ok := vc.setVariableMap[name]; ok {
r, err := regexp.Compile(pattern)
if err != nil {
return err
}

if r.MatchString(variable.Value) {
return nil
}

return fmt.Errorf("provided value for variable %q does not match pattern %q", name, pattern)
}

return fmt.Errorf("provided value for variable %q does not match pattern %q", name, pattern)
return fmt.Errorf("variable %q was not found in the current variable map", name)
}
159 changes: 159 additions & 0 deletions src/pkg/variables/variables_test.go
Racer159 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors

package variables

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPopulateVariables(t *testing.T) {
type test struct {
vc VariableConfig
vars []InteractiveVariable
presets map[string]string
wantErr bool
wantVars SetVariableMap
}

prompt := func(_ InteractiveVariable) (value string, err error) { return "Prompt", nil }

tests := []test{
{
vc: VariableConfig{setVariableMap: SetVariableMap{}},
vars: []InteractiveVariable{{Variable: Variable{Name: "NAME"}}},
presets: map[string]string{},
wantVars: SetVariableMap{"NAME": {Variable: Variable{Name: "NAME"}}},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME"}, Default: "Default"},
},
presets: map[string]string{},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME"}, Value: "Default"},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME"}, Default: "Default"},
},
presets: map[string]string{"NAME": "Set"},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME"}, Value: "Set"},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME", Sensitive: true, AutoIndent: true, Type: FileVariableType}},
},
presets: map[string]string{},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME", Sensitive: true, AutoIndent: true, Type: FileVariableType}},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME", Sensitive: true, AutoIndent: true, Type: FileVariableType}},
},
presets: map[string]string{"NAME": "Set"},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME", Sensitive: true, AutoIndent: true, Type: FileVariableType}, Value: "Set"},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}, prompt: prompt},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME"}, Prompt: true},
},
presets: map[string]string{},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME"}, Value: "Prompt"},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}, prompt: prompt},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME"}, Default: "Default", Prompt: true},
},
presets: map[string]string{},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME"}, Value: "Prompt"},
},
},
{
vc: VariableConfig{setVariableMap: SetVariableMap{}, prompt: prompt},
vars: []InteractiveVariable{
{Variable: Variable{Name: "NAME"}, Prompt: true},
},
presets: map[string]string{"NAME": "Set"},
wantVars: SetVariableMap{
"NAME": {Variable: Variable{Name: "NAME"}, Value: "Set"},
},
},
}

for _, tc := range tests {
gotErr := tc.vc.PopulateVariables(tc.vars, tc.presets)
if tc.wantErr {
require.Error(t, gotErr)
} else {
require.NoError(t, gotErr)
}

gotVars := tc.vc.setVariableMap

require.Equal(t, len(gotVars), len(tc.wantVars))

for key := range gotVars {
require.Equal(t, gotVars[key], tc.wantVars[key])
}
}
}

func TestCheckVariablePattern(t *testing.T) {
type test struct {
vc VariableConfig
name string
pattern string
wantErrMsg string
}

tests := []test{
{
vc: VariableConfig{setVariableMap: SetVariableMap{}}, name: "NAME", pattern: "n[a-z]me",
wantErrMsg: "variable \"NAME\" was not found in the current variable map",
},
{
vc: VariableConfig{
setVariableMap: SetVariableMap{"NAME": &SetVariable{Value: "name"}},
}, name: "NAME", pattern: "n[^a]me",
wantErrMsg: "provided value for variable \"NAME\" does not match pattern \"n[^a]me\"",
},
{
vc: VariableConfig{
setVariableMap: SetVariableMap{"NAME": &SetVariable{Value: "name"}},
}, name: "NAME", pattern: "n[a-z]me", wantErrMsg: "",
},
{
vc: VariableConfig{
setVariableMap: SetVariableMap{"NAME": &SetVariable{Value: "name"}},
}, name: "NAME", pattern: "n[a-z-bad-pattern", wantErrMsg: "error parsing regexp: missing closing ]: `[a-z-bad-pattern`",
},
}

for _, tc := range tests {
got := tc.vc.CheckVariablePattern(tc.name, tc.pattern)
if tc.wantErrMsg != "" {
require.EqualError(t, got, tc.wantErrMsg)
} else {
require.NoError(t, got)
}
}
}
Loading